mirror of
https://github.com/less/less.js.git
synced 2026-05-01 03:00:22 -04:00
much improved comment parsing
This commit is contained in:
@@ -156,7 +156,7 @@ var Parser = function Parser(env) {
|
||||
}
|
||||
function isWhitespace(str, pos) {
|
||||
var code = str.charCodeAt(pos | 0);
|
||||
return (code <= 32) && (code === 32 || code === 10 || code === 9);
|
||||
return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);
|
||||
}
|
||||
//
|
||||
// Parse from a token, regexp or string, and move forward if match
|
||||
@@ -228,21 +228,56 @@ var Parser = function Parser(env) {
|
||||
return tok;
|
||||
}
|
||||
|
||||
var CHARCODE_SPACE = 32,
|
||||
CHARCODE_TAB = 9,
|
||||
CHARCODE_LF = 10,
|
||||
CHARCODE_CR = 13,
|
||||
CHARCODE_FORWARD_SLASH = 47;
|
||||
|
||||
var autoCommentAbsorb = true,
|
||||
commentStore = [];
|
||||
|
||||
function skipWhitespace(length) {
|
||||
var oldi = i, oldj = j,
|
||||
curr = i - currentPos,
|
||||
endIndex = i + current.length - curr,
|
||||
mem = (i += length),
|
||||
inp = input,
|
||||
c;
|
||||
c, nextChar, comment;
|
||||
|
||||
for (; i < endIndex; i++) {
|
||||
c = inp.charCodeAt(i);
|
||||
if (c > 32) {
|
||||
|
||||
if (autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {
|
||||
nextChar = inp[i + 1];
|
||||
if (nextChar === '/') {
|
||||
comment = {index: i, isLineComment: true};
|
||||
var nextNewLine = inp.indexOf("\n", i + 1);
|
||||
if (nextNewLine < 0) {
|
||||
nextNewLine = endIndex;
|
||||
}
|
||||
i = nextNewLine;
|
||||
comment.text = inp.substr(comment.i, i - comment.i);
|
||||
commentStore.push(comment);
|
||||
continue;
|
||||
} else if (nextChar === '*') {
|
||||
var haystack = inp.substr(i);
|
||||
var comment_search_result = haystack.match(/^\/\*(?:[^*]|\*+[^\/*])*\*+\//);
|
||||
if (comment_search_result) {
|
||||
comment = {
|
||||
index: i,
|
||||
text: comment_search_result[0],
|
||||
isLineComment: false
|
||||
};
|
||||
i += comment.text.length - 1;
|
||||
commentStore.push(comment);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c !== 32) && (c !== 10) && (c !== 9) && (c !== 13)) {
|
||||
if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -403,6 +438,7 @@ var Parser = function Parser(env) {
|
||||
// with the `root` property set to true, so no `{}` are
|
||||
// output. The callback is called when the input is parsed.
|
||||
try {
|
||||
skipWhitespace(0);
|
||||
root = new(tree.Ruleset)(null, this.parsers.primary());
|
||||
root.root = true;
|
||||
root.firstRoot = true;
|
||||
@@ -530,7 +566,7 @@ var Parser = function Parser(env) {
|
||||
// string, so we've got a parsing error.
|
||||
//
|
||||
// We try to extract a \n delimited string,
|
||||
// showing the line where the parse error occured.
|
||||
// showing the line where the parse error occurred.
|
||||
// We split it up into two parts (the part which parsed,
|
||||
// and the part which didn't), so we can color them differently.
|
||||
if (i < input.length - 1) {
|
||||
@@ -643,8 +679,16 @@ var Parser = function Parser(env) {
|
||||
|
||||
while (current)
|
||||
{
|
||||
while(true) {
|
||||
node = this.comment();
|
||||
if (!node) { break; }
|
||||
root.push(node);
|
||||
}
|
||||
if (peekChar('}')) {
|
||||
break;
|
||||
}
|
||||
node = this.extendRule() || mixin.definition() || this.rule() || this.ruleset() ||
|
||||
mixin.call() || this.comment() || this.rulesetCall() || this.directive();
|
||||
mixin.call() || this.rulesetCall() || this.directive();
|
||||
if (node) {
|
||||
root.push(node);
|
||||
} else {
|
||||
@@ -652,43 +696,18 @@ var Parser = function Parser(env) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peekChar('}')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
},
|
||||
|
||||
// We create a Comment node for CSS comments `/* */`,
|
||||
// but keep the LeSS comments `//` silent, by just skipping
|
||||
// over them.
|
||||
// comments are collected by the main parsing mechanism and then assigned to nodes
|
||||
// where the current structure allows it
|
||||
comment: function () {
|
||||
var comment;
|
||||
|
||||
if (input.charAt(i) !== '/') { return; }
|
||||
|
||||
if (input.charAt(i + 1) === '/') {
|
||||
return new(tree.Comment)($re(/^\/\/.*/), true, i, env.currentFileInfo);
|
||||
if (commentStore.length) {
|
||||
var comment = commentStore.shift();
|
||||
return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, env.currentFileInfo);
|
||||
}
|
||||
comment = $re(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/);
|
||||
if (comment) {
|
||||
return new(tree.Comment)(comment, false, i, env.currentFileInfo);
|
||||
}
|
||||
},
|
||||
|
||||
comments: function () {
|
||||
var comment, comments = [];
|
||||
|
||||
while(true) {
|
||||
comment = this.comment();
|
||||
if (!comment) {
|
||||
break;
|
||||
}
|
||||
comments.push(comment);
|
||||
}
|
||||
|
||||
return comments;
|
||||
},
|
||||
|
||||
//
|
||||
@@ -824,9 +843,13 @@ var Parser = function Parser(env) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoCommentAbsorb = false;
|
||||
|
||||
value = this.quoted() || this.variable() ||
|
||||
$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
|
||||
|
||||
autoCommentAbsorb = true;
|
||||
|
||||
expectChar(')');
|
||||
|
||||
return new(tree.URL)((value.value != null || value instanceof tree.Variable)
|
||||
@@ -1062,7 +1085,7 @@ var Parser = function Parser(env) {
|
||||
if (isCall) {
|
||||
arg = parsers.detachedRuleset() || parsers.expression();
|
||||
} else {
|
||||
parsers.comments();
|
||||
commentStore.length = 0;
|
||||
if (input.charAt(i) === '.' && $re(/^\.{3}/)) {
|
||||
returner.variadic = true;
|
||||
if ($char(";") && !isSemiColonSeperated) {
|
||||
@@ -1212,7 +1235,7 @@ var Parser = function Parser(env) {
|
||||
return;
|
||||
}
|
||||
|
||||
parsers.comments();
|
||||
commentStore.length = 0;
|
||||
|
||||
if ($re(/^when/)) { // Guard
|
||||
cond = expect(parsers.conditions, 'expected condition');
|
||||
@@ -1239,9 +1262,8 @@ var Parser = function Parser(env) {
|
||||
entity: function () {
|
||||
var entities = this.entities;
|
||||
|
||||
return entities.literal() || entities.variable() || entities.url() ||
|
||||
entities.call() || entities.keyword() || entities.javascript() ||
|
||||
this.comment();
|
||||
return this.comment() || entities.literal() || entities.variable() || entities.url() ||
|
||||
entities.call() || entities.keyword() || entities.javascript();
|
||||
},
|
||||
|
||||
//
|
||||
@@ -1447,7 +1469,7 @@ var Parser = function Parser(env) {
|
||||
break;
|
||||
}
|
||||
if (selectors) { selectors.push(s); } else { selectors = [ s ]; }
|
||||
this.comments();
|
||||
commentStore.length = 0;
|
||||
if (s.condition && selectors.length > 1) {
|
||||
error("Guards are only currently allowed on a single selector.");
|
||||
}
|
||||
@@ -1455,7 +1477,7 @@ var Parser = function Parser(env) {
|
||||
if (s.condition) {
|
||||
error("Guards are only currently allowed on a single selector.");
|
||||
}
|
||||
this.comments();
|
||||
commentStore.length = 0;
|
||||
}
|
||||
|
||||
if (selectors && (rules = this.block())) {
|
||||
@@ -1930,6 +1952,11 @@ var Parser = function Parser(env) {
|
||||
var entities = [], e, delim;
|
||||
|
||||
do {
|
||||
e = this.comment();
|
||||
if (e) {
|
||||
entities.push(e);
|
||||
continue;
|
||||
}
|
||||
e = this.addition() || this.entity();
|
||||
if (e) {
|
||||
entities.push(e);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module.exports = function (tree) {
|
||||
|
||||
var Comment = function (value, silent, index, currentFileInfo) {
|
||||
var Comment = function (value, isLineComment, index, currentFileInfo) {
|
||||
this.value = value;
|
||||
this.silent = !!silent;
|
||||
this.isLineComment = isLineComment;
|
||||
this.currentFileInfo = currentFileInfo;
|
||||
};
|
||||
Comment.prototype = {
|
||||
@@ -11,13 +11,13 @@ Comment.prototype = {
|
||||
if (this.debugInfo) {
|
||||
output.add(tree.debugInfo(env, this), this.currentFileInfo, this.index);
|
||||
}
|
||||
output.add(this.value.trim()); //TODO shouldn't need to trim, we shouldn't grab the \n
|
||||
output.add(this.value);
|
||||
},
|
||||
toCSS: tree.toCSS,
|
||||
isSilent: function(env) {
|
||||
var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
|
||||
isCompressed = env.compress && !this.value.match(/^\/\*!/);
|
||||
return this.silent || isReference || isCompressed;
|
||||
isCompressed = env.compress && this.value[2] !== "!";
|
||||
return this.isLineComment || isReference || isCompressed;
|
||||
},
|
||||
eval: function () { return this; },
|
||||
markReferenced: function () {
|
||||
|
||||
Reference in New Issue
Block a user