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) {
|
function getNodeHelper(path, count) {
|
||||||
const s = path.stack;
|
const stackIndex = getNodeStackIndexHelper(path.stack, count);
|
||||||
|
return stackIndex === -1 ? null : path.stack[stackIndex];
|
||||||
for (let i = s.length - 1; i >= 0; i -= 2) {
|
}
|
||||||
const value = s[i];
|
|
||||||
|
|
||||||
|
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) {
|
if (value && !Array.isArray(value) && --count < 0) {
|
||||||
return value;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return -1;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FastPath.prototype.getNode = function getNode(count) {
|
FastPath.prototype.getNode = function getNode(count) {
|
||||||
|
@ -70,6 +71,14 @@ FastPath.prototype.call = function call(callback /*, name1, name2, ... */) {
|
||||||
return result;
|
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
|
// Similar to FastPath.prototype.call, except that the value obtained by
|
||||||
// accessing this.getValue()[name1][name2]... should be array-like. The
|
// accessing this.getValue()[name1][name2]... should be array-like. The
|
||||||
// callback will be called with a reference to this path object for each
|
// callback will be called with a reference to this path object for each
|
||||||
|
|
|
@ -85,11 +85,16 @@ function embed(path, print, textToDoc, options) {
|
||||||
line,
|
line,
|
||||||
textToDoc(
|
textToDoc(
|
||||||
node.value,
|
node.value,
|
||||||
options.parser === "angular"
|
Object.assign(
|
||||||
? { parser: "__ng_interpolation", trailingComma: "none" }
|
{
|
||||||
: options.parser === "vue"
|
__isInHtmlInterpolation: true // to avoid unexpected `}}`
|
||||||
? { parser: "__vue_expression" }
|
},
|
||||||
: { parser: "__js_expression" }
|
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(
|
indent(
|
||||||
concat([
|
concat([
|
||||||
line,
|
line,
|
||||||
ngTextToDoc(part, { parser: "__ng_interpolation" })
|
ngTextToDoc(part, {
|
||||||
|
parser: "__ng_interpolation",
|
||||||
|
__isInHtmlInterpolation: true // to avoid unexpected `}}`
|
||||||
|
})
|
||||||
])
|
])
|
||||||
),
|
),
|
||||||
line,
|
line,
|
||||||
|
|
|
@ -57,6 +57,16 @@ function needsParens(path, options) {
|
||||||
return false;
|
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.
|
// Only statements don't need parentheses.
|
||||||
if (isStatement(node)) {
|
if (isStatement(node)) {
|
||||||
return false;
|
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;
|
module.exports = needsParens;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,3 +54,13 @@
|
||||||
{{ aNormalValue | aPipe }}:
|
{{ aNormalValue | aPipe }}:
|
||||||
<strong>{{ aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis }}</strong>
|
<strong>{{ aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis }}</strong>
|
||||||
</span>
|
</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"], { trailingComma: "es5" });
|
||||||
run_spec(__dirname, ["angular"], { printWidth: 1 });
|
run_spec(__dirname, ["angular"], { printWidth: 1 });
|
||||||
run_spec(__dirname, ["angular"], { htmlWhitespaceSensitivity: "ignore" });
|
run_spec(__dirname, ["angular"], { htmlWhitespaceSensitivity: "ignore" });
|
||||||
|
run_spec(__dirname, ["angular"], { bracketSpacing: false });
|
||||||
|
|
Loading…
Reference in New Issue