@typespec/compiler 0.57.0-dev.8 → 0.58.0-dev.0

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.
Files changed (95) hide show
  1. package/dist/generated-defs/TypeSpec.d.ts +30 -24
  2. package/dist/generated-defs/TypeSpec.d.ts.map +1 -1
  3. package/dist/generated-defs/TypeSpec.ts-test.js +2 -1
  4. package/dist/generated-defs/TypeSpec.ts-test.js.map +1 -1
  5. package/dist/manifest.js +2 -2
  6. package/dist/src/config/config-schema.d.ts +1 -1
  7. package/dist/src/config/config-schema.d.ts.map +1 -1
  8. package/dist/src/core/charcode.d.ts +4 -1
  9. package/dist/src/core/charcode.d.ts.map +1 -1
  10. package/dist/src/core/charcode.js +4 -4
  11. package/dist/src/core/charcode.js.map +1 -1
  12. package/dist/src/core/checker.d.ts.map +1 -1
  13. package/dist/src/core/checker.js +284 -18
  14. package/dist/src/core/checker.js.map +1 -1
  15. package/dist/src/core/cli/utils.d.ts.map +1 -1
  16. package/dist/src/core/cli/utils.js +1 -0
  17. package/dist/src/core/cli/utils.js.map +1 -1
  18. package/dist/src/core/index.d.ts +1 -0
  19. package/dist/src/core/index.d.ts.map +1 -1
  20. package/dist/src/core/index.js +1 -0
  21. package/dist/src/core/index.js.map +1 -1
  22. package/dist/src/core/linter.d.ts +5 -1
  23. package/dist/src/core/linter.d.ts.map +1 -1
  24. package/dist/src/core/linter.js +32 -13
  25. package/dist/src/core/linter.js.map +1 -1
  26. package/dist/src/core/messages.d.ts +5 -0
  27. package/dist/src/core/messages.d.ts.map +1 -1
  28. package/dist/src/core/messages.js +1 -0
  29. package/dist/src/core/messages.js.map +1 -1
  30. package/dist/src/core/parser.d.ts +11 -2
  31. package/dist/src/core/parser.d.ts.map +1 -1
  32. package/dist/src/core/parser.js +216 -60
  33. package/dist/src/core/parser.js.map +1 -1
  34. package/dist/src/core/program.d.ts.map +1 -1
  35. package/dist/src/core/program.js +4 -2
  36. package/dist/src/core/program.js.map +1 -1
  37. package/dist/src/core/scanner.d.ts +17 -1
  38. package/dist/src/core/scanner.d.ts.map +1 -1
  39. package/dist/src/core/scanner.js +97 -1
  40. package/dist/src/core/scanner.js.map +1 -1
  41. package/dist/src/core/schema-validator.js +1 -1
  42. package/dist/src/core/schema-validator.js.map +1 -1
  43. package/dist/src/core/types.d.ts +103 -50
  44. package/dist/src/core/types.d.ts.map +1 -1
  45. package/dist/src/core/types.js +50 -46
  46. package/dist/src/core/types.js.map +1 -1
  47. package/dist/src/emitter-framework/asset-emitter.js +2 -2
  48. package/dist/src/emitter-framework/asset-emitter.js.map +1 -1
  49. package/dist/src/emitter-framework/type-emitter.d.ts +1 -1
  50. package/dist/src/emitter-framework/type-emitter.js +1 -1
  51. package/dist/src/formatter/print/printer.d.ts +1 -1
  52. package/dist/src/formatter/print/printer.d.ts.map +1 -1
  53. package/dist/src/formatter/print/printer.js +91 -12
  54. package/dist/src/formatter/print/printer.js.map +1 -1
  55. package/dist/src/init/init-template.d.ts +1 -1
  56. package/dist/src/init/init-template.d.ts.map +1 -1
  57. package/dist/src/lib/decorators.d.ts +2 -1
  58. package/dist/src/lib/decorators.d.ts.map +1 -1
  59. package/dist/src/lib/decorators.js +17 -0
  60. package/dist/src/lib/decorators.js.map +1 -1
  61. package/dist/src/server/classify.d.ts.map +1 -1
  62. package/dist/src/server/classify.js +4 -0
  63. package/dist/src/server/classify.js.map +1 -1
  64. package/dist/src/server/compile-service.d.ts +2 -2
  65. package/dist/src/server/compile-service.d.ts.map +1 -1
  66. package/dist/src/server/compile-service.js +26 -1
  67. package/dist/src/server/compile-service.js.map +1 -1
  68. package/dist/src/server/completion.d.ts +2 -2
  69. package/dist/src/server/completion.d.ts.map +1 -1
  70. package/dist/src/server/completion.js +136 -9
  71. package/dist/src/server/completion.js.map +1 -1
  72. package/dist/src/server/file-system-cache.d.ts +3 -1
  73. package/dist/src/server/file-system-cache.d.ts.map +1 -1
  74. package/dist/src/server/file-system-cache.js +13 -2
  75. package/dist/src/server/file-system-cache.js.map +1 -1
  76. package/dist/src/server/server.js +35 -8
  77. package/dist/src/server/server.js.map +1 -1
  78. package/dist/src/server/serverlib.d.ts.map +1 -1
  79. package/dist/src/server/serverlib.js +13 -31
  80. package/dist/src/server/serverlib.js.map +1 -1
  81. package/dist/src/server/tmlanguage.d.ts.map +1 -1
  82. package/dist/src/server/tmlanguage.js +1 -1
  83. package/dist/src/server/tmlanguage.js.map +1 -1
  84. package/dist/src/server/type-details.js +14 -6
  85. package/dist/src/server/type-details.js.map +1 -1
  86. package/dist/src/server/types.d.ts +9 -3
  87. package/dist/src/server/types.d.ts.map +1 -1
  88. package/dist/src/server/types.js.map +1 -1
  89. package/dist/src/testing/test-server-host.js +2 -2
  90. package/dist/src/testing/test-server-host.js.map +1 -1
  91. package/dist/typespec.tmLanguage +1 -1
  92. package/lib/std/decorators.tsp +6 -0
  93. package/lib/std/types.tsp +12 -0
  94. package/package.json +11 -11
  95. package/templates/scaffolding.json +4 -4
