@openrewrite/rewrite 8.92.16 → 8.92.18

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 (254) hide show
  1. package/README.md +48 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/java/formatting-utils.d.ts +2 -1
  6. package/dist/java/formatting-utils.d.ts.map +1 -1
  7. package/dist/java/formatting-utils.js +4 -3
  8. package/dist/java/formatting-utils.js.map +1 -1
  9. package/dist/java/rpc.d.ts.map +1 -1
  10. package/dist/java/rpc.js +2 -0
  11. package/dist/java/rpc.js.map +1 -1
  12. package/dist/java/tree.d.ts +8 -0
  13. package/dist/java/tree.d.ts.map +1 -1
  14. package/dist/java/tree.js +11 -1
  15. package/dist/java/tree.js.map +1 -1
  16. package/dist/java/type.d.ts +7 -1
  17. package/dist/java/type.d.ts.map +1 -1
  18. package/dist/java/type.js +16 -1
  19. package/dist/java/type.js.map +1 -1
  20. package/dist/javascript/add-import.d.ts +27 -21
  21. package/dist/javascript/add-import.d.ts.map +1 -1
  22. package/dist/javascript/add-import.js +303 -143
  23. package/dist/javascript/add-import.js.map +1 -1
  24. package/dist/javascript/amd.d.ts.map +1 -1
  25. package/dist/javascript/amd.js +25 -10
  26. package/dist/javascript/amd.js.map +1 -1
  27. package/dist/javascript/autodetect.js +36 -45
  28. package/dist/javascript/autodetect.js.map +1 -1
  29. package/dist/javascript/binding.d.ts +6 -4
  30. package/dist/javascript/binding.d.ts.map +1 -1
  31. package/dist/javascript/binding.js +54 -18
  32. package/dist/javascript/binding.js.map +1 -1
  33. package/dist/javascript/comparator.d.ts +22 -5
  34. package/dist/javascript/comparator.d.ts.map +1 -1
  35. package/dist/javascript/comparator.js +120 -38
  36. package/dist/javascript/comparator.js.map +1 -1
  37. package/dist/javascript/format/format.d.ts +2 -0
  38. package/dist/javascript/format/format.d.ts.map +1 -1
  39. package/dist/javascript/format/format.js +11 -1
  40. package/dist/javascript/format/format.js.map +1 -1
  41. package/dist/javascript/format/tabs-and-indents-visitor.d.ts.map +1 -1
  42. package/dist/javascript/format/tabs-and-indents-visitor.js +31 -4
  43. package/dist/javascript/format/tabs-and-indents-visitor.js.map +1 -1
  44. package/dist/javascript/index.d.ts +4 -2
  45. package/dist/javascript/index.d.ts.map +1 -1
  46. package/dist/javascript/index.js +10 -1
  47. package/dist/javascript/index.js.map +1 -1
  48. package/dist/javascript/markers.d.ts +12 -0
  49. package/dist/javascript/markers.d.ts.map +1 -1
  50. package/dist/javascript/markers.js +81 -2
  51. package/dist/javascript/markers.js.map +1 -1
  52. package/dist/javascript/method-matcher.d.ts +13 -2
  53. package/dist/javascript/method-matcher.d.ts.map +1 -1
  54. package/dist/javascript/method-matcher.js +32 -19
  55. package/dist/javascript/method-matcher.js.map +1 -1
  56. package/dist/javascript/node-resolution-result.js +3 -2
  57. package/dist/javascript/node-resolution-result.js.map +1 -1
  58. package/dist/javascript/package-name.d.ts +6 -0
  59. package/dist/javascript/package-name.d.ts.map +1 -0
  60. package/dist/javascript/package-name.js +47 -0
  61. package/dist/javascript/package-name.js.map +1 -0
  62. package/dist/javascript/parser.d.ts +9 -0
  63. package/dist/javascript/parser.d.ts.map +1 -1
  64. package/dist/javascript/parser.js +185 -88
  65. package/dist/javascript/parser.js.map +1 -1
  66. package/dist/javascript/preconditions.d.ts +4 -1
  67. package/dist/javascript/preconditions.d.ts.map +1 -1
  68. package/dist/javascript/preconditions.js +7 -4
  69. package/dist/javascript/preconditions.js.map +1 -1
  70. package/dist/javascript/print.d.ts +10 -1
  71. package/dist/javascript/print.d.ts.map +1 -1
  72. package/dist/javascript/print.js +120 -77
  73. package/dist/javascript/print.js.map +1 -1
  74. package/dist/javascript/recipes/change-method-target-to-import.d.ts +29 -0
  75. package/dist/javascript/recipes/change-method-target-to-import.d.ts.map +1 -0
  76. package/dist/javascript/recipes/change-method-target-to-import.js +164 -0
  77. package/dist/javascript/recipes/change-method-target-to-import.js.map +1 -0
  78. package/dist/javascript/recipes/index.d.ts +1 -0
  79. package/dist/javascript/recipes/index.d.ts.map +1 -1
  80. package/dist/javascript/recipes/index.js +1 -0
  81. package/dist/javascript/recipes/index.js.map +1 -1
  82. package/dist/javascript/scope.d.ts +60 -16
  83. package/dist/javascript/scope.d.ts.map +1 -1
  84. package/dist/javascript/scope.js +596 -131
  85. package/dist/javascript/scope.js.map +1 -1
  86. package/dist/javascript/search/uses-method.d.ts +1 -1
  87. package/dist/javascript/search/uses-method.d.ts.map +1 -1
  88. package/dist/javascript/search/uses-method.js +2 -2
  89. package/dist/javascript/search/uses-method.js.map +1 -1
  90. package/dist/javascript/search/uses-type.d.ts +14 -1
  91. package/dist/javascript/search/uses-type.d.ts.map +1 -1
  92. package/dist/javascript/search/uses-type.js +24 -9
  93. package/dist/javascript/search/uses-type.js.map +1 -1
  94. package/dist/javascript/templating/bindings.d.ts +1 -1
  95. package/dist/javascript/templating/bindings.d.ts.map +1 -1
  96. package/dist/javascript/templating/bindings.js +10 -50
  97. package/dist/javascript/templating/bindings.js.map +1 -1
  98. package/dist/javascript/templating/comparator.d.ts +8 -11
  99. package/dist/javascript/templating/comparator.d.ts.map +1 -1
  100. package/dist/javascript/templating/comparator.js +12 -110
  101. package/dist/javascript/templating/comparator.js.map +1 -1
  102. package/dist/javascript/templating/engine.d.ts +34 -24
  103. package/dist/javascript/templating/engine.d.ts.map +1 -1
  104. package/dist/javascript/templating/engine.js +208 -115
  105. package/dist/javascript/templating/engine.js.map +1 -1
  106. package/dist/javascript/templating/pattern.d.ts +11 -5
  107. package/dist/javascript/templating/pattern.d.ts.map +1 -1
  108. package/dist/javascript/templating/pattern.js +86 -20
  109. package/dist/javascript/templating/pattern.js.map +1 -1
  110. package/dist/javascript/templating/placeholder-replacement.d.ts +34 -3
  111. package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
  112. package/dist/javascript/templating/placeholder-replacement.js +126 -60
  113. package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
  114. package/dist/javascript/templating/precedence.d.ts +3 -1
  115. package/dist/javascript/templating/precedence.d.ts.map +1 -1
  116. package/dist/javascript/templating/precedence.js +28 -8
  117. package/dist/javascript/templating/precedence.js.map +1 -1
  118. package/dist/javascript/templating/template.d.ts +7 -6
  119. package/dist/javascript/templating/template.d.ts.map +1 -1
  120. package/dist/javascript/templating/template.js +31 -28
  121. package/dist/javascript/templating/template.js.map +1 -1
  122. package/dist/javascript/templating/types.d.ts +6 -3
  123. package/dist/javascript/templating/types.d.ts.map +1 -1
  124. package/dist/javascript/templating/utils.d.ts +10 -1
  125. package/dist/javascript/templating/utils.d.ts.map +1 -1
  126. package/dist/javascript/templating/utils.js +22 -3
  127. package/dist/javascript/templating/utils.js.map +1 -1
  128. package/dist/javascript/tree-debug.d.ts +2 -0
  129. package/dist/javascript/tree-debug.d.ts.map +1 -1
  130. package/dist/javascript/tree-debug.js +6 -0
  131. package/dist/javascript/tree-debug.js.map +1 -1
  132. package/dist/javascript/tsconfig.d.ts.map +1 -1
  133. package/dist/javascript/tsconfig.js +7 -17
  134. package/dist/javascript/tsconfig.js.map +1 -1
  135. package/dist/javascript/type-mapping.d.ts +35 -16
  136. package/dist/javascript/type-mapping.d.ts.map +1 -1
  137. package/dist/javascript/type-mapping.js +271 -252
  138. package/dist/javascript/type-mapping.js.map +1 -1
  139. package/dist/javascript/type-report-cli.d.ts +7 -0
  140. package/dist/javascript/type-report-cli.d.ts.map +1 -0
  141. package/dist/javascript/type-report-cli.js +129 -0
  142. package/dist/javascript/type-report-cli.js.map +1 -0
  143. package/dist/javascript/type-report.d.ts +61 -0
  144. package/dist/javascript/type-report.d.ts.map +1 -0
  145. package/dist/javascript/type-report.js +488 -0
  146. package/dist/javascript/type-report.js.map +1 -0
  147. package/dist/markers.d.ts +4 -0
  148. package/dist/markers.d.ts.map +1 -1
  149. package/dist/markers.js +8 -0
  150. package/dist/markers.js.map +1 -1
  151. package/dist/print.d.ts +6 -1
  152. package/dist/print.d.ts.map +1 -1
  153. package/dist/print.js +21 -7
  154. package/dist/print.js.map +1 -1
  155. package/dist/recipe.d.ts +5 -0
  156. package/dist/recipe.d.ts.map +1 -1
  157. package/dist/recipe.js +5 -0
  158. package/dist/recipe.js.map +1 -1
  159. package/dist/rewrite-javascript-version.txt +1 -1
  160. package/dist/rpc/java-rpc-client.d.ts +2 -0
  161. package/dist/rpc/java-rpc-client.d.ts.map +1 -1
  162. package/dist/rpc/java-rpc-client.js +1 -0
  163. package/dist/rpc/java-rpc-client.js.map +1 -1
  164. package/dist/rpc/queue.d.ts +24 -0
  165. package/dist/rpc/queue.d.ts.map +1 -1
  166. package/dist/rpc/queue.js +71 -11
  167. package/dist/rpc/queue.js.map +1 -1
  168. package/dist/rpc/request/get-object.d.ts +4 -0
  169. package/dist/rpc/request/get-object.d.ts.map +1 -1
  170. package/dist/rpc/request/get-object.js +23 -1
  171. package/dist/rpc/request/get-object.js.map +1 -1
  172. package/dist/rpc/request/parse.d.ts.map +1 -1
  173. package/dist/rpc/request/parse.js +3 -1
  174. package/dist/rpc/request/parse.js.map +1 -1
  175. package/dist/rpc/request/prepare-recipe.d.ts +3 -1
  176. package/dist/rpc/request/prepare-recipe.d.ts.map +1 -1
  177. package/dist/rpc/request/prepare-recipe.js +13 -6
  178. package/dist/rpc/request/prepare-recipe.js.map +1 -1
  179. package/dist/rpc/request/print.d.ts +8 -2
  180. package/dist/rpc/request/print.d.ts.map +1 -1
  181. package/dist/rpc/request/print.js +12 -9
  182. package/dist/rpc/request/print.js.map +1 -1
  183. package/dist/rpc/rewrite-rpc.d.ts +3 -2
  184. package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
  185. package/dist/rpc/rewrite-rpc.js +9 -3
  186. package/dist/rpc/rewrite-rpc.js.map +1 -1
  187. package/dist/rpc/server.d.ts.map +1 -1
  188. package/dist/rpc/server.js +19 -5
  189. package/dist/rpc/server.js.map +1 -1
  190. package/dist/search/is-source-file.d.ts +1 -0
  191. package/dist/search/is-source-file.d.ts.map +1 -1
  192. package/dist/search/is-source-file.js +7 -2
  193. package/dist/search/is-source-file.js.map +1 -1
  194. package/dist/test/java-rpc.d.ts.map +1 -1
  195. package/dist/test/java-rpc.js +3 -0
  196. package/dist/test/java-rpc.js.map +1 -1
  197. package/dist/test/rewrite-test.d.ts +5 -0
  198. package/dist/test/rewrite-test.d.ts.map +1 -1
  199. package/dist/test/rewrite-test.js +14 -3
  200. package/dist/test/rewrite-test.js.map +1 -1
  201. package/package.json +4 -3
  202. package/src/index.ts +3 -1
  203. package/src/java/formatting-utils.ts +5 -4
  204. package/src/java/rpc.ts +2 -0
  205. package/src/java/tree.ts +15 -0
  206. package/src/java/type.ts +19 -2
  207. package/src/javascript/add-import.ts +338 -152
  208. package/src/javascript/amd.ts +28 -12
  209. package/src/javascript/autodetect.ts +32 -41
  210. package/src/javascript/binding.ts +64 -22
  211. package/src/javascript/comparator.ts +129 -43
  212. package/src/javascript/format/format.ts +9 -0
  213. package/src/javascript/format/tabs-and-indents-visitor.ts +30 -3
  214. package/src/javascript/index.ts +6 -3
  215. package/src/javascript/markers.ts +77 -5
  216. package/src/javascript/method-matcher.ts +34 -22
  217. package/src/javascript/node-resolution-result.ts +3 -2
  218. package/src/javascript/package-name.ts +45 -0
  219. package/src/javascript/parser.ts +200 -91
  220. package/src/javascript/preconditions.ts +7 -4
  221. package/src/javascript/print.ts +123 -76
  222. package/src/javascript/recipes/change-method-target-to-import.ts +178 -0
  223. package/src/javascript/recipes/index.ts +1 -0
  224. package/src/javascript/scope.ts +705 -169
  225. package/src/javascript/search/uses-method.ts +2 -2
  226. package/src/javascript/search/uses-type.ts +30 -9
  227. package/src/javascript/templating/bindings.ts +13 -38
  228. package/src/javascript/templating/comparator.ts +16 -127
  229. package/src/javascript/templating/engine.ts +236 -129
  230. package/src/javascript/templating/pattern.ts +107 -28
  231. package/src/javascript/templating/placeholder-replacement.ts +154 -62
  232. package/src/javascript/templating/precedence.ts +33 -11
  233. package/src/javascript/templating/template.ts +35 -30
  234. package/src/javascript/templating/types.ts +6 -3
  235. package/src/javascript/templating/utils.ts +24 -2
  236. package/src/javascript/tree-debug.ts +9 -0
  237. package/src/javascript/tsconfig.ts +7 -17
  238. package/src/javascript/type-mapping.ts +277 -255
  239. package/src/javascript/type-report-cli.ts +96 -0
  240. package/src/javascript/type-report.ts +575 -0
  241. package/src/markers.ts +8 -0
  242. package/src/print.ts +23 -8
  243. package/src/recipe.ts +6 -0
  244. package/src/rpc/java-rpc-client.ts +3 -0
  245. package/src/rpc/queue.ts +80 -7
  246. package/src/rpc/request/get-object.ts +24 -0
  247. package/src/rpc/request/parse.ts +4 -1
  248. package/src/rpc/request/prepare-recipe.ts +16 -6
  249. package/src/rpc/request/print.ts +12 -8
  250. package/src/rpc/rewrite-rpc.ts +16 -5
  251. package/src/rpc/server.ts +18 -6
  252. package/src/search/is-source-file.ts +8 -3
  253. package/src/test/java-rpc.ts +3 -0
  254. package/src/test/rewrite-test.ts +14 -3
