eyeglass
Version:
Sass modules for npm.
256 lines • 10.5 kB
JavaScript
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const debug = __importStar(require("../util/debug"));
const SassImplementation_1 = require("../util/SassImplementation");
const URI_1 = require("../util/URI");
const AssetsCollection_1 = __importDefault(require("./AssetsCollection"));
const typescriptUtils_1 = require("../util/typescriptUtils");
const errorFor_1 = __importDefault(require("../util/errorFor"));
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
const ensureSymlink = require("ensure-symlink");
class Assets {
constructor(eyeglass, sassImpl) {
this.sassImpl = sassImpl;
this.eyeglass = eyeglass;
// create a master collection
this.collection = new AssetsCollection_1.default(eyeglass.options);
// and keep a list of module collections
this.moduleCollections = [];
}
/**
* @see AssetsCollection#asAssetImport
*/
asAssetImport(name) {
return this.collection.asAssetImport(name);
}
/**
* @see AssetsCollection#addSource
*/
addSource(src, opts) {
return this.collection.addSource(src, opts);
}
/**
* @see AssetsCollection#cacheKey
*/
cacheKey(name) {
return this.collection.cacheKey(name);
}
/**
* creates a new AssetsCollection and adds the given source
* @see #addSource
* @param {String} src - the source directory
* @param {Object} opts - the options
* @returns {AssetsCollection} the instance of the AssetsCollection
*/
export(src, opts) {
let assets = new AssetsCollection_1.default(this.eyeglass.options);
this.moduleCollections.push(assets);
return assets.addSource(src, opts);
}
/**
* resolves an asset given a uri
* @param {SassMap} $assetsMap - the map of registered Sass assets
* @param {SassString} $uri - the uri of the asset
* @param {Function} cb - the callback that is invoked when the asset resolves
*/
resolveAsset($assetsMap, $uri, cb) {
let sass = this.eyeglass.options.eyeglass.engines.sass;
let options = this.eyeglass.options.eyeglass;
let assets = this.eyeglass.assets;
if (!SassImplementation_1.isType(sass, $uri, "string")) {
cb(new SassImplementation_1.SassTypeError(sass, "string", $uri));
return;
}
// get a URI instance
let originalUri = $uri.getValue();
let uri = new URI_1.URI(originalUri);
// normalize the uri and resolve it
let $data = this.resolveAssetDefaults($assetsMap, uri.getPath());
if ($data) {
let filepath;
let assetUri;
for (let i = 0; i < $data.getLength(); i++) {
let k = $data.getKey(i).getValue();
let v = $data.getValue(i).getValue();
if (k === "filepath") {
filepath = v;
}
else if (k === "uri") {
assetUri = v;
}
}
// create the URI
let fullUri = URI_1.URI.join(options.httpRoot, options.assets.httpPrefix, assetUri);
assets.resolve(filepath, fullUri, function (error, assetInfo) {
if (error || !typescriptUtils_1.isPresent(assetInfo)) {
cb(errorFor_1.default(error, "Unable to resolve asset"));
}
else {
// if relativeTo is set
if (options.assets.relativeTo) {
// make the URI relative to the httpRoot + relativeTo path
uri.setPath(path.relative(URI_1.URI.join(options.httpRoot, options.assets.relativeTo), assetInfo.path));
}
else {
// otherwise, just update it to the path as is
uri.setPath(assetInfo.path);
}
// if a query param was specified, append it to the uri query
if (assetInfo.query) {
uri.addQuery(assetInfo.query);
}
assets.install(filepath, assetInfo.path, function (error, file) {
if (error) {
cb(errorFor_1.default(error, "Unable to install asset"));
}
else {
if (file) {
/* istanbul ignore next - don't test debug */
debug.assets && debug.assets("%s resolved to %s with URI %s", originalUri, path.relative(options.root, file), uri.toString());
}
cb(null, uri.toString(), file);
}
});
}
});
}
else {
cb(new Error("Asset not found: " + uri.getPath()));
}
}
/**
* resolves the asset uri
* @param {String} assetFile - the source file path
* @param {String} assetUri - the resolved uri path
* @param {Function} cb - the callback to pass the resolved uri to
*/
resolve(_assetFile, assetUri, cb) {
cb(null, { path: assetUri });
}
/**
* wraps the current resolver with a custom resolver
* @param {Function} resolver - the new resolver function
*/
resolver(resolver) {
let oldResolver = this.resolve.bind(this);
this.resolve = function (assetFile, assetUri, cb) {
resolver(assetFile, assetUri, oldResolver, cb);
};
}
/**
* installs the given asset
* @param {String} file - the source file path to install from
* @param {String} uri - the resolved uri path
* @param {Function} cb - the callback invoked after the installation is successful
*/
install(file, uri, cb) {
let options = this.eyeglass.options.eyeglass;
let httpRoot = options.httpRoot;
if (options.buildDir) {
// normalize the uri using the system OS path separator
// and make it relative to the httpRoot
uri = (new URI_1.URI(uri)).getPath(path.sep, httpRoot);
let dest = path.join(options.buildDir, uri);
this.eyeglass.once(`install:${dest}`, () => {
try {
if (options.installWithSymlinks) {
fs.mkdirpSync(path.dirname(dest));
ensureSymlink(file, dest);
debug.assets && debug.assets("symlinked %s to %s", file, dest);
}
else {
// we explicitly use copySync rather than copy to avoid starving system resources
fs.copySync(file, dest);
debug.assets && debug.assets("copied %s to %s", file, dest);
}
cb(null, dest);
}
catch (error) {
cb(errorFor_1.default(error, `Failed to install asset from ${file}:\n`));
}
}, () => {
cb(null, dest);
});
}
else {
cb(null, file);
}
}
/**
* wraps the current installer with a custom installer
* @param {Function} installer - the new installer function
*/
installer(installer) {
let oldInstaller = this.install.bind(this);
this.install = function (assetFile, assetUri, cb) {
installer(assetFile, assetUri, oldInstaller, cb);
};
}
// need types for sass utils
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolveAssetDefaults($registeredAssetsMap, relativePath) {
let appAssets;
let moduleAssets;
let moduleName, moduleRelativePath;
let slashAt = relativePath.indexOf("/");
if (slashAt > 0) {
moduleName = relativePath.substring(0, slashAt);
moduleRelativePath = relativePath.substring(slashAt + 1);
}
let size = $registeredAssetsMap.getLength();
for (let i = 0; i < size; i++) {
let k = $registeredAssetsMap.getKey(i);
if (k === this.sassImpl.types.Null.NULL) {
let v = $registeredAssetsMap.getValue(i);
if (SassImplementation_1.isSassMap(this.sassImpl, v)) {
appAssets = v;
}
}
else if (SassImplementation_1.isSassString(this.sassImpl, k) && k.getValue() === moduleName) {
let v = $registeredAssetsMap.getValue(i);
if (SassImplementation_1.isSassMap(this.sassImpl, v)) {
moduleAssets = v;
}
}
}
if (appAssets) {
let size = appAssets.getLength();
for (let i = 0; i < size; i++) {
let k = appAssets.getKey(i);
if (SassImplementation_1.isSassString(this.sassImpl, k) && k.getValue() === relativePath) {
let v = appAssets.getValue(i);
if (SassImplementation_1.isSassMap(this.sassImpl, v)) {
return v;
}
}
}
}
if (moduleAssets) {
let size = moduleAssets.getLength();
for (let i = 0; i < size; i++) {
let k = moduleAssets.getKey(i);
if (SassImplementation_1.isSassString(this.sassImpl, k) && k.getValue() === moduleRelativePath) {
let v = moduleAssets.getValue(i);
if (SassImplementation_1.isSassMap(this.sassImpl, v)) {
return v;
}
}
}
}
return;
}
}
exports.default = Assets;
//# sourceMappingURL=Assets.js.map