@@ -1,8 +1,8 @@
1
1
  import { isArray, mutate } from "../utils/misc.js";
2
- import { trim } from "./charcode.js";
2
+ import { codePointBefore, isIdentifierContinue, trim } from "./charcode.js";
3
3
  import { compilerAssert } from "./diagnostics.js";
4
4
  import { createDiagnostic } from "./messages.js";
5
- import { Token, TokenDisplay, TokenFlags, createScanner, isComment, isKeyword, isPunctuation, isStatementKeyword, isTrivia, } from "./scanner.js";
5
+ import { Token, TokenDisplay, TokenFlags, createScanner, isComment, isKeyword, isPunctuation, isStatementKeyword, isTrivia, skipContinuousIdentifier, skipTrivia, skipTriviaBackward, } from "./scanner.js";
6
6
  import { IdentifierKind, SyntaxKind, } from "./types.js";
7
7
  /**
8
8
  * The fixed set of options for each of the kinds of delimited lists in TypeSpec.
@@ -450,8 +450,8 @@ function createParser(code, options = {}) {
450
450
  function parseInterfaceStatement(pos, decorators) {
451
451
  parseExpected(Token.InterfaceKeyword);
452
452
  const id = parseIdentifier();
453
- const templateParameters = parseTemplateParameterList();
454
- let extendList = [];
453
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
454
+ let extendList = createEmptyList();
455
455
  if (token() === Token.ExtendsKeyword) {
456
456
  nextToken();
457
457
  extendList = parseList(ListKind.Heritage, parseReferenceExpression);
@@ -460,21 +460,23 @@ function createParser(code, options = {}) {
460
460
  error({ code: "token-expected", format: { token: "'extends' or '{'" } });
461
461
  nextToken();
462
462
  }
463
- const operations = parseList(ListKind.InterfaceMembers, (pos, decorators) => parseOperationStatement(pos, decorators, true));
463
+ const { items: operations, range: bodyRange } = parseList(ListKind.InterfaceMembers, (pos, decorators) => parseOperationStatement(pos, decorators, true));
464
464
  return {
465
465
  kind: SyntaxKind.InterfaceStatement,
466
466
  id,
467
467
  templateParameters,
468
+ templateParametersRange,
468
469
  operations,
469
- extends: extendList,
470
+ bodyRange,
471
+ extends: extendList.items,
470
472
  decorators,
471
473
  ...finishNode(pos),
472
474
  };
473
475
  }
474
476
  function parseTemplateParameterList() {
475
- const list = parseOptionalList(ListKind.TemplateParameters, parseTemplateParameter);
477
+ const detail = parseOptionalList(ListKind.TemplateParameters, parseTemplateParameter);
476
478
  let setDefault = false;
477
- for (const item of list) {
479
+ for (const item of detail.items) {
478
480
  if (!item.default && setDefault) {
479
481
  error({ code: "default-required", target: item });
480
482
  continue;
@@ -483,17 +485,18 @@ function createParser(code, options = {}) {
483
485
  setDefault = true;
484
486
  }
485
487
  }
486
- return list;
488
+ return detail;
487
489
  }
488
490
  function parseUnionStatement(pos, decorators) {
489
491
  parseExpected(Token.UnionKeyword);
490
492
  const id = parseIdentifier();
491
- const templateParameters = parseTemplateParameterList();
492
- const options = parseList(ListKind.UnionVariants, parseUnionVariant);
493
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
494
+ const { items: options } = parseList(ListKind.UnionVariants, parseUnionVariant);
493
495
  return {
494
496
  kind: SyntaxKind.UnionStatement,
495
497
  id,
496
498
  templateParameters,
499
+ templateParametersRange,
497
500
  decorators,
498
501
  options,
499
502
  ...finishNode(pos),
@@ -559,7 +562,7 @@ function createParser(code, options = {}) {
559
562
  parseExpected(Token.OpKeyword);
560
563
  }
561
564
  const id = parseIdentifier();
562
- const templateParameters = parseTemplateParameterList();
565
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
563
566
  // Make sure the next token is one that is expected
564
567
  const token = expectTokenIsOneOf(Token.OpenParen, Token.IsKeyword);
565
568
  // Check if we're parsing a declaration or reuse of another operation
@@ -593,6 +596,7 @@ function createParser(code, options = {}) {
593
596
  kind: SyntaxKind.OperationStatement,
594
597
  id,
595
598
  templateParameters,
599
+ templateParametersRange,
596
600
  signature,
597
601
  decorators,
598
602
  ...finishNode(pos),
@@ -600,10 +604,11 @@ function createParser(code, options = {}) {
600
604
  }
601
605
  function parseOperationParameters() {
602
606
  const pos = tokenPos();
603
- const properties = parseList(ListKind.OperationParameters, parseModelPropertyOrSpread);
607
+ const { items: properties, range: bodyRange } = parseList(ListKind.OperationParameters, parseModelPropertyOrSpread);
604
608
  const parameters = {
605
609
  kind: SyntaxKind.ModelExpression,
606
610
  properties,
611
+ bodyRange,
607
612
  ...finishNode(pos),
608
613
  };
609
614
  return parameters;
@@ -611,22 +616,22 @@ function createParser(code, options = {}) {
611
616
  function parseModelStatement(pos, decorators) {
612
617
  parseExpected(Token.ModelKeyword);
613
618
  const id = parseIdentifier();
614
- const templateParameters = parseTemplateParameterList();
619
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
615
620
  expectTokenIsOneOf(Token.OpenBrace, Token.Equals, Token.ExtendsKeyword, Token.IsKeyword);
616
621
  const optionalExtends = parseOptionalModelExtends();
617
622
  const optionalIs = optionalExtends ? undefined : parseOptionalModelIs();
618
- let properties = [];
623
+ let propDetail = createEmptyList();
619
624
  if (optionalIs) {
620
625
  const tok = expectTokenIsOneOf(Token.Semicolon, Token.OpenBrace);
621
626
  if (tok === Token.Semicolon) {
622
627
  nextToken();
623
628
  }
624
629
  else {
625
- properties = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
630
+ propDetail = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
626
631
  }
627
632
  }
628
633
  else {
629
- properties = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
634
+ propDetail = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
630
635
  }
631
636
  return {
632
637
  kind: SyntaxKind.ModelStatement,
@@ -634,8 +639,10 @@ function createParser(code, options = {}) {
634
639
  extends: optionalExtends,
635
640
  is: optionalIs,
636
641
  templateParameters,
642
+ templateParametersRange,
637
643
  decorators,
638
- properties,
644
+ properties: propDetail.items,
645
+ bodyRange: propDetail.range,
639
646
  ...finishNode(pos),
640
647
  };
641
648
  }
@@ -767,15 +774,17 @@ function createParser(code, options = {}) {
767
774
  function parseScalarStatement(pos, decorators) {
768
775
  parseExpected(Token.ScalarKeyword);
769
776
  const id = parseIdentifier();
770
- const templateParameters = parseTemplateParameterList();
777
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
771
778
  const optionalExtends = parseOptionalScalarExtends();
772
- const members = parseScalarMembers();
779
+ const { items: members, range: bodyRange } = parseScalarMembers();
773
780
  return {
774
781
  kind: SyntaxKind.ScalarStatement,
775
782
  id,
776
783
  templateParameters,
784
+ templateParametersRange,
777
785
  extends: optionalExtends,
778
786
  members,
787
+ bodyRange,
779
788
  decorators,
780
789
  ...finishNode(pos),
781
790
  };
@@ -789,7 +798,7 @@ function createParser(code, options = {}) {
789
798
  function parseScalarMembers() {
790
799
  if (token() === Token.Semicolon) {
791
800
  nextToken();
792
- return [];
801
+ return createEmptyList();
793
802
  }
794
803
  else {
795
804
  return parseList(ListKind.ScalarMembers, parseScalarMember);
@@ -799,7 +808,7 @@ function createParser(code, options = {}) {
799
808
  reportInvalidDecorators(decorators, "scalar member");
800
809
  parseExpected(Token.InitKeyword);
801
810
  const id = parseIdentifier();
802
- const parameters = parseFunctionParameters();
811
+ const { items: parameters } = parseFunctionParameters();
803
812
  return {
804
813
  kind: SyntaxKind.ScalarConstructor,
805
814
  id,
@@ -810,7 +819,7 @@ function createParser(code, options = {}) {
810
819
  function parseEnumStatement(pos, decorators) {
811
820
  parseExpected(Token.EnumKeyword);
812
821
  const id = parseIdentifier();
813
- const members = parseList(ListKind.EnumMembers, parseEnumMemberOrSpread);
822
+ const { items: members } = parseList(ListKind.EnumMembers, parseEnumMemberOrSpread);
814
823
  return {
815
824
  kind: SyntaxKind.EnumStatement,
816
825
  id,
@@ -864,7 +873,7 @@ function createParser(code, options = {}) {
864
873
  function parseAliasStatement(pos) {
865
874
  parseExpected(Token.AliasKeyword);
866
875
  const id = parseIdentifier();
867
- const templateParameters = parseTemplateParameterList();
876
+ const { items: templateParameters, range: templateParametersRange } = parseTemplateParameterList();
868
877
  parseExpected(Token.Equals);
869
878
  const value = parseExpression();
870
879
  parseExpected(Token.Semicolon);
@@ -872,6 +881,7 @@ function createParser(code, options = {}) {
872
881
  kind: SyntaxKind.AliasStatement,
873
882
  id,
874
883
  templateParameters,
884
+ templateParametersRange,
875
885
  value,
876
886
  ...finishNode(pos),
877
887
  };
@@ -1011,17 +1021,18 @@ function createParser(code, options = {}) {
1011
1021
  const pos = tokenPos();
1012
1022
  const target = parseIdentifierOrMemberExpression(message);
1013
1023
  if (token() === Token.OpenParen) {
1024
+ const { items: args } = parseList(ListKind.FunctionArguments, parseExpression);
1014
1025
  return {
1015
1026
  kind: SyntaxKind.CallExpression,
1016
1027
  target,
1017
- arguments: parseList(ListKind.FunctionArguments, parseExpression),
1028
+ arguments: args,
1018
1029
  ...finishNode(pos),
1019
1030
  };
1020
1031
  }
1021
1032
  return parseReferenceExpressionInternal(target, pos);
1022
1033
  }
1023
1034
  function parseReferenceExpressionInternal(target, pos) {
1024
- const args = parseOptionalList(ListKind.TemplateArguments, parseTemplateArgument);
1035
+ const { items: args } = parseOptionalList(ListKind.TemplateArguments, parseTemplateArgument);
1025
1036
  return {
1026
1037
  kind: SyntaxKind.TypeReference,
1027
1038
  target,
@@ -1072,29 +1083,31 @@ function createParser(code, options = {}) {
1072
1083
  // `@<missing identifier>` applied to `model Foo`, and not as `@model`
1073
1084
  // applied to invalid statement `Foo`.
1074
1085
  const target = parseIdentifierOrMemberExpression(undefined, false);
1075
- const args = parseOptionalList(ListKind.DecoratorArguments, parseExpression);
1086
+ const { items: args } = parseOptionalList(ListKind.DecoratorArguments, parseExpression);
1076
1087
  if (args.length === 0) {
1077
1088
  error({ code: "augment-decorator-target" });
1089
+ const emptyList = createEmptyList();
1078
1090
  return {
1079
1091
  kind: SyntaxKind.AugmentDecoratorStatement,
1080
1092
  target,
1081
1093
  targetType: {
1082
1094
  kind: SyntaxKind.TypeReference,
1083
1095
  target: createMissingIdentifier(),
1084
- arguments: [],
1096
+ arguments: emptyList.items,
1085
1097
  ...finishNode(pos),
1086
1098
  },
1087
- arguments: [],
1099
+ arguments: args,
1088
1100
  ...finishNode(pos),
1089
1101
  };
1090
1102
  }
1091
1103
  let [targetEntity, ...decoratorArgs] = args;
1092
1104
  if (targetEntity.kind !== SyntaxKind.TypeReference) {
1093
1105
  error({ code: "augment-decorator-target", target: targetEntity });
1106
+ const emptyList = createEmptyList();
1094
1107
  targetEntity = {
1095
1108
  kind: SyntaxKind.TypeReference,
1096
1109
  target: createMissingIdentifier(),
1097
- arguments: [],
1110
+ arguments: emptyList.items,
1098
1111
  ...finishNode(pos),
1099
1112
  };
1100
1113
  }
@@ -1126,7 +1139,7 @@ function createParser(code, options = {}) {
1126
1139
  // `@<missing identifier>` applied to `model Foo`, and not as `@model`
1127
1140
  // applied to invalid statement `Foo`.
1128
1141
  const target = parseIdentifierOrMemberExpression(undefined, false);
1129
- const args = parseOptionalList(ListKind.DecoratorArguments, parseExpression);
1142
+ const { items: args } = parseOptionalList(ListKind.DecoratorArguments, parseExpression);
1130
1143
  return {
1131
1144
  kind: SyntaxKind.DecoratorExpression,
1132
1145
  arguments: args,
@@ -1310,7 +1323,7 @@ function createParser(code, options = {}) {
1310
1323
  }
1311
1324
  function parseTupleExpression() {
1312
1325
  const pos = tokenPos();
1313
- const values = parseList(ListKind.Tuple, parseExpression);
1326
+ const { items: values } = parseList(ListKind.Tuple, parseExpression);
1314
1327
  return {
1315
1328
  kind: SyntaxKind.TupleExpression,
1316
1329
  values,
@@ -1319,25 +1332,27 @@ function createParser(code, options = {}) {
1319
1332
  }
1320
1333
  function parseModelExpression() {
1321
1334
  const pos = tokenPos();
1322
- const properties = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
1335
+ const { items: properties, range: bodyRange } = parseList(ListKind.ModelProperties, parseModelPropertyOrSpread);
1323
1336
  return {
1324
1337
  kind: SyntaxKind.ModelExpression,
1325
1338
  properties,
1339
+ bodyRange,
1326
1340
  ...finishNode(pos),
1327
1341
  };
1328
1342
  }
1329
1343
  function parseObjectLiteral() {
1330
1344
  const pos = tokenPos();
1331
- const properties = parseList(ListKind.ObjectLiteralProperties, parseObjectLiteralPropertyOrSpread);
1345
+ const { items: properties, range: bodyRange } = parseList(ListKind.ObjectLiteralProperties, parseObjectLiteralPropertyOrSpread);
1332
1346
  return {
1333
1347
  kind: SyntaxKind.ObjectLiteral,
1334
1348
  properties,
1349
+ bodyRange,
1335
1350
  ...finishNode(pos),
1336
1351
  };
1337
1352
  }
1338
1353
  function parseArrayLiteral() {
1339
1354
  const pos = tokenPos();
1340
- const values = parseList(ListKind.ArrayLiteral, parseExpression);
1355
+ const { items: values } = parseList(ListKind.ArrayLiteral, parseExpression);
1341
1356
  return {
1342
1357
  kind: SyntaxKind.ArrayLiteral,
1343
1358
  values,
@@ -1510,7 +1525,8 @@ function createParser(code, options = {}) {
1510
1525
  const modifierFlags = modifiersToFlags(modifiers);
1511
1526
  parseExpected(Token.DecKeyword);
1512
1527
  const id = parseIdentifier();
1513
- let [target, ...parameters] = parseFunctionParameters();
1528
+ const allParamListDetail = parseFunctionParameters();
1529
+ let [target, ...parameters] = allParamListDetail.items;
1514
1530
  if (target === undefined) {
1515
1531
  error({ code: "decorator-decl-target", target: { pos, end: previousTokenEnd } });
1516
1532
  target = {
@@ -1540,7 +1556,7 @@ function createParser(code, options = {}) {
1540
1556
  const modifierFlags = modifiersToFlags(modifiers);
1541
1557
  parseExpected(Token.FnKeyword);
1542
1558
  const id = parseIdentifier();
1543
- const parameters = parseFunctionParameters();
1559
+ const { items: parameters } = parseFunctionParameters();
1544
1560
  let returnType;
1545
1561
  if (parseOptional(Token.Colon)) {
1546
1562
  returnType = parseExpression();
@@ -1559,7 +1575,7 @@ function createParser(code, options = {}) {
1559
1575
  function parseFunctionParameters() {
1560
1576
  const parameters = parseList(ListKind.FunctionParameters, parseFunctionParameter);
1561
1577
  let foundOptional = false;
1562
- for (const [index, item] of parameters.entries()) {
1578
+ for (const [index, item] of parameters.items.entries()) {
1563
1579
  if (!item.optional && foundOptional) {
1564
1580
  error({ code: "required-parameter-first", target: item });
1565
1581
  continue;
@@ -1570,7 +1586,7 @@ function createParser(code, options = {}) {
1570
1586
  if (item.rest && item.optional) {
1571
1587
  error({ code: "rest-parameter-required", target: item });
1572
1588
  }
1573
- if (item.rest && index !== parameters.length - 1) {
1589
+ if (item.rest && index !== parameters.items.length - 1) {
1574
1590
  error({ code: "rest-parameter-last", target: item });
1575
1591
  }
1576
1592
  }
@@ -1662,7 +1678,7 @@ function createParser(code, options = {}) {
1662
1678
  }
1663
1679
  let parameters;
1664
1680
  if (token() === Token.OpenParen) {
1665
- parameters = parseList(ListKind.ProjectionParameter, parseProjectionParameter);
1681
+ parameters = parseList(ListKind.ProjectionParameter, parseProjectionParameter).items;
1666
1682
  }
1667
1683
  else {
1668
1684
  parameters = [];
@@ -1884,7 +1900,7 @@ function createParser(code, options = {}) {
1884
1900
  kind: SyntaxKind.ProjectionCallExpression,
1885
1901
  callKind: "method",
1886
1902
  target: expr,
1887
- arguments: parseList(ListKind.CallArguments, parseProjectionExpression),
1903
+ arguments: parseList(ListKind.CallArguments, parseProjectionExpression).items,
1888
1904
  ...finishNode(pos),
1889
1905
  };
1890
1906
  }
@@ -1967,7 +1983,7 @@ function createParser(code, options = {}) {
1967
1983
  }
1968
1984
  function parseProjectionLambdaOrParenthesizedExpression() {
1969
1985
  const pos = tokenPos();
1970
- const exprs = parseList(ListKind.ProjectionExpression, parseProjectionExpression);
1986
+ const exprs = parseList(ListKind.ProjectionExpression, parseProjectionExpression).items;
1971
1987
  if (token() === Token.EqualsGreaterThan) {
1972
1988
  // unpack the exprs (which should be just identifiers) into a param list
1973
1989
  const params = [];
@@ -2018,7 +2034,7 @@ function createParser(code, options = {}) {
2018
2034
  }
2019
2035
  function parseProjectionModelExpression() {
2020
2036
  const pos = tokenPos();
2021
- const properties = parseList(ListKind.ModelProperties, parseProjectionModelPropertyOrSpread);
2037
+ const { items: properties } = parseList(ListKind.ModelProperties, parseProjectionModelPropertyOrSpread);
2022
2038
  return {
2023
2039
  kind: SyntaxKind.ProjectionModelExpression,
2024
2040
  properties,
@@ -2092,7 +2108,7 @@ function createParser(code, options = {}) {
2092
2108
  }
2093
2109
  function parseProjectionTupleExpression() {
2094
2110
  const pos = tokenPos();
2095
- const values = parseList(ListKind.Tuple, parseProjectionExpression);
2111
+ const { items: values } = parseList(ListKind.Tuple, parseProjectionExpression);
2096
2112
  return {
2097
2113
  kind: SyntaxKind.ProjectionTupleExpression,
2098
2114
  values,
@@ -2242,11 +2258,31 @@ function createParser(code, options = {}) {
2242
2258
  start = tokenPos();
2243
2259
  while (parseOptional(Token.Whitespace))
2244
2260
  ;
2245
- if (parseOptional(Token.Star)) {
2261
+ if (!parseOptional(Token.Star)) {
2262
+ break;
2263
+ }
2264
+ if (!inCodeFence) {
2246
2265
  parseOptional(Token.Whitespace);
2247
2266
  start = tokenPos();
2248
2267
  break;
2249
2268
  }
2269
+ // If we are in a code fence we want to preserve the leading whitespace
2270
+ // except for the first space after the star which is used as indentation.
2271
+ const whitespaceStart = tokenPos();
2272
+ parseOptional(Token.Whitespace);
2273
+ // This `min` handles the case when there is no whitespace after the
2274
+ // star e.g. a case like this:
2275
+ //
2276
+ // /**
2277
+ // *```
2278
+ // *foo-bar
2279
+ // *```
2280
+ // */
2281
+ //
2282
+ // Not having space after the star isn't idiomatic, but we support this.
2283
+ // `whitespaceStart + 1` strips the first space before `foo-bar` if there
2284
+ // is a space after the star (the idiomatic case).
2285
+ start = Math.min(whitespaceStart + 1, tokenPos());
2250
2286
  break;