@@ -29,7 +29,7 @@ import {
29
29
  TypeTree,
30
30
  VariableDeclarator,
31
31
  } from '../java';
32
- import {DelegatedYield, FunctionDeclaration, Generator, JS, JSX, NonNullAssertion, Optional} from '.';
32
+ import {Computed, DelegatedYield, FunctionDeclaration, Generator, JS, JSX, NonNullAssertion, Optional} from '.';
33
33
  import {emptyMarkers, markers, Markers, MarkersKind, ParseExceptionResult, replaceMarkerByKind} from "../markers";
34
34
  import {NamedStyles} from "../style";
35
35
  import {Parser, ParserInput, parserInputFile, parserInputRead, ParserOptions, Parsers, SourcePath} from "../parser";
@@ -47,7 +47,7 @@ import {
47
47
  } from "./parser-utils";
48
48
  import {JavaScriptTypeMapping} from "./type-mapping";
49
49
  import {TsConfigResolver} from "./tsconfig";
50
- import {create as produce} from "mutative";
50
+ import {castDraft, create as produce} from "mutative";
51
51
  import ComputedPropertyName = JS.ComputedPropertyName;
52
52
  import Attribute = JSX.Attribute;
53
53
  import SpreadAttribute = JSX.SpreadAttribute;
@@ -626,26 +626,13 @@ export class JavaScriptParserVisitor {
626
626
 
627
627
  private mapModifiers(node: ts.VariableDeclarationList | ts.VariableStatement | ts.ClassDeclaration | ts.PropertyDeclaration
628
628
  | ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration
629
- | ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
630
- | ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration | ts.ExportDeclaration | ts.ExportAssignment | ts.FunctionExpression
631
- | ts.ConstructorTypeNode | ts.TypeParameterDeclaration | ts.ImportDeclaration | ts.ImportEqualsDeclaration
632
- | ts.PropertyAssignment | ts.ShorthandPropertyAssignment): J.Modifier[] {
633
- if (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) {
634
- const modifiers = (node as WithInvalidSyntaxSlots<typeof node>).modifiers;
635
- return modifiers ? modifiers.filter(ts.isModifier).map(this.mapModifier) : [];
636
- }
637
- if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node)
638
- || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node)
629
+ | ts.PropertySignature | ts.MethodSignature | ts.ConstructorDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
630
+ | ts.ArrowFunction | ts.FunctionExpression | ts.ConstructorTypeNode | ts.TypeParameterDeclaration): J.Modifier[] {
631
+ if (ts.isVariableStatement(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node)
632
+ || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isMethodSignature(node) || ts.isParameter(node)
639
633
  || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node)
640
- || ts.isIndexSignatureDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isExportDeclaration(node)
641
- || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isConstructorTypeNode(node) || ts.isTypeParameterDeclaration(node) || ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node)) {
642
- return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : [];
643
- } else if (ts.isExportAssignment(node)) {
644
- const defaultModifier = this.findChildNode(node, ts.SyntaxKind.DefaultKeyword);
645
- return [
646
- ...node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : [],
647
- ...defaultModifier && ts.isModifier(defaultModifier) ? [this.mapModifier(defaultModifier)] : []
648
- ]
634
+ || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isConstructorTypeNode(node) || ts.isTypeParameterDeclaration(node)) {
635
+ return this.mapKeywordModifiers(node.modifiers);
649
636
  } else if (ts.isVariableDeclarationList(node)) {
650
637
  let modifier: string | undefined;
651
638
  if ((node.flags & ts.NodeFlags.Let) !== 0) {
@@ -665,29 +652,72 @@ export class JavaScriptParserVisitor {
665
652
  annotations: []
666
653
  }] : [];
667
654
  } else if (ts.isGetAccessorDeclaration(node)) {
668
- return (node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []).concat({
655
+ return this.mapKeywordModifiers(node.modifiers).concat({
669
656
  kind: J.Kind.Modifier,
670
657
  id: randomId(),
671
658
  prefix: this.prefix(this.findChildNode(node, ts.SyntaxKind.GetKeyword)!),
672
659
  markers: emptyMarkers,
673
660
  keyword: 'get',
674
661
  type: J.ModifierType.LanguageExtension,
675
- annotations: []
662
+ annotations: this.mapTrailingDecorators(node)
676
663
  });
677
664
  } else if (ts.isSetAccessorDeclaration(node)) {
678
- return (node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []).concat({
665
+ return this.mapKeywordModifiers(node.modifiers).concat({
679
666
  kind: J.Kind.Modifier,
680
667
  id: randomId(),
681
668
  prefix: this.prefix(this.findChildNode(node, ts.SyntaxKind.SetKeyword)!),
682
669
  markers: emptyMarkers,
683
670
  keyword: 'set',
684
671
  type: J.ModifierType.LanguageExtension,
685
- annotations: []
672
+ annotations: this.mapTrailingDecorators(node)
686
673
  });
687
674
  }
688
675
  throw new Error(`Cannot get modifiers from ${node}`);
689
676
  }
690
677
 
678
+ // A decorator written after a modifier is an annotation of the modifier that follows it.
679
+ private mapKeywordModifiers(modifiers: readonly ts.ModifierLike[] | undefined): J.Modifier[] {
680
+ const mapped: J.Modifier[] = [];
681
+ let decorators: ts.Decorator[] = [];
682
+ for (const modifier of modifiers ?? []) {
683
+ if (ts.isDecorator(modifier)) {
684
+ decorators.push(modifier);
685
+ } else {
686
+ const annotations = mapped.length > 0 ? decorators.map(this.convert<J.Annotation>) : [];
687
+ mapped.push({...this.mapModifier(modifier), annotations});
688
+ decorators = [];
689
+ }
690
+ }
691
+ return mapped;
692
+ }
693
+
694
+ // For a tree with no annotations of its own: a decorator is an annotation of the modifier written after it.
695
+ private mapDecoratedModifiers(modifiers: readonly ts.ModifierLike[] | undefined): J.Modifier[] {
696
+ const mapped: J.Modifier[] = [];
697
+ let decorators: ts.Decorator[] = [];
698
+ for (const modifier of modifiers ?? []) {
699
+ if (ts.isDecorator(modifier)) {
700
+ decorators.push(modifier);
701
+ } else {
702
+ const annotations = decorators.map(this.convert<J.Annotation>);
703
+ mapped.push({...this.mapModifier(modifier), annotations});
704
+ decorators = [];
705
+ }
706
+ }
707
+ this.reject(decorators);
708
+ return mapped;
709
+ }
710
+
711
+ // What the model has no place for is refused in the compiler's words, never left out of the tree.
712
+ private reject(modifiers: readonly ts.ModifierLike[] | undefined): void {
713
+ if (!modifiers || modifiers.length === 0) {
714
+ return;
715
+ }
716
+ const {line, character} = this.sourceFile.getLineAndCharacterOfPosition(modifiers[0].getStart(this.sourceFile));
717
+ const message = ts.isDecorator(modifiers[0]) ? "Decorators are not valid here." : "Modifiers cannot appear here.";
718
+ throw new SyntaxError(`(${line + 1},${character + 1}): ${message}`);
719
+ }
720
+
691
721
  private mapModifier = (node: ts.Modifier | ts.ModifierLike): J.Modifier => {
692
722
  let kind: J.ModifierType;
693
723
  switch (node.kind) {
@@ -789,7 +819,7 @@ export class JavaScriptParserVisitor {
789
819
  id: randomId(),
790
820
  prefix: node.modifiers ? this.suffix(node.modifiers[node.modifiers.length - 1]) : this.prefix(node),
791
821
  markers: emptyMarkers,
792
- annotations: [],
822
+ annotations: this.mapTrailingDecorators(node),
793
823
  type: J.ClassDeclaration.Kind.Type.Class
794
824
  },
795
825
  name: node.name ? this.convert(node.name) : this.mapIdentifier(node, ""),
@@ -1157,6 +1187,7 @@ export class JavaScriptParserVisitor {
1157
1187
  };
1158
1188
  name = spread;
1159
1189
  }
1190
+ name = this.annotateName(name, this.trailingDecorators(node));
1160
1191
  return {
1161
1192
  kind: J.Kind.VariableDeclarations,
1162
1193
  id: randomId(),
@@ -1181,6 +1212,29 @@ export class JavaScriptParserVisitor {
1181
1212
  };
1182
1213
  }
1183
1214
 
1215
+ // A decorator written after the last modifier of a parameter is an annotation of the name it is written before.
1216
+ private annotateName(name: VariableDeclarator, decorators: ts.Decorator[]): VariableDeclarator {
1217
+ if (decorators.length === 0) {
1218
+ return name;
1219
+ }
1220
+ if (name.kind === J.Kind.Identifier) {
1221
+ const annotations = decorators.map(this.convert<J.Annotation>);
1222
+ return {...name as J.Identifier, annotations} satisfies J.Identifier as J.Identifier;
1223
+ }
1224
+ if (name.kind === JS.Kind.ObjectBindingPattern) {
1225
+ // a pattern prints its annotations after its prefix, so the space before its brace moves behind them
1226
+ const pattern = name as JS.ObjectBindingPattern;
1227
+ return {
1228
+ ...pattern,
1229
+ prefix: emptySpace,
1230
+ leadingAnnotations: decorators.map(this.convert<J.Annotation>),
1231
+ bindings: {...pattern.bindings, before: pattern.prefix}
1232
+ } satisfies JS.ObjectBindingPattern as JS.ObjectBindingPattern;
1233
+ }
1234
+ this.reject(decorators);
1235
+ return name;
1236
+ }
1237
+
1184
1238
  visitDecorator(node: ts.Decorator): J.Annotation | J.Unknown {
1185
1239
  let annotationType: NameTree | TypeTree;
1186
1240
  let _arguments: J.Container<Expression> | undefined = undefined;
@@ -1196,7 +1250,7 @@ export class JavaScriptParserVisitor {
1196
1250
  prefix: emptySpace,
1197
1251
  markers: emptyMarkers,
1198
1252
  clazz: this.convert<J>(node.expression.expression) as Expression,
1199
- typeArguments: this.mapTypeArguments(this.suffix(node.expression.expression), node.expression.typeArguments)
1253
+ typeArguments: this.mapTypeArguments(this.typeArgumentsPrefix(node.expression, node.expression.typeArguments), node.expression.typeArguments)
1200
1254
  } satisfies JS.ExpressionWithTypeArguments as JS.ExpressionWithTypeArguments;
1201
1255
  _arguments = this.mapCommaSeparatedList(node.expression.getChildren(this.sourceFile).slice(-3))
1202
1256
  } else if (ts.isCallExpression(node.expression)) {
@@ -1310,7 +1364,7 @@ export class JavaScriptParserVisitor {
1310
1364
  prefix: prefix,
1311
1365
  markers: emptyMarkers,
1312
1366
  leadingAnnotations: [], // no decorators allowed
1313
- modifiers: [], // no modifiers allowed
1367
+ modifiers: this.mapModifiers(node),
1314
1368
  typeParameters: this.mapTypeParametersAsObject(node),
1315
1369
  returnTypeExpression: this.mapTypeInfo(node),
1316
1370
  name: produce(this.convert<ComputedPropertyName>(node.name), draft => {
@@ -1331,7 +1385,7 @@ export class JavaScriptParserVisitor {
1331
1385
  prefix: prefix,
1332
1386
  markers: emptyMarkers,
1333
1387
  leadingAnnotations: [], // no decorators allowed
1334
- modifiers: [], // no modifiers allowed
1388
+ modifiers: this.mapModifiers(node),
1335
1389
  typeParameters: this.mapTypeParametersAsObject(node),
1336
1390
  returnTypeExpression: this.mapTypeInfo(node),
1337
1391
  nameAnnotations: [],
@@ -1361,6 +1415,7 @@ export class JavaScriptParserVisitor {
1361
1415
  });
1362
1416
 
1363
1417
  if (ts.isComputedPropertyName(node.name)) {
1418
+ this.reject(this.trailingDecorators(node));
1364
1419
  return {
1365
1420
  kind: JS.Kind.ComputedPropertyMethodDeclaration,
1366
1421
  id: randomId(),
@@ -1386,7 +1441,7 @@ export class JavaScriptParserVisitor {
1386
1441
  modifiers: this.mapModifiers(node),
1387
1442
  typeParameters: this.mapTypeParametersAsObject(node),
1388
1443
  returnTypeExpression: this.mapTypeInfo(node),
1389
- nameAnnotations: [],
1444
+ nameAnnotations: this.mapTrailingDecorators(node),
1390
1445
  name: name as J.Identifier,
1391
1446
  parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
1392
1447
  dimensionsAfterName: [],
@@ -1430,6 +1485,7 @@ export class JavaScriptParserVisitor {
1430
1485
  }
1431
1486
 
1432
1487
  visitClassStaticBlockDeclaration(node: ts.ClassStaticBlockDeclaration): J.Block {
1488
+ this.reject((node as WithInvalidSyntaxSlots<ts.ClassStaticBlockDeclaration>).modifiers);
1433
1489
  return {
1434
1490
  kind: J.Kind.Block,
1435
1491
  id: randomId(),
@@ -1606,7 +1662,7 @@ export class JavaScriptParserVisitor {
1606
1662
  id: randomId(),
1607
1663
  prefix: this.prefix(node),
1608
1664
  markers: emptyMarkers,
1609
- modifiers: this.mapModifiers(node),
1665
+ modifiers: this.mapDecoratedModifiers(node.modifiers),
1610
1666
  parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node, ts.SyntaxKind.OpenBracketToken)),
1611
1667
  typeExpression: this.leftPadded(this.prefix(node.getChildAt(node.getChildren().indexOf(node.type) - 1)), this.convert(node.type)),
1612
1668
  type: this.mapType(node)
@@ -1634,7 +1690,7 @@ export class JavaScriptParserVisitor {
1634
1690
  prefix: this.prefix(node),
1635
1691
  markers: emptyMarkers,
1636
1692
  class: this.visit(node.typeName),
1637
- typeParameters: this.mapTypeArguments(this.suffix(node.typeName), node.typeArguments),
1693
+ typeParameters: this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments),
1638
1694
  type: this.mapType(node)
1639
1695
  }
1640
1696
  }
@@ -1684,7 +1740,7 @@ export class JavaScriptParserVisitor {
1684
1740
  prefix: this.prefix(node),
1685
1741
  markers: emptyMarkers,
1686
1742
  typeExpression: this.convert(node.exprName),
1687
- typeArguments: node.typeArguments && this.mapTypeArguments(this.suffix(node.exprName), node.typeArguments),
1743
+ typeArguments: node.typeArguments && this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments),
1688
1744
  type: this.mapType(node)
1689
1745
  }
1690
1746
  }
@@ -2089,7 +2145,7 @@ export class JavaScriptParserVisitor {
2089
2145
  markers: emptyMarkers
2090
2146
  },
2091
2147
  qualifier: node.qualifier && this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.DotToken)!), this.visit(node.qualifier)),
2092
- typeArguments: node.typeArguments && this.mapTypeArguments(this.prefix(this.findChildNode(node, ts.SyntaxKind.LessThanToken)!), node.typeArguments),
2148
+ typeArguments: node.typeArguments && this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments),
2093
2149
  type: this.mapType(node)
2094
2150
  };
2095
2151
  }
@@ -2244,9 +2300,8 @@ export class JavaScriptParserVisitor {
2244
2300
 
2245
2301
  visitCallExpression(node: ts.CallExpression): J.MethodInvocation | JS.FunctionCall {
2246
2302
  const prefix = this.prefix(node);
2247
- const ltToken = this.findChildNode(node, ts.SyntaxKind.LessThanToken);
2248
- const typeArguments = node.typeArguments && ltToken
2249
- ? this.mapTypeArguments(this.prefix(ltToken), node.typeArguments)
2303
+ const typeArguments = node.typeArguments
2304
+ ? this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments)
2250
2305
  : undefined;
2251
2306
 
2252
2307
  let select: J.RightPadded<Expression> | undefined;
@@ -2348,7 +2403,7 @@ export class JavaScriptParserVisitor {
2348
2403
  }
2349
2404
  return typeTree;
2350
2405
  })(),
2351
- typeParameters: this.mapTypeArguments(this.prefix(this.findChildNode(node, ts.SyntaxKind.LessThanToken)!), node.typeArguments),
2406
+ typeParameters: this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments),
2352
2407
  type: undefined
