Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1b8e7ab

Browse files
JeanMechepkozlowski-opensource
authored andcommitted
feat(compiler): support the in keyword in Binary expression (#58432)
This commit adds the support for the `in` keyword as a relational operator, with the same precedence as the other relational operators (<,>, <=, >=) BREAKING CHANGE: 'in' in an expression now refers to the operator PR Close #58432
1 parent 9deaa67 commit 1b8e7ab

File tree

24 files changed

+177
-33
lines changed

24 files changed

+177
-33
lines changed

‎adev/src/content/guide/templates/expression-syntax.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Angular supports the following operators from standard JavaScript.
6767
| Property Accessor | `person['name']` |
6868
| typeof | `typeof 42` |
6969
| void | `void 1` |
70+
| in | `'model' in car` |
7071

7172
Angular expressions additionally also support the following non-standard operators:
7273

@@ -88,6 +89,8 @@ Angular expressions additionally also support the following non-standard operato
8889
| Array destructuring | `const [firstItem] = items` |
8990
| Comma operator | `x = (x++, x)` |
9091
| in | `'model' in car` |
92+
| typeof | `typeof 42` |
93+
| void | `void 1` |
9194
| instanceof | `car instanceof Automobile` |
9295
| new | `new Car()` |
9396

‎packages/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ export type BinaryOperator =
316316
| '!=='
317317
| '||'
318318
| '+'
319-
| '??';
319+
| '??'
320+
| 'in';
320321

321322
/**
322323
* The original location of the start or end of a node created by the `AstFactory`.

‎packages/compiler-cli/src/ngtsc/translator/src/translator.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const BINARY_OPERATORS = new Map<o.BinaryOperator, BinaryOperator>([
4444
[o.BinaryOperator.Plus, '+'],
4545
[o.BinaryOperator.NullishCoalesce, '??'],
4646
[o.BinaryOperator.Exponentiation, '**'],
47+
[o.BinaryOperator.In, 'in'],
4748
]);
4849

4950
export type RecordWrappedNodeFn<TExpression> = (node: o.WrappedNodeExpr<TExpression>) => void;

‎packages/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const BINARY_OPERATORS: Record<BinaryOperator, ts.BinaryOperator> = {
6060
'||': ts.SyntaxKind.BarBarToken,
6161
'+': ts.SyntaxKind.PlusToken,
6262
'??': ts.SyntaxKind.QuestionQuestionToken,
63+
'in': ts.SyntaxKind.InKeyword,
6364
};
6465

6566
const VAR_TYPES: Record<VariableDeclarationType, ts.NodeFlags> = {

‎packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const BINARY_OPS = new Map<string, ts.BinaryOperator>([
8585
['&', ts.SyntaxKind.AmpersandToken],
8686
['|', ts.SyntaxKind.BarToken],
8787
['??', ts.SyntaxKind.QuestionQuestionToken],
88+
['in', ts.SyntaxKind.InKeyword],
8889
]);
8990

9091
/**

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ describe('type check blocks', () => {
8282
expect(tcb('{{a ** b ** c}}')).toContain('((((this).a)) ** ((((this).b)) ** (((this).c))))');
8383
});
8484

85+
it('should handle "in" expressions', () => {
86+
expect(tcb(`{{'bar' in {bar: 'bar'} }}`)).toContain(`(("bar") in ({ "bar": "bar" }))`);
87+
expect(tcb(`{{!('bar' in {bar: 'bar'}) }}`)).toContain(`!((("bar") in ({ "bar": "bar" })))`);
88+
});
89+
8590
it('should handle attribute values for directive inputs', () => {
8691
const TEMPLATE = `<div dir inputA="value"></div>`;
8792
const DIRECTIVES: TestDeclaration[] = [

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/GOLDEN_PARTIAL.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-
9999
{{ typeof foo?.bar | identity }}
100100
{{ void 'test' }}
101101
{{ (-1) ** 3 }}
102+
{{ 'bar' in foo }}
102103
`, isInline: true, dependencies: [{ kind: "pipe", type: IdentityPipe, name: "identity" }] });
103104
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, decorators: [{
104105
type: Component,
@@ -113,6 +114,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
113114
{{ typeof foo?.bar | identity }}
114115
{{ void 'test' }}
115116
{{ (-1) ** 3 }}
117+
{{ 'bar' in foo }}
116118
`,
117119
imports: [IdentityPipe],
118120
}]

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/operators.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class IdentityPipe {
1818
{{ typeof foo?.bar | identity }}
1919
{{ void 'test' }}
2020
{{ (-1) ** 3 }}
21+
{{ 'bar' in foo }}
2122
`,
2223
imports: [IdentityPipe],
2324
})

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/operators_template.js‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ template: function MyApp_Template(rf, $ctx$) {
77
1 + 2, " ",
88
1 % 2 + 3 / 4 * 5 ** 6, " ",
99
+1, " ",
10-
typeof i0.ɵɵpureFunction0(11, _c0) === "object", " ",
11-
!(typeof i0.ɵɵpureFunction0(12, _c0) === "object"), " ",
10+
typeof i0.ɵɵpureFunction0(12, _c0) === "object", " ",
11+
!(typeof i0.ɵɵpureFunction0(13, _c0) === "object"), " ",
1212
typeof (ctx.foo == null ? null : ctx.foo.bar) === "string", " ",
13-
i0.ɵɵpipeBind1(1, 9, typeof (ctx.foo == null ? null : ctx.foo.bar)), " ",
13+
i0.ɵɵpipeBind1(1, 10, typeof (ctx.foo == null ? null : ctx.foo.bar)), " ",
1414
void "test", " ",
15-
(-1) ** 3, " "
15+
(-1) ** 3, " ",
16+
"bar" in ctx.foo, " "
1617
]);
1718
}
1819
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,25 @@ runInEachFileSystem(() => {
807807
expect(diags[0].messageText).toContain(`This comparison appears to be unintentional`);
808808
});
809809

810+
it('should error on invalid "in" binary expressions', () => {
811+
env.write(
812+
'test.ts',
813+
`
814+
import {Component} from '@angular/core';
815+
816+
@Component({
817+
template: \` {{'foo' in 'foobar'}} \`,
818+
})
819+
class TestCmp {
820+
}
821+
`,
822+
);
823+
824+
const diags = env.driveDiagnostics();
825+
expect(diags.length).toBe(1);
826+
expect(diags[0].messageText).toContain(`Type 'string' is not assignable to type 'object'`);
827+
});
828+
810829
describe('strictInputTypes', () => {
811830
beforeEach(() => {
812831
env.write(

0 commit comments

Comments
 (0)