diff --git a/changelog_unreleased/angular/14658.md b/changelog_unreleased/angular/14658.md
new file mode 100644
index 000000000..5858a73f2
--- /dev/null
+++ b/changelog_unreleased/angular/14658.md
@@ -0,0 +1,13 @@
+#### Support computed optional chaining (#14658 by @fisker)
+
+
+```html
+
+
+
+
+
+
+
+
+```
diff --git a/package.json b/package.json
index ea60253dc..92137448c 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"@typescript-eslint/visitor-keys": "5.55.0",
"acorn": "8.8.2",
"acorn-jsx": "5.3.2",
- "angular-estree-parser": "6.1.0",
+ "angular-estree-parser": "6.2.0",
"angular-html-parser": "4.0.1",
"camelcase": "7.0.1",
"chalk": "5.2.0",
diff --git a/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap b/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
index 3eac504e5..c6fe89f66 100644
--- a/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/angular/angular/__snapshots__/jsfmt.spec.js.snap
@@ -334,10 +334,10 @@ printWidth: 80
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -354,6 +354,8 @@ printWidth: 80
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -366,6 +368,8 @@ printWidth: 80
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -410,14 +414,14 @@ printWidth: 80
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
@@ -466,6 +470,8 @@ printWidth: 80
[target]="a"
[target]="a // hello"
[target]="a.b"
+ [target]="a?.b"
+ [target]="a?.[b]"
[target]=" javascript : 'hello world' "
[target]="a?.b()"
[target]="a?.b"
@@ -478,6 +484,8 @@ printWidth: 80
(target)="(a); (b)"
(event)="(0)"
(event)="(a.b)"
+ (event)="(a?.b)"
+ (event)="(a?.[b])"
(event)="(hello)"
(event)="hello()"
(event)="(a && b)"
@@ -545,14 +553,14 @@ printWidth: 80
test="{{ 'test' | translate }}"
test="foo {{ invalid invalid }} bar {{ valid }} baz"
test="foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz"
i18n="Normal i18n text"
i18n="
@@ -605,10 +613,10 @@ printWidth: 80
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -625,6 +633,8 @@ printWidth: 80
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -637,6 +647,8 @@ printWidth: 80
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -681,14 +693,14 @@ printWidth: 80
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
@@ -737,6 +749,8 @@ printWidth: 80
[target]="a"
[target]="a // hello"
[target]="a.b"
+ [target]="a?.b"
+ [target]="a?.[b]"
[target]=" javascript : 'hello world' "
[target]="a?.b()"
[target]="a?.b"
@@ -749,6 +763,8 @@ printWidth: 80
(target)="(a); (b)"
(event)="(0)"
(event)="(a.b)"
+ (event)="(a?.b)"
+ (event)="(a?.[b])"
(event)="(hello)"
(event)="hello()"
(event)="(a && b)"
@@ -816,14 +832,14 @@ printWidth: 80
test="{{ 'test' | translate }}"
test="foo {{ invalid invalid }} bar {{ valid }} baz"
test="foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz"
i18n="Normal i18n text"
i18n="
@@ -875,10 +891,10 @@ printWidth: 1
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -895,6 +911,8 @@ printWidth: 1
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -907,6 +925,8 @@ printWidth: 1
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -951,14 +971,14 @@ printWidth: 1
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
@@ -1088,6 +1108,14 @@ printWidth: 1
[target]="
a.b
"
+ [target]="
+ a?.b
+ "
+ [target]="
+ a?.[
+ b
+ ]
+ "
[target]=" javascript : 'hello world' "
[target]="
a?.b()
@@ -1126,6 +1154,14 @@ printWidth: 1
(event)="
(a.b)
"
+ (event)="
+ (a?.b)
+ "
+ (event)="
+ (a?.[
+ b
+ ])
+ "
(event)="
(hello)
"
@@ -1323,16 +1359,16 @@ printWidth: 1
valid
}} baz"
test="foo
-
+
{{ invalid
- invalid }}
-
- bar
-
+ invalid }}
+
+ bar
+
{{
valid
- }}
-
+ }}
+
baz"
i18n="
Normal
@@ -1474,10 +1510,10 @@ trailingComma: "es5"
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -1494,6 +1530,8 @@ trailingComma: "es5"
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -1506,6 +1544,8 @@ trailingComma: "es5"
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -1550,14 +1590,14 @@ trailingComma: "es5"
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
@@ -1606,6 +1646,8 @@ trailingComma: "es5"
[target]="a"
[target]="a // hello"
[target]="a.b"
+ [target]="a?.b"
+ [target]="a?.[b]"
[target]=" javascript : 'hello world' "
[target]="a?.b()"
[target]="a?.b"
@@ -1618,6 +1660,8 @@ trailingComma: "es5"
(target)="(a); (b)"
(event)="(0)"
(event)="(a.b)"
+ (event)="(a?.b)"
+ (event)="(a?.[b])"
(event)="(hello)"
(event)="hello()"
(event)="(a && b)"
@@ -1685,14 +1729,14 @@ trailingComma: "es5"
test="{{ 'test' | translate }}"
test="foo {{ invalid invalid }} bar {{ valid }} baz"
test="foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz"
i18n="Normal i18n text"
i18n="
@@ -1745,10 +1789,10 @@ trailingComma: "none"
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -1765,6 +1809,8 @@ trailingComma: "none"
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -1777,6 +1823,8 @@ trailingComma: "none"
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -1821,14 +1869,14 @@ trailingComma: "none"
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
@@ -1877,6 +1925,8 @@ trailingComma: "none"
[target]="a"
[target]="a // hello"
[target]="a.b"
+ [target]="a?.b"
+ [target]="a?.[b]"
[target]=" javascript : 'hello world' "
[target]="a?.b()"
[target]="a?.b"
@@ -1889,6 +1939,8 @@ trailingComma: "none"
(target)="(a); (b)"
(event)="(0)"
(event)="(a.b)"
+ (event)="(a?.b)"
+ (event)="(a?.[b])"
(event)="(hello)"
(event)="hello()"
(event)="(a && b)"
@@ -1956,14 +2008,14 @@ trailingComma: "none"
test="{{ 'test' | translate }}"
test="foo {{ invalid invalid }} bar {{ valid }} baz"
test="foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz"
i18n="Normal i18n text"
i18n="
diff --git a/tests/format/angular/angular/attributes.component.html b/tests/format/angular/angular/attributes.component.html
index 1fa9c3894..a911ddb32 100644
--- a/tests/format/angular/angular/attributes.component.html
+++ b/tests/format/angular/angular/attributes.component.html
@@ -13,10 +13,10 @@
[target]=" [ 1 ] "
[target]=" { 'a' : 1 } "
[target]=" { a : 1 } "
- [target]=" {
+ [target]=" {
trailingComma : 'notAllowed'
}"
- [target]=" [
+ [target]=" [
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
]"
[target]=" true "
@@ -33,6 +33,8 @@
[target]=" a "
[target]=" a // hello "
[target]=" a . b "
+ [target]=" a ?. b "
+ [target]=" a ?. [b] "
[target]=" javascript : 'hello world' "
[target]=" a ?. b ( ) "
[target]=" a ?. b "
@@ -45,6 +47,8 @@
(target)=" a ; b "
(event)=" 0 "
(event)=" a.b "
+ (event)=" a ?.b "
+ (event)=" a?.[ b] "
(event)=" hello "
(event)=" hello() "
(event)=" a && b "
@@ -89,14 +93,14 @@
test='{{ "test" | translate }}'
test='foo {{ invalid invalid }} bar {{ valid }} baz'
test='foo
-
+
{{ invalid
- invalid }}
-
- bar
-
- {{ valid }}
-
+ invalid }}
+
+ bar
+
+ {{ valid }}
+
baz'
i18n="Normal i18n text"
i18n="This is a very long internationalization description text, exceeding the configured print width, but could easily be formatted"
diff --git a/tests/format/angular/interpolation/__snapshots__/jsfmt.spec.js.snap b/tests/format/angular/interpolation/__snapshots__/jsfmt.spec.js.snap
index c173512de..811bcbc17 100644
--- a/tests/format/angular/interpolation/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/angular/interpolation/__snapshots__/jsfmt.spec.js.snap
@@ -1,5 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`computed-optional-member-expression.ng - {"trailingComma":"none"} format 1`] = `
+====================================options=====================================
+parsers: ["__ng_interpolation"]
+printWidth: 80
+trailingComma: "none"
+ | printWidth
+=====================================input======================================
+[
+ a?.[0]
+]
+
+=====================================output=====================================
+[a?.[0]]
+================================================================================
+`;
+
exports[`logical-expression.ng - {"trailingComma":"none"} format 1`] = `
====================================options=====================================
parsers: ["__ng_interpolation"]
diff --git a/tests/format/angular/interpolation/computed-optional-member-expression.ng b/tests/format/angular/interpolation/computed-optional-member-expression.ng
new file mode 100644
index 000000000..b0c955e71
--- /dev/null
+++ b/tests/format/angular/interpolation/computed-optional-member-expression.ng
@@ -0,0 +1,3 @@
+[
+ a?.[0]
+]
diff --git a/yarn.lock b/yarn.lock
index 749fe56a8..1b106b2c0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1944,15 +1944,15 @@ __metadata:
languageName: node
linkType: hard
-"angular-estree-parser@npm:6.1.0":
- version: 6.1.0
- resolution: "angular-estree-parser@npm:6.1.0"
+"angular-estree-parser@npm:6.2.0":
+ version: 6.2.0
+ resolution: "angular-estree-parser@npm:6.2.0"
dependencies:
lines-and-columns: ^2.0.3
tslib: ^2.5.0
peerDependencies:
- "@angular/compiler": ^15.2.2
- checksum: 0b772796e8b924a6f792a9d9caa2332a9b84643580bf2320062c3cb772a28fea2af897fdcc03f6070e6d9353d267736c1fd5daa5339ba536f0c8d00790574164
+ "@angular/compiler": ^15.2.5
+ checksum: 7c062ac8f73b753fdba62d274a6fb082da1360bbf551dfd06f2fd9d8a3c8e42b092a98d2fc8d03e647fd9d8acaa4d2d7f00c1c25d9e49c211a26c344db228410
languageName: node
linkType: hard
@@ -6731,7 +6731,7 @@ __metadata:
"@typescript-eslint/visitor-keys": 5.55.0
acorn: 8.8.2
acorn-jsx: 5.3.2
- angular-estree-parser: 6.1.0
+ angular-estree-parser: 6.2.0
angular-html-parser: 4.0.1
benchmark: 2.1.4
browserslist-to-esbuild: 1.2.0