2353
2408
  } satisfies J.ParameterizedType as J.ParameterizedType : this.mapTypeTree(node.expression),
2354
2409
  arguments: node.arguments ?
@@ -2369,7 +2424,7 @@ export class JavaScriptParserVisitor {
2369
2424
  id: randomId(),
2370
2425
  prefix: this.prefix(node),
2371
2426
  markers: emptyMarkers,
2372
- tag: this.rightPadded(this.visit(node.tag), this.suffix(node.tag)),
2427
+ tag: this.rightPadded(this.visit(node.tag), node.typeArguments ? this.typeArgumentsPrefix(node, node.typeArguments) : this.suffix(node.tag)),
2373
2428
  typeArguments: node.typeArguments && this.mapTypeArguments(emptySpace, node.typeArguments),
2374
2429
  templateExpression: this.convert(node.template),
2375
2430
  type: this.mapType(node)
@@ -2838,13 +2893,13 @@ export class JavaScriptParserVisitor {
2838
2893
  prefix: emptySpace,
2839
2894
  markers: emptyMarkers,
2840
2895
  leadingAnnotations: this.mapDecorators(node),
2841
- modifiers: [],
2896
+ modifiers: this.mapKeywordModifiers(node.modifiers),
2842
2897
  classKind: {
2843
2898
  kind: J.Kind.ClassDeclarationKind,
2844
2899
  id: randomId(),
2845
2900
  prefix: node.modifiers ? this.suffix(node.modifiers[node.modifiers.length - 1]) : this.prefix(node),
2846
2901
  markers: emptyMarkers,
2847
- annotations: [],
2902
+ annotations: this.mapTrailingDecorators(node),
2848
2903
  type: J.ClassDeclaration.Kind.Type.Class
2849
2904
  },
2850
2905
  name: node.name ? this.convert(node.name) : this.mapIdentifier(node, ""),
@@ -2885,7 +2940,7 @@ export class JavaScriptParserVisitor {
2885
2940
  prefix: this.prefix(node),
2886
2941
  markers: emptyMarkers,
2887
2942
  clazz: this.visit(node.expression),
2888
- typeArguments: this.mapTypeArguments(this.suffix(node.expression), node.typeArguments),
2943
+ typeArguments: this.mapTypeArguments(this.typeArgumentsPrefix(node, node.typeArguments), node.typeArguments),
2889
2944
  type: this.mapType(node)
2890
2945
  }
2891
2946
  }
@@ -2976,12 +3031,36 @@ export class JavaScriptParserVisitor {
2976
3031
 
2977
3032
  visitVariableStatement(node: ts.VariableStatement): JS.ScopedVariableDeclarations | J.VariableDeclarations {
2978
3033
  const prefix = this.prefix(node);
3034
+ const leading = this.mapDecorators(node);
3035
+ const modifiers = this.mapModifiers(node);
3036
+ const trailing = this.mapTrailingDecorators(node);
2979
3037
  return produce(this.visitVariableDeclarationList(node.declarationList), draft => {
2980
3038
  draft.prefix = prefix;
2981
- draft.modifiers = this.mapModifiers(node).concat(draft.modifiers);
3039
+ // `const`, `let` or `var` is the modifier that follows them
3040
+ draft.modifiers[0].annotations = castDraft(trailing);
3041
+ draft.modifiers = castDraft(modifiers).concat(draft.modifiers);
3042
+ if (draft.kind === J.Kind.VariableDeclarations) {
3043
+ draft.leadingAnnotations = castDraft(leading);
3044
+ } else if (leading.length > 0) {
3045
+ draft.modifiers[0].annotations = castDraft(leading);
3046
+ }
2982
3047
  });
2983
3048
  }
2984
3049
 
3050
+ // A loop variable is a statement in the model, which a pattern or an access expression is not.
3051
+ private asStatement(tree: J): Statement {
3052
+ if (isStatement(tree)) {
3053
+ return tree;
3054
+ }
3055
+ return {
3056
+ kind: JS.Kind.ExpressionStatement,
3057
+ id: randomId(),
3058
+ prefix: emptySpace,
3059
+ markers: emptyMarkers,
3060
+ expression: tree as Expression
3061
+ } satisfies JS.ExpressionStatement as JS.ExpressionStatement;
3062
+ }
3063
+
2985
3064
  visitExpressionStatement(node: ts.ExpressionStatement): Statement {
2986
3065
  const expression: Expression = this.visit(node.expression) as Expression;
2987
3066
  if (isStatement(expression)) {
@@ -3152,7 +3231,7 @@ export class JavaScriptParserVisitor {
3152
3231
  prefix: emptySpace
3153
3232
  }, this.suffix(node.initializer));
3154
3233
  } else {
3155
- return this.rightPadded(this.visit(node.initializer), this.suffix(node.initializer))
3234
+ return this.rightPadded(this.asStatement(this.visit(node.initializer)), this.suffix(node.initializer))
3156
3235
  }
3157
3236
  })(),
