Skip to content

Commit 8b44958

Browse files
committed
Support optional chaining
Fixes #522
1 parent faa8f6e commit 8b44958

File tree

7 files changed

+670
-113
lines changed

7 files changed

+670
-113
lines changed

TypeScript.YAML-tmLanguage

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ uuid: ef98eb90-bf9b-11e4-bb52-0800200c9a66
88
variables:
99
startOfIdentifier: (?<![_$[:alnum:]])(?:(?<=\.\.\.)|(?<!\.))
1010
endOfIdentifier: (?![_$[:alnum:]])(?:(?=\.\.\.)|(?!\.))
11+
propertyAccess: (?:(\.)|(\?\.(?!\s*[[:digit:]])))
12+
propertyAccessPreIdentifier: \??\.\s*
1113
identifier: '[_$[:alpha:]][_$[:alnum:]]*'
1214
constantIdentifier: '[[:upper:]][_$[:digit:][:upper:]]*'
1315
quotedStrings: (\'([^\'\\]|\\\'|\\)*\')|(\"([^\"\\]|\\\"|\\)*\")
@@ -22,6 +24,7 @@ variables:
2224
typeArgumentsStart: ({{typeParamersStart}}|(\'[^\']*\')|(\"[^\"]*\")|(\`[^\`]*\`))
2325
typeArgumentsInnerExpressionPart: '[^<>\(]|{{matchingParenthesis}}'
2426
typeArguments: (<\s*{{typeArgumentsStart}}({{typeArgumentsInnerExpressionPart}}|\<\s*{{typeArgumentsStart}}({{typeArgumentsInnerExpressionPart}})*\>)*>\s*)
27+
functionCallLookup: \s*(\?\.\s*)?{{typeArguments}}?\(
2528
arrowLookup: |-
2629
# sure shot arrow functions even if => is on new line
2730
(
@@ -676,10 +679,11 @@ repository:
676679
# match expressions before matching identifiers
677680
- include: '#expressionWithoutIdentifiers'
678681
# identifiers are treated as inherited class
679-
- match: ({{identifier}})\s*(\.)(?=\s*{{identifier}}(\s*\.\s*{{identifier}})*\s*)
682+
- match: '({{identifier}})\s*{{propertyAccess}}(?=\s*{{identifier}}(\s*{{propertyAccessPreIdentifier}}{{identifier}})*\s*)'
680683
captures:
681684
'1': { name: entity.name.type.module.ts }
682685
'2': { name: punctuation.accessor.ts }
686+
'3': { name: punctuation.accessor.optional.ts }
683687
- match: ({{identifier}})
684688
captures:
685689
'1': { name: entity.other.inherited-class.ts }
@@ -815,10 +819,11 @@ repository:
815819
end: (?=;|$|^)
816820
patterns:
817821
- include: '#comment'
818-
- match: ({{identifier}})\s*(\.)
822+
- match: ({{identifier}})\s*{{propertyAccess}}
819823
captures:
820824
'1': { name: entity.name.type.module.ts }
821825
'2': { name: punctuation.accessor.ts }
826+
'3': { name: punctuation.accessor.optional.ts }
822827
- name: variable.other.readwrite.ts
823828
match: ({{identifier}})
824829

@@ -1037,9 +1042,9 @@ repository:
10371042

10381043
#ternary expression
10391044
ternary-expression:
1040-
begin: (\?)
1045+
begin: (?!\?\.\s*[^[:digit:]])(\?)
10411046
beginCaptures:
1042-
'0': { name: keyword.operator.ternary.ts }
1047+
'1': { name: keyword.operator.ternary.ts }
10431048
end: (:)
10441049
endCaptures:
10451050
'0': { name: keyword.operator.ternary.ts }
@@ -1048,12 +1053,12 @@ repository:
10481053

10491054
#function call and new expression
10501055
function-call:
1051-
begin: (?=(({{identifier}}\s*\.\s*)*|(\.\s*)?)({{identifier}})\s*{{typeArguments}}?\()
1052-
end: (?<=\))(?!(({{identifier}}\s*\.\s*)*|(\.\s*)?)({{identifier}})\s*{{typeArguments}}?\()
1056+
begin: (?=(({{identifier}}\s*{{propertyAccessPreIdentifier}})*|({{propertyAccessPreIdentifier}})?)({{identifier}}){{functionCallLookup}})
1057+
end: (?<=\))(?!(({{identifier}}\s*{{propertyAccessPreIdentifier}})*|({{propertyAccessPreIdentifier}})?)({{identifier}}){{functionCallLookup}})
10531058
patterns:
10541059
- name: meta.function-call.ts
1055-
begin: (?=(({{identifier}}\s*\.\s*)*|(\.\s*)?)({{identifier}}))
1056-
end: (?=\s*{{typeArguments}}?\()
1060+
begin: (?=(({{identifier}}\s*{{propertyAccessPreIdentifier}})*|({{propertyAccessPreIdentifier}})?)({{identifier}}))
1061+
end: (?={{functionCallLookup}})
10571062
patterns:
10581063
- include: '#literal'
10591064
- include: '#support-objects'
@@ -1064,6 +1069,8 @@ repository:
10641069
- name: entity.name.function.ts
10651070
match: ({{identifier}})
10661071
- include: '#comment'
1072+
- name: meta.function-call.ts punctuation.accessor.optional.ts
1073+
match: \?\.
10671074
- name: meta.type.parameters.ts
10681075
begin: \<
10691076
beginCaptures:
@@ -1294,7 +1301,7 @@ repository:
12941301
isFinite|isNaN|parseFloat|parseInt|require|set(Interval|Timeout)|super|unescape|uneval)(?=\s*\()
12951302
# Math
12961303
- match: |-
1297-
(?x){{startOfIdentifier}}(Math)(?:\s*(\.)\s*(?:
1304+
(?x){{startOfIdentifier}}(Math)(?:\s*{{propertyAccess}}\s*(?:
12981305
(abs|acos|acosh|asin|asinh|atan|atan2|atanh|cbrt|ceil|clz32|cos|cosh|exp|
12991306
expm1|floor|fround|hypot|imul|log|log10|log1p|log2|max|min|pow|random|
13001307
round|sign|sin|sinh|sqrt|tan|tanh|trunc)
@@ -1303,33 +1310,37 @@ repository:
13031310
captures:
13041311
'1': { name: support.constant.math.ts }
13051312
'2': { name: punctuation.accessor.ts }
1306-
'3': { name: support.function.math.ts }
1307-
'4': { name: support.constant.property.math.ts }
1313+
'3': { name: punctuation.accessor.optional.ts }
1314+
'4': { name: support.function.math.ts }
1315+
'5': { name: support.constant.property.math.ts }
13081316
# console
13091317
- match: |-
1310-
(?x){{startOfIdentifier}}(console)(?:\s*(\.)\s*(
1318+
(?x){{startOfIdentifier}}(console)(?:\s*{{propertyAccess}}\s*(
13111319
assert|clear|count|debug|dir|error|group|groupCollapsed|groupEnd|info|log
13121320
|profile|profileEnd|table|time|timeEnd|timeStamp|trace|warn))?\b(?!\$)
13131321
captures:
13141322
'1': { name: support.class.console.ts }
13151323
'2': { name: punctuation.accessor.ts }
1316-
'3': { name: support.function.console.ts }
1324+
'3': { name: punctuation.accessor.optional.ts }
1325+
'4': { name: support.function.console.ts }
13171326
# JSON
1318-
- match: '{{startOfIdentifier}}(JSON)(?:\s*(\.)\s*(parse|stringify))?\b(?!\$)'
1327+
- match: '{{startOfIdentifier}}(JSON)(?:\s*{{propertyAccess}}\s*(parse|stringify))?\b(?!\$)'
13191328
captures:
13201329
'1': { name: support.constant.json.ts }
13211330
'2': { name: punctuation.accessor.ts }
1322-
'3': { name: support.function.json.ts }
1331+
'3': { name: punctuation.accessor.optional.ts }
1332+
'4': { name: support.function.json.ts }
13231333
# DOM
13241334
- match: |-
1325-
(?x) (\.) \s* (?:
1335+
(?x) {{propertyAccess}} \s* (?:
13261336
(constructor|length|prototype|__proto__)
13271337
|
13281338
(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY))\b(?!\$)
13291339
captures:
13301340
'1': { name: punctuation.accessor.ts }
1331-
'2': { name: support.variable.property.ts }
1332-
'3': { name: support.constant.ts }
1341+
'2': { name: punctuation.accessor.optional.ts }
1342+
'3': { name: support.variable.property.ts }
1343+
'4': { name: support.constant.ts }
13331344
- match: |-
13341345
(?x) {{startOfIdentifier}} \b (?:
13351346
(document|event|navigator|performance|screen|window)
@@ -1397,7 +1408,7 @@ repository:
13971408
'1': { name: support.variable.dom.ts }
13981409
'2': { name: support.class.dom.ts }
13991410
- match: |-
1400-
(?x) (\.) \s* (?:
1411+
(?x) {{propertyAccess}} \s* (?:
14011412
(ATTRIBUTE_NODE|CDATA_SECTION_NODE|COMMENT_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE
14021413
|DOMSTRING_SIZE_ERR|ELEMENT_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|HIERARCHY_REQUEST_ERR|INDEX_SIZE_ERR
14031414
|INUSE_ATTRIBUTE_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR
@@ -1431,35 +1442,38 @@ repository:
14311442
|vAlign|value|valueType|vendor|vendorSub|version|visibility|vspace|whiteSpace|width|X[MS]LDocument|zIndex))\b(?!\$|\s*{{typeParameters}}?\()
14321443
captures:
14331444
'1': { name: punctuation.accessor.ts }
1434-
'2': { name: support.constant.dom.ts }
1435-
'3': { name: support.variable.property.dom.ts }
1445+
'2': { name: punctuation.accessor.optional.ts }
1446+
'3': { name: support.constant.dom.ts }
1447+
'4': { name: support.variable.property.dom.ts }
14361448
# Node
14371449
- name: support.class.node.ts
14381450
match: |-
14391451
(?x){{startOfIdentifier}}(Buffer|EventEmitter|Server|Pipe|Socket|REPLServer|ReadStream|WriteStream|Stream
14401452
|Inflate|Deflate|InflateRaw|DeflateRaw|GZip|GUnzip|Unzip|Zip)\b(?!\$)
14411453
- match: |-
1442-
(?x){{startOfIdentifier}}(process)(?:(\.)(?:
1454+
(?x){{startOfIdentifier}}(process)(?:{{propertyAccess}}(?:
14431455
(arch|argv|config|connected|env|execArgv|execPath|exitCode|mainModule|pid|platform|release|stderr|stdin|stdout|title|version|versions)
14441456
|
14451457
(abort|chdir|cwd|disconnect|exit|[sg]ete?[gu]id|send|[sg]etgroups|initgroups|kill|memoryUsage|nextTick|umask|uptime|hrtime)
14461458
))?\b(?!\$)
14471459
captures:
14481460
'1': { name: support.variable.object.process.ts }
14491461
'2': { name: punctuation.accessor.ts }
1450-
'3': { name: support.variable.property.process.ts }
1451-
'4': { name: support.function.process.ts }
1452-
- match: '{{startOfIdentifier}}(?:(exports)|(module)(?:(\.)(exports|id|filename|loaded|parent|children))?)\b(?!\$)'
1462+
'3': { name: punctuation.accessor.optional.ts }
1463+
'4': { name: support.variable.property.process.ts }
1464+
'5': { name: support.function.process.ts }
1465+
- match: '{{startOfIdentifier}}(?:(exports)|(module)(?:{{propertyAccess}}(exports|id|filename|loaded|parent|children))?)\b(?!\$)'
14531466
captures:
14541467
'1': { name: support.type.object.module.ts }
14551468
'2': { name: support.type.object.module.ts }
14561469
'3': { name: punctuation.accessor.ts }
1457-
'4': { name: support.type.object.module.ts }
1470+
'4': { name: punctuation.accessor.optional.ts }
1471+
'5': { name: support.type.object.module.ts }
14581472
- name: support.variable.object.node.ts
14591473
match: '{{startOfIdentifier}}(global|GLOBAL|root|__dirname|__filename)\b(?!\$)'
14601474
# method calls
14611475
- match: |-
1462-
(?x) (\.) \s*
1476+
(?x) {{propertyAccess}} \s*
14631477
(?:
14641478
(on(?:Rowsinserted|Rowsdelete|Rowenter|Rowexit|Resize|Resizestart|Resizeend|Reset|
14651479
Readystatechange|Mouseout|Mouseover|Mousedown|Mouseup|Mousemove|
@@ -1536,29 +1550,33 @@ repository:
15361550
)(?=\s*\()
15371551
captures:
15381552
'1': { name: punctuation.accessor.ts }
1539-
'2': { name: support.function.event-handler.ts }
1540-
'3': { name: support.function.ts }
1541-
'4': { name: support.function.dom.ts }
1553+
'2': { name: punctuation.accessor.optional.ts }
1554+
'3': { name: support.function.event-handler.ts }
1555+
'4': { name: support.function.ts }
1556+
'5': { name: support.function.dom.ts }
15421557
15431558
identifiers:
15441559
patterns:
15451560
- include: '#object-identifiers'
15461561
# function and method assignment
15471562
- match: |-
1548-
(?x)(?:(\.)\s*)?({{identifier}})(?=\s*={{functionOrArrowLookup}})
1563+
(?x)(?:{{propertyAccess}}\s*)?({{identifier}})(?=\s*={{functionOrArrowLookup}})
15491564
captures:
15501565
'1': { name: punctuation.accessor.ts }
1551-
'2': { name: entity.name.function.ts }
1566+
'2': { name: punctuation.accessor.optional.ts }
1567+
'3': { name: entity.name.function.ts }
15521568
# const properties
1553-
- match: (\.)\s*{{constantVar}}
1569+
- match: '{{propertyAccess}}\s*{{constantVar}}'
15541570
captures:
15551571
'1': { name: punctuation.accessor.ts }
1556-
'2': { name: variable.other.constant.property.ts }
1572+
'2': { name: punctuation.accessor.optional.ts }
1573+
'3': { name: variable.other.constant.property.ts }
15571574
# properties
1558-
- match: (\.)\s*({{identifier}})
1575+
- match: '{{propertyAccess}}\s*({{identifier}})'
15591576
captures:
15601577
'1': { name: punctuation.accessor.ts }
1561-
'2': { name: variable.other.property.ts }
1578+
'2': { name: punctuation.accessor.optional.ts }
1579+
'3': { name: variable.other.property.ts }
15621580
# const
15631581
- name: variable.other.constant.ts
15641582
match: '{{constantVar}}'
@@ -1570,23 +1588,24 @@ repository:
15701588
patterns:
15711589
# class
15721590
- name: support.class.ts
1573-
match: ({{identifier}})(?=\s*\.\s*prototype\b(?!\$))
1591+
match: ({{identifier}})(?=\s*{{propertyAccessPreIdentifier}}prototype\b(?!\$))
15741592
# object properties
15751593
- match: |-
1576-
(?x)(\.)\s*(?:
1594+
(?x){{propertyAccess}}\s*(?:
15771595
({{constantIdentifier}}) |
15781596
({{identifier}})
1579-
)(?=\s*\.\s*{{identifier}})
1597+
)(?=\s*{{propertyAccessPreIdentifier}}{{identifier}})
15801598
captures:
15811599
'1': { name: punctuation.accessor.ts }
1582-
'2': { name: variable.other.constant.object.property.ts }
1583-
'3': { name: variable.other.object.property.ts }
1600+
'2': { name: punctuation.accessor.optional.ts }
1601+
'3': { name: variable.other.constant.object.property.ts }
1602+
'4': { name: variable.other.object.property.ts }
15841603
# objects
15851604
- match: |-
15861605
(?x)(?:
15871606
({{constantIdentifier}}) |
15881607
({{identifier}})
1589-
)(?=\s*\.\s*{{identifier}})
1608+
)(?=\s*{{propertyAccessPreIdentifier}}{{identifier}})
15901609
captures:
15911610
'1': { name: variable.other.constant.object.ts }
15921611
'2': { name: variable.other.object.ts }
@@ -1845,10 +1864,11 @@ repository:
18451864
#name of the type
18461865
type-name:
18471866
patterns:
1848-
- match: ({{identifier}})\s*(\.)
1867+
- match: ({{identifier}})\s*{{propertyAccess}}
18491868
captures:
18501869
'1': { name: entity.name.type.module.ts }
18511870
'2': { name: punctuation.accessor.ts }
1871+
'3': { name: punctuation.accessor.optional.ts }
18521872
- name: entity.name.type.ts
18531873
match: '{{identifier}}'
18541874

@@ -1862,8 +1882,10 @@ repository:
18621882
match: ';'
18631883

18641884
punctuation-accessor:
1865-
name: punctuation.accessor.ts
1866-
match: '\.'
1885+
match: '{{propertyAccess}}'
1886+
captures:
1887+
'1': { name: punctuation.accessor.ts }
1888+
'2': { name: punctuation.accessor.optional.ts }
18671889

18681890
#strings and template strings
18691891
string:

0 commit comments

Comments
 (0)