2251
2287
  case Token.EndOfFile:
2252
2288
  break loop;
@@ -2256,6 +2292,12 @@ function createParser(code, options = {}) {
2256
2292
  }
2257
2293
  nextToken();
2258
2294
  break;
2295
+ case Token.DocText:
2296
+ parts.push(source.substring(start, tokenPos()));
2297
+ parts.push(tokenValue());
2298
+ nextToken();
2299
+ start = tokenPos();
2300
+ break;
2259
2301
  default:
2260
2302
  nextToken();
2261
2303
  break;
@@ -2285,6 +2327,8 @@ function createParser(code, options = {}) {
2285
2327
  return parseDocParamLikeTag(pos, tagName, SyntaxKind.DocParamTag, "param");
2286
2328
  case "template":
2287
2329
  return parseDocParamLikeTag(pos, tagName, SyntaxKind.DocTemplateTag, "templateParam");
2330
+ case "prop":
2331
+ return parseDocPropTag(pos, tagName);
2288
2332
  case "return":
2289
2333
  case "returns":
2290
2334
  return parseDocSimpleTag(pos, tagName, SyntaxKind.DocReturnsTag);
@@ -2299,9 +2343,7 @@ function createParser(code, options = {}) {
2299
2343
  * For example, `@param` and `@template`.
2300
2344
  */
2301
2345
  function parseDocParamLikeTag(pos, tagName, kind, messageId) {
2302
- const name = parseDocIdentifier(messageId);
2303
- parseOptionalHyphenDocParamLikeTag();
2304
- const content = parseDocContent();
2346
+ const { name, content } = parseDocParamLikeTagInternal(messageId);
2305
2347
  return {
2306
2348
  kind,
2307
2349
  tagName,
@@ -2310,6 +2352,22 @@ function createParser(code, options = {}) {
2310
2352
  ...finishNode(pos),
2311
2353
  };
2312
2354
  }
2355
+ function parseDocPropTag(pos, tagName) {
2356
+ const { name, content } = parseDocParamLikeTagInternal("prop");
2357
+ return {
2358
+ kind: SyntaxKind.DocPropTag,
2359
+ tagName,
2360
+ propName: name,
2361
+ content,
2362
+ ...finishNode(pos),
2363
+ };
2364
+ }
2365
+ function parseDocParamLikeTagInternal(messageId) {
2366
+ const name = parseDocIdentifier(messageId);
2367
+ parseOptionalHyphenDocParamLikeTag();
2368
+ const content = parseDocContent();
2369
+ return { name, content };
2370
+ }
2313
2371
  /**
2314
2372
  * Handles the optional hyphen in param-like documentation comment tags.
2315
2373
  *
@@ -2434,10 +2492,11 @@ function createParser(code, options = {}) {
2434
2492
  }
2435
2493
  function createMissingTypeReference() {
2436
2494
  const pos = tokenPos();
2495
+ const { items: args } = createEmptyList();
2437
2496
  return {
2438
2497
  kind: SyntaxKind.TypeReference,
2439
2498
  target: createMissingIdentifier(),
2440
- arguments: [],
2499
+ arguments: args,
2441
2500
  ...finishNode(pos),
2442
2501
  };
2443
2502
  }
@@ -2450,6 +2509,12 @@ function createParser(code, options = {}) {
2450
2509
  function withSymbol(obj) {
2451
2510
  return obj;
2452
2511
  }
2512
+ function createEmptyList(range = { pos: -1, end: -1 }) {
2513
+ return {
2514
+ items: [],
2515
+ range,
2516
+ };
2517
+ }
2453
2518
  /**
2454
2519
  * Parse a delimited list of elements, including the surrounding open and
2455
2520
  * close punctuation
@@ -2466,13 +2531,17 @@ function createParser(code, options = {}) {
2466
2531
  * do not go through here.
2467
2532
  */
2468
2533
  function parseList(kind, parseItem) {
2534
+ const r = createEmptyList();
2469
2535
  if (kind.open !== Token.None) {
2470
- parseExpected(kind.open);
2536
+ const t = tokenPos();
2537
+ if (parseExpected(kind.open)) {
2538
+ mutate(r.range).pos = t;
2539
+ }
2471
2540
  }
2472
2541
  if (kind.allowEmpty && parseOptional(kind.close)) {
2473
- return [];
2542
+ mutate(r.range).end = previousTokenEnd;
2543
+ return r;
2474
2544
  }
2475
- const items = [];
2476
2545
  while (true) {
2477
2546
  const startingPos = tokenPos();
2478
2547
  const { pos, docs, directives, decorators } = parseAnnotations({
@@ -2487,7 +2556,9 @@ function createParser(code, options = {}) {
2487
2556
  // of file. Note, however, that we must parse a missing element if
2488
2557
  // there were directives or decorators as we cannot drop those from
2489
2558
  // the tree.
2490
- parseExpected(kind.close);
2559
+ if (parseExpected(kind.close)) {
2560
+ mutate(r.range).end = previousTokenEnd;
2561
+ }
2491
2562
  break;
2492
2563
  }
2493
2564
  let item;
@@ -2499,12 +2570,13 @@ function createParser(code, options = {}) {
2499
2570
  mutate(item).docs = docs;
2500
2571
  mutate(item).directives = directives;
2501
2572
  }
2502
- items.push(item);
2573
+ r.items.push(item);
2503
2574
  const delimiter = token();
2504
2575
  const delimiterPos = tokenPos();
2505
2576
  if (parseOptionalDelimiter(kind)) {
2506
2577
  // Delimiter found: check if it's trailing.
2507
2578
  if (parseOptional(kind.close)) {
2579
+ mutate(r.range).end = previousTokenEnd;
2508
2580
  if (!kind.trailingDelimiterIsValid) {
2509
2581
  error({
2510
2582
  code: "trailing-token",
@@ -2528,6 +2600,7 @@ function createParser(code, options = {}) {
2528
2600
  break;
2529
2601
  }
2530
2602
  else if (parseOptional(kind.close)) {
2603
+ mutate(r.range).end = previousTokenEnd;
2531
2604
  // If a list *is* surrounded by punctuation, then the list ends when we
2532
2605
  // reach the close token.
2533
2606
  break;
@@ -2538,7 +2611,9 @@ function createParser(code, options = {}) {
2538
2611
  // assumption that the closing delimiter is missing. This check is
2539
2612
  // duplicated from above to preempt the parseExpected(delimeter)
2540
2613
  // below.
2541
- parseExpected(kind.close);
2614
+ if (parseExpected(kind.close)) {
2615
+ mutate(r.range).end = previousTokenEnd;
2616
+ }
2542
2617
  break;
2543
2618
  }
2544
2619
  else {
@@ -2557,21 +2632,23 @@ function createParser(code, options = {}) {
2557
2632
  //
2558
2633
  // Simple repro: `model M { ]` would loop forever without this check.
2559
2634
  //
2560
- parseExpected(kind.close);
2635
+ if (parseExpected(kind.close)) {
2636
+ mutate(r.range).end = previousTokenEnd;
2637
+ }
2561
2638
  nextToken();
2562
2639
  // remove the item that was entirely inserted by error recovery.
2563
- items.pop();
2640
+ r.items.pop();
2564
2641
  break;
2565
2642
  }
2566
2643
  }
2567
- return items;
2644
+ return r;
2568
2645
  }
2569
2646
  /**
2570
2647
  * Parse a delimited list with surrounding open and close punctuation if the
2571
2648
  * open token is present. Otherwise, return an empty list.
2572
2649
  */
2573
2650
  function parseOptionalList(kind, parseItem) {
2574
- return token() === kind.open ? parseList(kind, parseItem) : [];
2651
+ return token() === kind.open ? parseList(kind, parseItem) : createEmptyList();
2575
2652
  }
2576
2653
  function parseOptionalDelimiter(kind) {
2577
2654
  if (parseOptional(kind.delimiter)) {
@@ -2918,6 +2995,8 @@ export function visitChildren(node, cb) {
2918
2995
  case SyntaxKind.DocParamTag:
2919
2996
  case SyntaxKind.DocTemplateTag:
2920
2997
  return (visitNode(cb, node.tagName) || visitNode(cb, node.paramName) || visitEach(cb, node.content));
2998
+ case SyntaxKind.DocPropTag:
2999
+ return (visitNode(cb, node.tagName) || visitNode(cb, node.propName) || visitEach(cb, node.content));
2921
3000
  case SyntaxKind.DocReturnsTag:
2922
3001
  case SyntaxKind.DocErrorsTag:
2923
3002
  case SyntaxKind.DocUnknownTag:
@@ -2983,6 +3062,60 @@ function visitEach(cb, nodes) {
2983
3062
  }
2984
3063
  return;
2985
3064
  }
3065
+ /**
3066
+ * check whether a position belongs to a range (excluding the start and end pos)
3067
+ * i.e. <range.pos>{<start to return true>...<end to return true>}<range.end>
3068
+ *
3069
+ * remark: if range.pos is -1 means no start point found, so return false
3070
+ * if range.end is -1 means no end point found, so return true if position is greater than range.pos
3071
+ */
3072
+ export function positionInRange(position, range) {
3073
+ return range.pos >= 0 && position > range.pos && (range.end === -1 || position < range.end);
3074
+ }
3075
+ export function getNodeAtPositionDetail(script, position, filter = () => true) {
3076
+ const cur = getNodeAtPosition(script, position, (n) => filter(n, "cur"));
3077
+ const input = script.file.text;
3078
+ const char = input.charCodeAt(position);
3079
+ const preChar = position >= 0 ? input.charCodeAt(position - 1) : NaN;
3080
+ const nextChar = position < input.length ? input.charCodeAt(position + 1) : NaN;
3081
+ let inTrivia = false;
3082
+ let triviaStart;
3083
+ let triviaEnd;
3084
+ if (!cur || cur.kind !== SyntaxKind.StringLiteral) {
3085
+ const { char: cp } = codePointBefore(input, position);
3086
+ if (!cp || !isIdentifierContinue(cp)) {
3087
+ triviaEnd = skipTrivia(input, position);
3088
+ triviaStart = skipTriviaBackward(script, position) + 1;
3089
+ inTrivia = triviaEnd !== position;
3090
+ }
3091
+ }
3092
+ if (!inTrivia) {
3093
+ const beforeId = skipContinuousIdentifier(input, position, true /*isBackward*/);
3094
+ triviaStart = skipTriviaBackward(script, beforeId) + 1;
3095
+ const afterId = skipContinuousIdentifier(input, position, false /*isBackward*/);
3096
+ triviaEnd = skipTrivia(input, afterId);
3097
+ }
3098
+ if (triviaStart === undefined || triviaEnd === undefined) {
3099
+ compilerAssert(false, "unexpected, triviaStart and triviaEnd should be defined");
3100
+ }
3101
+ return {
3102
+ node: cur,
3103
+ char,
3104
+ preChar,
3105
+ nextChar,
3106
+ position,
3107
+ inTrivia,
3108
+ triviaStartPosition: triviaStart,
3109
+ triviaEndPosition: triviaEnd,
3110
+ getPositionDetailBeforeTrivia: () => {
3111
+ // getNodeAtPosition will also include the 'node.end' position which is the triviaStart pos
3112
+ return getNodeAtPositionDetail(script, triviaStart, (n) => filter(n, "pre"));
3113
+ },
3114
+ getPositionDetailAfterTrivia: () => {
3115
+ return getNodeAtPositionDetail(script, triviaEnd, (n) => filter(n, "post"));
3116
+ },
3117
+ };
3118
+ }
2986
3119
  export function getNodeAtPosition(script, position, filter = (node) => true) {
2987
3120
  return visit(script);
2988
3121
  function visit(node) {
@@ -3050,7 +3183,10 @@ function isBlocklessNamespace(node) {
3050
3183
  }
3051
3184
  return node.statements === undefined;
3052
3185
  }
3053
- export function getFirstAncestor(node, test) {
3186
+ export function getFirstAncestor(node, test, includeSelf = false) {
3187
+ if (includeSelf && test(node)) {
3188
+ return node;
3189
+ }
3054
3190
  for (let n = node.parent; n; n = n.parent) {
3055
3191
  if (test(n)) {
3056
3192
  return n;
@@ -3079,6 +3215,26 @@ export function getIdentifierContext(id) {
3079
3215
  case SyntaxKind.TemplateArgument:
3080
3216
  kind = IdentifierKind.TemplateArgument;
3081
3217
  break;
3218
+ case SyntaxKind.ObjectLiteralProperty:
3219
+ kind = IdentifierKind.ObjectLiteralProperty;
3220
+ break;
3221
+ case SyntaxKind.ModelProperty:
3222
+ switch (node.parent?.kind) {
3223
+ case SyntaxKind.ModelExpression:
3224
+ kind = IdentifierKind.ModelExpressionProperty;
3225
+ break;
3226
+ case SyntaxKind.ModelStatement:
3227
+ kind = IdentifierKind.ModelStatementProperty;
3228
+ break;
3229
+ default:
3230
+ compilerAssert("false", "ModelProperty with unexpected parent kind.");
3231
+ kind =
3232
+ id.parent.id === id
3233
+ ? IdentifierKind.Declaration
3234
+ : IdentifierKind.Other;
3235
+ break;
3236
+ }
3237
+ break;
3082
3238
  default:
3083
3239
  kind =
3084
3240
  id.parent.id === id