123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- var split = require('../utils/split');
- var URL_PREFIX = 'url(';
- var UPPERCASE_URL_PREFIX = 'URL(';
- var URL_SUFFIX = ')';
- var SINGLE_QUOTE_URL_SUFFIX = '\')';
- var DOUBLE_QUOTE_URL_SUFFIX = '")';
- var DATA_URI_PREFIX_PATTERN = /^\s*['"]?\s*data:/;
- var DATA_URI_TRAILER_PATTERN = /[\s\};,\/!]/;
- var IMPORT_URL_PREFIX = '@import';
- var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT';
- var COMMENT_END_MARKER = /\*\//;
- function byUrl(data, context, callback) {
- var nextStart = 0;
- var nextStartUpperCase = 0;
- var nextEnd = 0;
- var firstMatch;
- var isDataURI = false;
- var cursor = 0;
- var tempData = [];
- var hasUppercaseUrl = data.indexOf(UPPERCASE_URL_PREFIX) > -1;
- for (; nextEnd < data.length;) {
- nextStart = data.indexOf(URL_PREFIX, nextEnd);
- nextStartUpperCase = hasUppercaseUrl ? data.indexOf(UPPERCASE_URL_PREFIX, nextEnd) : -1;
- if (nextStart == -1 && nextStartUpperCase == -1)
- break;
- if (nextStart == -1 && nextStartUpperCase > -1)
- nextStart = nextStartUpperCase;
- if (data[nextStart + URL_PREFIX.length] == '"') {
- nextEnd = data.indexOf(DOUBLE_QUOTE_URL_SUFFIX, nextStart);
- } else if (data[nextStart + URL_PREFIX.length] == '\'') {
- nextEnd = data.indexOf(SINGLE_QUOTE_URL_SUFFIX, nextStart);
- } else {
- isDataURI = DATA_URI_PREFIX_PATTERN.test(data.substring(nextStart + URL_PREFIX.length));
- if (isDataURI) {
- firstMatch = split(data.substring(nextStart), DATA_URI_TRAILER_PATTERN, false, '(', ')', true).pop();
- if (firstMatch && firstMatch[firstMatch.length - 1] == URL_SUFFIX) {
- nextEnd = nextStart + firstMatch.length - URL_SUFFIX.length;
- } else {
- nextEnd = -1;
- }
- } else {
- nextEnd = data.indexOf(URL_SUFFIX, nextStart);
- }
- }
- // Following lines are a safety mechanism to ensure
- // incorrectly terminated urls are processed correctly.
- if (nextEnd == -1) {
- nextEnd = data.indexOf('}', nextStart);
- if (nextEnd == -1)
- nextEnd = data.length;
- else
- nextEnd--;
- context.warnings.push('Broken URL declaration: \'' + data.substring(nextStart, nextEnd + 1) + '\'.');
- } else {
- if (data[nextEnd] != URL_SUFFIX)
- nextEnd = data.indexOf(URL_SUFFIX, nextEnd);
- }
- tempData.push(data.substring(cursor, nextStart));
- var url = data.substring(nextStart, nextEnd + 1);
- callback(url, tempData);
- cursor = nextEnd + 1;
- }
- return tempData.length > 0 ?
- tempData.join('') + data.substring(cursor, data.length) :
- data;
- }
- function byImport(data, context, callback) {
- var nextImport = 0;
- var nextImportUpperCase = 0;
- var nextStart = 0;
- var nextEnd = 0;
- var cursor = 0;
- var tempData = [];
- var nextSingleQuote = 0;
- var nextDoubleQuote = 0;
- var untilNextQuote;
- var withQuote;
- var SINGLE_QUOTE = '\'';
- var DOUBLE_QUOTE = '"';
- for (; nextEnd < data.length;) {
- nextImport = data.indexOf(IMPORT_URL_PREFIX, nextEnd);
- nextImportUpperCase = data.indexOf(UPPERCASE_IMPORT_URL_PREFIX, nextEnd);
- if (nextImport == -1 && nextImportUpperCase == -1)
- break;
- if (nextImport > -1 && nextImportUpperCase > -1 && nextImportUpperCase < nextImport)
- nextImport = nextImportUpperCase;
- nextSingleQuote = data.indexOf(SINGLE_QUOTE, nextImport);
- nextDoubleQuote = data.indexOf(DOUBLE_QUOTE, nextImport);
- if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote < nextDoubleQuote) {
- nextStart = nextSingleQuote;
- withQuote = SINGLE_QUOTE;
- } else if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote > nextDoubleQuote) {
- nextStart = nextDoubleQuote;
- withQuote = DOUBLE_QUOTE;
- } else if (nextSingleQuote > -1) {
- nextStart = nextSingleQuote;
- withQuote = SINGLE_QUOTE;
- } else if (nextDoubleQuote > -1) {
- nextStart = nextDoubleQuote;
- withQuote = DOUBLE_QUOTE;
- } else {
- break;
- }
- tempData.push(data.substring(cursor, nextStart));
- nextEnd = data.indexOf(withQuote, nextStart + 1);
- untilNextQuote = data.substring(nextImport, nextEnd);
- if (nextEnd == -1 || /^@import\s+(url\(|__ESCAPED)/i.test(untilNextQuote) || COMMENT_END_MARKER.test(untilNextQuote)) {
- cursor = nextStart;
- break;
- }
- var url = data.substring(nextStart, nextEnd + 1);
- callback(url, tempData);
- cursor = nextEnd + 1;
- }
- return tempData.length > 0 ?
- tempData.join('') + data.substring(cursor, data.length) :
- data;
- }
- function reduceAll(data, context, callback) {
- data = byUrl(data, context, callback);
- data = byImport(data, context, callback);
- return data;
- }
- module.exports = reduceAll;
|