Move toCSS out to a new class (still need to remove creation of that class from parser)

This commit is contained in:
Luke Page
2014-09-04 17:42:38 +01:00
parent 20025f10b1
commit d3c6f2208f
9 changed files with 127 additions and 117 deletions

View File

@@ -1,26 +1,32 @@
var utils = require("./utils.js");
var LessError = module.exports = function LessError(parser, e, env) {
var input = parser.getInput(e, env),
loc = parser.getLocation(e.index, input),
line = loc.line,
col = loc.column,
callLine = e.call && parser.getLocation(e.call, input).line,
lines = input.split('\n');
var LessError = module.exports = function LessError(e, importManager, currentFilename) {
this.type = e.type || 'Syntax';
var filename = e.filename || currentFilename;
if (importManager && filename) {
var input = importManager.contents[filename],
loc = utils.getLocation(e.index, input),
line = loc.line,
col = loc.column,
callLine = e.call && utils.getLocation(e.call, input).line,
lines = input.split('\n');
this.type = e.type || 'Syntax';
this.filename = filename;
this.index = e.index;
this.line = typeof(line) === 'number' ? line + 1 : null;
this.callLine = callLine + 1;
this.callExtract = lines[callLine];
this.column = col;
this.extract = [
lines[line - 1],
lines[line],
lines[line + 1]
];
}
this.message = e.message;
this.filename = e.filename || env.currentFileInfo.filename;
this.index = e.index;
this.line = typeof(line) === 'number' ? line + 1 : null;
this.callLine = callLine + 1;
this.callExtract = lines[callLine];
this.stack = e.stack;
this.column = col;
this.extract = [
lines[line - 1],
lines[line],
lines[line + 1]
];
};
LessError.prototype = new Error();

55
lib/less/parse-tree.js Normal file
View File

@@ -0,0 +1,55 @@
var LessError = require('./less-error.js'),
transformTree = require("./transform-tree.js");
module.exports = function(environment)
{
var SourceMapOutput = require("./source-map-output")(environment);
var ParseTree = function(root, imports) {
this.root = root;
this.imports = imports;
};
ParseTree.prototype.toCSS = function(options) {
var evaldRoot;
try {
evaldRoot = transformTree(this.root, options);
} catch (e) {
throw new LessError(e, this.imports);
}
var css;
try {
if (options.sourceMap) {
evaldRoot = new SourceMapOutput(
{
contentsIgnoredCharsMap: this.imports.contentsIgnoredChars,
writeSourceMap: options.writeSourceMap,
rootNode: evaldRoot,
contentsMap: this.imports.contents,
sourceMapFilename: options.sourceMapFilename,
sourceMapURL: options.sourceMapURL,
outputFilename: options.sourceMapOutputFilename,
sourceMapBasepath: options.sourceMapBasepath,
sourceMapRootpath: options.sourceMapRootpath,
outputSourceFiles: options.outputSourceFiles,
sourceMapGenerator: options.sourceMapGenerator
});
}
css = evaldRoot.toCSS({
compress: Boolean(options.compress),
dumpLineNumbers: options.dumpLineNumbers,
strictUnits: Boolean(options.strictUnits),
numPrecision: 8});
} catch (e) {
throw new LessError(e, this.imports);
}
if (options.compress) {
return css.replace(/(^(\s)+)|((\s)+$)/g, "");
} else {
return css;
}
};
return ParseTree;
};

View File

@@ -70,7 +70,7 @@ module.exports = function(environment, env, Parser) {
} else {
new(Parser)(newEnv).parse(contents, function (e, root) {
fileParsedFunc(e, root, resolvedFilename);
});
}, null, true);
}
});
}

View File

