fix(ng,vue): add parens to avoid unexpected `}}` in interpolations (#5657)
parent
7c4cebeaa5
commit
3de36e3a2b
|
@ -29,17 +29,18 @@ FastPath.prototype.getValue = function getValue() {
|
|||
};
|
||||
|
||||
function getNodeHelper(path, count) {
|
||||
const s = path.stack;
|
||||
|
||||
for (let i = s.length - 1; i >= 0; i -= 2) {
|
||||
const value = s[i];
|
||||
const stackIndex = getNodeStackIndexHelper(path.stack, count);
|
||||
return stackIndex === -1 ? null : path.stack[stackIndex];
|
||||
}
|
||||
|
||||
function getNodeStackIndexHelper(stack, count) {
|
||||
for (let i = stack.length - 1; i >= 0; i -= 2) {
|
||||
const value = stack[i];
|
||||
if (value && !Array.isArray(value) && --count < 0) {
|
||||
return value;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FastPath.prototype.getNode = function getNode(count) {
|
||||
|
@ -70,6 +71,14 @@ FastPath.prototype.call = function call(callback /*, name1, name2, ... */) {
|
|||
return result;
|
||||
};
|
||||
|
||||
FastPath.prototype.callParent = function callParent(callback, count) {
|
||||
const stackIndex = getNodeStackIndexHelper(this.stack, ~~count + 1);
|
||||
const parentValues = this.stack.splice(stackIndex + 1);
|
||||
const result = callback(this);
|
||||
Array.prototype.push.apply(this.stack, parentValues);
|
||||
return result;
|
||||
};
|
||||
|
||||
// Similar to FastPath.prototype.call, except that the value obtained by
|
||||
// accessing this.getValue()[name1][name2]... should be array-like. The
|
||||
// callback will be called with a reference to this path object for each
|
||||
|
|
|
@ -85,11 +85,16 @@ function embed(path, print, textToDoc, options) {
|
|||
line,
|
||||
textToDoc(
|
||||
node.value,
|
||||
options.parser === "angular"
|
||||
? { parser: "__ng_interpolation", trailingComma: "none" }
|
||||
: options.parser === "vue"
|
||||
? { parser: "__vue_expression" }
|
||||
: { parser: "__js_expression" }
|
||||
Object.assign(
|
||||
{
|
||||
__isInHtmlInterpolation: true // to avoid unexpected `}}`
|
||||
},
|
||||
options.parser === "angular"
|
||||
? { parser: "__ng_interpolation", trailingComma: "none" }
|
||||
: options.parser === "vue"
|
||||
? { parser: "__vue_expression" }
|
||||
: { parser: "__js_expression" }
|
||||
)
|
||||
)
|
||||
])
|
||||
),
|
||||
|
@ -1043,7 +1048,10 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
|||
indent(
|
||||
concat([
|
||||
line,
|
||||
ngTextToDoc(part, { parser: "__ng_interpolation" })
|
||||
ngTextToDoc(part, {
|
||||
parser: "__ng_interpolation",
|
||||
__isInHtmlInterpolation: true // to avoid unexpected `}}`
|
||||
})
|
||||
])
|
||||
),
|
||||
line,
|
||||
|
|
|
@ -57,6 +57,16 @@ function needsParens(path, options) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// to avoid unexpected `}}` in HTML interpolations
|
||||
if (
|
||||
options.__isInHtmlInterpolation &&
|
||||
!options.bracketSpacing &&
|
||||
endsWithRightBracket(node) &&
|
||||
isFollowedByRightBracket(path)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only statements don't need parentheses.
|
||||
if (isStatement(node)) {
|
||||
return false;
|
||||
|
@ -688,4 +698,55 @@ function isStatement(node) {
|
|||
);
|
||||
}
|
||||
|
||||
function endsWithRightBracket(node) {
|
||||
switch (node.type) {
|
||||
case "ObjectExpression":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isFollowedByRightBracket(path) {
|
||||
const node = path.getValue();
|
||||
const parent = path.getParentNode();
|
||||
const name = path.getName();
|
||||
switch (parent.type) {
|
||||
case "NGPipeExpression":
|
||||
if (
|
||||
typeof name === "number" &&
|
||||
parent.arguments[name] === node &&
|
||||
parent.arguments.length - 1 === name
|
||||
) {
|
||||
return path.callParent(isFollowedByRightBracket);
|
||||
}
|
||||
break;
|
||||
case "ObjectProperty":
|
||||
if (name === "value") {
|
||||
const parentParent = path.getParentNode(1);
|
||||
return (
|
||||
parentParent.properties[parentParent.properties.length - 1] === parent
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "BinaryExpression":
|
||||
case "LogicalExpression":
|
||||
if (name === "right") {
|
||||
return path.callParent(isFollowedByRightBracket);
|
||||
}
|
||||
break;
|
||||
case "ConditionalExpression":
|
||||
if (name === "alternate") {
|
||||
return path.callParent(isFollowedByRightBracket);
|
||||
}
|
||||
break;
|
||||
case "UnaryExpression":
|
||||
if (parent.prefix) {
|
||||
return path.callParent(isFollowedByRightBracket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = needsParens;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,3 +54,13 @@
|
|||
{{ aNormalValue | aPipe }}:
|
||||
<strong>{{ aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis }}</strong>
|
||||
</span>
|
||||
<p>
|
||||
{{
|
||||
'delete'
|
||||
| translate: {what: ('entities' | translate: {count: array.length})}
|
||||
}}
|
||||
</p>
|
||||
<p>{{ {a:1+{} } }}</p>
|
||||
<p>{{ {a:a==={} } }}</p>
|
||||
<p>{{ {a:!{} } }}</p>
|
||||
<p>{{ {a:a?b:{} } }}</p>
|
||||
|
|
|
@ -2,3 +2,4 @@ run_spec(__dirname, ["angular"]);
|
|||
run_spec(__dirname, ["angular"], { trailingComma: "es5" });
|
||||
run_spec(__dirname, ["angular"], { printWidth: 1 });
|
||||
run_spec(__dirname, ["angular"], { htmlWhitespaceSensitivity: "ignore" });
|
||||
run_spec(__dirname, ["angular"], { bracketSpacing: false });
|
||||
|
|
Loading…
Reference in New Issue