1 parent
bfcfdccdf8
commit
5ca2fc9be8
16 files changed
+508
-1
No files matched your search
@@ -0,0 +1,17 @@
|
||||
#### Support `@let` declaration syntax (#16474 by @sosukesuzuki)
|
||||
|
||||
Adds support for Angular v18 `@let` declaration syntax.
|
||||
|
||||
Please see the following code example. The `@let` declaration allows you to define local variables within the template:
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
@let name = 'Frodo';
|
||||
|
||||
<h1>Dashboard for {{name}}</h1>
|
||||
Hello, {{name}}
|
||||
```
|
||||
|
||||
For more details, please refer to the excellent blog post by the Angular Team: [Introducing @let in Angular](https://blog.angular.dev/introducing-let-in-angular-686f9f383f0f).
|
||||
|
||||
We also appreciate the Angular Team for kindly answering our questions to implement this feature.
|
||||
@@ -61,6 +61,10 @@ function clean(original, cloned) {
|
||||
if (original.type === "angularIcuExpression") {
|
||||
cloned.switchValue = original.switchValue.trim();
|
||||
}
|
||||
|
||||
if (original.type === "angularLetDeclarationInitializer") {
|
||||
delete cloned.value;
|
||||
}
|
||||
}
|
||||
|
||||
clean.ignoredProperties = ignoredProperties;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import printFrontMatter from "../utils/front-matter/print.js";
|
||||
import printAngularControlFlowBlockParameters from "./embed/angular-control-flow-block-parameters.js";
|
||||
import printAttribute from "./embed/attribute.js";
|
||||
import { formatAttributeValue } from "./embed/utils.js";
|
||||
import getNodeContent from "./get-node-content.js";
|
||||
import {
|
||||
needsToBorrowPrevClosingTagEndMarker,
|
||||
@@ -148,6 +149,13 @@ function embed(path, options) {
|
||||
}
|
||||
|
||||
return printAngularControlFlowBlockParameters;
|
||||
|
||||
case "angularLetDeclarationInitializer":
|
||||
return (textToDoc) =>
|
||||
formatAttributeValue(node.value, textToDoc, {
|
||||
parser: "__ng_binding",
|
||||
__isInHtmlAttribute: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,24 @@ function normalizeAngularControlFlowBlock(node) {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAngularLetDeclaration(node) {
|
||||
if (node.type !== "letDeclaration") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Similar to `VariableDeclarator` in estree
|
||||
node.type = "angularLetDeclaration";
|
||||
node.id = node.name;
|
||||
node.init = {
|
||||
type: "angularLetDeclarationInitializer",
|
||||
sourceSpan: new ParseSourceSpan(node.valueSpan.start, node.valueSpan.end),
|
||||
value: node.value,
|
||||
};
|
||||
|
||||
delete node.name;
|
||||
delete node.value;
|
||||
}
|
||||
|
||||
function normalizeAngularIcuExpression(node) {
|
||||
if (node.type === "plural" || node.type === "select") {
|
||||
node.clause = node.type;
|
||||
@@ -103,6 +121,7 @@ function ngHtmlParser(input, parseOptions, options) {
|
||||
shouldParseAsRawText(...args) ? TagContentType.RAW_TEXT : undefined
|
||||
: undefined,
|
||||
tokenizeAngularBlocks: name === "angular" ? true : undefined,
|
||||
tokenizeAngularLetDeclaration: name === "angular" ? true : undefined,
|
||||
});
|
||||
|
||||
if (name === "vue") {
|
||||
@@ -395,6 +414,7 @@ function parse(
|
||||
}
|
||||
|
||||
normalizeAngularControlFlowBlock(node);
|
||||
normalizeAngularLetDeclaration(node);
|
||||
normalizeAngularIcuExpression(node);
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @typedef {import("../document/builders.js").Doc} Doc
|
||||
*/
|
||||
|
||||
import { fill, group, hardline } from "../document/builders.js";
|
||||
import { fill, group, hardline, indent, line } from "../document/builders.js";
|
||||
import { cleanDoc, replaceEndOfLine } from "../document/utils.js";
|
||||
import getPreferredQuote from "../utils/get-preferred-quote.js";
|
||||
import htmlWhitespaceUtils from "../utils/html-whitespace-utils.js";
|
||||
@@ -53,6 +53,18 @@ function genericPrint(path, options, print) {
|
||||
case "angularControlFlowBlockParameter":
|
||||
return htmlWhitespaceUtils.trim(node.expression);
|
||||
|
||||
case "angularLetDeclaration":
|
||||
// print like "break-after-operator" layout assignment in estree printer
|
||||
return group([
|
||||
"@let ",
|
||||
group([node.id, " =", group(indent([line, print("init")]))]),
|
||||
// semicolon is required
|
||||
";",
|
||||
]);
|
||||
case "angularLetDeclarationInitializer":
|
||||
// basically printed via embedded formatting
|
||||
return node.value;
|
||||
|
||||
case "angularIcuExpression":
|
||||
return printAngularIcuExpression(path, options, print);
|
||||
case "angularIcuCase":
|
||||
|
||||
@@ -14,6 +14,8 @@ const visitorKeys = {
|
||||
angularControlFlowBlock: ["children", "parameters"],
|
||||
angularControlFlowBlockParameters: ["children"],
|
||||
angularControlFlowBlockParameter: [],
|
||||
angularLetDeclaration: ["init"],
|
||||
angularLetDeclarationInitializer: [],
|
||||
angularIcuExpression: ["cases"],
|
||||
angularIcuCase: ["expression"],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`basic-01.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
@let name = 'Frodo';
|
||||
<h1>Dashboard for {{name}}</h1>
|
||||
Hello, {{name}}
|
||||
|
||||
=====================================output=====================================
|
||||
@let name = "Frodo";
|
||||
<h1>Dashboard for {{ name }}</h1>
|
||||
Hello, {{ name }}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`basic-02.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
<input #name>
|
||||
|
||||
@let greeting = 'Hello ' + name.value;
|
||||
|
||||
@let user = user$ | async;
|
||||
|
||||
=====================================output=====================================
|
||||
<input #name />
|
||||
|
||||
@let greeting = "Hello " + name.value;
|
||||
|
||||
@let user = user$ | async;
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`basic-03.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
@let topLevel = value;
|
||||
|
||||
@if (condition) {
|
||||
@let nested = value;
|
||||
}
|
||||
|
||||
<div *ngIf="condition">
|
||||
@let nestedNgIf = value;
|
||||
</div>
|
||||
|
||||
{{topLevel}}
|
||||
|
||||
{{nested}}
|
||||
|
||||
{{nestedNgIf}}
|
||||
|
||||
=====================================output=====================================
|
||||
@let topLevel = value;
|
||||
|
||||
@if (condition) {
|
||||
@let nested = value;
|
||||
}
|
||||
|
||||
<div *ngIf="condition">
|
||||
@let nestedNgIf = value;
|
||||
</div>
|
||||
|
||||
{{ topLevel }}
|
||||
|
||||
{{ nested }}
|
||||
|
||||
{{ nestedNgIf }}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`complex.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
@let foo = a | b : c:d :e;
|
||||
@let foo = a | pipe;
|
||||
@let foo = 0 - 1;
|
||||
@let foo = - 1;
|
||||
@let foo = a ? 1 : 2;
|
||||
@let foo = a ( 1 ) ( 2 );
|
||||
@let foo = a [ b ];
|
||||
@let foo = [ 1 ];
|
||||
@let foo = { 'a' : 1 };
|
||||
@let foo = { a : 1 };
|
||||
@let foo = true;
|
||||
@let foo = undefined;
|
||||
@let foo = null;
|
||||
@let foo = ( 1 );
|
||||
@let foo = 1;
|
||||
@let foo = 'hello';
|
||||
@let foo = a ( 1 , 2 );
|
||||
@let foo = a . b ( 1 , 2 );
|
||||
@let foo = x !;
|
||||
@let foo = ! x;
|
||||
@let foo = ( ( a ) );
|
||||
@let foo = a;
|
||||
@let foo = a; // hello
|
||||
@let foo = a . b;
|
||||
@let foo = a ?. b ( );
|
||||
@let foo = a ?. b;
|
||||
@let foo = a; // hello
|
||||
@let foo = "SearchSelection.transmissionLayoutRadioButton" | localize:localizationSection;
|
||||
@let foo = copyTypes[options.copyType];
|
||||
@let foo = listRow.NextScheduledSendStatus == 1 || listRow.NextScheduledSendStatus == 2 || listRow.NextScheduledSendStatus == 3;
|
||||
@let foo = a;
|
||||
@let foo = b;
|
||||
@let foo = aNormalValue | aPipe;
|
||||
@let foo = aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis;
|
||||
@let foo = 'delete' | translate: {what: ('entities' | translate: {count: array.length})};
|
||||
@let foo = {a:1+{} };
|
||||
@let foo = {a:a==={} };
|
||||
@let foo = {a:!{} };
|
||||
@let foo = {a:a?b:{} };
|
||||
|
||||
=====================================output=====================================
|
||||
@let foo = a | b: c : d : e;
|
||||
@let foo = a | pipe;
|
||||
@let foo = 0 - 1;
|
||||
@let foo = -1;
|
||||
@let foo = a ? 1 : 2;
|
||||
@let foo = a(1)(2);
|
||||
@let foo = a[b];
|
||||
@let foo = [1];
|
||||
@let foo = { a: 1 };
|
||||
@let foo = { a: 1 };
|
||||
@let foo = true;
|
||||
@let foo = undefined;
|
||||
@let foo = null;
|
||||
@let foo = 1;
|
||||
@let foo = 1;
|
||||
@let foo = "hello";
|
||||
@let foo = a(1, 2);
|
||||
@let foo = a.b(1, 2);
|
||||
@let foo = x!;
|
||||
@let foo = !x;
|
||||
@let foo = a;
|
||||
@let foo = a;
|
||||
@let foo = a; // hello
|
||||
@let foo = a.b;
|
||||
@let foo = a?.b();
|
||||
@let foo = a?.b;
|
||||
@let foo = a; // hello
|
||||
@let foo =
|
||||
"SearchSelection.transmissionLayoutRadioButton"
|
||||
| localize: localizationSection;
|
||||
@let foo = copyTypes[options.copyType];
|
||||
@let foo =
|
||||
listRow.NextScheduledSendStatus == 1 ||
|
||||
listRow.NextScheduledSendStatus == 2 ||
|
||||
listRow.NextScheduledSendStatus == 3;
|
||||
@let foo = a;
|
||||
@let foo = b;
|
||||
@let foo = aNormalValue | aPipe;
|
||||
@let foo = aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis;
|
||||
@let foo =
|
||||
"delete"
|
||||
| translate: { what: ("entities" | translate: { count: array.length }) };
|
||||
@let foo = { a: 1 + {} };
|
||||
@let foo = { a: a === {} };
|
||||
@let foo = { a: !{} };
|
||||
@let foo = { a: a ? b : {} };
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`valid-from-tokenizer-test.html format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
<!-- import from https://github.com/angular/angular/commit/62c5b66b4119b7e1dfaf1e28c100e5f8431cb05b -->
|
||||
|
||||
@let foo = 123 + 456;
|
||||
|
||||
@let foo = 123 + 456;
|
||||
@let foo=123 + 456;
|
||||
@let foo =123 + 456;
|
||||
@let foo= 123 + 456;
|
||||
|
||||
@let
|
||||
foo = 123;
|
||||
@let
|
||||
foo = 123;
|
||||
@let
|
||||
foo = 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let
|
||||
foo
|
||||
= 123;
|
||||
|
||||
@let foo =
|
||||
123 +
|
||||
456 +
|
||||
789
|
||||
;
|
||||
|
||||
@block {@let foo = 123 + 456;}
|
||||
|
||||
@let foo = 'a; b';
|
||||
@let foo = "';'";
|
||||
|
||||
@let foo = '\\';\\'' + "\\",";
|
||||
|
||||
@let foo = fn(a, b) + fn2(c, d, e);
|
||||
|
||||
@let foo = [1, 2, 3];
|
||||
|
||||
@let foo = [0, [foo[1]], 3];
|
||||
|
||||
@let foo = {a: 1, b: {c: something + 2}};
|
||||
@let foo = {};
|
||||
@let foo = {foo: ";"};
|
||||
|
||||
@let foo = fn({a: 1, b: [otherFn([{c: ";"}], 321, {d: [',']})]});
|
||||
|
||||
=====================================output=====================================
|
||||
<!-- import from https://github.com/angular/angular/commit/62c5b66b4119b7e1dfaf1e28c100e5f8431cb05b -->
|
||||
|
||||
@let foo = 123 + 456;
|
||||
|
||||
@let foo = 123 + 456;
|
||||
@let foo = 123 + 456;
|
||||
@let foo = 123 + 456;
|
||||
@let foo = 123 + 456;
|
||||
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
@let foo = 123;
|
||||
|
||||
@let foo = 123 + 456 + 789;
|
||||
|
||||
@block {
|
||||
@let foo = 123 + 456;
|
||||
}
|
||||
|
||||
@let foo = "a; b";
|
||||
@let foo = "';'";
|
||||
|
||||
@let foo = "';'" + '",';
|
||||
|
||||
@let foo = fn(a, b) + fn2(c, d, e);
|
||||
|
||||
@let foo = [1, 2, 3];
|
||||
|
||||
@let foo = [0, [foo[1]], 3];
|
||||
|
||||
@let foo = { a: 1, b: { c: something + 2 } };
|
||||
@let foo = {};
|
||||
@let foo = { foo: ";" };
|
||||
|
||||
@let foo = fn({ a: 1, b: [otherFn([{ c: ";" }], 321, { d: [","] })] });
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1,3 @@
|
||||
@let name = 'Frodo';
|
||||
<h1>Dashboard for {{name}}</h1>
|
||||
Hello, {{name}}
|
||||
@@ -0,0 +1,5 @@
|
||||
<input #name>
|
||||
|
||||
@let greeting = 'Hello ' + name.value;
|
||||
|
||||
@let user = user$ | async;
|
||||
@@ -0,0 +1,15 @@
|
||||
@let topLevel = value;
|
||||
|
||||
@if (condition) {
|
||||
@let nested = value;
|
||||
}
|
||||
|
||||
<div *ngIf="condition">
|
||||
@let nestedNgIf = value;
|
||||
</div>
|
||||
|
||||
{{topLevel}}
|
||||
|
||||
{{nested}}
|
||||
|
||||
{{nestedNgIf}}
|
||||
@@ -0,0 +1,39 @@
|
||||
@let foo = a | b : c:d :e;
|
||||
@let foo = a | pipe;
|
||||
@let foo = 0 - 1;
|
||||
@let foo = - 1;
|
||||
@let foo = a ? 1 : 2;
|
||||
@let foo = a ( 1 ) ( 2 );
|
||||
@let foo = a [ b ];
|
||||
@let foo = [ 1 ];
|
||||
@let foo = { 'a' : 1 };
|
||||
@let foo = { a : 1 };
|
||||
@let foo = true;
|
||||
@let foo = undefined;
|
||||
@let foo = null;
|
||||
@let foo = ( 1 );
|
||||
@let foo = 1;
|
||||
@let foo = 'hello';
|
||||
@let foo = a ( 1 , 2 );
|
||||
@let foo = a . b ( 1 , 2 );
|
||||
@let foo = x !;
|
||||
@let foo = ! x;
|
||||
@let foo = ( ( a ) );
|
||||
@let foo = a;
|
||||
@let foo = a; // hello
|
||||
@let foo = a . b;
|
||||
@let foo = a ?. b ( );
|
||||
@let foo = a ?. b;
|
||||
@let foo = a; // hello
|
||||
@let foo = "SearchSelection.transmissionLayoutRadioButton" | localize:localizationSection;
|
||||
@let foo = copyTypes[options.copyType];
|
||||
@let foo = listRow.NextScheduledSendStatus == 1 || listRow.NextScheduledSendStatus == 2 || listRow.NextScheduledSendStatus == 3;
|
||||
@let foo = a;
|
||||
@let foo = b;
|
||||
@let foo = aNormalValue | aPipe;
|
||||
@let foo = aReallyReallySuperLongValue | andASuperLongPipeJustToBreakThis;
|
||||
@let foo = 'delete' | translate: {what: ('entities' | translate: {count: array.length})};
|
||||
@let foo = {a:1+{} };
|
||||
@let foo = {a:a==={} };
|
||||
@let foo = {a:!{} };
|
||||
@let foo = {a:a?b:{} };
|
||||
@@ -0,0 +1 @@
|
||||
runFormatTest(import.meta, ["angular"]);
|
||||
@@ -0,0 +1,29 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`snippet: #0 - {"embeddedLanguageFormatting":"off"} format 1`] = `
|
||||
====================================options=====================================
|
||||
embeddedLanguageFormatting: "off"
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
@let foo = 'Hello' + ', World';
|
||||
=====================================output=====================================
|
||||
@let foo = 'Hello' + ', World';
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`snippet: #0 - {"semi":false} format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["angular"]
|
||||
printWidth: 80
|
||||
semi: false
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
@let foo = 'Hello' + ', World';
|
||||
=====================================output=====================================
|
||||
@let foo = "Hello" + ", World";
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1,19 @@
|
||||
const snippets = ["@let foo = 'Hello' + ', World'; "];
|
||||
|
||||
runFormatTest(
|
||||
{
|
||||
importMeta: import.meta,
|
||||
snippets,
|
||||
},
|
||||
["angular"],
|
||||
{ embeddedLanguageFormatting: "off" },
|
||||
);
|
||||
|
||||
runFormatTest(
|
||||
{
|
||||
importMeta: import.meta,
|
||||
snippets,
|
||||
},
|
||||
["angular"],
|
||||
{ semi: false },
|
||||
);
|
||||
@@ -0,0 +1,49 @@
|
||||
<!-- import from https://github.com/angular/angular/commit/62c5b66b4119b7e1dfaf1e28c100e5f8431cb05b -->
|
||||
|
||||
@let foo = 123 + 456;
|
||||
|
||||
@let foo = 123 + 456;
|
||||
@let foo=123 + 456;
|
||||
@let foo =123 + 456;
|
||||
@let foo= 123 + 456;
|
||||
|
||||
@let
|
||||
foo = 123;
|
||||
@let
|
||||
foo = 123;
|
||||
@let
|
||||
foo = 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let foo
|
||||
= 123;
|
||||
@let
|
||||
foo
|
||||
= 123;
|
||||
|
||||
@let foo =
|
||||
123 +
|
||||
456 +
|
||||
789
|
||||
;
|
||||
|
||||
@block {@let foo = 123 + 456;}
|
||||
|
||||
@let foo = 'a; b';
|
||||
@let foo = "';'";
|
||||
|
||||
@let foo = '\';\'' + "\",";
|
||||
|
||||
@let foo = fn(a, b) + fn2(c, d, e);
|
||||
|
||||
@let foo = [1, 2, 3];
|
||||
|
||||
@let foo = [0, [foo[1]], 3];
|
||||
|
||||
@let foo = {a: 1, b: {c: something + 2}};
|
||||
@let foo = {};
|
||||
@let foo = {foo: ";"};
|
||||
|
||||
@let foo = fn({a: 1, b: [otherFn([{c: ";"}], 321, {d: [',']})]});
|
||||
@@ -1427,6 +1427,10 @@ exports[`visitor keys html 1`] = `
|
||||
"angularIcuExpression": [
|
||||
"cases",
|
||||
],
|
||||
"angularLetDeclaration": [
|
||||
"init",
|
||||
],
|
||||
"angularLetDeclarationInitializer": [],
|
||||
"attribute": [],
|
||||
"cdata": [],
|
||||
"comment": [],
|
||||
|
||||
Reference in new issue
Block a user