3158
3237
  iterable: this.rightPadded(this.visit(node.expression), this.suffix(node.expression))
@@ -3215,7 +3294,7 @@ export class JavaScriptParserVisitor {
3215
3294
  } satisfies JS.ArrayBindingPattern as JS.ArrayBindingPattern,
3216
3295
  } satisfies JS.ExpressionStatement as JS.ExpressionStatement, this.suffix(node.initializer));
3217
3296
  } else if (ts.isObjectLiteralExpression(node.initializer)) {
3218
- return this.rightPadded({
3297
+ return this.rightPadded(this.asStatement({
3219
3298
  kind: JS.Kind.ObjectBindingPattern,
3220
3299
  id: randomId(),
3221
3300
  leadingAnnotations: [],
@@ -3230,9 +3309,9 @@ export class JavaScriptParserVisitor {
3230
3309
  },
3231
3310
  markers: emptyMarkers,
3232
3311
  prefix: emptySpace
3233
- }, this.suffix(node.initializer))
3312
+ } satisfies JS.ObjectBindingPattern as JS.ObjectBindingPattern), this.suffix(node.initializer))
3234
3313
  } else {
3235
- return this.rightPadded(this.visit(node.initializer), this.suffix(node.initializer))
3314
+ return this.rightPadded(this.asStatement(this.visit(node.initializer)), this.suffix(node.initializer))
3236
3315
  }