@@ -211,27 +211,6 @@ module.exports = function() {
return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
};
parserInput.getLocation = function(index, inputStream) {
inputStream = inputStream == null ? input : inputStream;
var n = index + 1,
line = null,
column = -1;
while (--n >= 0 && inputStream.charAt(n) !== '\n') {
column++;
}
if (typeof index === 'number') {
line = (inputStream.slice(0, index).match(/\n/g) || "").length;
}
return {
line: line,
column: column
};
};
parserInput.start = function(str, chunkInput, parser, env) {
input = str;
parserInput.i = j = currentPos = furthest = 0;

View File

@@ -3,10 +3,11 @@ var LessError = require('../less-error.js'),
visitor = require("../visitor/index.js"),
contexts = require("../contexts.js"),
getImportManager = require("./imports.js"),
getParserInput = require("./parser-input.js");
getParserInput = require("./parser-input.js"),
utils = require("../utils.js");
module.exports = function(environment) {
var SourceMapOutput = require("../source-map-output")(environment);
var ParseTree = require("../parse-tree.js")(environment);
//
// less.js - parser
//
@@ -79,20 +80,12 @@ var Parser = function Parser(env) {
throw e;
}
function getInput(e, env) {
if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
return parser.imports.contents[e.filename];
} else {
return parserInput.getInput();
}
}
function getDebugInfo(index) {
var filename = env.currentFileInfo.filename;
filename = environment.getAbsolutePath(env, filename);
return {
lineNumber: parserInput.getLocation(index).line + 1,
lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1,
fileName: filename
};
}
@@ -109,7 +102,7 @@ var Parser = function Parser(env) {
// @param callback call `callback` when done.
// @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
//
parse: function (str, callback, additionalData) {
parse: function (str, callback, additionalData, returnSubParseTree) {
var root, error = null, globalVars, modifyVars, preText = "";
globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : '';
@@ -136,54 +129,9 @@ var Parser = function Parser(env) {
root.root = true;
root.firstRoot = true;
} catch (e) {
return callback(new LessError(parser, e, env));
return callback(new LessError(e, parser.imports, env.currentFileInfo.filename));
}
root.toCSS = (function (evaluate) {
return function (options) {
var transformTree = require("../transform-tree.js"),
evaldRoot;
try {
evaldRoot = transformTree(this, options);
} catch (e) {
throw new LessError(parser, e, env);
}
var css;
try {
if (options.sourceMap) {
evaldRoot = new SourceMapOutput(
{
contentsIgnoredCharsMap: parser.imports.contentsIgnoredChars,
writeSourceMap: options.writeSourceMap,
rootNode: evaldRoot,
contentsMap: parser.imports.contents,
sourceMapFilename: options.sourceMapFilename,
sourceMapURL: options.sourceMapURL,
outputFilename: options.sourceMapOutputFilename,
sourceMapBasepath: options.sourceMapBasepath,
sourceMapRootpath: options.sourceMapRootpath,
outputSourceFiles: options.outputSourceFiles,
sourceMapGenerator: options.sourceMapGenerator
});
}
css = evaldRoot.toCSS({
compress: Boolean(options.compress),
dumpLineNumbers: env.dumpLineNumbers,
strictUnits: Boolean(options.strictUnits),
numPrecision: 8});
} catch (e) {
throw new LessError(parser, e, env);
}
if (options.compress) {
return css.replace(/(^(\s)+)|((\s)+$)/g, "");
} else {
return css;
}
};
})(root.eval);
// If `i` is smaller than the `input.length - 1`,
// it means the parser wasn't able to parse the whole
// string, so we've got a parsing error.
@@ -208,12 +156,12 @@ var Parser = function Parser(env) {
}
}
error = new LessError(parser, {
error = new LessError({
type: "Parse",
message: message,
index: endInfo.furthest,
filename: env.currentFileInfo.filename
}, env);
}, parser.imports);
}
var finish = function (e) {
@@ -221,13 +169,14 @@ var Parser = function Parser(env) {
if (e) {
if (!(e instanceof LessError)) {
e = new LessError(parser, e, env);
e = new LessError(e, parser.imports, env.currentFileInfo.filename);
}
return callback(e);
}
else {
return callback(null, root);
return callback(null,
returnSubParseTree ? root : new ParseTree(root, parser.imports));
}
};
@@ -547,7 +496,7 @@ var Parser = function Parser(env) {
js = parserInput.$re(/^(~)?`([^`]*)`/);
if (js) {
return new(tree.JavaScript)(js[2], index, Boolean(js[1]));
return new(tree.JavaScript)(js[2], Boolean(js[1]), index, env.currentFileInfo);
}
}
},
@@ -1636,9 +1585,6 @@ var Parser = function Parser(env) {
}
};
parser.getInput = getInput;
parser.getLocation = parserInput.getLocation;
return parser;
};
Parser.serializeVars = function(vars) {

View File

@@ -3,10 +3,11 @@ var JsEvalNode = require("./js-eval-node.js"),
Quoted = require("./quoted.js"),
Anonymous = require("./anonymous.js");
var JavaScript = function (string, index, escaped) {
var JavaScript = function (string, escaped, index, currentFileInfo) {
this.escaped = escaped;
this.expression = string;
this.index = index;
this.currentFileInfo = currentFileInfo;
};
JavaScript.prototype = new JsEvalNode();
JavaScript.prototype.type = "JavaScript";

View File

@@ -1,28 +1,30 @@
var Node = require("./node.js"),
Variable = require("./variable.js");
var jsEvalNode = function() {
var JsEvalNode = function() {
};
jsEvalNode.prototype = new Node();
JsEvalNode.prototype = new Node();
jsEvalNode.prototype.evaluateJavaScript = function (expression, env) {
JsEvalNode.prototype.evaluateJavaScript = function (expression, env) {
var result,
that = this,
context = {};
if (env.javascriptEnabled !== undefined && !env.javascriptEnabled) {
throw { message: "You are using JavaScript, which has been disabled." ,
throw { message: "You are using JavaScript, which has been disabled.",
filename: this.currentFileInfo.filename,
index: this.index };
}
expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
return that.jsify(new(Variable)('@' + name, that.index).eval(env));
return that.jsify(new(Variable)('@' + name, that.index, that.currentFileInfo).eval(env));
});
try {
expression = new(Function)('return (' + expression + ')');
} catch (e) {
throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
filename: this.currentFileInfo.filename,
index: this.index };
}
@@ -43,11 +45,12 @@ jsEvalNode.prototype.evaluateJavaScript = function (expression, env) {
result = expression.call(context);
} catch (e) {
throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
filename: this.currentFileInfo.filename,
index: this.index };
}
return result;
};
jsEvalNode.prototype.jsify = function (obj) {
JsEvalNode.prototype.jsify = function (obj) {
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
} else {
@@ -55,4 +58,4 @@ jsEvalNode.prototype.jsify = function (obj) {
}
};
module.exports = jsEvalNode;
module.exports = JsEvalNode;

View File

@@ -11,13 +11,13 @@ Variable.prototype.eval = function (env) {
var variable, name = this.name;
if (name.indexOf('@@') === 0) {
name = '@' + new(Variable)(name.slice(1)).eval(env).value;
name = '@' + new(Variable)(name.slice(1), this.index, this.currentFileInfo).eval(env).value;
}
if (this.evaluating) {
throw { type: 'Name',
message: "Recursive variable definition for " + name,
filename: this.currentFileInfo.file,
filename: this.currentFileInfo.filename,
index: this.index };
}

20
lib/less/utils.js Normal file
View File

@@ -0,0 +1,20 @@
module.exports = {
getLocation: function(index, inputStream) {
var n = index + 1,
line = null,
column = -1;
while (--n >= 0 && inputStream.charAt(n) !== '\n') {
column++;
}
if (typeof index === 'number') {
line = (inputStream.slice(0, index).match(/\n/g) || "").length;
}
return {
line: line,
column: column
};
}
};