var applySourceMaps = require('./apply-source-maps');
var extractImportUrlAndMedia = require('./extract-import-url-and-media');
var isAllowedResource = require('./is-allowed-resource');
-var isAlreadyLoaded = require('./is-already-loaded');
var loadOriginalSources = require('./load-original-sources');
var loadRemoteResource = require('./load-remote-resource');
var rebase = require('./rebase');
function doReadSources(input, context, callback) {
if (typeof input == 'string') {
- return fromString(input, context, {}, callback);
+ return fromString(input, context, callback);
} else if (Buffer.isBuffer(input)) {
- return fromString(input.toString(), context, {}, callback);
+ return fromString(input.toString(), context, callback);
} else if (Array.isArray(input)) {
- return fromArray(input, context, {}, callback);
+ return fromArray(input, context, callback);
} else if (typeof input == 'object') {
- return fromHash(input, context, {}, callback);
+ return fromHash(input, context, callback);
}
}
-function fromString(input, context, parentInlinerContext, callback) {
- var inputAsHash = {};
+function fromString(input, context, callback) {
+ context.source = undefined;
+ context.sourcesContent[undefined] = input;
+ context.stats.originalSize += input.length;
- inputAsHash[UNKNOWN_URI] = {
- styles: input,
- sourceMap: (typeof context.options.sourceMap !== 'boolean') ? context.options.sourceMap : null
- };
+ if (context.options.sourceMap && (typeof context.options.sourceMap !== 'boolean')) {
+ trackSourceMap(context.options.sourceMap, undefined, context);
+ }
- return fromHash(inputAsHash, context, parentInlinerContext, callback);
+ return fromStyles(input, context, { processImports: context.options.processImport }, callback);
}
-function fromArray(input, context, parentInlinerContext, callback) {
- var currentPath = path.resolve('');
- var inputAsHash = input.reduce(function (accumulator, uri) {
- var absoluteUri = isAbsoluteResource(uri) || isRemoteResource(uri) ?
- uri :
- path.resolve(uri);
- var relativeToCurrentPath;
-
- if (isRemoteResource(uri)) {
- accumulator[uri] = {
- styles: restoreImport(uri, '') + Marker.SEMICOLON
- };
- } else if (!fs.existsSync(absoluteUri) || !fs.statSync(absoluteUri).isFile()) {
- context.errors.push('Ignoring "' + absoluteUri + '" as resource is missing.');
- } else {
- relativeToCurrentPath = path.relative(currentPath, absoluteUri);
- accumulator[relativeToCurrentPath] = {
- styles: fs.readFileSync(absoluteUri, 'utf-8')
- };
- }
-
+function fromArray(input, context, callback) {
+ var inputAsImports = input.reduce(function (accumulator, uri) {
+ accumulator.push(restoreAsRelativeImport(uri));
return accumulator;
- }, {});
+ }, []);
- return fromHash(inputAsHash, context, parentInlinerContext, callback);
+ return fromStyles(inputAsImports.join(''), context, { processImports: true }, callback);
}
-function fromHash(input, context, parentInlinerContext, callback) {
- var tokens = [];
- var newTokens = [];
+function fromHash(input, context, callback) {
var uri;
- var realUri;
var source;
- var parsedMap;
- var rebasedMap;
- var rebaseConfig;
+ var inputAsImports = [];
for (uri in input) {
source = input[uri];
- realUri = uri == UNKNOWN_URI ? undefined : uri;
+ inputAsImports.push(restoreAsRelativeImport(uri));
+
+ context.sourcesContent[uri] = source.styles;
if (source.sourceMap) {
- parsedMap = typeof source.sourceMap == 'string' ?
- JSON.parse(source.sourceMap) :
- source.sourceMap;
- rebasedMap = isRemoteResource(uri) ?
- rebaseRemoteMap(parsedMap, uri) :
- rebaseLocalMap(parsedMap, uri, context.options.rebaseTo);
- context.inputSourceMapTracker.track(realUri, rebasedMap);
+ trackSourceMap(source.sourceMap, uri, context);
}
-
- context.sourcesContent[realUri] = source.styles;
}
- for (uri in input) {
- source = input[uri];
- realUri = uri == UNKNOWN_URI ? undefined : uri;
- rebaseConfig = {};
-
- if (uri == UNKNOWN_URI) {
- rebaseConfig.fromBase = path.resolve('');
- rebaseConfig.toBase = context.options.rebaseTo;
- } else if (isRemoteResource(uri)) {
- rebaseConfig.fromBase = uri;
- rebaseConfig.toBase = uri;
- } else if (isAbsoluteResource(uri)) {
- rebaseConfig.fromBase = path.dirname(uri);
- rebaseConfig.toBase = context.options.rebaseTo;
- } else {
- rebaseConfig.fromBase = path.dirname(path.resolve(uri));
- rebaseConfig.toBase = context.options.rebaseTo;
- }
+ return fromStyles(inputAsImports.join(''), context, { processImports: true }, callback);
+}
- context.source = realUri;
+function trackSourceMap(sourceMap, uri, context) {
+ var parsedMap = typeof sourceMap == 'string' ?
+ JSON.parse(sourceMap) :
+ sourceMap;
+ var rebasedMap = isRemoteResource(uri) ?
+ rebaseRemoteMap(parsedMap, uri) :
+ rebaseLocalMap(parsedMap, uri || UNKNOWN_URI, context.options.rebaseTo);
- newTokens = tokenize(source.styles, context);
- newTokens = rebase(newTokens, context.options.rebase, context.validator, rebaseConfig);
+ context.inputSourceMapTracker.track(uri, rebasedMap);
+}
- tokens = tokens.concat(newTokens);
+function restoreAsRelativeImport(uri) {
+ var currentPath = path.resolve('');
+ var absoluteUri;
+ var relativeToCurrentPath;
+
+ if (isRemoteResource(uri)) {
+ return restoreImport(uri, '') + Marker.SEMICOLON;
+ } else {
+ absoluteUri = isAbsoluteResource(uri) ?
+ uri :
+ path.resolve(uri);
+ relativeToCurrentPath = path.relative(currentPath, absoluteUri);
- context.stats.originalSize += source.styles.length;
+ return restoreImport(relativeToCurrentPath, '') + Marker.SEMICOLON;
}
+}
- return context.options.processImport ?
+function fromStyles(styles, context, parentInlinerContext, callback) {
+ var tokens;
+ var rebaseConfig = {};
+
+ if (!context.source) {
+ rebaseConfig.fromBase = path.resolve('');
+ rebaseConfig.toBase = context.options.rebaseTo;
+ } else if (isRemoteResource(context.source)) {
+ rebaseConfig.fromBase = context.source;
+ rebaseConfig.toBase = context.source;
+ } else if (isAbsoluteResource(context.source)) {
+ rebaseConfig.fromBase = path.dirname(context.source);
+ rebaseConfig.toBase = context.options.rebaseTo;
+ } else {
+ rebaseConfig.fromBase = path.dirname(path.resolve(context.source));
+ rebaseConfig.toBase = context.options.rebaseTo;
+ }
+
+ tokens = tokenize(styles, context);
+ tokens = rebase(tokens, context.options.rebase, context.validator, rebaseConfig);
+
+ return parentInlinerContext.processImports ?
inlineImports(tokens, context, parentInlinerContext, callback) :
callback(tokens);
}
isRemote: parentInlinerContext.isRemote || false,
localOnly: externalContext.localOnly,
outputTokens: [],
+ processImports: parentInlinerContext.processImports,
processImportFrom: externalContext.options.processImportFrom,
rebaseTo: externalContext.options.rebaseTo,
sourceTokens: tokens,
function inlineRemoteStylesheet(uri, mediaQuery, metadata, inlinerContext) {
var isAllowed = isAllowedResource(uri, true, inlinerContext.processImportFrom);
var originalUri = uri;
- var isLoaded = isAlreadyLoaded(uri, inlinerContext.externalContext.sourcesContent);
+ var isLoaded = uri in inlinerContext.externalContext.sourcesContent;
if (inlinerContext.inlinedStylesheets.indexOf(uri) > -1) {
inlinerContext.warnings.push('Ignoring remote @import of "' + uri + '" as it has already been imported.');
inlinerContext.inlinedStylesheets.push(uri);
function whenLoaded(error, importedStyles) {
- var sourceHash = {};
-
if (error) {
inlinerContext.errors.push('Broken @import declaration of "' + uri + '" - ' + error);
});
}
- sourceHash[originalUri] = {
- styles: importedStyles
- };
+ inlinerContext.processImports = inlinerContext.externalContext.options.processImport;
+ inlinerContext.isRemote = true;
+ inlinerContext.externalContext.source = originalUri;
inlinerContext.externalContext.sourcesContent[uri] = importedStyles;
- inlinerContext.isRemote = true;
- fromHash(sourceHash, inlinerContext.externalContext, inlinerContext, function (importedTokens) {
+ inlinerContext.externalContext.stats.originalSize += importedStyles.length;
+
+ return fromStyles(importedStyles, inlinerContext.externalContext, inlinerContext, function (importedTokens) {
importedTokens = wrapInMedia(importedTokens, mediaQuery, metadata);
inlinerContext.outputTokens = inlinerContext.outputTokens.concat(importedTokens);
inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1);
- doInlineImports(inlinerContext);
+ return doInlineImports(inlinerContext);
});
}
var importedStyles;
var importedTokens;
var isAllowed = isAllowedResource(uri, false, inlinerContext.processImportFrom);
- var sourceHash = {};
- var isLoaded = isAlreadyLoaded(relativeToCurrentPath, inlinerContext.externalContext.sourcesContent);
+ var isLoaded = relativeToCurrentPath in inlinerContext.externalContext.sourcesContent;
if (inlinerContext.inlinedStylesheets.indexOf(absoluteUri) > -1) {
inlinerContext.warnings.push('Ignoring local @import of "' + uri + '" as it has already been imported.');
- } else if (!isLoaded && !fs.existsSync(absoluteUri) || !fs.statSync(absoluteUri).isFile()) {
+ } else if (!isLoaded && (!fs.existsSync(absoluteUri) || !fs.statSync(absoluteUri).isFile())) {
inlinerContext.errors.push('Ignoring local @import of "' + uri + '" as resource is missing.');
} else if (!isAllowed && inlinerContext.afterContent) {
inlinerContext.warnings.push('Ignoring local @import of "' + uri + '" as resource is not allowed and after other content.');
importedStyles = isLoaded ?
inlinerContext.externalContext.sourcesContent[relativeToCurrentPath] :
fs.readFileSync(absoluteUri, 'utf-8');
+
inlinerContext.inlinedStylesheets.push(absoluteUri);
+ inlinerContext.processImports = inlinerContext.externalContext.options.processImport;
- sourceHash[relativeToCurrentPath] = {
- styles: importedStyles
- };
+ inlinerContext.externalContext.source = relativeToCurrentPath;
inlinerContext.externalContext.sourcesContent[relativeToCurrentPath] = importedStyles;
+ inlinerContext.externalContext.stats.originalSize += importedStyles.length;
- importedTokens = fromHash(sourceHash, inlinerContext.externalContext, inlinerContext, function (tokens) { return tokens; });
+ importedTokens = fromStyles(importedStyles, inlinerContext.externalContext, inlinerContext, function (tokens) { return tokens; });
importedTokens = wrapInMedia(importedTokens, mediaQuery, metadata);
inlinerContext.outputTokens = inlinerContext.outputTokens.concat(importedTokens);