3237
3316
  })(),
3238
3317
  iterable: this.rightPadded(this.visit(node.expression), this.suffix(node.expression))
@@ -3509,8 +3588,8 @@ export class JavaScriptParserVisitor {
3509
3588
  } satisfies Generator as Generator);
3510
3589
  }
3511
3590
  }),
3512
- leadingAnnotations: [],
3513
- nameAnnotations: [],
3591
+ leadingAnnotations: this.mapDecorators(node),
3592
+ nameAnnotations: this.mapTrailingDecorators(node),
3514
3593
  modifiers: this.mapModifiers(node),
3515
3594
  name: this.mapMethodName(node, methodType) as J.Identifier,
3516
3595
  typeParameters: this.mapTypeParametersAsObject(node),
@@ -3538,14 +3617,14 @@ export class JavaScriptParserVisitor {
3538
3617
  id: randomId(),
3539
3618
  prefix: this.prefix(node),
3540
3619
  markers: emptyMarkers,
3541
- leadingAnnotations: [],
3620
+ leadingAnnotations: this.mapDecorators(node),
3542
3621
  modifiers: this.mapModifiers(node),
3543
3622
  classKind: {
3544
3623
  kind: J.Kind.ClassDeclarationKind,
3545
3624
  id: randomId(),
3546
3625
  prefix: node.modifiers ? this.suffix(node.modifiers[node.modifiers.length - 1]) : this.prefix(node),
3547
3626
  markers: emptyMarkers,
3548
- annotations: [],
3627
+ annotations: this.mapTrailingDecorators(node),
3549
3628
  type: J.ClassDeclaration.Kind.Type.Interface
3550
3629
  },
3551
3630
  name: node.name ? this.convert(node.name) : this.mapIdentifier(node, ""),
@@ -3575,7 +3654,7 @@ export class JavaScriptParserVisitor {
3575
3654
  id: randomId(),
3576
3655
  prefix: this.prefix(node),
3577
3656
  markers: emptyMarkers,
3578
- modifiers: this.mapModifiers(node),
3657
+ modifiers: this.mapDecoratedModifiers(node.modifiers),
3579
3658
  name: this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.TypeKeyword)!), this.visit(node.name)),
