@typespec/compiler 1.16.0 → 1.17.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest.js +2 -2
- package/dist/src/core/binder.d.ts +1 -1
- package/dist/src/core/binder.d.ts.map +1 -1
- package/dist/src/core/binder.js +33 -0
- package/dist/src/core/binder.js.map +1 -1
- package/dist/src/core/checker.d.ts.map +1 -1
- package/dist/src/core/checker.js +168 -53
- package/dist/src/core/checker.js.map +1 -1
- package/dist/src/core/features.d.ts +3 -0
- package/dist/src/core/features.d.ts.map +1 -1
- package/dist/src/core/features.js +3 -0
- package/dist/src/core/features.js.map +1 -1
- package/dist/src/core/helpers/type-name-utils.js +19 -3
- package/dist/src/core/helpers/type-name-utils.js.map +1 -1
- package/dist/src/core/inspector/node.js +6 -1
- package/dist/src/core/inspector/node.js.map +1 -1
- package/dist/src/core/messages.d.ts +38 -2
- package/dist/src/core/messages.d.ts.map +1 -1
- package/dist/src/core/messages.js +12 -0
- package/dist/src/core/messages.js.map +1 -1
- package/dist/src/core/modifiers.d.ts +9 -2
- package/dist/src/core/modifiers.d.ts.map +1 -1
- package/dist/src/core/modifiers.js +8 -0
- package/dist/src/core/modifiers.js.map +1 -1
- package/dist/src/core/name-resolver.d.ts.map +1 -1
- package/dist/src/core/name-resolver.js +30 -4
- package/dist/src/core/name-resolver.js.map +1 -1
- package/dist/src/core/parser.d.ts.map +1 -1
- package/dist/src/core/parser.js +257 -23
- package/dist/src/core/parser.js.map +1 -1
- package/dist/src/core/scanner.d.ts +5 -0
- package/dist/src/core/scanner.d.ts.map +1 -1
- package/dist/src/core/scanner.js +10 -0
- package/dist/src/core/scanner.js.map +1 -1
- package/dist/src/core/type-utils.d.ts.map +1 -1
- package/dist/src/core/type-utils.js +3 -0
- package/dist/src/core/type-utils.js.map +1 -1
- package/dist/src/core/types.d.ts +111 -14
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +4 -0
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/formatter/print/comment-handler.js +11 -1
- package/dist/src/formatter/print/comment-handler.js.map +1 -1
- package/dist/src/formatter/print/printer.d.ts +2 -2
- package/dist/src/formatter/print/printer.d.ts.map +1 -1
- package/dist/src/formatter/print/printer.js +106 -15
- package/dist/src/formatter/print/printer.js.map +1 -1
- package/dist/src/init/init.d.ts.map +1 -1
- package/dist/src/init/init.js +3 -1
- package/dist/src/init/init.js.map +1 -1
- package/dist/src/init/prompts.d.ts +1 -1
- package/dist/src/init/prompts.d.ts.map +1 -1
- package/dist/src/init/prompts.js +1 -1
- package/dist/src/init/prompts.js.map +1 -1
- package/dist/src/init/scaffold.d.ts.map +1 -1
- package/dist/src/init/scaffold.js +31 -3
- package/dist/src/init/scaffold.js.map +1 -1
- package/dist/src/init/template-source/in-memory-template-source.d.ts +1 -1
- package/dist/src/init/template-source/in-memory-template-source.d.ts.map +1 -1
- package/dist/src/init/template-source/in-memory-template-source.js +2 -1
- package/dist/src/init/template-source/in-memory-template-source.js.map +1 -1
- package/dist/src/init/template-source/types.d.ts +1 -0
- package/dist/src/init/template-source/types.d.ts.map +1 -1
- package/dist/src/init/template-source/types.js +10 -1
- package/dist/src/init/template-source/types.js.map +1 -1
- package/dist/src/init/template-source/uri-template-source.d.ts +1 -1
- package/dist/src/init/template-source/uri-template-source.d.ts.map +1 -1
- package/dist/src/init/template-source/uri-template-source.js +23 -2
- package/dist/src/init/template-source/uri-template-source.js.map +1 -1
- package/dist/src/module-resolver/utils.d.ts.map +1 -1
- package/dist/src/module-resolver/utils.js +6 -2
- package/dist/src/module-resolver/utils.js.map +1 -1
- package/dist/src/server/classify.d.ts.map +1 -1
- package/dist/src/server/classify.js +12 -4
- package/dist/src/server/classify.js.map +1 -1
- package/dist/src/server/completion.js +14 -1
- package/dist/src/server/completion.js.map +1 -1
- package/dist/src/server/tmlanguage.d.ts.map +1 -1
- package/dist/src/server/tmlanguage.js +69 -1
- package/dist/src/server/tmlanguage.js.map +1 -1
- package/dist/src/server/type-signature.js +4 -1
- package/dist/src/server/type-signature.js.map +1 -1
- package/dist/src/testing/tester.d.ts +11 -0
- package/dist/src/testing/tester.d.ts.map +1 -1
- package/dist/src/testing/tester.js +28 -3
- package/dist/src/testing/tester.js.map +1 -1
- package/dist/src/typekit/kits/enum.d.ts +14 -1
- package/dist/src/typekit/kits/enum.d.ts.map +1 -1
- package/dist/src/typekit/kits/enum.js +2 -1
- package/dist/src/typekit/kits/enum.js.map +1 -1
- package/dist/src/typekit/kits/model.d.ts +12 -1
- package/dist/src/typekit/kits/model.d.ts.map +1 -1
- package/dist/src/typekit/kits/model.js +3 -2
- package/dist/src/typekit/kits/model.js.map +1 -1
- package/dist/src/typekit/kits/union.d.ts +12 -1
- package/dist/src/typekit/kits/union.d.ts.map +1 -1
- package/dist/src/typekit/kits/union.js +3 -3
- package/dist/src/typekit/kits/union.js.map +1 -1
- package/dist/src/typekit/utils.d.ts.map +1 -1
- package/dist/src/typekit/utils.js +17 -0
- package/dist/src/typekit/utils.js.map +1 -1
- package/dist/typespec.tmLanguage +209 -37
- package/package.json +12 -9
package/dist/src/core/parser.js
CHANGED
|
@@ -3,7 +3,7 @@ import { codePointBefore, isIdentifierContinue, trim } from "./charcode.js";
|
|
|
3
3
|
import { compilerAssert } from "./diagnostics.js";
|
|
4
4
|
import { createDiagnostic } from "./messages.js";
|
|
5
5
|
import { modifiersToFlags } from "./modifiers.js";
|
|
6
|
-
import { createScanner, isComment, isKeyword, isModifier, isPunctuation, isReservedKeyword, isStatementKeyword, isTrivia, skipContinuousIdentifier, skipTrivia, skipTriviaBackward, Token, TokenDisplay, TokenFlags, } from "./scanner.js";
|
|
6
|
+
import { createScanner, isComment, isDeclarationExpressionStatementKeyword, isKeyword, isModifier, isPunctuation, isReservedKeyword, isStatementKeyword, isTrivia, skipContinuousIdentifier, skipTrivia, skipTriviaBackward, Token, TokenDisplay, TokenFlags, } from "./scanner.js";
|
|
7
7
|
import { IdentifierKind, ModifierFlags, NodeFlags, SyntaxKind } from "./types.js";
|
|
8
8
|
/**
|
|
9
9
|
* The fixed set of options for each of the kinds of delimited lists in TypeSpec.
|
|
@@ -26,10 +26,12 @@ var ListKind;
|
|
|
26
26
|
ListKind.DecoratorArguments = {
|
|
27
27
|
...ListKind.OperationParameters,
|
|
28
28
|
invalidAnnotationTarget: "expression",
|
|
29
|
+
allowDeclarationExpression: true,
|
|
29
30
|
};
|
|
30
31
|
ListKind.FunctionArguments = {
|
|
31
32
|
...ListKind.OperationParameters,
|
|
32
33
|
invalidAnnotationTarget: "expression",
|
|
34
|
+
allowDeclarationExpression: true,
|
|
33
35
|
};
|
|
34
36
|
ListKind.ModelProperties = {
|
|
35
37
|
...PropertiesBase,
|
|
@@ -91,12 +93,14 @@ var ListKind;
|
|
|
91
93
|
};
|
|
92
94
|
ListKind.TemplateArguments = {
|
|
93
95
|
...ListKind.TemplateParameters,
|
|
96
|
+
allowDeclarationExpression: true,
|
|
94
97
|
};
|
|
95
98
|
ListKind.CallArguments = {
|
|
96
99
|
...ExpresionsBase,
|
|
97
100
|
allowEmpty: true,
|
|
98
101
|
open: Token.OpenParen,
|
|
99
102
|
close: Token.CloseParen,
|
|
103
|
+
allowDeclarationExpression: true,
|
|
100
104
|
};
|
|
101
105
|
ListKind.Heritage = {
|
|
102
106
|
...ExpresionsBase,
|
|
@@ -109,6 +113,7 @@ var ListKind;
|
|
|
109
113
|
allowEmpty: true,
|
|
110
114
|
open: Token.OpenBracket,
|
|
111
115
|
close: Token.CloseBracket,
|
|
116
|
+
allowDeclarationExpression: true,
|
|
112
117
|
};
|
|
113
118
|
ListKind.ArrayLiteral = {
|
|
114
119
|
...ExpresionsBase,
|
|
@@ -466,6 +471,25 @@ function createParser(code, options = {}) {
|
|
|
466
471
|
}
|
|
467
472
|
return undefined;
|
|
468
473
|
}
|
|
474
|
+
function parseUnionDeclarationExpression(pos, decorators = []) {
|
|
475
|
+
parseExpected(Token.UnionKeyword);
|
|
476
|
+
const id = parseOptionalDeclarationExpressionIdentifier();
|
|
477
|
+
const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
|
|
478
|
+
const optionalExtends = parseOptionalUnionExtends();
|
|
479
|
+
const { items: options } = parseList(ListKind.UnionVariants, parseUnionVariant);
|
|
480
|
+
return {
|
|
481
|
+
kind: SyntaxKind.UnionDeclarationExpression,
|
|
482
|
+
id,
|
|
483
|
+
templateParameters,
|
|
484
|
+
templateParametersRange,
|
|
485
|
+
extends: optionalExtends,
|
|
486
|
+
decorators,
|
|
487
|
+
modifiers: [],
|
|
488
|
+
modifierFlags: ModifierFlags.None,
|
|
489
|
+
options,
|
|
490
|
+
...finishNode(pos),
|
|
491
|
+
};
|
|
492
|
+
}
|
|
469
493
|
function parseIdOrValueForVariant() {
|
|
470
494
|
const nextToken = token();
|
|
471
495
|
let id;
|
|
@@ -611,35 +635,74 @@ function createParser(code, options = {}) {
|
|
|
611
635
|
parseExpected(Token.ModelKeyword);
|
|
612
636
|
const id = parseIdentifier();
|
|
613
637
|
const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
|
|
638
|
+
const { extends: optionalExtends, is: optionalIs, properties, bodyRange } = parseModelBody();
|
|
639
|
+
return {
|
|
640
|
+
kind: SyntaxKind.ModelStatement,
|
|
641
|
+
id,
|
|
642
|
+
extends: optionalExtends,
|
|
643
|
+
is: optionalIs,
|
|
644
|
+
templateParameters,
|
|
645
|
+
templateParametersRange,
|
|
646
|
+
decorators,
|
|
647
|
+
properties,
|
|
648
|
+
bodyRange,
|
|
649
|
+
modifiers,
|
|
650
|
+
modifierFlags: modifiersToFlags(modifiers),
|
|
651
|
+
...finishNode(pos),
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function parseModelDeclarationExpression(pos, decorators = []) {
|
|
655
|
+
parseExpected(Token.ModelKeyword);
|
|
656
|
+
const id = parseOptionalDeclarationExpressionIdentifier();
|
|
657
|
+
const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
|
|
658
|
+
const { extends: optionalExtends, is: optionalIs, properties, bodyRange, } = parseModelBody(true);
|
|
659
|
+
return {
|
|
660
|
+
kind: SyntaxKind.ModelDeclarationExpression,
|
|
661
|
+
id,
|
|
662
|
+
extends: optionalExtends,
|
|
663
|
+
is: optionalIs,
|
|
664
|
+
templateParameters,
|
|
665
|
+
templateParametersRange,
|
|
666
|
+
decorators,
|
|
667
|
+
properties,
|
|
668
|
+
bodyRange,
|
|
669
|
+
modifiers: [],
|
|
670
|
+
modifierFlags: ModifierFlags.None,
|
|
671
|
+
...finishNode(pos),
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function parseModelBody(inExpressionPosition = false) {
|
|
614
675
|
expectTokenIsOneOf(Token.OpenBrace, Token.Equals, Token.ExtendsKeyword, Token.IsKeyword);
|
|
615
676
|
const optionalExtends = parseOptionalModelExtends();
|
|
616
677
|
const optionalIs = optionalExtends ? undefined : parseOptionalModelIs();
|
|
617
678
|
let propDetail = createEmptyList();
|
|
618
679
|
if (optionalIs) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
680
|
+
if (inExpressionPosition) {
|
|
681
|
+
// In expression position there is no `;` terminator (it belongs to the enclosing
|
|
682
|
+
// construct): only parse a `{ ... }` body when present, otherwise the model has no
|
|
683
|
+
// own properties.
|
|
684
|
+
if (token() === Token.OpenBrace) {
|
|
685
|
+
propDetail = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
|
|
686
|
+
}
|
|
622
687
|
}
|
|
623
688
|
else {
|
|
624
|
-
|
|
689
|
+
const tok = expectTokenIsOneOf(Token.Semicolon, Token.OpenBrace);
|
|
690
|
+
if (tok === Token.Semicolon) {
|
|
691
|
+
nextToken();
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
propDetail = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
|
|
695
|
+
}
|
|
625
696
|
}
|
|
626
697
|
}
|
|
627
698
|
else {
|
|
628
699
|
propDetail = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
|
|
629
700
|
}
|
|
630
701
|
return {
|
|
631
|
-
kind: SyntaxKind.ModelStatement,
|
|
632
|
-
id,
|
|
633
702
|
extends: optionalExtends,
|
|
634
703
|
is: optionalIs,
|
|
635
|
-
templateParameters,
|
|
636
|
-
templateParametersRange,
|
|
637
|
-
decorators,
|
|
638
704
|
properties: propDetail.items,
|
|
639
705
|
bodyRange: propDetail.range,
|
|
640
|
-
modifiers,
|
|
641
|
-
modifierFlags: modifiersToFlags(modifiers),
|
|
642
|
-
...finishNode(pos),
|
|
643
706
|
};
|
|
644
707
|
}
|
|
645
708
|
function parseOptionalModelExtends() {
|
|
@@ -789,13 +852,38 @@ function createParser(code, options = {}) {
|
|
|
789
852
|
...finishNode(pos),
|
|
790
853
|
};
|
|
791
854
|
}
|
|
855
|
+
function parseScalarDeclarationExpression(pos, decorators = []) {
|
|
856
|
+
parseExpected(Token.ScalarKeyword);
|
|
857
|
+
const id = parseOptionalDeclarationExpressionIdentifier();
|
|
858
|
+
const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
|
|
859
|
+
const optionalExtends = parseOptionalScalarExtends();
|
|
860
|
+
const { items: members, range: bodyRange } = parseScalarMembers(true);
|
|
861
|
+
return {
|
|
862
|
+
kind: SyntaxKind.ScalarDeclarationExpression,
|
|
863
|
+
id,
|
|
864
|
+
templateParameters,
|
|
865
|
+
templateParametersRange,
|
|
866
|
+
extends: optionalExtends,
|
|
867
|
+
members,
|
|
868
|
+
bodyRange,
|
|
869
|
+
decorators,
|
|
870
|
+
modifiers: [],
|
|
871
|
+
modifierFlags: ModifierFlags.None,
|
|
872
|
+
...finishNode(pos),
|
|
873
|
+
};
|
|
874
|
+
}
|
|
792
875
|
function parseOptionalScalarExtends() {
|
|
793
876
|
if (parseOptional(Token.ExtendsKeyword)) {
|
|
794
877
|
return parseReferenceExpression();
|
|
795
878
|
}
|
|
796
879
|
return undefined;
|
|
797
880
|
}
|
|
798
|
-
function parseScalarMembers() {
|
|
881
|
+
function parseScalarMembers(inExpressionPosition = false) {
|
|
882
|
+
// In expression position there is no `;` terminator: only parse a `{ ... }` body
|
|
883
|
+
// when present, otherwise the scalar has no members.
|
|
884
|
+
if (inExpressionPosition && token() !== Token.OpenBrace) {
|
|
885
|
+
return createEmptyList();
|
|
886
|
+
}
|
|
799
887
|
if (token() === Token.Semicolon) {
|
|
800
888
|
nextToken();
|
|
801
889
|
return createEmptyList();
|
|
@@ -830,6 +918,20 @@ function createParser(code, options = {}) {
|
|
|
830
918
|
...finishNode(pos),
|
|
831
919
|
};
|
|
832
920
|
}
|
|
921
|
+
function parseEnumDeclarationExpression(pos, decorators = []) {
|
|
922
|
+
parseExpected(Token.EnumKeyword);
|
|
923
|
+
const id = parseOptionalDeclarationExpressionIdentifier();
|
|
924
|
+
const { items: members } = parseList(ListKind.EnumMembers, parseEnumMemberOrSpread);
|
|
925
|
+
return {
|
|
926
|
+
kind: SyntaxKind.EnumDeclarationExpression,
|
|
927
|
+
id,
|
|
928
|
+
decorators,
|
|
929
|
+
modifiers: [],
|
|
930
|
+
modifierFlags: ModifierFlags.None,
|
|
931
|
+
members,
|
|
932
|
+
...finishNode(pos),
|
|
933
|
+
};
|
|
934
|
+
}
|
|
833
935
|
function parseEnumMemberOrSpread(pos, decorators) {
|
|
834
936
|
return token() === Token.Ellipsis
|
|
835
937
|
? parseEnumSpreadMember(pos, decorators)
|
|
@@ -1277,6 +1379,35 @@ function createParser(code, options = {}) {
|
|
|
1277
1379
|
}
|
|
1278
1380
|
return base;
|
|
1279
1381
|
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Parse a declaration used in expression position (`model`/`enum`/`union`/`scalar`).
|
|
1384
|
+
* {@link pos} should point at the start of the node (the first decorator's `@` when
|
|
1385
|
+
* {@link decorators} are provided, otherwise the keyword). A leading doc comment
|
|
1386
|
+
* ({@link docs}) is attached to the node so it is applied just like an `@doc` decorator.
|
|
1387
|
+
*/
|
|
1388
|
+
function parseDeclarationExpression(pos, decorators = [], docs = []) {
|
|
1389
|
+
let node;
|
|
1390
|
+
switch (token()) {
|
|
1391
|
+
case Token.ModelKeyword:
|
|
1392
|
+
node = parseModelDeclarationExpression(pos, decorators);
|
|
1393
|
+
break;
|
|
1394
|
+
case Token.EnumKeyword:
|
|
1395
|
+
node = parseEnumDeclarationExpression(pos, decorators);
|
|
1396
|
+
break;
|
|
1397
|
+
case Token.UnionKeyword:
|
|
1398
|
+
node = parseUnionDeclarationExpression(pos, decorators);
|
|
1399
|
+
break;
|
|
1400
|
+
case Token.ScalarKeyword:
|
|
1401
|
+
node = parseScalarDeclarationExpression(pos, decorators);
|
|
1402
|
+
break;
|
|
1403
|
+
default:
|
|
1404
|
+
compilerAssert(false, "Expected a declaration expression keyword.");
|
|
1405
|
+
}
|
|
1406
|
+
if (docs.length > 0) {
|
|
1407
|
+
mutate(node).docs = docs;
|
|
1408
|
+
}
|
|
1409
|
+
return node;
|
|
1410
|
+
}
|
|
1280
1411
|
function parsePrimaryExpression() {
|
|
1281
1412
|
while (true) {
|
|
1282
1413
|
switch (token()) {
|
|
@@ -1297,14 +1428,36 @@ function createParser(code, options = {}) {
|
|
|
1297
1428
|
return parseNumericLiteral();
|
|
1298
1429
|
case Token.OpenBrace:
|
|
1299
1430
|
return parseModelExpression();
|
|
1431
|
+
case Token.ModelKeyword:
|
|
1432
|
+
case Token.EnumKeyword:
|
|
1433
|
+
case Token.UnionKeyword:
|
|
1434
|
+
case Token.ScalarKeyword: {
|
|
1435
|
+
// A leading doc comment applies to the declaration expression, just like `@doc`.
|
|
1436
|
+
// `pos` starts at the doc comment so the resulting node span includes it.
|
|
1437
|
+
const [pos, docs] = parseDocList();
|
|
1438
|
+
return parseDeclarationExpression(pos, [], docs);
|
|
1439
|
+
}
|
|
1300
1440
|
case Token.OpenBracket:
|
|
1301
1441
|
return parseTupleExpression();
|
|
1302
1442
|
case Token.OpenParen:
|
|
1303
1443
|
return parseParenthesizedExpression();
|
|
1304
|
-
case Token.At:
|
|
1444
|
+
case Token.At: {
|
|
1445
|
+
// Capture a doc comment that precedes the decorators before they are parsed
|
|
1446
|
+
// (parsing decorators advances the scanner and clears the pending doc range).
|
|
1447
|
+
const [docPos, docs] = parseDocList();
|
|
1448
|
+
// `pos` starts at the doc comment (if any) or the `@` so the resulting node
|
|
1449
|
+
// span includes the docs and decorators.
|
|
1450
|
+
const pos = docs.length > 0 ? docPos : tokenPos();
|
|
1305
1451
|
const decorators = parseDecoratorList();
|
|
1452
|
+
// Decorators are only valid in expression position when they decorate a
|
|
1453
|
+
// declaration expression (the keyword forms below). `pos` starts at the `@`
|
|
1454
|
+
// so the resulting node span includes the decorators.
|
|
1455
|
+
if (isDeclarationExpressionStatementKeyword(token())) {
|
|
1456
|
+
return parseDeclarationExpression(pos, decorators, docs);
|
|
1457
|
+
}
|
|
1306
1458
|
reportInvalidDecorators(decorators, "expression");
|
|
1307
1459
|
continue;
|
|
1460
|
+
}
|
|
1308
1461
|
case Token.Hash:
|
|
1309
1462
|
const directives = parseDirectiveList();
|
|
1310
1463
|
reportInvalidDirective(directives, "expression");
|
|
@@ -1533,6 +1686,13 @@ function createParser(code, options = {}) {
|
|
|
1533
1686
|
...finishNode(pos),
|
|
1534
1687
|
};
|
|
1535
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Parse the optional identifier of a declaration used in expression position. The name
|
|
1691
|
+
* is only parsed when actually present; an anonymous declaration expression has no `id`.
|
|
1692
|
+
*/
|
|
1693
|
+
function parseOptionalDeclarationExpressionIdentifier() {
|
|
1694
|
+
return token() === Token.Identifier ? parseIdentifier() : undefined;
|
|
1695
|
+
}
|
|
1536
1696
|
function parseIdentifier(options) {
|
|
1537
1697
|
if (isKeyword(token())) {
|
|
1538
1698
|
if (!(isModifier(token()) && options?.allowReservedIdentifier)) {
|
|
@@ -1721,15 +1881,26 @@ function createParser(code, options = {}) {
|
|
|
1721
1881
|
if (docRanges.length === 0 || options.docs === false) {
|
|
1722
1882
|
return [tokenPos(), []];
|
|
1723
1883
|
}
|
|
1884
|
+
return [docRanges[0].pos, parseDocRanges(docRanges)];
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Parse the given doc comment ranges into doc nodes. Unlike {@link parseDocList} this does
|
|
1888
|
+
* not read the pending {@link docRanges}, so it can be used to attach doc comments that were
|
|
1889
|
+
* captured earlier (e.g. before a list element's decorators were parsed).
|
|
1890
|
+
*/
|
|
1891
|
+
function parseDocRanges(ranges) {
|
|
1892
|
+
if (ranges.length === 0 || options.docs === false) {
|
|
1893
|
+
return [];
|
|
1894
|
+
}
|
|
1724
1895
|
const docs = [];
|
|
1725
|
-
for (const range of
|
|
1896
|
+
for (const range of ranges) {
|
|
1726
1897
|
const doc = parseRange(ParseMode.Doc, innerDocRange(range), () => parseDoc(range));
|
|
1727
1898
|
docs.push(doc);
|
|
1728
1899
|
if (range.comment) {
|
|
1729
1900
|
mutate(range.comment).parsedAsDocs = true;
|
|
1730
1901
|
}
|
|
1731
1902
|
}
|
|
1732
|
-
return
|
|
1903
|
+
return docs;
|
|
1733
1904
|
}
|
|
1734
1905
|
function parseDoc(range) {
|
|
1735
1906
|
const content = [];
|
|
@@ -2065,14 +2236,28 @@ function createParser(code, options = {}) {
|
|
|
2065
2236
|
}
|
|
2066
2237
|
while (true) {
|
|
2067
2238
|
const startingPos = tokenPos();
|
|
2239
|
+
// Capture any pending doc comment before `parseAnnotations` parses (and clears the
|
|
2240
|
+
// pending range for) decorators, so a doc comment preceding a decorated declaration
|
|
2241
|
+
// expression element can still be attached to it below.
|
|
2242
|
+
const pendingDocRanges = kind.allowDeclarationExpression ? docRanges : undefined;
|
|
2068
2243
|
const { pos, docs, directives, decorators } = parseAnnotations({
|
|
2069
2244
|
skipParsingDocNodes: Boolean(kind.invalidAnnotationTarget),
|
|
2070
2245
|
});
|
|
2246
|
+
// A declaration expression element (e.g. `enum { a }`) can carry decorators (and a
|
|
2247
|
+
// doc comment) even in an expression list. Attach them to the declaration expression
|
|
2248
|
+
// instead of rejecting them as an invalid annotation target.
|
|
2249
|
+
const declarationExpressionWithDecorators = kind.allowDeclarationExpression &&
|
|
2250
|
+
decorators.length > 0 &&
|
|
2251
|
+
isDeclarationExpressionStatementKeyword(token());
|
|
2071
2252
|
if (kind.invalidAnnotationTarget) {
|
|
2072
|
-
reportInvalidDecorators(decorators, kind.invalidAnnotationTarget);
|
|
2073
2253
|
reportInvalidDirective(directives, kind.invalidAnnotationTarget);
|
|
2254
|
+
if (!declarationExpressionWithDecorators) {
|
|
2255
|
+
reportInvalidDecorators(decorators, kind.invalidAnnotationTarget);
|
|
2256
|
+
}
|
|
2074
2257
|
}
|
|
2075
|
-
if (directives.length === 0 &&
|
|
2258
|
+
if (directives.length === 0 &&
|
|
2259
|
+
decorators.length === 0 &&
|
|
2260
|
+
atEndOfListWithError(kind, { atElementStart: true })) {
|
|
2076
2261
|
// Error recovery: end surrounded list at statement keyword or end
|
|
2077
2262
|
// of file. Note, however, that we must parse a missing element if
|
|
2078
2263
|
// there were directives or decorators as we cannot drop those from
|
|
@@ -2083,7 +2268,14 @@ function createParser(code, options = {}) {
|
|
|
2083
2268
|
break;
|
|
2084
2269
|
}
|
|
2085
2270
|
let item;
|
|
2086
|
-
if (
|
|
2271
|
+
if (declarationExpressionWithDecorators) {
|
|
2272
|
+
const declDocs = pendingDocRanges ? parseDocRanges(pendingDocRanges) : [];
|
|
2273
|
+
// When a doc comment precedes the decorators, start the node span at the doc
|
|
2274
|
+
// comment so the doc nodes stay within the parent node's range.
|
|
2275
|
+
const declPos = declDocs.length > 0 ? pendingDocRanges[0].pos : pos;
|
|
2276
|
+
item = parseDeclarationExpression(declPos, decorators, declDocs);
|
|
2277
|
+
}
|
|
2278
|
+
else if (kind.invalidAnnotationTarget) {
|
|
2087
2279
|
item = parseItem();
|
|
2088
2280
|
}
|
|
2089
2281
|
else {
|
|
@@ -2114,7 +2306,7 @@ function createParser(code, options = {}) {
|
|
|
2114
2306
|
// reach the close token.
|
|
2115
2307
|
break;
|
|
2116
2308
|
}
|
|
2117
|
-
else if (atEndOfListWithError(kind)) {
|
|
2309
|
+
else if (atEndOfListWithError(kind, { atElementStart: false })) {
|
|
2118
2310
|
// Error recovery: If a list *is* surrounded by punctuation, then
|
|
2119
2311
|
// the list ends at statement keyword or end-of-file under the
|
|
2120
2312
|
// assumption that the closing delimiter is missing. This check is
|
|
@@ -2172,10 +2364,28 @@ function createParser(code, options = {}) {
|
|
|
2172
2364
|
}
|
|
2173
2365
|
return false;
|
|
2174
2366
|
}
|
|
2175
|
-
|
|
2367
|
+
/**
|
|
2368
|
+
* Whether the parser is at a position where the current list (when surrounded by
|
|
2369
|
+
* punctuation) should be ended under the assumption that its closing token is missing —
|
|
2370
|
+
* i.e. the current token is a statement keyword or end-of-file.
|
|
2371
|
+
*
|
|
2372
|
+
* @param atElementStart Whether we are about to parse a new element (`true`) or have just
|
|
2373
|
+
* parsed one and found neither a delimiter nor the close token (`false`). A
|
|
2374
|
+
* declaration-expression keyword (`model`/`enum`/`union`/`scalar`) is a valid element
|
|
2375
|
+
* start in lists that {@link ListKind.allowDeclarationExpression allow declaration
|
|
2376
|
+
* expressions}, so it must not end the list at the start of an element. After an element,
|
|
2377
|
+
* a declaration-expression keyword cannot start a new element (a delimiter is required
|
|
2378
|
+
* first), so it is treated like any other statement keyword and ends the list — restoring
|
|
2379
|
+
* error recovery for an unclosed delimiter (e.g. `@foo(model X {}` followed by a
|
|
2380
|
+
* statement).
|
|
2381
|
+
*/
|
|
2382
|
+
function atEndOfListWithError(kind, { atElementStart }) {
|
|
2176
2383
|
return (kind.close !== Token.None &&
|
|
2177
2384
|
(isStatementKeyword(token()) || token() === Token.EndOfFile) &&
|
|
2178
|
-
token() !== kind.allowedStatementKeyword
|
|
2385
|
+
token() !== kind.allowedStatementKeyword &&
|
|
2386
|
+
!(atElementStart &&
|
|
2387
|
+
kind.allowDeclarationExpression &&
|
|
2388
|
+
isDeclarationExpressionStatementKeyword(token())));
|
|
2179
2389
|
}
|
|
2180
2390
|
function parseEmptyStatement(pos) {
|
|
2181
2391
|
parseExpected(Token.Semicolon);
|
|
@@ -2402,6 +2612,13 @@ export function visitChildren(node, cb) {
|
|
|
2402
2612
|
visitNode(cb, node.extends) ||
|
|
2403
2613
|
visitNode(cb, node.is) ||
|
|
2404
2614
|
visitEach(cb, node.properties));
|
|
2615
|
+
case SyntaxKind.ModelDeclarationExpression:
|
|
2616
|
+
return (visitEach(cb, node.decorators) ||
|
|
2617
|
+
visitNode(cb, node.id) ||
|
|
2618
|
+
visitEach(cb, node.templateParameters) ||
|
|
2619
|
+
visitNode(cb, node.extends) ||
|
|
2620
|
+
visitNode(cb, node.is) ||
|
|
2621
|
+
visitEach(cb, node.properties));
|
|
2405
2622
|
case SyntaxKind.ScalarStatement:
|
|
2406
2623
|
return (visitEach(cb, node.modifiers) ||
|
|
2407
2624
|
visitEach(cb, node.decorators) ||
|
|
@@ -2409,6 +2626,12 @@ export function visitChildren(node, cb) {
|
|
|
2409
2626
|
visitEach(cb, node.templateParameters) ||
|
|
2410
2627
|
visitEach(cb, node.members) ||
|
|
2411
2628
|
visitNode(cb, node.extends));
|
|
2629
|
+
case SyntaxKind.ScalarDeclarationExpression:
|
|
2630
|
+
return (visitEach(cb, node.decorators) ||
|
|
2631
|
+
visitNode(cb, node.id) ||
|
|
2632
|
+
visitEach(cb, node.templateParameters) ||
|
|
2633
|
+
visitEach(cb, node.members) ||
|
|
2634
|
+
visitNode(cb, node.extends));
|
|
2412
2635
|
case SyntaxKind.ScalarConstructor:
|
|
2413
2636
|
return visitNode(cb, node.id) || visitEach(cb, node.parameters);
|
|
2414
2637
|
case SyntaxKind.UnionStatement:
|
|
@@ -2418,6 +2641,12 @@ export function visitChildren(node, cb) {
|
|
|
2418
2641
|
visitEach(cb, node.templateParameters) ||
|
|
2419
2642
|
visitNode(cb, node.extends) ||
|
|
2420
2643
|
visitEach(cb, node.options));
|
|
2644
|
+
case SyntaxKind.UnionDeclarationExpression:
|
|
2645
|
+
return (visitEach(cb, node.decorators) ||
|
|
2646
|
+
visitNode(cb, node.id) ||
|
|
2647
|
+
visitEach(cb, node.templateParameters) ||
|
|
2648
|
+
visitNode(cb, node.extends) ||
|
|
2649
|
+
visitEach(cb, node.options));
|
|
2421
2650
|
case SyntaxKind.UnionVariant:
|
|
2422
2651
|
return visitEach(cb, node.decorators) || visitNode(cb, node.id) || visitNode(cb, node.value);
|
|
2423
2652
|
case SyntaxKind.EnumStatement:
|
|
@@ -2425,6 +2654,8 @@ export function visitChildren(node, cb) {
|
|
|
2425
2654
|
visitEach(cb, node.decorators) ||
|
|
2426
2655
|
visitNode(cb, node.id) ||
|
|
2427
2656
|
visitEach(cb, node.members));
|
|
2657
|
+
case SyntaxKind.EnumDeclarationExpression:
|
|
2658
|
+
return (visitEach(cb, node.decorators) || visitNode(cb, node.id) || visitEach(cb, node.members));
|
|
2428
2659
|
case SyntaxKind.EnumMember:
|
|
2429
2660
|
return visitEach(cb, node.decorators) || visitNode(cb, node.id) || visitNode(cb, node.value);
|
|
2430
2661
|
case SyntaxKind.EnumSpreadMember:
|
|
@@ -2698,6 +2929,9 @@ export function getIdentifierContext(id) {
|
|
|
2698
2929
|
case SyntaxKind.ModelStatement:
|
|
2699
2930
|
kind = IdentifierKind.ModelStatementProperty;
|
|
2700
2931
|
break;
|
|
2932
|
+
case SyntaxKind.ModelDeclarationExpression:
|
|
2933
|
+
kind = IdentifierKind.ModelStatementProperty;
|
|
2934
|
+
break;
|
|
2701
2935
|
default:
|
|
2702
2936
|
compilerAssert("false", "ModelProperty with unexpected parent kind.");
|
|
2703
2937
|
kind =
|