node_modules

This commit is contained in:
saeid
2019-07-15 13:07:31 +04:30
parent d3735c6d30
commit ce1a3ebf9c
35713 changed files with 3639219 additions and 1 deletions
+567
View File
@@ -0,0 +1,567 @@
/*!
* Stylus - Compiler
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Visitor = require('./')
, utils = require('../utils')
, fs = require('fs');
/**
* Initialize a new `Compiler` with the given `root` Node
* and the following `options`.
*
* Options:
*
* - `compress` Compress the CSS output (default: false)
*
* @param {Node} root
* @api public
*/
var Compiler = module.exports = function Compiler(root, options) {
options = options || {};
this.compress = options.compress;
this.firebug = options.firebug;
this.linenos = options.linenos;
this.spaces = options['indent spaces'] || 2;
this.indents = 1;
Visitor.call(this, root);
this.stack = [];
};
/**
* Inherit from `Visitor.prototype`.
*/
Compiler.prototype.__proto__ = Visitor.prototype;
/**
* Compile to css, and return a string of CSS.
*
* @return {String}
* @api private
*/
Compiler.prototype.compile = function(){
return this.visit(this.root);
};
/**
* Output `str`
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
Compiler.prototype.out = function(str, node){
return str;
};
/**
* Return indentation string.
*
* @return {String}
* @api private
*/
Compiler.prototype.__defineGetter__('indent', function(){
if (this.compress) return '';
return new Array(this.indents).join(Array(this.spaces + 1).join(' '));
});
/**
* Check if given `node` needs brackets.
*
* @param {Node} node
* @return {Boolean}
* @api private
*/
Compiler.prototype.needBrackets = function(node){
return 1 == this.indents
|| 'atrule' != node.nodeName
|| node.hasOnlyProperties;
};
/**
* Visit Root.
*/
Compiler.prototype.visitRoot = function(block){
this.buf = '';
for (var i = 0, len = block.nodes.length; i < len; ++i) {
var node = block.nodes[i];
if (this.linenos || this.firebug) this.debugInfo(node);
var ret = this.visit(node);
if (ret) this.buf += this.out(ret + '\n', node);
}
return this.buf;
};
/**
* Visit Block.
*/
Compiler.prototype.visitBlock = function(block){
var node
, separator = this.compress ? '' : '\n'
, needBrackets;
if (block.hasProperties && !block.lacksRenderedSelectors) {
needBrackets = this.needBrackets(block.node);
if (needBrackets) {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
}
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.last = len - 1 == i;
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'group':
case 'block':
case 'unit':
case 'media':
case 'keyframes':
case 'atrule':
case 'supports':
continue;
// inline comments
case !this.compress && node.inline && 'comment':
this.buf = this.buf.slice(0, -1);
this.buf += this.out(' ' + this.visit(node) + '\n', node);
break;
case 'property':
var ret = this.visit(node) + separator;
this.buf += this.compress ? ret : this.out(ret, node);
break;
default:
this.buf += this.out(this.visit(node) + separator, node);
}
}
if (needBrackets) {
--this.indents;
this.buf += this.out(this.indent + '}' + separator);
}
}
// Nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'group':
case 'block':
case 'keyframes':
if (this.linenos || this.firebug) this.debugInfo(node);
this.visit(node);
break;
case 'media':
case 'import':
case 'atrule':
case 'supports':
this.visit(node);
break;
case 'comment':
// only show unsuppressed comments
if (!node.suppress) {
this.buf += this.out(this.indent + this.visit(node) + '\n', node);
}
break;
case 'charset':
case 'literal':
case 'namespace':
this.buf += this.out(this.visit(node) + '\n', node);
break;
}
}
};
/**
* Visit Keyframes.
*/
Compiler.prototype.visitKeyframes = function(node){
if (!node.frames) return;
var prefix = 'official' == node.prefix
? ''
: '-' + node.prefix + '-';
this.buf += this.out('@' + prefix + 'keyframes '
+ this.visit(node.val)
+ (this.compress ? '{' : ' {\n'), node);
this.keyframe = true;
++this.indents;
this.visit(node.block);
--this.indents;
this.keyframe = false;
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
/**
* Visit Media.
*/
Compiler.prototype.visitMedia = function(media){
var val = media.val;
if (!media.hasOutput || !val.nodes.length) return;
this.buf += this.out('@media ', media);
this.visit(val);
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(media.block);
--this.indents;
this.buf += this.out('}' + (this.compress ? '' : '\n'));
};
/**
* Visit QueryList.
*/
Compiler.prototype.visitQueryList = function(queries){
for (var i = 0, len = queries.nodes.length; i < len; ++i) {
this.visit(queries.nodes[i]);
if (len - 1 != i) this.buf += this.out(',' + (this.compress ? '' : ' '));
}
};
/**
* Visit Query.
*/
Compiler.prototype.visitQuery = function(node){
var len = node.nodes.length;
if (node.predicate) this.buf += this.out(node.predicate + ' ');
if (node.type) this.buf += this.out(node.type + (len ? ' and ' : ''));
for (var i = 0; i < len; ++i) {
this.buf += this.out(this.visit(node.nodes[i]));
if (len - 1 != i) this.buf += this.out(' and ');
}
};
/**
* Visit Feature.
*/
Compiler.prototype.visitFeature = function(node){
if (!node.expr) {
return node.name;
} else if (node.expr.isEmpty) {
return '(' + node.name + ')';
} else {
return '(' + node.name + ':' + (this.compress ? '' : ' ') + this.visit(node.expr) + ')';
}
};
/**
* Visit Import.
*/
Compiler.prototype.visitImport = function(imported){
this.buf += this.out('@import ' + this.visit(imported.path) + ';\n', imported);
};
/**
* Visit Atrule.
*/
Compiler.prototype.visitAtrule = function(atrule){
var newline = this.compress ? '' : '\n';
this.buf += this.out(this.indent + '@' + atrule.type, atrule);
if (atrule.val) this.buf += this.out(' ' + atrule.val.trim());
if (atrule.block) {
if (atrule.hasOnlyProperties) {
this.visit(atrule.block);
} else {
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(atrule.block);
--this.indents;
this.buf += this.out(this.indent + '}' + newline);
}
} else {
this.buf += this.out(';' + newline);
}
};
/**
* Visit Supports.
*/
Compiler.prototype.visitSupports = function(node){
if (!node.hasOutput) return;
this.buf += this.out(this.indent + '@supports ', node);
this.isCondition = true;
this.buf += this.out(this.visit(node.condition));
this.isCondition = false;
this.buf += this.out(this.compress ? '{' : ' {\n');
++this.indents;
this.visit(node.block);
--this.indents;
this.buf += this.out(this.indent + '}' + (this.compress ? '' : '\n'));
},
/**
* Visit Comment.
*/
Compiler.prototype.visitComment = function(comment){
return this.compress
? comment.suppress
? ''
: comment.str
: comment.str;
};
/**
* Visit Function.
*/
Compiler.prototype.visitFunction = function(fn){
return fn.name;
};
/**
* Visit Charset.
*/
Compiler.prototype.visitCharset = function(charset){
return '@charset ' + this.visit(charset.val) + ';';
};
/**
* Visit Namespace.
*/
Compiler.prototype.visitNamespace = function(namespace){
return '@namespace '
+ (namespace.prefix ? this.visit(namespace.prefix) + ' ' : '')
+ this.visit(namespace.val) + ';';
};
/**
* Visit Literal.
*/
Compiler.prototype.visitLiteral = function(lit){
var val = lit.val;
if (lit.css) val = val.replace(/^ /gm, '');
return val;
};
/**
* Visit Boolean.
*/
Compiler.prototype.visitBoolean = function(bool){
return bool.toString();
};
/**
* Visit RGBA.
*/
Compiler.prototype.visitRGBA = function(rgba){
return rgba.toString();
};
/**
* Visit HSLA.
*/
Compiler.prototype.visitHSLA = function(hsla){
return hsla.rgba.toString();
};
/**
* Visit Unit.
*/
Compiler.prototype.visitUnit = function(unit){
var type = unit.type || ''
, n = unit.val
, float = n != (n | 0);
// Compress
if (this.compress) {
// Always return '0' unless the unit is a percentage or time
if ('%' != type && 's' != type && 'ms' != type && 0 == n) return '0';
// Omit leading '0' on floats
if (float && n < 1 && n > -1) {
return n.toString().replace('0.', '.') + type;
}
}
return (float ? parseFloat(n.toFixed(15)) : n).toString() + type;
};
/**
* Visit Group.
*/
Compiler.prototype.visitGroup = function(group){
var stack = this.keyframe ? [] : this.stack
, comma = this.compress ? ',' : ',\n';
stack.push(group.nodes);
// selectors
if (group.block.hasProperties) {
var selectors = utils.compileSelectors.call(this, stack)
, len = selectors.length;
if (len) {
if (this.keyframe) comma = this.compress ? ',' : ', ';
for (var i = 0; i < len; ++i) {
var selector = selectors[i]
, last = (i == len - 1);
// keyframe blocks (10%, 20% { ... })
if (this.keyframe) selector = i ? selector.trim() : selector;
this.buf += this.out(selector + (last ? '' : comma), group.nodes[i]);
}
} else {
group.block.lacksRenderedSelectors = true;
}
}
// output block
this.visit(group.block);
stack.pop();
};
/**
* Visit Ident.
*/
Compiler.prototype.visitIdent = function(ident){
return ident.name;
};
/**
* Visit String.
*/
Compiler.prototype.visitString = function(string){
return this.isURL
? string.val
: string.toString();
};
/**
* Visit Null.
*/
Compiler.prototype.visitNull = function(node){
return '';
};
/**
* Visit Call.
*/
Compiler.prototype.visitCall = function(call){
this.isURL = 'url' == call.name;
var args = call.args.nodes.map(function(arg){
return this.visit(arg);
}, this).join(this.compress ? ',' : ', ');
if (this.isURL) args = '"' + args + '"';
this.isURL = false;
return call.name + '(' + args + ')';
};
/**
* Visit Expression.
*/
Compiler.prototype.visitExpression = function(expr){
var buf = []
, self = this
, len = expr.nodes.length
, nodes = expr.nodes.map(function(node){ return self.visit(node); });
nodes.forEach(function(node, i){
var last = i == len - 1;
buf.push(node);
if ('/' == nodes[i + 1] || '/' == node) return;
if (last) return;
var space = self.isURL || (self.isCondition
&& (')' == nodes[i + 1] || '(' == node))
? '' : ' ';
buf.push(expr.isList
? (self.compress ? ',' : ', ')
: space);
});
return buf.join('');
};
/**
* Visit Arguments.
*/
Compiler.prototype.visitArguments = Compiler.prototype.visitExpression;
/**
* Visit Property.
*/
Compiler.prototype.visitProperty = function(prop){
var val = this.visit(prop.expr).trim()
, name = (prop.name || prop.segments.join(''))
, arr = [];
arr.push(
this.out(this.indent),
this.out(name + (this.compress ? ':' : ': '), prop),
this.out(val, prop.expr),
this.out(this.compress ? (this.last ? '' : ';') : ';')
);
return arr.join('');
};
/**
* Debug info.
*/
Compiler.prototype.debugInfo = function(node){
var path = node.filename == 'stdin' ? 'stdin' : fs.realpathSync(node.filename)
, line = (node.nodes && node.nodes.length ? node.nodes[0].lineno : node.lineno) || 1;
if (this.linenos){
this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n';
}
if (this.firebug){
// debug info for firebug, the crazy formatting is needed
path = 'file\\\:\\\/\\\/' + path.replace(/([.:/\\])/g, function(m) {
return '\\' + (m === '\\' ? '\/' : m)
});
line = '\\00003' + line;
this.buf += '\n@media -stylus-debug-info'
+ '{filename{font-family:' + path
+ '}line{font-family:' + line + '}}\n';
}
}
+169
View File
@@ -0,0 +1,169 @@
/**
* Module dependencies.
*/
var Visitor = require('./')
, Parser = require('../parser')
, nodes = require('../nodes')
, utils = require('../utils')
, dirname = require('path').dirname
, fs = require('fs');
/**
* Initialize a new `DepsResolver` with the given `root` Node
* and the `options`.
*
* @param {Node} root
* @param {Object} options
* @api private
*/
var DepsResolver = module.exports = function DepsResolver(root, options) {
this.root = root;
this.filename = options.filename;
this.paths = options.paths || [];
this.paths.push(dirname(options.filename || '.'));
this.options = options;
this.functions = {};
this.deps = [];
};
/**
* Inherit from `Visitor.prototype`.
*/
DepsResolver.prototype.__proto__ = Visitor.prototype;
var visit = DepsResolver.prototype.visit;
DepsResolver.prototype.visit = function(node) {
switch (node.nodeName) {
case 'root':
case 'block':
case 'expression':
this.visitRoot(node);
break;
case 'group':
case 'media':
case 'atblock':
case 'atrule':
case 'keyframes':
case 'each':
case 'supports':
this.visit(node.block);
break;
default:
visit.call(this, node);
}
};
/**
* Visit Root.
*/
DepsResolver.prototype.visitRoot = function(block) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
this.visit(block.nodes[i]);
}
};
/**
* Visit Ident.
*/
DepsResolver.prototype.visitIdent = function(ident) {
this.visit(ident.val);
};
/**
* Visit If.
*/
DepsResolver.prototype.visitIf = function(node) {
this.visit(node.block);
this.visit(node.cond);
for (var i = 0, len = node.elses.length; i < len; ++i) {
this.visit(node.elses[i]);
}
};
/**
* Visit Function.
*/
DepsResolver.prototype.visitFunction = function(fn) {
this.functions[fn.name] = fn.block;
};
/**
* Visit Call.
*/
DepsResolver.prototype.visitCall = function(call) {
if (call.name in this.functions) this.visit(this.functions[call.name]);
if (call.block) this.visit(call.block);
};
/**
* Visit Import.
*/
DepsResolver.prototype.visitImport = function(node) {
var path = node.path.first.val
, literal, found, oldPath;
if (!path) return;
literal = /\.css(?:"|$)/.test(path);
// support optional .styl
if (!literal && !/\.styl$/i.test(path)) {
oldPath = path;
path += '.styl';
}
// Lookup
found = utils.find(path, this.paths, this.filename);
// support optional index
if (!found && oldPath) found = utils.lookupIndex(oldPath, this.paths, this.filename);
if (!found) return;
this.deps = this.deps.concat(found);
if (literal) return;
// nested imports
for (var i = 0, len = found.length; i < len; ++i) {
var file = found[i]
, dir = dirname(file)
, str = fs.readFileSync(file, 'utf-8')
, block = new nodes.Block
, parser = new Parser(str, utils.merge({ root: block }, this.options));
if (!~this.paths.indexOf(dir)) this.paths.push(dir);
try {
block = parser.parse();
} catch (err) {
err.filename = file;
err.lineno = parser.lexer.lineno;
err.column = parser.lexer.column;
err.input = str;
throw err;
}
this.visit(block);
}
};
/**
* Get dependencies.
*/
DepsResolver.prototype.resolve = function() {
this.visit(this.root);
return utils.uniq(this.deps);
};
+1610
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
/*!
* Stylus - Visitor
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Initialize a new `Visitor` with the given `root` Node.
*
* @param {Node} root
* @api private
*/
var Visitor = module.exports = function Visitor(root) {
this.root = root;
};
/**
* Visit the given `node`.
*
* @param {Node|Array} node
* @api public
*/
Visitor.prototype.visit = function(node, fn){
var method = 'visit' + node.constructor.name;
if (this[method]) return this[method](node);
return node;
};
+424
View File
@@ -0,0 +1,424 @@
/*!
* Stylus - Normalizer
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Visitor = require('./')
, nodes = require('../nodes')
, utils = require('../utils');
/**
* Initialize a new `Normalizer` with the given `root` Node.
*
* This visitor implements the first stage of the duel-stage
* compiler, tasked with stripping the "garbage" from
* the evaluated nodes, ditching null rules, resolving
* ruleset selectors etc. This step performs the logic
* necessary to facilitate the "@extend" functionality,
* as these must be resolved _before_ buffering output.
*
* @param {Node} root
* @api public
*/
var Normalizer = module.exports = function Normalizer(root, options) {
options = options || {};
Visitor.call(this, root);
this.hoist = options['hoist atrules'];
this.stack = [];
this.map = {};
this.imports = [];
};
/**
* Inherit from `Visitor.prototype`.
*/
Normalizer.prototype.__proto__ = Visitor.prototype;
/**
* Normalize the node tree.
*
* @return {Node}
* @api private
*/
Normalizer.prototype.normalize = function(){
var ret = this.visit(this.root);
if (this.hoist) {
// hoist @import
if (this.imports.length) ret.nodes = this.imports.concat(ret.nodes);
// hoist @charset
if (this.charset) ret.nodes = [this.charset].concat(ret.nodes);
}
return ret;
};
/**
* Bubble up the given `node`.
*
* @param {Node} node
* @api private
*/
Normalizer.prototype.bubble = function(node){
var props = []
, other = []
, self = this;
function filterProps(block) {
block.nodes.forEach(function(node) {
node = self.visit(node);
switch (node.nodeName) {
case 'property':
props.push(node);
break;
case 'block':
filterProps(node);
break;
default:
other.push(node);
}
});
}
filterProps(node.block);
if (props.length) {
var selector = new nodes.Selector([new nodes.Literal('&')]);
selector.lineno = node.lineno;
selector.column = node.column;
selector.filename = node.filename;
selector.val = '&';
var group = new nodes.Group;
group.lineno = node.lineno;
group.column = node.column;
group.filename = node.filename;
var block = new nodes.Block(node.block, group);
block.lineno = node.lineno;
block.column = node.column;
block.filename = node.filename;
props.forEach(function(prop){
block.push(prop);
});
group.push(selector);
group.block = block;
node.block.nodes = [];
node.block.push(group);
other.forEach(function(n){
node.block.push(n);
});
var group = this.closestGroup(node.block);
if (group) node.group = group.clone();
node.bubbled = true;
}
};
/**
* Return group closest to the given `block`.
*
* @param {Block} block
* @return {Group}
* @api private
*/
Normalizer.prototype.closestGroup = function(block){
var parent = block.parent
, node;
while (parent && (node = parent.node)) {
if ('group' == node.nodeName) return node;
parent = node.block && node.block.parent;
}
};
/**
* Visit Root.
*/
Normalizer.prototype.visitRoot = function(block){
var ret = new nodes.Root
, node;
for (var i = 0; i < block.nodes.length; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'unit':
case 'atblock':
continue;
default:
this.rootIndex = i;
ret.push(this.visit(node));
}
}
return ret;
};
/**
* Visit Property.
*/
Normalizer.prototype.visitProperty = function(prop){
this.visit(prop.expr);
return prop;
};
/**
* Visit Expression.
*/
Normalizer.prototype.visitExpression = function(expr){
expr.nodes = expr.nodes.map(function(node){
// returns `block` literal if mixin's block
// is used as part of a property value
if ('block' == node.nodeName) {
var literal = new nodes.Literal('block');
literal.lineno = expr.lineno;
literal.column = expr.column;
return literal;
}
return node;
});
return expr;
};
/**
* Visit Block.
*/
Normalizer.prototype.visitBlock = function(block){
var node;
if (block.hasProperties) {
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
switch (node.nodeName) {
case 'null':
case 'expression':
case 'function':
case 'group':
case 'unit':
case 'atblock':
continue;
default:
block.nodes[i] = this.visit(node);
}
}
}
// nesting
for (var i = 0, len = block.nodes.length; i < len; ++i) {
node = block.nodes[i];
block.nodes[i] = this.visit(node);
}
return block;
};
/**
* Visit Group.
*/
Normalizer.prototype.visitGroup = function(group){
var stack = this.stack
, map = this.map
, parts;
// normalize interpolated selectors with comma
group.nodes.forEach(function(selector, i){
if (!~selector.val.indexOf(',')) return;
if (~selector.val.indexOf('\\,')) {
selector.val = selector.val.replace(/\\,/g, ',');
return;
}
parts = selector.val.split(',');
var root = '/' == selector.val.charAt(0)
, part, s;
for (var k = 0, len = parts.length; k < len; ++k){
part = parts[k].trim();
if (root && k > 0 && !~part.indexOf('&')) {
part = '/' + part;
}
s = new nodes.Selector([new nodes.Literal(part)]);
s.val = part;
s.block = group.block;
group.nodes[i++] = s;
}
});
stack.push(group.nodes);
var selectors = utils.compileSelectors(stack, true);
// map for extension lookup
selectors.forEach(function(selector){
map[selector] = map[selector] || [];
map[selector].push(group);
});
// extensions
this.extend(group, selectors);
stack.pop();
return group;
};
/**
* Visit Function.
*/
Normalizer.prototype.visitFunction = function(){
return nodes.null;
};
/**
* Visit Media.
*/
Normalizer.prototype.visitMedia = function(media){
var medias = []
, group = this.closestGroup(media.block)
, parent;
function mergeQueries(block) {
block.nodes.forEach(function(node, i){
switch (node.nodeName) {
case 'media':
node.val = media.val.merge(node.val);
medias.push(node);
block.nodes[i] = nodes.null;
break;
case 'block':
mergeQueries(node);
break;
default:
if (node.block && node.block.nodes)
mergeQueries(node.block);
}
});
}
mergeQueries(media.block);
this.bubble(media);
if (medias.length) {
medias.forEach(function(node){
if (group) {
group.block.push(node);
} else {
this.root.nodes.splice(++this.rootIndex, 0, node);
}
node = this.visit(node);
parent = node.block.parent;
if (node.bubbled && (!group || 'group' == parent.node.nodeName)) {
node.group.block = node.block.nodes[0].block;
node.block.nodes[0] = node.group;
}
}, this);
}
return media;
};
/**
* Visit Supports.
*/
Normalizer.prototype.visitSupports = function(node){
this.bubble(node);
return node;
};
/**
* Visit Atrule.
*/
Normalizer.prototype.visitAtrule = function(node){
if (node.block) node.block = this.visit(node.block);
return node;
};
/**
* Visit Keyframes.
*/
Normalizer.prototype.visitKeyframes = function(node){
var frames = node.block.nodes.filter(function(frame){
return frame.block && frame.block.hasProperties;
});
node.frames = frames.length;
return node;
};
/**
* Visit Import.
*/
Normalizer.prototype.visitImport = function(node){
this.imports.push(node);
return this.hoist ? nodes.null : node;
};
/**
* Visit Charset.
*/
Normalizer.prototype.visitCharset = function(node){
this.charset = node;
return this.hoist ? nodes.null : node;
};
/**
* Apply `group` extensions.
*
* @param {Group} group
* @param {Array} selectors
* @api private
*/
Normalizer.prototype.extend = function(group, selectors){
var map = this.map
, self = this
, parent = this.closestGroup(group.block);
group.extends.forEach(function(extend){
var groups = map[extend.selector];
if (!groups) {
if (extend.optional) return;
var err = new Error('Failed to @extend "' + extend.selector + '"');
err.lineno = extend.lineno;
err.column = extend.column;
throw err;
}
selectors.forEach(function(selector){
var node = new nodes.Selector;
node.val = selector;
node.inherits = false;
groups.forEach(function(group){
// prevent recursive extend
if (!parent || (parent != group)) self.extend(group, selectors);
group.push(node);
});
});
});
group.block = this.visit(group.block);
};
+203
View File
@@ -0,0 +1,203 @@
/*!
* Stylus - SourceMapper
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Compiler = require('./compiler')
, SourceMapGenerator = require('source-map').SourceMapGenerator
, basename = require('path').basename
, extname = require('path').extname
, dirname = require('path').dirname
, join = require('path').join
, relative = require('path').relative
, sep = require('path').sep
, fs = require('fs');
/**
* Initialize a new `SourceMapper` generator with the given `root` Node
* and the following `options`.
*
* @param {Node} root
* @api public
*/
var SourceMapper = module.exports = function SourceMapper(root, options){
options = options || {};
this.column = 1;
this.lineno = 1;
this.contents = {};
this.filename = options.filename;
this.dest = options.dest;
var sourcemap = options.sourcemap;
this.basePath = sourcemap.basePath || '.';
this.inline = sourcemap.inline;
this.comment = sourcemap.comment;
if (this.dest && extname(this.dest) === '.css') {
this.basename = basename(this.dest);
this.dest = dirname(this.dest);
} else {
this.basename = basename(this.filename, extname(this.filename)) + '.css';
}
this.utf8 = false;
this.map = new SourceMapGenerator({
file: this.basename,
sourceRoot: sourcemap.sourceRoot || null
});
Compiler.call(this, root, options);
};
/**
* Inherit from `Compiler.prototype`.
*/
SourceMapper.prototype.__proto__ = Compiler.prototype;
/**
* Generate and write source map.
*
* @return {String}
* @api private
*/
var compile = Compiler.prototype.compile;
SourceMapper.prototype.compile = function(){
var css = compile.call(this)
, out = this.basename + '.map'
, url = this.normalizePath(this.dest
? join(this.dest, out)
: join(dirname(this.filename), out))
, map;
if (this.inline) {
map = this.map.toString();
url = 'data:application/json;'
+ (this.utf8 ? 'charset=utf-8;' : '') + 'base64,'
+ new Buffer(map).toString('base64');
}
if (this.inline || false !== this.comment)
css += '/*# sourceMappingURL=' + url + ' */';
return css;
};
/**
* Add mapping information.
*
* @param {String} str
* @param {Node} node
* @return {String}
* @api private
*/
SourceMapper.prototype.out = function(str, node){
if (node && node.lineno) {
var filename = this.normalizePath(node.filename);
this.map.addMapping({
original: {
line: node.lineno,
column: node.column - 1
},
generated: {
line: this.lineno,
column: this.column - 1
},
source: filename
});
if (this.inline && !this.contents[filename]) {
this.map.setSourceContent(filename, fs.readFileSync(node.filename, 'utf-8'));
this.contents[filename] = true;
}
}
this.move(str);
return str;
};
/**
* Move current line and column position.
*
* @param {String} str
* @api private
*/
SourceMapper.prototype.move = function(str){
var lines = str.match(/\n/g)
, idx = str.lastIndexOf('\n');
if (lines) this.lineno += lines.length;
this.column = ~idx
? str.length - idx
: this.column + str.length;
};
/**
* Normalize the given `path`.
*
* @param {String} path
* @return {String}
* @api private
*/
SourceMapper.prototype.normalizePath = function(path){
path = relative(this.dest || this.basePath, path);
if ('\\' == sep) {
path = path.replace(/^[a-z]:\\/i, '/')
.replace(/\\/g, '/');
}
return path;
};
/**
* Visit Literal.
*/
var literal = Compiler.prototype.visitLiteral;
SourceMapper.prototype.visitLiteral = function(lit){
var val = literal.call(this, lit)
, filename = this.normalizePath(lit.filename)
, indentsRe = /^\s+/
, lines = val.split('\n');
// add mappings for multiline literals
if (lines.length > 1) {
lines.forEach(function(line, i) {
var indents = line.match(indentsRe)
, column = indents && indents[0]
? indents[0].length
: 0;
if (lit.css) column += 2;
this.map.addMapping({
original: {
line: lit.lineno + i,
column: column
},
generated: {
line: this.lineno + i,
column: 0
},
source: filename
});
}, this);
}
return val;
};
/**
* Visit Charset.
*/
var charset = Compiler.prototype.visitCharset;
SourceMapper.prototype.visitCharset = function(node){
this.utf8 = ('utf-8' == node.val.string.toLowerCase());
return charset.call(this, node);
};