3580
3659
  typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
3581
3660
  initializer: this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.EqualsToken)!), this.convert(node.type)),
@@ -3589,14 +3668,14 @@ export class JavaScriptParserVisitor {
3589
3668
  id: randomId(),
3590
3669
  prefix: this.prefix(node),
3591
3670
  markers: emptyMarkers,
3592
- leadingAnnotations: [],
3671
+ leadingAnnotations: this.mapDecorators(node),
3593
3672
  modifiers: this.mapModifiers(node),
3594
3673
  classKind: {
3595
3674
  kind: J.Kind.ClassDeclarationKind,
3596
3675
  id: randomId(),
3597
3676
  prefix: node.modifiers ? this.suffix(node.modifiers[node.modifiers.length - 1]) : this.prefix(node),
3598
3677
  markers: emptyMarkers,
3599
- annotations: [],
3678
+ annotations: this.mapTrailingDecorators(node),
3600
3679
  type: J.ClassDeclaration.Kind.Type.Enum
3601
3680
  },
3602
3681
  name: node.name ? this.convert(node.name) : this.mapIdentifier(node, ""),
@@ -3648,7 +3727,7 @@ export class JavaScriptParserVisitor {
3648
3727
  id: randomId(),
3649
3728
  prefix: emptySpace,
3650
3729
  markers: emptyMarkers,
3651
- modifiers: this.mapModifiers(node),
3730
+ modifiers: this.mapDecoratedModifiers(node.modifiers),
3652
3731
  keywordType: this.leftPadded(
3653
3732
  namespaceKeyword ? this.prefix(namespaceKeyword) : emptySpace,
3654
3733
  keywordType
@@ -3680,7 +3759,7 @@ export class JavaScriptParserVisitor {
3680
3759
  id: randomId(),
3681
3760
  prefix: this.prefix(node),
3682
3761
  markers: emptyMarkers,
3683
- modifiers: this.mapModifiers(node),
3762
+ modifiers: this.mapDecoratedModifiers(node.modifiers),
3684
3763
  keywordType: this.leftPadded(
3685
3764
  namespaceKeyword ? this.prefix(namespaceKeyword) : emptySpace,
3686
3765
  keywordType
@@ -3757,21 +3836,15 @@ export class JavaScriptParserVisitor {
3757
3836
  }
3758
3837
 
3759
3838
  visitNamespaceExportDeclaration(node: ts.NamespaceExportDeclaration): JS.NamespaceDeclaration {
3839
+ const prefix = this.prefix(node);
3840
+ const written = (node as WithInvalidSyntaxSlots<ts.NamespaceExportDeclaration>).modifiers ?? [];
3760
3841
  return {
3761
3842
  kind: JS.Kind.NamespaceDeclaration,
3762
3843
  id: randomId(),
3763
- prefix: this.prefix(node),
3844
+ prefix,
3764
3845
  markers: emptyMarkers,
3765
3846
  modifiers: [
3766
- {
3767
- kind: J.Kind.Modifier,
3768
- id: randomId(),
3769
- prefix: emptySpace,
3770
- markers: emptyMarkers,
3771
- keyword: 'export',
3772
- type: J.ModifierType.LanguageExtension,
3773
- annotations: []
3774
- },
3847
+ ...this.mapDecoratedModifiers([...written, this.findChildNode(node, ts.SyntaxKind.ExportKeyword) as ts.Modifier]),
3775
3848
  {
3776
3849
  kind: J.Kind.Modifier,
3777
3850
  id: randomId(),
@@ -3788,24 +3861,14 @@ export class JavaScriptParserVisitor {
3788
3861
  }
3789
3862
 
3790
3863
  visitImportEqualsDeclaration(node: ts.ImportEqualsDeclaration): JS.Import {
3791
- let exportModifierSuffix: J.Space | undefined = undefined;
3864
+ // mapped before the prefix, so that what is written first takes the leading whitespace
3865
+ const modifiers = this.mapDecoratedModifiers(node.modifiers);
3792
3866
  return {
3793
3867
  kind: JS.Kind.Import,
3794
3868
  id: randomId(),
3795
- modifiers: (() => {
3796
- const exportModifier = node.modifiers?.find(m => m.kind === ts.SyntaxKind.ExportKeyword);
3797
- exportModifierSuffix = exportModifier && this.suffix(exportModifier);
3798
- return exportModifier ? [{
3799
- kind: J.Kind.Modifier,
3800
- id: randomId(),
3801
- prefix: this.prefix(exportModifier),
3802
- markers: emptyMarkers,
3803
- keyword: 'export',
3804
- type: J.ModifierType.LanguageExtension,
3805
- annotations: []
3806
- }] : [];
3807
- })(),
3808
- prefix: exportModifierSuffix ? exportModifierSuffix : this.prefix(node),
3869
+ prefix: this.prefix(this.findChildNode(node, ts.SyntaxKind.ImportKeyword)!),
3870
+ markers: emptyMarkers,
3871
+ modifiers,
3809
3872
  importClause: {
3810
3873
  kind: JS.Kind.ImportClause,
3811
3874
  id: randomId(),
@@ -3822,7 +3885,6 @@ export class JavaScriptParserVisitor {
3822
3885
  name: node.name && this.rightPadded(this.visit(node.name), this.suffix(node.name)),
3823
3886
  namedBindings: undefined
3824
3887
  },
3825
- markers: emptyMarkers,
3826
3888
  moduleSpecifier: undefined,
3827
3889
  attributes: undefined,
3828
3890
  initializer: this.leftPadded(this.suffix(node.name), this.visit(node.moduleReference))
@@ -3835,12 +3897,13 @@ export class JavaScriptParserVisitor {
3835
3897
  }
3836
3898
 
3837
3899
  visitImportDeclaration(node: ts.ImportDeclaration): JS.Import {
3900
+ const modifiers = this.mapDecoratedModifiers(node.modifiers);
3838
3901
  return {
3839
3902
  kind: JS.Kind.Import,
3840
3903
  id: randomId(),
3841
- prefix: this.prefix(node),
3904
+ prefix: this.prefix(this.findChildNode(node, ts.SyntaxKind.ImportKeyword)!),
3842
3905
  markers: emptyMarkers,
3843
- modifiers: [],
3906
+ modifiers,
3844
3907
  importClause: node.importClause && this.visit(node.importClause),
3845
3908
  moduleSpecifier: this.leftPadded(node.importClause ? this.prefix(this.findChildNode(node, ts.SyntaxKind.FromKeyword)!) : emptySpace, this.visit(node.moduleSpecifier)),
3846
3909
  attributes: node.attributes && this.visit(node.attributes)
@@ -3928,6 +3991,7 @@ export class JavaScriptParserVisitor {
3928
3991
  }
3929
3992
 
3930
3993
  visitExportAssignment(node: ts.ExportAssignment): JS.ExportAssignment {
3994
+ this.reject(node.modifiers);
3931
3995
  return {
3932
3996
  kind: JS.Kind.ExportAssignment,
3933
3997
  id: randomId(),
@@ -3942,12 +4006,13 @@ export class JavaScriptParserVisitor {
3942
4006
  }
3943
4007
 
3944
4008
  visitExportDeclaration(node: ts.ExportDeclaration): JS.ExportDeclaration {
4009
+ const modifiers = this.mapDecoratedModifiers(node.modifiers);
3945
4010
  return {
3946
4011
  kind: JS.Kind.ExportDeclaration,
3947
4012
  id: randomId(),
3948
- prefix: this.prefix(node),
4013
+ prefix: this.prefix(this.findChildNode(node, ts.SyntaxKind.ExportKeyword)!),
3949
4014
  markers: emptyMarkers,
3950
- modifiers: this.mapModifiers(node),
4015
+ modifiers,
3951
4016
  typeOnly: this.leftPadded(node.isTypeOnly ? this.prefix(this.findChildNode(node, ts.SyntaxKind.TypeKeyword)!) : emptySpace, node.isTypeOnly),
3952
4017
  exportClause: node.exportClause ? this.visit(node.exportClause) : this.mapIdentifier(this.findChildNode(node, ts.SyntaxKind.AsteriskToken)!, "*"),
3953
4018
  moduleSpecifier: node.moduleSpecifier && this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.FromKeyword)!), this.visit(node.moduleSpecifier)),
@@ -4295,7 +4360,7 @@ export class JavaScriptParserVisitor {
4295
4360
  id: randomId(),
4296
4361
  prefix: this.prefix(node),
4297
4362
  markers: emptyMarkers,
4298
- modifiers: this.mapModifiers(node),
4363
+ modifiers: this.mapDecoratedModifiers((node as WithInvalidSyntaxSlots<ts.PropertyAssignment>).modifiers),
4299
4364
  name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
4300
4365
  assigmentToken: JS.PropertyAssignment.Token.Colon,
4301
4366
  initializer: this.visit(node.initializer)
@@ -4308,7 +4373,7 @@ export class JavaScriptParserVisitor {
4308
4373
  id: randomId(),
4309
4374
  prefix: this.prefix(node),
4310
4375
  markers: emptyMarkers,
4311
- modifiers: this.mapModifiers(node),
4376
+ modifiers: this.mapDecoratedModifiers((node as WithInvalidSyntaxSlots<ts.ShorthandPropertyAssignment>).modifiers),
4312
4377
  name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
4313
4378
  assigmentToken: JS.PropertyAssignment.Token.Equals,
4314
4379
  initializer: node.objectAssignmentInitializer && this.visit(node.objectAssignmentInitializer)
@@ -4333,7 +4398,11 @@ export class JavaScriptParserVisitor {
4333
4398
  prefix: this.prefix(node),
4334
4399
  markers: emptyMarkers,
4335
4400
  annotations: [],
4336
- name: node.name ? ts.isStringLiteral(node.name) ? this.mapIdentifier(node.name, node.name.getText()) : this.convert(node.name) : this.mapIdentifier(node, ""),
4401
+ name: node.name ?
4402
+ ts.isStringLiteral(node.name) ? this.mapIdentifier(node.name, node.name.getText()) :
4403
+ ts.isComputedPropertyName(node.name) ? this.mapComputedEnumMemberName(node.name) :
4404
+ this.convert(node.name) :
4405
+ this.mapIdentifier(node, ""),
4337
4406
  initializer: node.initializer && {
4338
4407
  kind: J.Kind.NewClass,
4339
4408
  id: randomId(),
@@ -4351,6 +4420,18 @@ export class JavaScriptParserVisitor {
4351
4420
  }
4352
4421
  }
4353
4422
 
4423
+ // An enum member is named by an identifier in the model, so the brackets go in a marker.
4424
+ private mapComputedEnumMemberName(node: ts.ComputedPropertyName): J.Identifier {
4425
+ return {
4426
+ ...this.mapIdentifier(node.expression, node.expression.getText()),
4427
+ markers: markers({
4428
+ kind: JS.Markers.Computed,
4429
+ id: randomId(),
4430
+ suffix: this.suffix(node.expression)
4431
+ } satisfies Computed as Computed)
4432
+ };
4433
+ }
4434
+
4354
4435
  visitBundle(node: ts.Bundle) {
4355
4436
  return this.visitUnknown(node);
4356
4437
  }
@@ -4604,6 +4685,17 @@ export class JavaScriptParserVisitor {
4604
4685
  return this.mapToContainer(nodes, this.trailingComma(nodes));
4605
4686
  }
4606
4687
 
4688
+ // `<<` is scanned as one token, so a list whose first type argument starts with `<` has no `<` among the children.
4689
+ private typeArgumentsPrefix(node: ts.Node, typeArguments: ts.NodeArray<ts.TypeNode>): J.Space {
4690
+ const lessThan = this.findChildNode(node, ts.SyntaxKind.LessThanToken);
4691
+ if (lessThan) {
4692
+ return this.prefix(lessThan);
4693
+ }
4694
+ const start = typeArguments.pos - 1;
4695
+ const fullStart = node.getChildren(this.sourceFile).map(child => child.getEnd()).filter(end => end <= start).pop() ?? start;
4696
+ return this.prefix({getFullStart: () => fullStart, getStart: () => start} as ts.Node);
4697
+ }
4698
+
4607
4699
  private mapTypeArguments(prefix: J.Space, nodes: readonly ts.Node[]): J.Container<Expression> {
4608
4700
  if (nodes.length === 0) {
4609
4701
  return emptyContainer();
@@ -4706,8 +4798,25 @@ export class JavaScriptParserVisitor {
4706
4798
  }
4707
4799
  }
4708
4800
 
4709
- private mapDecorators(node: ts.ClassDeclaration | ts.FunctionDeclaration | ts.MethodDeclaration | ts.ConstructorDeclaration | ts.ParameterDeclaration | ts.PropertyDeclaration | ts.SetAccessorDeclaration | ts.GetAccessorDeclaration | ts.ClassExpression): J.Annotation[] {
4710
- return node.modifiers?.filter(ts.isDecorator)?.map(this.convert<J.Annotation>) ?? [];
4801
+ private mapDecorators(node: { readonly modifiers?: ts.NodeArray<ts.ModifierLike> }): J.Annotation[] {
4802
+ const modifiers = node.modifiers ?? [];
4803
+ const firstKeyword = modifiers.findIndex(ts.isModifier);
4804
+ return modifiers.slice(0, firstKeyword < 0 ? modifiers.length : firstKeyword)
4805
+ .filter(ts.isDecorator).map(this.convert<J.Annotation>);
4806
+ }
4807
+
4808
+ // The decorators between the last modifier and the keyword of the declaration.
4809
+ private mapTrailingDecorators(node: { readonly modifiers?: ts.NodeArray<ts.ModifierLike> }): J.Annotation[] {
4810
+ return this.trailingDecorators(node).map(this.convert<J.Annotation>);
4811
+ }
4812
+
4813
+ private trailingDecorators(node: { readonly modifiers?: ts.NodeArray<ts.ModifierLike> }): ts.Decorator[] {
4814
+ const modifiers = node.modifiers ?? [];
4815
+ let afterKeywords = modifiers.length;
4816
+ while (afterKeywords > 0 && ts.isDecorator(modifiers[afterKeywords - 1])) {
4817
+ afterKeywords--;
4818
+ }
4819
+ return afterKeywords === 0 ? [] : modifiers.slice(afterKeywords).filter(ts.isDecorator);
4711
4820
  }
4712
4821
 
4713
4822
  private mapTypeParametersAsContainer(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.ClassExpression): J.Container<J.TypeParameter> | undefined {