String interpolation AST (#5175)
* updated grammar * empty chunks * remove unused * remove unused * add comment
This commit is contained in:
parent
4549f9a4c5
commit
eaeb77a527
|
@ -214,7 +214,8 @@
|
||||||
function() {
|
function() {
|
||||||
return new StringWithInterpolations(Block.wrap($2),
|
return new StringWithInterpolations(Block.wrap($2),
|
||||||
{
|
{
|
||||||
quote: $1.quote
|
quote: $1.quote,
|
||||||
|
startQuote: LOC(1)(new Literal($1.toString()))
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|
|
@ -165,8 +165,12 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get a lookup hash for a token based on its location data.
|
||||||
|
// Multiple tokens might have the same location hash, but using exclusive
|
||||||
|
// location data distinguishes e.g. zero-length generated tokens from
|
||||||
|
// actual source tokens.
|
||||||
buildLocationHash = function(loc) {
|
buildLocationHash = function(loc) {
|
||||||
return `${loc.first_line}x${loc.first_column}-${loc.last_line}x${loc.last_column}`;
|
return `${loc.range[0]}-${loc.range[1]}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build a dictionary of extra token properties organized by tokens’ locations
|
// Build a dictionary of extra token properties organized by tokens’ locations
|
||||||
|
|
|
@ -377,7 +377,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delimiter = quote.charAt(0);
|
delimiter = quote.charAt(0);
|
||||||
this.mergeInterpolationTokens(tokens, {quote, indent}, (value) => {
|
this.mergeInterpolationTokens(tokens, {
|
||||||
|
quote,
|
||||||
|
indent,
|
||||||
|
endOffset: end
|
||||||
|
}, (value) => {
|
||||||
return this.validateUnicodeCodePointEscapes(value, {
|
return this.validateUnicodeCodePointEscapes(value, {
|
||||||
delimiter: quote
|
delimiter: quote
|
||||||
});
|
});
|
||||||
|
@ -450,8 +454,9 @@
|
||||||
// this comment to; and follow with a newline.
|
// this comment to; and follow with a newline.
|
||||||
commentAttachments[0].newLine = true;
|
commentAttachments[0].newLine = true;
|
||||||
this.lineToken(this.chunk.slice(comment.length));
|
this.lineToken(this.chunk.slice(comment.length));
|
||||||
placeholderToken = this.makeToken('JS', '');
|
placeholderToken = this.makeToken('JS', '', {
|
||||||
placeholderToken.generated = true;
|
generated: true
|
||||||
|
});
|
||||||
placeholderToken.comments = commentAttachments;
|
placeholderToken.comments = commentAttachments;
|
||||||
this.tokens.push(placeholderToken);
|
this.tokens.push(placeholderToken);
|
||||||
this.newlineToken(0);
|
this.newlineToken(0);
|
||||||
|
@ -562,7 +567,8 @@
|
||||||
});
|
});
|
||||||
this.mergeInterpolationTokens(tokens, {
|
this.mergeInterpolationTokens(tokens, {
|
||||||
double: true,
|
double: true,
|
||||||
heregex: {flags}
|
heregex: {flags},
|
||||||
|
endOffset: end
|
||||||
}, (str) => {
|
}, (str) => {
|
||||||
return this.validateUnicodeCodePointEscapes(str, {delimiter});
|
return this.validateUnicodeCodePointEscapes(str, {delimiter});
|
||||||
});
|
});
|
||||||
|
@ -864,7 +870,9 @@
|
||||||
tokens,
|
tokens,
|
||||||
index: end
|
index: end
|
||||||
} = this.matchWithInterpolations(INSIDE_CSX, '>', '</', CSX_INTERPOLATION));
|
} = this.matchWithInterpolations(INSIDE_CSX, '>', '</', CSX_INTERPOLATION));
|
||||||
this.mergeInterpolationTokens(tokens, {}, (value) => {
|
this.mergeInterpolationTokens(tokens, {
|
||||||
|
endOffset: end
|
||||||
|
}, (value) => {
|
||||||
return this.validateUnicodeCodePointEscapes(value, {
|
return this.validateUnicodeCodePointEscapes(value, {
|
||||||
delimiter: '>'
|
delimiter: '>'
|
||||||
});
|
});
|
||||||
|
@ -1127,7 +1135,7 @@
|
||||||
// This method allows us to have strings within interpolations within strings,
|
// This method allows us to have strings within interpolations within strings,
|
||||||
// ad infinitum.
|
// ad infinitum.
|
||||||
matchWithInterpolations(regex, delimiter, closingDelimiter = delimiter, interpolators = /^#\{/) {
|
matchWithInterpolations(regex, delimiter, closingDelimiter = delimiter, interpolators = /^#\{/) {
|
||||||
var braceInterpolator, close, column, firstToken, index, interpolationOffset, interpolator, lastToken, line, match, nested, offset, offsetInChunk, open, ref, ref1, rest, str, strPart, tokens;
|
var braceInterpolator, close, column, index, interpolationOffset, interpolator, line, match, nested, offset, offsetInChunk, open, ref, ref1, rest, str, strPart, tokens;
|
||||||
tokens = [];
|
tokens = [];
|
||||||
offsetInChunk = delimiter.length;
|
offsetInChunk = delimiter.length;
|
||||||
if (this.chunk.slice(0, offsetInChunk) !== delimiter) {
|
if (this.chunk.slice(0, offsetInChunk) !== delimiter) {
|
||||||
|
@ -1172,6 +1180,8 @@
|
||||||
[open] = nested, [close] = slice.call(nested, -1);
|
[open] = nested, [close] = slice.call(nested, -1);
|
||||||
open[0] = 'INTERPOLATION_START';
|
open[0] = 'INTERPOLATION_START';
|
||||||
open[1] = '(';
|
open[1] = '(';
|
||||||
|
open[2].first_column -= interpolationOffset;
|
||||||
|
open[2].range = [open[2].range[0] - interpolationOffset, open[2].range[1]];
|
||||||
close[0] = 'INTERPOLATION_END';
|
close[0] = 'INTERPOLATION_END';
|
||||||
close[1] = ')';
|
close[1] = ')';
|
||||||
close.origin = ['', 'end of interpolation', close[2]];
|
close.origin = ['', 'end of interpolation', close[2]];
|
||||||
|
@ -1206,21 +1216,6 @@
|
||||||
length: delimiter.length
|
length: delimiter.length
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
[firstToken] = tokens, [lastToken] = slice.call(tokens, -1);
|
|
||||||
firstToken[2].first_column -= delimiter.length;
|
|
||||||
firstToken[2].range[0] -= delimiter.length;
|
|
||||||
lastToken[2].range[1] += closingDelimiter.length;
|
|
||||||
if (lastToken[1].substr(-1) === '\n') {
|
|
||||||
lastToken[2].last_line += 1;
|
|
||||||
lastToken[2].last_column = closingDelimiter.length - 1;
|
|
||||||
} else {
|
|
||||||
lastToken[2].last_column += closingDelimiter.length;
|
|
||||||
}
|
|
||||||
lastToken[2].last_column_exclusive += closingDelimiter.length;
|
|
||||||
if (lastToken[1].length === 0) {
|
|
||||||
lastToken[2].last_column -= 1;
|
|
||||||
lastToken[2].range[1] -= 1;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
tokens,
|
tokens,
|
||||||
index: offsetInChunk + closingDelimiter.length
|
index: offsetInChunk + closingDelimiter.length
|
||||||
|
@ -1232,11 +1227,11 @@
|
||||||
// of `'NEOSTRING'`s are converted using `fn` and turned into strings using
|
// of `'NEOSTRING'`s are converted using `fn` and turned into strings using
|
||||||
// `options` first.
|
// `options` first.
|
||||||
mergeInterpolationTokens(tokens, options, fn) {
|
mergeInterpolationTokens(tokens, options, fn) {
|
||||||
var $, converted, double, firstIndex, heregex, i, indent, j, k, lastToken, len, len1, locationToken, lparen, placeholderToken, quote, rparen, tag, token, tokensToPush, val, value;
|
var $, converted, double, endOffset, firstIndex, heregex, i, indent, j, k, lastToken, len, len1, locationToken, lparen, placeholderToken, quote, ref, ref1, rparen, tag, token, tokensToPush, val, value;
|
||||||
({quote, indent, double, heregex} = options);
|
({quote, indent, double, heregex, endOffset} = options);
|
||||||
if (tokens.length > 1) {
|
if (tokens.length > 1) {
|
||||||
lparen = this.token('STRING_START', '(', {
|
lparen = this.token('STRING_START', '(', {
|
||||||
length: 0,
|
length: (ref = quote != null ? quote.length : void 0) != null ? ref : 0,
|
||||||
data: {quote}
|
data: {quote}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1289,6 +1284,20 @@
|
||||||
}
|
}
|
||||||
token[0] = 'STRING';
|
token[0] = 'STRING';
|
||||||
token[1] = '"' + converted + '"';
|
token[1] = '"' + converted + '"';
|
||||||
|
if (tokens.length === 1 && (quote != null)) {
|
||||||
|
token[2].first_column -= quote.length;
|
||||||
|
if (token[1].substr(-2, 1) === '\n') {
|
||||||
|
token[2].last_line += 1;
|
||||||
|
token[2].last_column = quote.length - 1;
|
||||||
|
} else {
|
||||||
|
token[2].last_column += quote.length;
|
||||||
|
if (token[1].length === 2) {
|
||||||
|
token[2].last_column -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token[2].last_column_exclusive += quote.length;
|
||||||
|
token[2].range = [token[2].range[0] - quote.length, token[2].range[1] + quote.length];
|
||||||
|
}
|
||||||
locationToken = token;
|
locationToken = token;
|
||||||
tokensToPush = [token];
|
tokensToPush = [token];
|
||||||
}
|
}
|
||||||
|
@ -1311,16 +1320,10 @@
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
lparen[2] = lparen.origin[2];
|
lparen[2] = lparen.origin[2];
|
||||||
rparen = this.token('STRING_END', ')');
|
return rparen = this.token('STRING_END', ')', {
|
||||||
return rparen[2] = {
|
offset: endOffset - (quote != null ? quote : '').length,
|
||||||
first_line: lastToken[2].last_line,
|
length: (ref1 = quote != null ? quote.length : void 0) != null ? ref1 : 0
|
||||||
first_column: lastToken[2].last_column,
|
});
|
||||||
last_line: lastToken[2].last_line,
|
|
||||||
last_column: lastToken[2].last_column,
|
|
||||||
last_line_exclusive: lastToken[2].last_line_exclusive,
|
|
||||||
last_column_exclusive: lastToken[2].last_column_exclusive,
|
|
||||||
range: lastToken[2].range
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,7 +1385,7 @@
|
||||||
// so if last_column == first_column, then we’re looking at a character of length 1.
|
// so if last_column == first_column, then we’re looking at a character of length 1.
|
||||||
lastCharacter = length > 0 ? length - 1 : 0;
|
lastCharacter = length > 0 ? length - 1 : 0;
|
||||||
[locationData.last_line, locationData.last_column, endOffset] = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter);
|
[locationData.last_line, locationData.last_column, endOffset] = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter);
|
||||||
[locationData.last_line_exclusive, locationData.last_column_exclusive] = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter + 1);
|
[locationData.last_line_exclusive, locationData.last_column_exclusive] = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter + (length > 0 ? 1 : 0));
|
||||||
locationData.range[1] = length > 0 ? endOffset + 1 : endOffset;
|
locationData.range[1] = length > 0 ? endOffset + 1 : endOffset;
|
||||||
return locationData;
|
return locationData;
|
||||||
}
|
}
|
||||||
|
@ -1392,13 +1395,17 @@
|
||||||
makeToken(tag, value, {
|
makeToken(tag, value, {
|
||||||
offset: offsetInChunk = 0,
|
offset: offsetInChunk = 0,
|
||||||
length = value.length,
|
length = value.length,
|
||||||
origin
|
origin,
|
||||||
|
generated
|
||||||
} = {}) {
|
} = {}) {
|
||||||
var token;
|
var token;
|
||||||
token = [tag, value, this.makeLocationData({offsetInChunk, length})];
|
token = [tag, value, this.makeLocationData({offsetInChunk, length})];
|
||||||
if (origin) {
|
if (origin) {
|
||||||
token.origin = origin;
|
token.origin = origin;
|
||||||
}
|
}
|
||||||
|
if (generated) {
|
||||||
|
token.generated = true;
|
||||||
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1408,9 +1415,9 @@
|
||||||
// not specified, the length of `value` will be used.
|
// not specified, the length of `value` will be used.
|
||||||
|
|
||||||
// Returns the new token.
|
// Returns the new token.
|
||||||
token(tag, value, {offset, length, origin, data} = {}) {
|
token(tag, value, {offset, length, origin, data, generated} = {}) {
|
||||||
var token;
|
var token;
|
||||||
token = this.makeToken(tag, value, {offset, length, origin});
|
token = this.makeToken(tag, value, {offset, length, origin, generated});
|
||||||
if (data) {
|
if (data) {
|
||||||
addTokenData(token, data);
|
addTokenData(token, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||||
// but some are created by other nodes as a method of code generation. To convert
|
// but some are created by other nodes as a method of code generation. To convert
|
||||||
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
||||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Catch, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncDirectiveReturn, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, MetaProperty, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, SwitchCase, SwitchWhen, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isAstLocGreater, isFunction, isLiteralArguments, isLiteralThis, isLocationDataEndGreater, isLocationDataStartGreater, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Catch, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncDirectiveReturn, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, MetaProperty, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, SwitchCase, SwitchWhen, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, TemplateElement, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isAstLocGreater, isFunction, isLiteralArguments, isLiteralThis, isLocationDataEndGreater, isLocationDataStartGreater, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||||
indexOf = [].indexOf,
|
indexOf = [].indexOf,
|
||||||
splice = [].splice,
|
splice = [].splice,
|
||||||
slice1 = [].slice;
|
slice1 = [].slice;
|
||||||
|
@ -6620,10 +6620,11 @@
|
||||||
//### StringWithInterpolations
|
//### StringWithInterpolations
|
||||||
exports.StringWithInterpolations = StringWithInterpolations = (function() {
|
exports.StringWithInterpolations = StringWithInterpolations = (function() {
|
||||||
class StringWithInterpolations extends Base {
|
class StringWithInterpolations extends Base {
|
||||||
constructor(body1, {quote} = {}) {
|
constructor(body1, {quote, startQuote} = {}) {
|
||||||
super();
|
super();
|
||||||
this.body = body1;
|
this.body = body1;
|
||||||
this.quote = quote;
|
this.quote = quote;
|
||||||
|
this.startQuote = startQuote;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `unwrap` returns `this` to stop ancestor nodes reaching in to grab @body,
|
// `unwrap` returns `this` to stop ancestor nodes reaching in to grab @body,
|
||||||
|
@ -6637,13 +6638,8 @@
|
||||||
return this.body.shouldCache();
|
return this.body.shouldCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
compileNode(o) {
|
extractElements(o) {
|
||||||
var code, element, elements, expr, fragments, j, len1, salvagedComments, wrapped;
|
var elements, expr, salvagedComments;
|
||||||
if (this.csxAttribute) {
|
|
||||||
wrapped = new Parens(new StringWithInterpolations(this.body));
|
|
||||||
wrapped.csxAttribute = true;
|
|
||||||
return wrapped.compileNode(o);
|
|
||||||
}
|
|
||||||
// Assumes that `expr` is `Block`
|
// Assumes that `expr` is `Block`
|
||||||
expr = this.body.unwrap();
|
expr = this.body.unwrap();
|
||||||
elements = [];
|
elements = [];
|
||||||
|
@ -6697,6 +6693,20 @@
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
compileNode(o) {
|
||||||
|
var code, element, elements, fragments, j, len1, ref1, wrapped;
|
||||||
|
if (this.comments == null) {
|
||||||
|
this.comments = (ref1 = this.startQuote) != null ? ref1.comments : void 0;
|
||||||
|
}
|
||||||
|
if (this.csxAttribute) {
|
||||||
|
wrapped = new Parens(new StringWithInterpolations(this.body));
|
||||||
|
wrapped.csxAttribute = true;
|
||||||
|
return wrapped.compileNode(o);
|
||||||
|
}
|
||||||
|
elements = this.extractElements(o);
|
||||||
fragments = [];
|
fragments = [];
|
||||||
if (!this.csx) {
|
if (!this.csx) {
|
||||||
fragments.push(this.makeCode('`'));
|
fragments.push(this.makeCode('`'));
|
||||||
|
@ -6722,8 +6732,8 @@
|
||||||
}
|
}
|
||||||
code = element.compileToFragments(o, LEVEL_PAREN);
|
code = element.compileToFragments(o, LEVEL_PAREN);
|
||||||
if (!this.isNestedTag(element) || code.some(function(fragment) {
|
if (!this.isNestedTag(element) || code.some(function(fragment) {
|
||||||
var ref1;
|
var ref2;
|
||||||
return (ref1 = fragment.comments) != null ? ref1.some(function(comment) {
|
return (ref2 = fragment.comments) != null ? ref2.some(function(comment) {
|
||||||
return comment.here === false;
|
return comment.here === false;
|
||||||
}) : void 0;
|
}) : void 0;
|
||||||
})) {
|
})) {
|
||||||
|
@ -6752,6 +6762,29 @@
|
||||||
return this.csx && call instanceof CSXElement;
|
return this.csx && call instanceof CSXElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
astType() {
|
||||||
|
return 'TemplateLiteral';
|
||||||
|
}
|
||||||
|
|
||||||
|
astProperties(o) {
|
||||||
|
var element, elements, expressions, index, j, last, len1, quasis;
|
||||||
|
elements = this.extractElements(o);
|
||||||
|
[last] = slice1.call(elements, -1);
|
||||||
|
quasis = [];
|
||||||
|
expressions = [];
|
||||||
|
for (index = j = 0, len1 = elements.length; j < len1; index = ++j) {
|
||||||
|
element = elements[index];
|
||||||
|
if (element instanceof StringLiteral) {
|
||||||
|
quasis.push(new TemplateElement(element.originalValue, {
|
||||||
|
tail: element === last
|
||||||
|
}).withLocationDataFrom(element).ast(o));
|
||||||
|
} else {
|
||||||
|
expressions.push(element.unwrap().ast(o));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {expressions, quasis, quote: this.quote};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
StringWithInterpolations.prototype.children = ['body'];
|
StringWithInterpolations.prototype.children = ['body'];
|
||||||
|
@ -6760,6 +6793,26 @@
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
||||||
|
exports.TemplateElement = TemplateElement = class TemplateElement extends Base {
|
||||||
|
constructor(value1, {
|
||||||
|
tail: tail1
|
||||||
|
} = {}) {
|
||||||
|
super();
|
||||||
|
this.value = value1;
|
||||||
|
this.tail = tail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
astProperties() {
|
||||||
|
return {
|
||||||
|
value: {
|
||||||
|
raw: this.value
|
||||||
|
},
|
||||||
|
tail: !!this.tail
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
exports.Interpolation = Interpolation = (function() {
|
exports.Interpolation = Interpolation = (function() {
|
||||||
class Interpolation extends Base {
|
class Interpolation extends Base {
|
||||||
constructor(expression1) {
|
constructor(expression1) {
|
||||||
|
|
|
@ -169,7 +169,8 @@ break;
|
||||||
case 43:
|
case 43:
|
||||||
this.$ = yy.addDataToNode(yy, _$[$0-2], $$[$0-2], _$[$0], $$[$0], true)(new yy.StringWithInterpolations(yy.Block.wrap($$[$0-1]),
|
this.$ = yy.addDataToNode(yy, _$[$0-2], $$[$0-2], _$[$0], $$[$0], true)(new yy.StringWithInterpolations(yy.Block.wrap($$[$0-1]),
|
||||||
{
|
{
|
||||||
quote: $$[$0-2].quote
|
quote: $$[$0-2].quote,
|
||||||
|
startQuote: yy.addDataToNode(yy, _$[$0-2], $$[$0-2], null, null, true)(new yy.Literal($$[$0-2].toString()))
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
case 44: case 107: case 154: case 173: case 195: case 228: case 242: case 246: case 297: case 343:
|
case 44: case 107: case 154: case 173: case 195: case 228: case 242: case 246: case 297: case 343:
|
||||||
|
|
|
@ -766,8 +766,8 @@
|
||||||
// location corresponding to the last “real” token under the node.
|
// location corresponding to the last “real” token under the node.
|
||||||
fixOutdentLocationData() {
|
fixOutdentLocationData() {
|
||||||
return this.scanTokens(function(token, i, tokens) {
|
return this.scanTokens(function(token, i, tokens) {
|
||||||
var prevLocationData;
|
var prevLocationData, ref;
|
||||||
if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END') || (token.generated && token[0] === '}'))) {
|
if (!(token[0] === 'OUTDENT' || (token.generated && token[0] === 'CALL_END' && !((ref = token.data) != null ? ref.closingTagNameToken : void 0)) || (token.generated && token[0] === '}'))) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prevLocationData = tokens[i - 1][2];
|
prevLocationData = tokens[i - 1][2];
|
||||||
|
|
|
@ -183,7 +183,7 @@ grammar =
|
||||||
double: $1.double
|
double: $1.double
|
||||||
heregex: $1.heregex
|
heregex: $1.heregex
|
||||||
)
|
)
|
||||||
o 'STRING_START Interpolations STRING_END', -> new StringWithInterpolations Block.wrap($2), quote: $1.quote
|
o 'STRING_START Interpolations STRING_END', -> new StringWithInterpolations Block.wrap($2), quote: $1.quote, startQuote: LOC(1)(new Literal $1.toString())
|
||||||
]
|
]
|
||||||
|
|
||||||
Interpolations: [
|
Interpolations: [
|
||||||
|
|
|
@ -114,8 +114,12 @@ buildLocationData = (first, last) ->
|
||||||
last.range[1]
|
last.range[1]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Get a lookup hash for a token based on its location data.
|
||||||
|
# Multiple tokens might have the same location hash, but using exclusive
|
||||||
|
# location data distinguishes e.g. zero-length generated tokens from
|
||||||
|
# actual source tokens.
|
||||||
buildLocationHash = (loc) ->
|
buildLocationHash = (loc) ->
|
||||||
"#{loc.first_line}x#{loc.first_column}-#{loc.last_line}x#{loc.last_column}"
|
"#{loc.range[0]}-#{loc.range[1]}"
|
||||||
|
|
||||||
# Build a dictionary of extra token properties organized by tokens’ locations
|
# Build a dictionary of extra token properties organized by tokens’ locations
|
||||||
# used as lookup hashes.
|
# used as lookup hashes.
|
||||||
|
|
|
@ -301,7 +301,7 @@ exports.Lexer = class Lexer
|
||||||
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
||||||
|
|
||||||
delimiter = quote.charAt(0)
|
delimiter = quote.charAt(0)
|
||||||
@mergeInterpolationTokens tokens, {quote, indent}, (value) =>
|
@mergeInterpolationTokens tokens, {quote, indent, endOffset: end}, (value) =>
|
||||||
@validateUnicodeCodePointEscapes value, delimiter: quote
|
@validateUnicodeCodePointEscapes value, delimiter: quote
|
||||||
|
|
||||||
if @atCSXTag()
|
if @atCSXTag()
|
||||||
|
@ -355,8 +355,7 @@ exports.Lexer = class Lexer
|
||||||
# this comment to; and follow with a newline.
|
# this comment to; and follow with a newline.
|
||||||
commentAttachments[0].newLine = yes
|
commentAttachments[0].newLine = yes
|
||||||
@lineToken @chunk[comment.length..] # Set the indent.
|
@lineToken @chunk[comment.length..] # Set the indent.
|
||||||
placeholderToken = @makeToken 'JS', ''
|
placeholderToken = @makeToken 'JS', '', generated: yes
|
||||||
placeholderToken.generated = yes
|
|
||||||
placeholderToken.comments = commentAttachments
|
placeholderToken.comments = commentAttachments
|
||||||
@tokens.push placeholderToken
|
@tokens.push placeholderToken
|
||||||
@newlineToken 0
|
@newlineToken 0
|
||||||
|
@ -417,7 +416,7 @@ exports.Lexer = class Lexer
|
||||||
@token 'REGEX_START', '(', {length: 0, origin}
|
@token 'REGEX_START', '(', {length: 0, origin}
|
||||||
@token 'IDENTIFIER', 'RegExp', length: 0
|
@token 'IDENTIFIER', 'RegExp', length: 0
|
||||||
@token 'CALL_START', '(', length: 0
|
@token 'CALL_START', '(', length: 0
|
||||||
@mergeInterpolationTokens tokens, {double: yes, heregex: {flags}}, (str) =>
|
@mergeInterpolationTokens tokens, {double: yes, heregex: {flags}, endOffset: end}, (str) =>
|
||||||
@validateUnicodeCodePointEscapes str, {delimiter}
|
@validateUnicodeCodePointEscapes str, {delimiter}
|
||||||
if flags
|
if flags
|
||||||
@token ',', ',', offset: index - 1, length: 0
|
@token ',', ',', offset: index - 1, length: 0
|
||||||
|
@ -613,7 +612,7 @@ exports.Lexer = class Lexer
|
||||||
@token ',', 'JSX_COMMA', generated: yes
|
@token ',', 'JSX_COMMA', generated: yes
|
||||||
{tokens, index: end} =
|
{tokens, index: end} =
|
||||||
@matchWithInterpolations INSIDE_CSX, '>', '</', CSX_INTERPOLATION
|
@matchWithInterpolations INSIDE_CSX, '>', '</', CSX_INTERPOLATION
|
||||||
@mergeInterpolationTokens tokens, {}, (value) =>
|
@mergeInterpolationTokens tokens, {endOffset: end}, (value) =>
|
||||||
@validateUnicodeCodePointEscapes value, delimiter: '>'
|
@validateUnicodeCodePointEscapes value, delimiter: '>'
|
||||||
match = CSX_IDENTIFIER.exec(@chunk[end...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
|
match = CSX_IDENTIFIER.exec(@chunk[end...]) or CSX_FRAGMENT_IDENTIFIER.exec(@chunk[end...])
|
||||||
if not match or match[1] isnt "#{csxTag.name}#{(".#{property}" for property in csxTag.properties).join ''}"
|
if not match or match[1] isnt "#{csxTag.name}#{(".#{property}" for property in csxTag.properties).join ''}"
|
||||||
|
@ -821,6 +820,11 @@ exports.Lexer = class Lexer
|
||||||
[open, ..., close] = nested
|
[open, ..., close] = nested
|
||||||
open[0] = 'INTERPOLATION_START'
|
open[0] = 'INTERPOLATION_START'
|
||||||
open[1] = '('
|
open[1] = '('
|
||||||
|
open[2].first_column -= interpolationOffset
|
||||||
|
open[2].range = [
|
||||||
|
open[2].range[0] - interpolationOffset
|
||||||
|
open[2].range[1]
|
||||||
|
]
|
||||||
close[0] = 'INTERPOLATION_END'
|
close[0] = 'INTERPOLATION_END'
|
||||||
close[1] = ')'
|
close[1] = ')'
|
||||||
close.origin = ['', 'end of interpolation', close[2]]
|
close.origin = ['', 'end of interpolation', close[2]]
|
||||||
|
@ -845,20 +849,6 @@ exports.Lexer = class Lexer
|
||||||
unless str[...closingDelimiter.length] is closingDelimiter
|
unless str[...closingDelimiter.length] is closingDelimiter
|
||||||
@error "missing #{closingDelimiter}", length: delimiter.length
|
@error "missing #{closingDelimiter}", length: delimiter.length
|
||||||
|
|
||||||
[firstToken, ..., lastToken] = tokens
|
|
||||||
firstToken[2].first_column -= delimiter.length
|
|
||||||
firstToken[2].range[0] -= delimiter.length
|
|
||||||
lastToken[2].range[1] += closingDelimiter.length
|
|
||||||
if lastToken[1].substr(-1) is '\n'
|
|
||||||
lastToken[2].last_line += 1
|
|
||||||
lastToken[2].last_column = closingDelimiter.length - 1
|
|
||||||
else
|
|
||||||
lastToken[2].last_column += closingDelimiter.length
|
|
||||||
lastToken[2].last_column_exclusive += closingDelimiter.length
|
|
||||||
if lastToken[1].length is 0
|
|
||||||
lastToken[2].last_column -= 1
|
|
||||||
lastToken[2].range[1] -= 1
|
|
||||||
|
|
||||||
{tokens, index: offsetInChunk + closingDelimiter.length}
|
{tokens, index: offsetInChunk + closingDelimiter.length}
|
||||||
|
|
||||||
# Merge the array `tokens` of the fake token types `'TOKENS'` and `'NEOSTRING'`
|
# Merge the array `tokens` of the fake token types `'TOKENS'` and `'NEOSTRING'`
|
||||||
|
@ -866,10 +856,10 @@ exports.Lexer = class Lexer
|
||||||
# of `'NEOSTRING'`s are converted using `fn` and turned into strings using
|
# of `'NEOSTRING'`s are converted using `fn` and turned into strings using
|
||||||
# `options` first.
|
# `options` first.
|
||||||
mergeInterpolationTokens: (tokens, options, fn) ->
|
mergeInterpolationTokens: (tokens, options, fn) ->
|
||||||
{quote, indent, double, heregex} = options
|
{quote, indent, double, heregex, endOffset} = options
|
||||||
|
|
||||||
if tokens.length > 1
|
if tokens.length > 1
|
||||||
lparen = @token 'STRING_START', '(', length: 0, data: {quote}
|
lparen = @token 'STRING_START', '(', length: quote?.length ? 0, data: {quote}
|
||||||
|
|
||||||
firstIndex = @tokens.length
|
firstIndex = @tokens.length
|
||||||
$ = tokens.length - 1
|
$ = tokens.length - 1
|
||||||
|
@ -900,6 +890,19 @@ exports.Lexer = class Lexer
|
||||||
addTokenData token, {heregex} if heregex
|
addTokenData token, {heregex} if heregex
|
||||||
token[0] = 'STRING'
|
token[0] = 'STRING'
|
||||||
token[1] = '"' + converted + '"'
|
token[1] = '"' + converted + '"'
|
||||||
|
if tokens.length is 1 and quote?
|
||||||
|
token[2].first_column -= quote.length
|
||||||
|
if token[1].substr(-2, 1) is '\n'
|
||||||
|
token[2].last_line +=1
|
||||||
|
token[2].last_column = quote.length - 1
|
||||||
|
else
|
||||||
|
token[2].last_column += quote.length
|
||||||
|
token[2].last_column -= 1 if token[1].length is 2
|
||||||
|
token[2].last_column_exclusive += quote.length
|
||||||
|
token[2].range = [
|
||||||
|
token[2].range[0] - quote.length
|
||||||
|
token[2].range[1] + quote.length
|
||||||
|
]
|
||||||
locationToken = token
|
locationToken = token
|
||||||
tokensToPush = [token]
|
tokensToPush = [token]
|
||||||
@tokens.push tokensToPush...
|
@tokens.push tokensToPush...
|
||||||
|
@ -919,15 +922,7 @@ exports.Lexer = class Lexer
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
lparen[2] = lparen.origin[2]
|
lparen[2] = lparen.origin[2]
|
||||||
rparen = @token 'STRING_END', ')'
|
rparen = @token 'STRING_END', ')', offset: endOffset - (quote ? '').length, length: quote?.length ? 0
|
||||||
rparen[2] =
|
|
||||||
first_line: lastToken[2].last_line
|
|
||||||
first_column: lastToken[2].last_column
|
|
||||||
last_line: lastToken[2].last_line
|
|
||||||
last_column: lastToken[2].last_column
|
|
||||||
last_line_exclusive: lastToken[2].last_line_exclusive
|
|
||||||
last_column_exclusive: lastToken[2].last_column_exclusive
|
|
||||||
range: lastToken[2].range
|
|
||||||
|
|
||||||
# Pairs up a closing token, ensuring that all listed pairs of tokens are
|
# Pairs up a closing token, ensuring that all listed pairs of tokens are
|
||||||
# correctly balanced throughout the course of the token stream.
|
# correctly balanced throughout the course of the token stream.
|
||||||
|
@ -982,16 +977,17 @@ exports.Lexer = class Lexer
|
||||||
[locationData.last_line, locationData.last_column, endOffset] =
|
[locationData.last_line, locationData.last_column, endOffset] =
|
||||||
@getLineAndColumnFromChunk offsetInChunk + lastCharacter
|
@getLineAndColumnFromChunk offsetInChunk + lastCharacter
|
||||||
[locationData.last_line_exclusive, locationData.last_column_exclusive] =
|
[locationData.last_line_exclusive, locationData.last_column_exclusive] =
|
||||||
@getLineAndColumnFromChunk offsetInChunk + lastCharacter + 1
|
@getLineAndColumnFromChunk offsetInChunk + lastCharacter + (if length > 0 then 1 else 0)
|
||||||
locationData.range[1] = if length > 0 then endOffset + 1 else endOffset
|
locationData.range[1] = if length > 0 then endOffset + 1 else endOffset
|
||||||
|
|
||||||
locationData
|
locationData
|
||||||
|
|
||||||
# Same as `token`, except this just returns the token without adding it
|
# Same as `token`, except this just returns the token without adding it
|
||||||
# to the results.
|
# to the results.
|
||||||
makeToken: (tag, value, {offset: offsetInChunk = 0, length = value.length, origin} = {}) ->
|
makeToken: (tag, value, {offset: offsetInChunk = 0, length = value.length, origin, generated} = {}) ->
|
||||||
token = [tag, value, @makeLocationData {offsetInChunk, length}]
|
token = [tag, value, @makeLocationData {offsetInChunk, length}]
|
||||||
token.origin = origin if origin
|
token.origin = origin if origin
|
||||||
|
token.generated = yes if generated
|
||||||
token
|
token
|
||||||
|
|
||||||
# Add a token to the results.
|
# Add a token to the results.
|
||||||
|
@ -1000,8 +996,8 @@ exports.Lexer = class Lexer
|
||||||
# not specified, the length of `value` will be used.
|
# not specified, the length of `value` will be used.
|
||||||
#
|
#
|
||||||
# Returns the new token.
|
# Returns the new token.
|
||||||
token: (tag, value, {offset, length, origin, data} = {}) ->
|
token: (tag, value, {offset, length, origin, data, generated} = {}) ->
|
||||||
token = @makeToken tag, value, {offset, length, origin}
|
token = @makeToken tag, value, {offset, length, origin, generated}
|
||||||
addTokenData token, data if data
|
addTokenData token, data if data
|
||||||
@tokens.push token
|
@tokens.push token
|
||||||
token
|
token
|
||||||
|
|
|
@ -4426,7 +4426,7 @@ exports.Parens = class Parens extends Base
|
||||||
#### StringWithInterpolations
|
#### StringWithInterpolations
|
||||||
|
|
||||||
exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
||||||
constructor: (@body, {@quote} = {}) ->
|
constructor: (@body, {@quote, @startQuote} = {}) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
children: ['body']
|
children: ['body']
|
||||||
|
@ -4438,12 +4438,7 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
||||||
|
|
||||||
shouldCache: -> @body.shouldCache()
|
shouldCache: -> @body.shouldCache()
|
||||||
|
|
||||||
compileNode: (o) ->
|
extractElements: (o) ->
|
||||||
if @csxAttribute
|
|
||||||
wrapped = new Parens new StringWithInterpolations @body
|
|
||||||
wrapped.csxAttribute = yes
|
|
||||||
return wrapped.compileNode o
|
|
||||||
|
|
||||||
# Assumes that `expr` is `Block`
|
# Assumes that `expr` is `Block`
|
||||||
expr = @body.unwrap()
|
expr = @body.unwrap()
|
||||||
|
|
||||||
|
@ -4483,6 +4478,18 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
||||||
delete node.comments
|
delete node.comments
|
||||||
return yes
|
return yes
|
||||||
|
|
||||||
|
elements
|
||||||
|
|
||||||
|
compileNode: (o) ->
|
||||||
|
@comments ?= @startQuote?.comments
|
||||||
|
|
||||||
|
if @csxAttribute
|
||||||
|
wrapped = new Parens new StringWithInterpolations @body
|
||||||
|
wrapped.csxAttribute = yes
|
||||||
|
return wrapped.compileNode o
|
||||||
|
|
||||||
|
elements = @extractElements o
|
||||||
|
|
||||||
fragments = []
|
fragments = []
|
||||||
fragments.push @makeCode '`' unless @csx
|
fragments.push @makeCode '`' unless @csx
|
||||||
for element in elements
|
for element in elements
|
||||||
|
@ -4518,6 +4525,36 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Base
|
||||||
call = element.unwrapAll?()
|
call = element.unwrapAll?()
|
||||||
@csx and call instanceof CSXElement
|
@csx and call instanceof CSXElement
|
||||||
|
|
||||||
|
astType: -> 'TemplateLiteral'
|
||||||
|
|
||||||
|
astProperties: (o) ->
|
||||||
|
elements = @extractElements o
|
||||||
|
[..., last] = elements
|
||||||
|
|
||||||
|
quasis = []
|
||||||
|
expressions = []
|
||||||
|
|
||||||
|
for element, index in elements
|
||||||
|
if element instanceof StringLiteral
|
||||||
|
quasis.push new TemplateElement(
|
||||||
|
element.originalValue
|
||||||
|
tail: element is last
|
||||||
|
).withLocationDataFrom(element).ast o
|
||||||
|
else
|
||||||
|
expressions.push element.unwrap().ast o
|
||||||
|
|
||||||
|
{expressions, quasis, @quote}
|
||||||
|
|
||||||
|
exports.TemplateElement = class TemplateElement extends Base
|
||||||
|
constructor: (@value, {@tail} = {}) ->
|
||||||
|
super()
|
||||||
|
|
||||||
|
astProperties: ->
|
||||||
|
return
|
||||||
|
value:
|
||||||
|
raw: @value
|
||||||
|
tail: !!@tail
|
||||||
|
|
||||||
exports.Interpolation = class Interpolation extends Base
|
exports.Interpolation = class Interpolation extends Base
|
||||||
constructor: (@expression) ->
|
constructor: (@expression) ->
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -539,7 +539,7 @@ exports.Rewriter = class Rewriter
|
||||||
fixOutdentLocationData: ->
|
fixOutdentLocationData: ->
|
||||||
@scanTokens (token, i, tokens) ->
|
@scanTokens (token, i, tokens) ->
|
||||||
return 1 unless token[0] is 'OUTDENT' or
|
return 1 unless token[0] is 'OUTDENT' or
|
||||||
(token.generated and token[0] is 'CALL_END') or
|
(token.generated and token[0] is 'CALL_END' and not token.data?.closingTagNameToken) or
|
||||||
(token.generated and token[0] is '}')
|
(token.generated and token[0] is '}')
|
||||||
prevLocationData = tokens[i - 1][2]
|
prevLocationData = tokens[i - 1][2]
|
||||||
token[2] =
|
token[2] =
|
||||||
|
|
|
@ -2215,23 +2215,108 @@ test "AST as expected for Parens node", ->
|
||||||
type: 'NumericLiteral'
|
type: 'NumericLiteral'
|
||||||
value: 1
|
value: 1
|
||||||
|
|
||||||
# test "AST as expected for StringWithInterpolations node", ->
|
test "AST as expected for StringWithInterpolations node", ->
|
||||||
# testExpression '"#{o}/"',
|
testExpression '"a#{b}c"',
|
||||||
# type: 'StringWithInterpolations'
|
type: 'TemplateLiteral'
|
||||||
# quote: '"'
|
expressions: [
|
||||||
# body:
|
ID 'b'
|
||||||
# type: 'Block'
|
]
|
||||||
# expressions: [
|
quasis: [
|
||||||
# originalValue: ''
|
type: 'TemplateElement'
|
||||||
# ,
|
value:
|
||||||
# type: 'Interpolation'
|
raw: 'a'
|
||||||
# expression:
|
tail: no
|
||||||
# type: 'Value'
|
,
|
||||||
# base:
|
type: 'TemplateElement'
|
||||||
# value: 'o'
|
value:
|
||||||
# ,
|
raw: 'c'
|
||||||
# originalValue: '/'
|
tail: yes
|
||||||
# ]
|
]
|
||||||
|
quote: '"'
|
||||||
|
|
||||||
|
testExpression '"""a#{b}c"""',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
ID 'b'
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: 'a'
|
||||||
|
tail: no
|
||||||
|
,
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: 'c'
|
||||||
|
tail: yes
|
||||||
|
]
|
||||||
|
quote: '"""'
|
||||||
|
|
||||||
|
testExpression '"#{b}"',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
ID 'b'
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: ''
|
||||||
|
tail: no
|
||||||
|
,
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: ''
|
||||||
|
tail: yes
|
||||||
|
]
|
||||||
|
quote: '"'
|
||||||
|
|
||||||
|
testExpression '''
|
||||||
|
" a
|
||||||
|
#{b}
|
||||||
|
c
|
||||||
|
"
|
||||||
|
''',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
ID 'b'
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: ' a\n '
|
||||||
|
tail: no
|
||||||
|
,
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: '\n c\n'
|
||||||
|
tail: yes
|
||||||
|
]
|
||||||
|
quote: '"'
|
||||||
|
|
||||||
|
testExpression '''
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
b#{
|
||||||
|
c
|
||||||
|
}d
|
||||||
|
"""
|
||||||
|
''',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
ID 'c'
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: '\n a\n b'
|
||||||
|
tail: no
|
||||||
|
,
|
||||||
|
type: 'TemplateElement'
|
||||||
|
value:
|
||||||
|
raw: 'd\n'
|
||||||
|
tail: yes
|
||||||
|
]
|
||||||
|
quote: '"""'
|
||||||
|
|
||||||
test "AST as expected for For node", ->
|
test "AST as expected for For node", ->
|
||||||
testStatement 'for x, i in arr when x? then return',
|
testStatement 'for x, i in arr when x? then return',
|
||||||
|
|
|
@ -5376,3 +5376,256 @@ test "AST location data as expected for For node", ->
|
||||||
end:
|
end:
|
||||||
line: 2
|
line: 2
|
||||||
column: 3
|
column: 3
|
||||||
|
|
||||||
|
test "AST location data as expected for StringWithInterpolations node", ->
|
||||||
|
testAstLocationData '"a#{b}c"',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
start: 4
|
||||||
|
end: 5
|
||||||
|
range: [4, 5]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 4
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 5
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
start: 1
|
||||||
|
end: 2
|
||||||
|
range: [1, 2]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 1
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 2
|
||||||
|
,
|
||||||
|
start: 6
|
||||||
|
end: 7
|
||||||
|
range: [6, 7]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 6
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 7
|
||||||
|
]
|
||||||
|
start: 0
|
||||||
|
end: 8
|
||||||
|
range: [0, 8]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 0
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 8
|
||||||
|
|
||||||
|
testAstLocationData '"""a#{b}c"""',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
start: 6
|
||||||
|
end: 7
|
||||||
|
range: [6, 7]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 6
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 7
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
start: 3
|
||||||
|
end: 4
|
||||||
|
range: [3, 4]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 3
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 4
|
||||||
|
,
|
||||||
|
start: 8
|
||||||
|
end: 9
|
||||||
|
range: [8, 9]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 8
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 9
|
||||||
|
]
|
||||||
|
start: 0
|
||||||
|
end: 12
|
||||||
|
range: [0, 12]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 0
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 12
|
||||||
|
|
||||||
|
testAstLocationData '"#{b}"',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
start: 3
|
||||||
|
end: 4
|
||||||
|
range: [3, 4]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 3
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 4
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
start: 1
|
||||||
|
end: 1
|
||||||
|
range: [1, 1]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 1
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 1
|
||||||
|
,
|
||||||
|
start: 5
|
||||||
|
end: 5
|
||||||
|
range: [5, 5]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 5
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 5
|
||||||
|
]
|
||||||
|
start: 0
|
||||||
|
end: 6
|
||||||
|
range: [0, 6]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 0
|
||||||
|
end:
|
||||||
|
line: 1
|
||||||
|
column: 6
|
||||||
|
|
||||||
|
testAstLocationData '''
|
||||||
|
" a
|
||||||
|
#{b}
|
||||||
|
c
|
||||||
|
"
|
||||||
|
''',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
start: 8
|
||||||
|
end: 9
|
||||||
|
range: [8, 9]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 2
|
||||||
|
column: 4
|
||||||
|
end:
|
||||||
|
line: 2
|
||||||
|
column: 5
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
start: 1
|
||||||
|
end: 6
|
||||||
|
range: [1, 6]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 1
|
||||||
|
end:
|
||||||
|
line: 2
|
||||||
|
column: 2
|
||||||
|
,
|
||||||
|
start: 10
|
||||||
|
end: 15
|
||||||
|
range: [10, 15]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 2
|
||||||
|
column: 6
|
||||||
|
end:
|
||||||
|
line: 4
|
||||||
|
column: 0
|
||||||
|
]
|
||||||
|
start: 0
|
||||||
|
end: 16
|
||||||
|
range: [0, 16]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 0
|
||||||
|
end:
|
||||||
|
line: 4
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
testAstLocationData '''
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
b#{
|
||||||
|
c
|
||||||
|
}d
|
||||||
|
"""
|
||||||
|
''',
|
||||||
|
type: 'TemplateLiteral'
|
||||||
|
expressions: [
|
||||||
|
start: 20
|
||||||
|
end: 21
|
||||||
|
range: [20, 21]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 4
|
||||||
|
column: 4
|
||||||
|
end:
|
||||||
|
line: 4
|
||||||
|
column: 5
|
||||||
|
]
|
||||||
|
quasis: [
|
||||||
|
start: 3
|
||||||
|
end: 13
|
||||||
|
range: [3, 13]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 3
|
||||||
|
end:
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
|
,
|
||||||
|
start: 25
|
||||||
|
end: 27
|
||||||
|
range: [25, 27]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 5
|
||||||
|
column: 3
|
||||||
|
end:
|
||||||
|
line: 6
|
||||||
|
column: 0
|
||||||
|
]
|
||||||
|
start: 0
|
||||||
|
end: 30
|
||||||
|
range: [0, 30]
|
||||||
|
loc:
|
||||||
|
start:
|
||||||
|
line: 1
|
||||||
|
column: 0
|
||||||
|
end:
|
||||||
|
line: 6
|
||||||
|
column: 3
|
||||||
|
|
|
@ -72,7 +72,7 @@ test 'Verify locations in string interpolation (in "string")', ->
|
||||||
[a, b, c] = getMatchingTokens '"a#{b}c"', '"a"', 'b', '"c"'
|
[a, b, c] = getMatchingTokens '"a#{b}c"', '"a"', 'b', '"c"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 1
|
||||||
eq a[2].last_line, 0
|
eq a[2].last_line, 0
|
||||||
eq a[2].last_column, 1
|
eq a[2].last_column, 1
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ test 'Verify locations in string interpolation (in "string")', ->
|
||||||
eq c[2].first_line, 0
|
eq c[2].first_line, 0
|
||||||
eq c[2].first_column, 6
|
eq c[2].first_column, 6
|
||||||
eq c[2].last_line, 0
|
eq c[2].last_line, 0
|
||||||
eq c[2].last_column, 7
|
eq c[2].last_column, 6
|
||||||
|
|
||||||
test 'Verify locations in string interpolation (in "string", multiple interpolation)', ->
|
test 'Verify locations in string interpolation (in "string", multiple interpolation)', ->
|
||||||
[a, b, c] = getMatchingTokens '"#{a}b#{c}"', 'a', '"b"', 'c'
|
[a, b, c] = getMatchingTokens '"#{a}b#{c}"', 'a', '"b"', 'c'
|
||||||
|
@ -180,7 +180,7 @@ test 'Verify locations in string interpolation (in """string""", line breaks)',
|
||||||
[a, b, c] = getMatchingTokens '"""a\n#{b}\nc"""', '"a\n"', 'b', '"\nc"'
|
[a, b, c] = getMatchingTokens '"""a\n#{b}\nc"""', '"a\n"', 'b', '"\nc"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 3
|
||||||
eq a[2].last_line, 0
|
eq a[2].last_line, 0
|
||||||
eq a[2].last_column, 4
|
eq a[2].last_column, 4
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ test 'Verify locations in string interpolation (in """string""", line breaks)',
|
||||||
eq c[2].first_line, 1
|
eq c[2].first_line, 1
|
||||||
eq c[2].first_column, 4
|
eq c[2].first_column, 4
|
||||||
eq c[2].last_line, 2
|
eq c[2].last_line, 2
|
||||||
eq c[2].last_column, 3
|
eq c[2].last_column, 0
|
||||||
|
|
||||||
test 'Verify locations in string interpolation (in """string""", starting with a line break)', ->
|
test 'Verify locations in string interpolation (in """string""", starting with a line break)', ->
|
||||||
[b, c] = getMatchingTokens '"""\n#{b}\nc"""', 'b', '"\nc"'
|
[b, c] = getMatchingTokens '"""\n#{b}\nc"""', 'b', '"\nc"'
|
||||||
|
@ -205,13 +205,13 @@ test 'Verify locations in string interpolation (in """string""", starting with a
|
||||||
eq c[2].first_line, 1
|
eq c[2].first_line, 1
|
||||||
eq c[2].first_column, 4
|
eq c[2].first_column, 4
|
||||||
eq c[2].last_line, 2
|
eq c[2].last_line, 2
|
||||||
eq c[2].last_column, 3
|
eq c[2].last_column, 0
|
||||||
|
|
||||||
test 'Verify locations in string interpolation (in """string""", starting with line breaks)', ->
|
test 'Verify locations in string interpolation (in """string""", starting with line breaks)', ->
|
||||||
[a, b, c] = getMatchingTokens '"""\n\n#{b}\nc"""', '"\n\n"', 'b', '"\nc"'
|
[a, b, c] = getMatchingTokens '"""\n\n#{b}\nc"""', '"\n\n"', 'b', '"\nc"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 3
|
||||||
eq a[2].last_line, 1
|
eq a[2].last_line, 1
|
||||||
eq a[2].last_column, 0
|
eq a[2].last_column, 0
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ test 'Verify locations in string interpolation (in """string""", starting with l
|
||||||
eq c[2].first_line, 2
|
eq c[2].first_line, 2
|
||||||
eq c[2].first_column, 4
|
eq c[2].first_column, 4
|
||||||
eq c[2].last_line, 3
|
eq c[2].last_line, 3
|
||||||
eq c[2].last_column, 3
|
eq c[2].last_column, 0
|
||||||
|
|
||||||
test 'Verify locations in string interpolation (in """string""", multiple interpolation)', ->
|
test 'Verify locations in string interpolation (in """string""", multiple interpolation)', ->
|
||||||
[a, b, c] = getMatchingTokens '"""#{a}\nb\n#{c}"""', 'a', '"\nb\n"', 'c'
|
[a, b, c] = getMatchingTokens '"""#{a}\nb\n#{c}"""', 'a', '"\nb\n"', 'c'
|
||||||
|
@ -301,7 +301,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
[a, b, c] = getMatchingTokens '///a#{b}c///', '"a"', 'b', '"c"'
|
[a, b, c] = getMatchingTokens '///a#{b}c///', '"a"', 'b', '"c"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 3
|
||||||
eq a[2].last_line, 0
|
eq a[2].last_line, 0
|
||||||
eq a[2].last_column, 3
|
eq a[2].last_column, 3
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
eq c[2].first_line, 0
|
eq c[2].first_line, 0
|
||||||
eq c[2].first_column, 8
|
eq c[2].first_column, 8
|
||||||
eq c[2].last_line, 0
|
eq c[2].last_line, 0
|
||||||
eq c[2].last_column, 11
|
eq c[2].last_column, 8
|
||||||
|
|
||||||
test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks)', ->
|
test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks)', ->
|
||||||
[a, b, c] = getMatchingTokens '///#{a}\nb\n#{c}///', 'a', '"\nb\n"', 'c'
|
[a, b, c] = getMatchingTokens '///#{a}\nb\n#{c}///', 'a', '"\nb\n"', 'c'
|
||||||
|
@ -355,7 +355,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
[a, b, c] = getMatchingTokens '///a\n\n\n#{b}\n\n\nc///', '"a\n\n\n"', 'b', '"\n\n\nc"'
|
[a, b, c] = getMatchingTokens '///a\n\n\n#{b}\n\n\nc///', '"a\n\n\n"', 'b', '"\n\n\nc"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 3
|
||||||
eq a[2].last_line, 2
|
eq a[2].last_line, 2
|
||||||
eq a[2].last_column, 0
|
eq a[2].last_column, 0
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
eq c[2].first_line, 3
|
eq c[2].first_line, 3
|
||||||
eq c[2].first_column, 4
|
eq c[2].first_column, 4
|
||||||
eq c[2].last_line, 6
|
eq c[2].last_line, 6
|
||||||
eq c[2].last_column, 3
|
eq c[2].last_column, 0
|
||||||
|
|
||||||
test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks and starting with linebreak)', ->
|
test 'Verify locations in heregex interpolation (in ///regex///, multiple interpolation and line breaks and starting with linebreak)', ->
|
||||||
[a, b, c] = getMatchingTokens '///\n#{a}\nb\n#{c}///', 'a', '"\nb\n"', 'c'
|
[a, b, c] = getMatchingTokens '///\n#{a}\nb\n#{c}///', 'a', '"\nb\n"', 'c'
|
||||||
|
@ -409,7 +409,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
[a, b, c] = getMatchingTokens '///\n\n\na\n\n\n#{b}\n\n\nc///', '"\n\n\na\n\n\n"', 'b', '"\n\n\nc"'
|
[a, b, c] = getMatchingTokens '///\n\n\na\n\n\n#{b}\n\n\nc///', '"\n\n\na\n\n\n"', 'b', '"\n\n\nc"'
|
||||||
|
|
||||||
eq a[2].first_line, 0
|
eq a[2].first_line, 0
|
||||||
eq a[2].first_column, 0
|
eq a[2].first_column, 3
|
||||||
eq a[2].last_line, 5
|
eq a[2].last_line, 5
|
||||||
eq a[2].last_column, 0
|
eq a[2].last_column, 0
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ test 'Verify locations in heregex interpolation (in ///regex///, multiple interp
|
||||||
eq c[2].first_line, 6
|
eq c[2].first_line, 6
|
||||||
eq c[2].first_column, 4
|
eq c[2].first_column, 4
|
||||||
eq c[2].last_line, 9
|
eq c[2].last_line, 9
|
||||||
eq c[2].last_column, 3
|
eq c[2].last_column, 0
|
||||||
|
|
||||||
test "#3822: Simple string/regex start/end should include delimiters", ->
|
test "#3822: Simple string/regex start/end should include delimiters", ->
|
||||||
[stringToken] = CoffeeScript.tokens "'string'"
|
[stringToken] = CoffeeScript.tokens "'string'"
|
||||||
|
|
Loading…
Reference in New Issue