Skip to content

Commit f2d5cf7

Browse files
mmalerbakirjs
authored andcommitted
feat(compiler): support exponentiation operator in templates (#59894)
Adds support for the exponentiation (`**`) operator in templates Ex: ``` @component { template: '{{2 ** 3}}' } ``` PR Close #59894
1 parent 0361c2d commit f2d5cf7

File tree

21 files changed

+138
-18
lines changed

21 files changed

+138
-18
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Angular supports the following operators from standard JavaScript.
5353
| Multiply | `41 * 6` |
5454
| Divide | `20 / 4` |
5555
| Remainder (Modulo) | `17 % 5` |
56+
| Exponentiation | `10 ** 3` |
5657
| Parenthesis | `9 * (8 + 4)` |
5758
| Conditional (Ternary) | `a > b ? true : false` |
5859
| And (Logical) | `&&` |

packages/compiler-cli/linker/babel/test/ast/babel_ast_factory_spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ describe('BabelAstFactory', () => {
8282
expect(t.isLogicalExpression(expr)).toBe(true);
8383
expect(generate(expr).code).toEqual('17 && 42');
8484
});
85+
86+
it('should create a binary operation node for exponentiation', () => {
87+
const left = expression.ast`2`;
88+
const right = expression.ast`3`;
89+
const expr = factory.createBinaryExpression(left, '**', right);
90+
expect(generate(expr).code).toEqual('2 ** 3');
91+
});
8592
});
8693

8794
describe('createBlock()', () => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ export type BinaryOperator =
311311
| '-'
312312
| '%'
313313
| '*'
314+
| '**'
314315
| '!='
315316
| '!=='
316317
| '||'

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const BINARY_OPERATORS = new Map<o.BinaryOperator, BinaryOperator>([
4343
[o.BinaryOperator.Or, '||'],
4444
[o.BinaryOperator.Plus, '+'],
4545
[o.BinaryOperator.NullishCoalesce, '??'],
46+
[o.BinaryOperator.Exponentiation, '**'],
4647
]);
4748

4849
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
@@ -54,6 +54,7 @@ const BINARY_OPERATORS: Record<BinaryOperator, ts.BinaryOperator> = {
5454
'-': ts.SyntaxKind.MinusToken,
5555
'%': ts.SyntaxKind.PercentToken,
5656
'*': ts.SyntaxKind.AsteriskToken,
57+
'**': ts.SyntaxKind.AsteriskAsteriskToken,
5758
'!=': ts.SyntaxKind.ExclamationEqualsToken,
5859
'!==': ts.SyntaxKind.ExclamationEqualsEqualsToken,
5960
'||': ts.SyntaxKind.BarBarToken,

packages/compiler-cli/src/ngtsc/translator/test/typescript_ast_factory_spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ describe('TypeScriptAstFactory', () => {
7373
const assignment = factory.createBinaryExpression(left, '+', right);
7474
expect(generate(assignment)).toEqual('17 + 42');
7575
});
76+
77+
it('should create a binary operation node for exponentiation', () => {
78+
const {
79+
items: [left, right],
80+
generate,
81+
} = setupExpressions(`2`, `3`);
82+
const assignment = factory.createBinaryExpression(left, '**', right);
83+
expect(generate(assignment)).toEqual('2 ** 3');
84+
});
7685
});
7786

7887
describe('createDynamicImport()', () => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const BINARY_OPS = new Map<string, ts.BinaryOperator>([
7676
['==', ts.SyntaxKind.EqualsEqualsToken],
7777
['===', ts.SyntaxKind.EqualsEqualsEqualsToken],
7878
['*', ts.SyntaxKind.AsteriskToken],
79+
['**', ts.SyntaxKind.AsteriskAsteriskToken],
7980
['/', ts.SyntaxKind.SlashToken],
8081
['%', ts.SyntaxKind.PercentToken],
8182
['!=', ts.SyntaxKind.ExclamationEqualsToken],

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ describe('type check blocks', () => {
7575
expect(tcb('{{!(void a === "object")}}')).toContain('!((void (((this).a))) === ("object"))');
7676
});
7777

78+
it('should handle exponentiation expressions', () => {
79+
expect(tcb('{{a * b ** c + d}}')).toContain(
80+
'(((((this).a)) * ((((this).b)) ** (((this).c)))) + (((this).d)))',
81+
);
82+
});
83+
7884
it('should handle attribute values for directive inputs', () => {
7985
const TEMPLATE = `<div dir inputA="value"></div>`;
8086
const DIRECTIVES: TestDeclaration[] = [

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class MyApp {
9191
MyApp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, deps: [], target: i0.ɵɵFactoryTarget.Component });
9292
MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyApp, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
9393
{{ 1 + 2 }}
94-
{{ (1 % 2) + 3 / 4 * 5 }}
94+
{{ (1 % 2) + 3 / 4 * 5 ** 6 }}
9595
{{ +1 }}
9696
{{ typeof {} === 'object' }}
9797
{{ !(typeof {} === 'object') }}
@@ -104,7 +104,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
104104
args: [{
105105
template: `
106106
{{ 1 + 2 }}
107-
{{ (1 % 2) + 3 / 4 * 5 }}
107+
{{ (1 % 2) + 3 / 4 * 5 ** 6 }}
108108
{{ +1 }}
109109
{{ typeof {} === 'object' }}
110110
{{ !(typeof {} === 'object') }}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
"cases": [
44
{
55
"description": "should be able to generate the TODO example",
6-
"inputFiles": [
7-
"todo_example.ts"
8-
],
6+
"inputFiles": ["todo_example.ts"],
97
"expectations": [
108
{
119
"files": [
@@ -20,9 +18,10 @@
2018
},
2119
{
2220
"description": "should handle binary and unary operators",
23-
"inputFiles": [
24-
"operators.ts"
25-
],
21+
"compilerOptions": {
22+
"target": "es2020"
23+
},
24+
"inputFiles": ["operators.ts"],
2625
"expectations": [
2726
{
2827
"files": [

0 commit comments

Comments
 (0)