| var fs = require('fs'); | 
| var path = require('path'); | 
|   | 
| var applySourceMaps = require('./apply-source-maps'); | 
| var extractImportUrlAndMedia = require('./extract-import-url-and-media'); | 
| var isAllowedResource = require('./is-allowed-resource'); | 
| var loadOriginalSources = require('./load-original-sources'); | 
| var normalizePath = require('./normalize-path'); | 
| var rebase = require('./rebase'); | 
| var rebaseLocalMap = require('./rebase-local-map'); | 
| var rebaseRemoteMap = require('./rebase-remote-map'); | 
| var restoreImport = require('./restore-import'); | 
|   | 
| var tokenize = require('../tokenizer/tokenize'); | 
| var Token = require('../tokenizer/token'); | 
| var Marker = require('../tokenizer/marker'); | 
| var hasProtocol = require('../utils/has-protocol'); | 
| var isImport = require('../utils/is-import'); | 
| var isRemoteResource = require('../utils/is-remote-resource'); | 
|   | 
| var UNKNOWN_URI = 'uri:unknown'; | 
|   | 
| function readSources(input, context, callback) { | 
|   return doReadSources(input, context, function (tokens) { | 
|     return applySourceMaps(tokens, context, function () { | 
|       return loadOriginalSources(context, function () { return callback(tokens); }); | 
|     }); | 
|   }); | 
| } | 
|   | 
| function doReadSources(input, context, callback) { | 
|   if (typeof input == 'string') { | 
|     return fromString(input, context, callback); | 
|   } else if (Buffer.isBuffer(input)) { | 
|     return fromString(input.toString(), context, callback); | 
|   } else if (Array.isArray(input)) { | 
|     return fromArray(input, context, callback); | 
|   } else if (typeof input == 'object') { | 
|     return fromHash(input, context, callback); | 
|   } | 
| } | 
|   | 
| function fromString(input, context, callback) { | 
|   context.source = undefined; | 
|   context.sourcesContent[undefined] = input; | 
|   context.stats.originalSize += input.length; | 
|   | 
|   return fromStyles(input, context, { inline: context.options.inline }, callback); | 
| } | 
|   | 
| function fromArray(input, context, callback) { | 
|   var inputAsImports = input.reduce(function (accumulator, uriOrHash) { | 
|     if (typeof uriOrHash === 'string') { | 
|       return addStringSource(uriOrHash, accumulator); | 
|     } else { | 
|       return addHashSource(uriOrHash, context, accumulator); | 
|     } | 
|   | 
|   }, []); | 
|   | 
|   return fromStyles(inputAsImports.join(''), context, { inline: ['all'] }, callback); | 
| } | 
|   | 
| function fromHash(input, context, callback) { | 
|   var inputAsImports = addHashSource(input, context, []); | 
|   return fromStyles(inputAsImports.join(''), context, { inline: ['all'] }, callback); | 
| } | 
|   | 
| function addStringSource(input, imports) { | 
|   imports.push(restoreAsImport(normalizeUri(input))); | 
|   return imports; | 
| } | 
|   | 
| function addHashSource(input, context, imports) { | 
|   var uri; | 
|   var normalizedUri; | 
|   var source; | 
|   | 
|   for (uri in input) { | 
|     source = input[uri]; | 
|     normalizedUri = normalizeUri(uri); | 
|   | 
|     imports.push(restoreAsImport(normalizedUri)); | 
|   | 
|     context.sourcesContent[normalizedUri] = source.styles; | 
|   | 
|     if (source.sourceMap) { | 
|       trackSourceMap(source.sourceMap, normalizedUri, context); | 
|     } | 
|   } | 
|   | 
|   return imports; | 
| } | 
|   | 
| function normalizeUri(uri) { | 
|   var currentPath = path.resolve(''); | 
|   var absoluteUri; | 
|   var relativeToCurrentPath; | 
|   var normalizedUri; | 
|   | 
|   if (isRemoteResource(uri)) { | 
|     return uri; | 
|   } | 
|   | 
|   absoluteUri = path.isAbsolute(uri) ? | 
|     uri : | 
|     path.resolve(uri); | 
|   relativeToCurrentPath = path.relative(currentPath, absoluteUri); | 
|   normalizedUri = normalizePath(relativeToCurrentPath); | 
|   | 
|   return normalizedUri; | 
| } | 
|   | 
| 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); | 
|   | 
|   context.inputSourceMapTracker.track(uri, rebasedMap); | 
| } | 
|   | 
| function restoreAsImport(uri) { | 
|   return restoreImport('url(' + uri + ')', '') + Marker.SEMICOLON; | 
| } | 
|   | 
| 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 (path.isAbsolute(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 allowsAnyImports(parentInlinerContext.inline) ? | 
|     inline(tokens, context, parentInlinerContext, callback) : | 
|     callback(tokens); | 
| } | 
|   | 
| function allowsAnyImports(inline) { | 
|   return !(inline.length == 1 && inline[0] == 'none'); | 
| } | 
|   | 
| function inline(tokens, externalContext, parentInlinerContext, callback) { | 
|   var inlinerContext = { | 
|     afterContent: false, | 
|     callback: callback, | 
|     errors: externalContext.errors, | 
|     externalContext: externalContext, | 
|     fetch: externalContext.options.fetch, | 
|     inlinedStylesheets: parentInlinerContext.inlinedStylesheets || externalContext.inlinedStylesheets, | 
|     inline: parentInlinerContext.inline, | 
|     inlineRequest: externalContext.options.inlineRequest, | 
|     inlineTimeout: externalContext.options.inlineTimeout, | 
|     isRemote: parentInlinerContext.isRemote || false, | 
|     localOnly: externalContext.localOnly, | 
|     outputTokens: [], | 
|     rebaseTo: externalContext.options.rebaseTo, | 
|     sourceTokens: tokens, | 
|     warnings: externalContext.warnings | 
|   }; | 
|   | 
|   return doInlineImports(inlinerContext); | 
| } | 
|   | 
| function doInlineImports(inlinerContext) { | 
|   var token; | 
|   var i, l; | 
|   | 
|   for (i = 0, l = inlinerContext.sourceTokens.length; i < l; i++) { | 
|     token = inlinerContext.sourceTokens[i]; | 
|   | 
|     if (token[0] == Token.AT_RULE && isImport(token[1])) { | 
|       inlinerContext.sourceTokens.splice(0, i); | 
|       return inlineStylesheet(token, inlinerContext); | 
|     } else if (token[0] == Token.AT_RULE || token[0] == Token.COMMENT) { | 
|       inlinerContext.outputTokens.push(token); | 
|     } else { | 
|       inlinerContext.outputTokens.push(token); | 
|       inlinerContext.afterContent = true; | 
|     } | 
|   } | 
|   | 
|   inlinerContext.sourceTokens = []; | 
|   return inlinerContext.callback(inlinerContext.outputTokens); | 
| } | 
|   | 
| function inlineStylesheet(token, inlinerContext) { | 
|   var uriAndMediaQuery = extractImportUrlAndMedia(token[1]); | 
|   var uri = uriAndMediaQuery[0]; | 
|   var mediaQuery = uriAndMediaQuery[1]; | 
|   var metadata = token[2]; | 
|   | 
|   return isRemoteResource(uri) ? | 
|     inlineRemoteStylesheet(uri, mediaQuery, metadata, inlinerContext) : | 
|     inlineLocalStylesheet(uri, mediaQuery, metadata, inlinerContext); | 
| } | 
|   | 
| function inlineRemoteStylesheet(uri, mediaQuery, metadata, inlinerContext) { | 
|   var isAllowed = isAllowedResource(uri, true, inlinerContext.inline); | 
|   var originalUri = uri; | 
|   var isLoaded = uri in inlinerContext.externalContext.sourcesContent; | 
|   var isRuntimeResource = !hasProtocol(uri); | 
|   | 
|   if (inlinerContext.inlinedStylesheets.indexOf(uri) > -1) { | 
|     inlinerContext.warnings.push('Ignoring remote @import of "' + uri + '" as it has already been imported.'); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } else if (inlinerContext.localOnly && inlinerContext.afterContent) { | 
|     inlinerContext.warnings.push('Ignoring remote @import of "' + uri + '" as no callback given and after other content.'); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } else if (isRuntimeResource) { | 
|     inlinerContext.warnings.push('Skipping remote @import of "' + uri + '" as no protocol given.'); | 
|     inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1)); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } else if (inlinerContext.localOnly && !isLoaded) { | 
|     inlinerContext.warnings.push('Skipping remote @import of "' + uri + '" as no callback given.'); | 
|     inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1)); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } else if (!isAllowed && inlinerContext.afterContent) { | 
|     inlinerContext.warnings.push('Ignoring remote @import of "' + uri + '" as resource is not allowed and after other content.'); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } else if (!isAllowed) { | 
|     inlinerContext.warnings.push('Skipping remote @import of "' + uri + '" as resource is not allowed.'); | 
|     inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1)); | 
|     inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|     return doInlineImports(inlinerContext); | 
|   } | 
|   | 
|   inlinerContext.inlinedStylesheets.push(uri); | 
|   | 
|   function whenLoaded(error, importedStyles) { | 
|     if (error) { | 
|       inlinerContext.errors.push('Broken @import declaration of "' + uri + '" - ' + error); | 
|   | 
|       return process.nextTick(function () { | 
|         inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1)); | 
|         inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|         doInlineImports(inlinerContext); | 
|       }); | 
|     } | 
|   | 
|     inlinerContext.inline = inlinerContext.externalContext.options.inline; | 
|     inlinerContext.isRemote = true; | 
|   | 
|     inlinerContext.externalContext.source = originalUri; | 
|     inlinerContext.externalContext.sourcesContent[uri] = importedStyles; | 
|     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); | 
|   | 
|       return doInlineImports(inlinerContext); | 
|     }); | 
|   } | 
|   | 
|   return isLoaded ? | 
|     whenLoaded(null, inlinerContext.externalContext.sourcesContent[uri]) : | 
|     inlinerContext.fetch(uri, inlinerContext.inlineRequest, inlinerContext.inlineTimeout, whenLoaded); | 
| } | 
|   | 
| function inlineLocalStylesheet(uri, mediaQuery, metadata, inlinerContext) { | 
|   var currentPath = path.resolve(''); | 
|   var absoluteUri = path.isAbsolute(uri) ? | 
|     path.resolve(currentPath, uri[0] == '/' ? uri.substring(1) : uri) : | 
|     path.resolve(inlinerContext.rebaseTo, uri); | 
|   var relativeToCurrentPath = path.relative(currentPath, absoluteUri); | 
|   var importedStyles; | 
|   var isAllowed = isAllowedResource(uri, false, inlinerContext.inline); | 
|   var normalizedPath = normalizePath(relativeToCurrentPath); | 
|   var isLoaded = normalizedPath 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())) { | 
|     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.'); | 
|   } else if (inlinerContext.afterContent) { | 
|     inlinerContext.warnings.push('Ignoring local @import of "' + uri + '" as after other content.'); | 
|   } else if (!isAllowed) { | 
|     inlinerContext.warnings.push('Skipping local @import of "' + uri + '" as resource is not allowed.'); | 
|     inlinerContext.outputTokens = inlinerContext.outputTokens.concat(inlinerContext.sourceTokens.slice(0, 1)); | 
|   } else { | 
|     importedStyles = isLoaded ? | 
|       inlinerContext.externalContext.sourcesContent[normalizedPath] : | 
|       fs.readFileSync(absoluteUri, 'utf-8'); | 
|   | 
|     inlinerContext.inlinedStylesheets.push(absoluteUri); | 
|     inlinerContext.inline = inlinerContext.externalContext.options.inline; | 
|   | 
|     inlinerContext.externalContext.source = normalizedPath; | 
|     inlinerContext.externalContext.sourcesContent[normalizedPath] = importedStyles; | 
|     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); | 
|   | 
|       return doInlineImports(inlinerContext); | 
|     }); | 
|   } | 
|   | 
|   inlinerContext.sourceTokens = inlinerContext.sourceTokens.slice(1); | 
|   | 
|   return doInlineImports(inlinerContext); | 
| } | 
|   | 
| function wrapInMedia(tokens, mediaQuery, metadata) { | 
|   if (mediaQuery) { | 
|     return [[Token.NESTED_BLOCK, [[Token.NESTED_BLOCK_SCOPE, '@media ' + mediaQuery, metadata]], tokens]]; | 
|   } else { | 
|     return tokens; | 
|   } | 
| } | 
|   | 
| module.exports = readSources; |