8000 feat(core): add support for let syntax (#56715) · angular/angular@0a48d58 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0a48d58

Browse files
crisbetodylhunn
authored andcommitted
feat(core): add support for let syntax (#56715)
Enables the new `@let` syntax by default. `@let` declarations are defined as: 1. The `@let` keyword. 2. Followed by one or more whitespaces. 3. Followed by a valid JavaScript name and zero or more whitespaces. 4. Followed by the `=` symbol and zero or more whitespaces. 5. Followed by an Angular expression which can be multi-line. 6. Terminated by the `;` symbol. Example usage: ``` @let user = user$ | async; @let greeting = user ? 'Hello, ' + user.name : 'Loading'; <h1>{{greeting}}</h1> ``` Fixes #15280. PR Close #56715
1 parent c19a4e7 commit 0a48d58

29 files changed

+102
-236
lines changed

packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_component_linker_1.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,13 @@ export class PartialComponentLinkerVersion1<TStatement, TExpression>
100100
const templateSource = metaObj.getValue('template');
101101
const isInline = metaObj.has('isInline') ? metaObj.getBoolean('isInline') : false;
102102
const templateInfo = this.getTemplateInfo(templateSource, isInline);
103+
const {major, minor} = new semver.SemVer(version);
103104

104105
// Enable the new block syntax if compiled with v17 and
105106
// above, or when using the local placeholder version.
106-
const enableBlockSyntax = semver.major(version) >= 17 || version === PLACEHOLDER_VERSION;
107-
const enableLetSyntax = version === PLACEHOLDER_VERSION;
107+
const enableBlockSyntax = major >= 17 || version === PLACEHOLDER_VERSION;
108+
const enableLetSyntax =
109+
major > 18 || (major === 18 && minor >= 1) || version === PLACEHOLDER_VERSION;
108110

109111
const template = parseTemplate(templateInfo.code, templateInfo.sourceUrl, {
110112
escapedString: templateInfo.isEscaped,

packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function setup(
142142
new DeferredSymbolTracker(checker, /* onlyExplicitDeferDependencyImports */ false),
143143
/* forbidOrphanRenderering */ false,
144144
/* enableBlockSyntax */ true,
145-
/* enableLetSyntax */ false,
145+
/* enableLetSyntax */ true,
146146
/* localCompilationExtraImportsTracker */ null,
147147
);
148148
return {reflectionHost, handler, resourceLoader, metaRegistry};

packages/compiler-cli/src/ngtsc/core/src/compiler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ export class NgCompiler {
455455
enableTemplateTypeChecker || (options['_enableTemplateTypeChecker'] ?? false);
456456
// TODO(crisbeto): remove this flag and base `enableBlockSyntax` on the `angularCoreVersion`.
457457
this.enableBlockSyntax = options['_enableBlockSyntax'] ?? true;
458-
this.enableLetSyntax = options['_enableLetSyntax'] ?? false;
458+
this.enableLetSyntax = options['_enableLetSyntax'] ?? true;
459459
this.angularCoreVersion = options['_angularCoreVersion'] ?? null;
460460
this.constructionDiagnostics.push(
461461
...this.adapter.constructionDiagnostics,

packages/compiler-cli/src/ngtsc/indexer/test/template_spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ function bind(template: string) {
2929
return util.getBoundTemplate(template, {
3030
preserveWhitespaces: true,
3131
leadingTriviaChars: [],
32-
enableLetSyntax: true,
3332
});
3433
}
3534

packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,12 +1971,8 @@ describe('type check blocks', () => {
19711971
});
19721972

19731973
describe('let declarations', () => {
1974-
function letTcb(template: string) {
1975-
return tcb(template, undefined, undefined, undefined, {enableLetSyntax: true});
1976-
}
1977-
19781974
it('should generate let declarations as constants', () => {
1979-
const result = letTcb(`
1975+
const result = tcb(`
19801976
@let one = 1;
19811977
@let two = 2;
19821978
@let sum = one + two;
@@ -1990,7 +1986,7 @@ describe('type check blocks', () => {
19901986
});
19911987

19921988
it('should rewrite references to let declarations inside event listeners', () => {
1993-
const result = letTcb(`
1989+
const result = tcb(`
19941990
@let value = 1;
19951991
<button (click)="doStuff(value)"></button>
19961992
`);

packages/compiler-cli/src/ngtsc/typecheck/test/type_checker__completion_spec.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,14 @@ runInEachFileSystem(() => {
8484
`;
8585
const {
8686
completions: {templateContext: outerContext},
87-
} = setupCompletions(template, '', null, {
88-
enableLetSyntax: true,
89-
});
87+
} = setupCompletions(template);
9088
expect(Array.from(outerContext.keys())).toEqual(['one', 'three']);
9189
expect(outerContext.get('one')?.kind).toBe(CompletionKind.LetDeclaration);
9290
expect(outerContext.get('three')?.kind).toBe(CompletionKind.LetDeclaration);
9391

9492
const {
9593
completions: {templateContext: innerContext},
96-
} = setupCompletions(template, '', 1, {
97-
enableLetSyntax: true,
98-
});
94+
} = setupCompletions(template, '', 1);
9995

10096
expect(Array.from(innerContext.keys())).toEqual(['one', 'three', 'two']);
10197
expect(innerContext.get('one')?.kind).toBe(CompletionKind.LetDeclaration);

packages/compiler-cli/src/ngtsc/typecheck/test/type_checker__get_symbol_of_template_node_spec.ts

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,38 +1966,32 @@ runInEachFileSystem(() => {
19661966
@let message = 'The value is ' + value;
19671967
<div [dir]="message"></div>
19681968
`;
1969-
const testValues = setup(
1970-
[
1971-
{
1972-
fileName,
1973-
templates: {'Cmp': templateString},
1974-
source: `
1969+
const testValues = setup([
1970+
{
1971+
fileName,
1972+
templates: {'Cmp': templateString},
1973+
source: `
19751974
export class Cmp {
19761975
value = 1;
19771976
}
19781977
`,
1979-
declarations: [
1980-
{
1981-
name: 'TestDir',
1982-
selector: '[dir]',
1983-
file: dirFile,
1984-
type: 'directive',
1985-
exportAs: ['dir'],
1986-
inputs: {dir: 'dir'},
1987-
},
1988-
],
1989-
},
1990-
{
1991-
fileName: dirFile,
1992-
source: `export class TestDir {dir: any;}`,
1993-
templates: {},
1994-
},
1995-
],
1996-
undefined,
1978+
declarations: [
1979+
{
1980+
name: 'TestDir',
1981+
selector: '[dir]',
1982+
file: dirFile,
1983+
type: 'directive',
1984+
exportAs: ['dir'],
1985+
inputs: {dir: 'dir'},
1986+
},
1987+
],
1988+
},
19971989
{
1998-
enableLetSyntax: true,
1990+
fileName: dirFile,
1991+
source: `export class TestDir {dir: any;}`,
1992+
templates: {},
19991993
},
2000-
);
1994+
]);
20011995
templateTypeChecker = testValues.templateTypeChecker;
20021996
program = testValues.program;
20031997
const sf = getSourceFileOrError(testValues.program, fileName);

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_let/TEST_CASES.json

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
"cases": [
44
{
55
"description": "should create a simple @let declaration",
6-
"angularCompilerOptions": {
7-
"_enableLetSyntax": true
8-
},
96
"inputFiles": [
107
"simple_let.ts"
118
],
@@ -23,9 +20,6 @@
2320
},
2421
{
2522
"description": "should create multiple @let declarations that depend on each other",
26-
"angularCompilerOptions": {
27-
"_enableLetSyntax": true
28-
},
2923
"inputFiles": [
3024
"multiple_let.ts"
3125
],
@@ -43,9 +37,6 @@
4337
},
4438
{
4539
"description": "should create a let using a pipe",
46-
"angularCompilerOptions": {
47-
"_enableLetSyntax": true
48-
},
4940
"inputFiles": [
5041
"let_with_pipe.ts"
5142
],
@@ -63,9 +54,6 @@
6354
},
6455
{
6556
"description": "should be able to use let declarations in event listeners",
66-
"angularCompilerOptions": {
67-
"_enableLetSyntax": true
68-
},
6957
"inputFiles": [
7058
"let_in_listener.ts"
7159
],
@@ -83,9 +71,6 @@
8371
},
8472
{
8573
"description": "should be able to use let declarations in child views",
86-
"angularCompilerOptions": {
87-
"_enableLetSyntax": true
88-
},
8974
"inputFiles": [
9075
"let_in_child_view.ts"
9176
],
@@ -103,9 +88,6 @@
10388
},
10489
{
10590
"description": "should share let declarations between parent and child views",
106-
"angularCompilerOptions": {
107-
"_enableLetSyntax": true
108-
},
10991
"inputFiles": [
11092
"let_shared_with_child_view.ts"
11193
],
@@ -123,9 +105,6 @@
123105
},
124106
{
125107
"description": "should be able to use let declarations in event listeners inside child views",
126-
"angularCompilerOptions": {
127-
"_enableLetSyntax": true
128-
},
129108
"inputFiles": [
130109
"let_in_child_view_listener.ts"
131110
],
@@ -143,9 +122,6 @@
143122
},
144123
{
145124
"description": "should be able to use local references in let declarations",
146-
"angularCompilerOptions": {
147-
"_enableLetSyntax": true
148-
},
149125
"inputFiles": [
150126
"let_local_refs.ts"
151127
],
@@ -163,9 +139,6 @@
163139
},
164140
{
165141
"description": "should be able to use forward references defined after the let declaration",
166-
"angularCompilerOptions": {
167-
"_enableLetSyntax": true
168-
},
169142
"inputFiles": [
170143
"let_local_forward_refs.ts"
171144
],
@@ -183,9 +156,6 @@
183156
},
184157
{
185158
"description": "should be able to use for loop variables in let declarations",
186-
"angularCompilerOptions": {
187-
"_enableLetSyntax": true
188-
},
189159
"inputFiles": [
190160
"let_for_loop.ts"
191161
],
@@ -204,7 +174,6 @@
204174
{
205175
"description": "should transform an invalid let reference to undefined",
206176
"angularCompilerOptions": {
207-
"_enableLetSyntax": true,
208177
"checkTemplateBodies": false
209178
},
210179
"inputFiles": [
@@ -224,9 +193,6 @@
224193
},
225194
{
226195
"description": "should remove a single unused let declaration",
227-
"angularCompilerOptions": {
228-
"_enableLetSyntax": true
229-
},
230196
"inputFiles": [
231197
"let_single_optimization.ts"
232198
],
@@ -244,9 +210,6 @@
244210
},
245211
{
246212
"description": "should remove a chain of unused let declarations",
247-
"angularCompilerOptions": {
248-
"_enableLetSyntax": true
249-
},
250213
"inputFiles": [
251214
"let_multiple_optimization.ts"
252215
],
@@ -264,9 +227,6 @@
264227
},
265228
{
266229
"description": "should remove only the unused let declarations from the middle of a chain of declarations",
267-
"angularCompilerOptions": {
268-
"_enableLetSyntax": true
269-
},
270230
"inputFiles": [
271231
"let_partial_optimization.ts"
272232
],
@@ -284,9 +244,6 @@
284244
},
285245
{
286246
"description": "should not remove let declarations that are only used in an event listener",
287-
"angularCompilerOptions": {
288-
"_enableLetSyntax": true
289-
},
290247
"inputFiles": [
291248
"let_optimization_listener.ts"
292249
],
@@ -304,9 +261,6 @@
304261
},
305262
{
306263
"description": "should not remove let declarations that are only used in a child view",
307-
"angularCompilerOptions": {
308-
"_enableLetSyntax": true
309-
},
310264
"inputFiles": [
311265
"let_optimization_child_view.ts"
312266
],

packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6611,7 +6611,7 @@ suppress
66116611
});
66126612

66136613
describe('@let declarations', () => {
6614-
beforeEach(() => env.tsconfig({_enableLetSyntax: true, strictTemplates: true}));
6614+
beforeEach(() => env.tsconfig({strictTemplates: true}));
66156615

66166616
it('should infer the type of a let declaration', () => {
66176617
env.write(

packages/compiler/src/jit_compiler_facade.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,6 @@ import {ResourceLoader} from './resource_loader';
106106
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
107107
import {SelectorMatcher} from './selector';
108108

109-
let enableLetSyntax = false;
110-
111-
/** Temporary utility that enables `@let` declarations in JIT compilations. */
112-
export function ɵsetEnableLetSyntax(value: boolean): void {
113-
enableLetSyntax = value;
114-
}
115-
116109
export class CompilerFacadeImpl implements CompilerFacade {
117110
FactoryTarget = FactoryTarget;
118111
ResourceLoader = ResourceLoader;
@@ -726,7 +719,6 @@ function parseJitTemplate(
726719
const parsed = parseTemplate(template, sourceMapUrl, {
727720
preserveWhitespaces,
728721
interpolationConfig,
729-
enableLetSyntax,
730722
});
731723
if (parsed.errors !== null) {
732724
const errors = parsed.errors.map((err) => err.toString()).join(', ');

packages/compiler/src/ml_parser/lexer.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ class _Tokenizer {
192192
this._preserveLineEndings = options.preserveLineEndings || false;
193193
this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
194194
this._tokenizeBlocks = options.tokenizeBlocks ?? true;
195-
// TODO(crisbeto): eventually set this to true.
196-
this._tokenizeLet = options.tokenizeLet || false;
195+
this._tokenizeLet = options.tokenizeLet ?? true;
197196
try {
198197
this._cursor.init();
199198
} catch (e) {

packages/compiler/src/render3/view/template.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export function parseTemplate(
161161
...options,
162162
tokenizeExpansionForms: true,
163163
tokenizeBlocks: options.enableBlockSyntax ?? true,
164-
tokenizeLet: options.enableLetSyntax ?? false,
164+
tokenizeLet: options.enableLetSyntax ?? true,
165165
});
166166

167167
if (

0 commit comments

Comments
 (0)
0