@gi-tcg/gts-transpiler 0.6.0 → 0.6.1

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/index.js CHANGED
@@ -1633,7 +1633,6 @@ const DEFAULT_VOLAR_MAPPING_DATA = {
1633
1633
  completion: true,
1634
1634
  format: true,
1635
1635
  navigation: true,
1636
- semantic: true,
1637
1636
  structure: true,
1638
1637
  verification: true
1639
1638
  };
@@ -1646,7 +1645,7 @@ const LITERAL_FROM_ID_MAPPING_DATA = {
1646
1645
  literalFromId: true
1647
1646
  };
1648
1647
  const DIRECT_ACTION_STUB_MAPPING_DATA = {
1649
- ...DEFAULT_VOLAR_MAPPING_DATA,
1648
+ semantic: true,
1650
1649
  directActionStub: true
1651
1650
  };
1652
1651
  const VERIFICATION_ONLY_MAPPING_DATA = { verification: true };
@@ -1666,13 +1665,22 @@ function getPrintOptions(source, state) {
1666
1665
  getLeadingComments: (node) => node.leadingComments,
1667
1666
  getTrailingComments: (node) => node.trailingComments,
1668
1667
  getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
1669
- beforeWriteNode: ({ range, isUntouched, context }) => {
1670
- if (isUntouched || !range) return;
1668
+ beforeWriteNode: ({ range, node, isUntouched, context }) => {
1669
+ if (isUntouched || !range || node.type === "ImportDeclaration") return;
1671
1670
  context.writeMapped("", range.start, range.start, VERIFICATION_ONLY_MAPPING_DATA);
1672
1671
  },
1673
- afterWriteNode: ({ range, isUntouched, context }) => {
1674
- if (isUntouched || !range) return;
1675
- context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
1672
+ afterWriteNode: ({ range, node, isUntouched, context }) => {
1673
+ const [lastImportDecl, lastImportGenerated] = state.lastImportDeclaration ?? [];
1674
+ if (node.type === "ImportDeclaration" && lastImportDecl === node) {
1675
+ context.write("\n");
1676
+ let sourceOffsetBaseBase = lastImportGenerated ? state.contentStartOffset : node.range?.[1] ?? 0;
1677
+ const sourceOffset = sourceOffsetBaseBase + Math.max(0, context.source.slice(sourceOffsetBaseBase).search(/\n/));
1678
+ context.createExtraMapping({
1679
+ start: sourceOffset + 1,
1680
+ end: sourceOffset + 1
1681
+ }, context.generatedOffset, context.generatedOffset, DEFAULT_VOLAR_MAPPING_DATA);
1682
+ } else if (isUntouched || !range) return;
1683
+ else context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
1676
1684
  },
1677
1685
  printers: {
1678
1686
  Identifier(node, context) {
@@ -1726,16 +1734,6 @@ function getPrintOptions(source, state) {
1726
1734
  }, generatedStart, generatedEnd, VERIFICATION_ONLY_MAPPING_DATA);
1727
1735
  }
1728
1736
  },
1729
- ImportDeclaration(node, context) {
1730
- defaultPrinters.ImportDeclaration(node, context);
1731
- if (state.lastImportDeclarationIfGen === node) {
1732
- context.write("\n");
1733
- context.createExtraMapping({
1734
- start: state.contentStartOffset,
1735
- end: state.contentStartOffset + 1
1736
- }, context.generatedOffset, context.generatedOffset + 1, DEFAULT_VOLAR_MAPPING_DATA);
1737
- }
1738
- },
1739
1737
  GTSAttributeNameHintStatement(node, context) {
1740
1738
  context.writeNode(node.object);
1741
1739
  context.write(".");
@@ -1847,7 +1845,7 @@ function transformForVolar(ast, option, sourceInfo) {
1847
1845
  directActionStubRange: /* @__PURE__ */ new WeakMap(),
1848
1846
  literalFromIdentifier: /* @__PURE__ */ new WeakSet(),
1849
1847
  lastArgNodes: /* @__PURE__ */ new WeakSet(),
1850
- lastImportDeclarationIfGen: null,
1848
+ lastImportDeclaration: null,
1851
1849
  diagnosticsOnTopNodes: /* @__PURE__ */ new WeakSet(),
1852
1850
  extraMappings: [],
1853
1851
  contentStartOffset: getContentStartOffset(sourceInfo.content)
@@ -1863,9 +1861,16 @@ function transformForVolar(ast, option, sourceInfo) {
1863
1861
  if (lastArg) state.lastArgNodes.add(lastArg);
1864
1862
  },
1865
1863
  ImportDeclaration(node, { state }) {
1866
- if (!state.sourceNodes.has(node)) state.lastImportDeclarationIfGen = node;
1864
+ state.lastImportDeclaration = [node, !state.sourceNodes.has(node)];
1867
1865
  }
1868
1866
  });
1867
+ walk(newAst, state, { Program(node, { state }) {
1868
+ const lastImportDeclarationNode = state.lastImportDeclaration?.[0];
1869
+ if (lastImportDeclarationNode) {
1870
+ const index = node.body.indexOf(lastImportDeclarationNode);
1871
+ if (index >= 0) node.body.splice(index + 1, 0, { type: "EmptyStatement" });
1872
+ }
1873
+ } });
1869
1874
  let { code, mappings } = print$1(newAst, getPrintOptions(sourceInfo.content, state));
1870
1875
  code = applyReplacements(state, code, mappings);
1871
1876
  for (const extraMapping of state.extraMappings) {
@@ -1878,12 +1883,6 @@ function transformForVolar(ast, option, sourceInfo) {
1878
1883
  data: VERIFICATION_ONLY_MAPPING_DATA
1879
1884
  });
1880
1885
  }
1881
- walk(newAst, null, { ImportDeclaration(node) {
1882
- if (!node.range) return;
1883
- const endOffset = node.range[1];
1884
- const mappingEndsWithThisImport = mappings.find((m) => m.sourceOffsets[0] + m.lengths[0] === endOffset);
1885
- if (mappingEndsWithThisImport?.lengths[0]) mappingEndsWithThisImport.lengths[0] += 1;
1886
- } });
1887
1886
  return {
1888
1887
  code,
1889
1888
  mappings
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gi-tcg/gts-transpiler",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/piovium/gts.git"
@@ -46,7 +46,7 @@ export function transformForVolar(
46
46
  directActionStubRange: new WeakMap(),
47
47
  literalFromIdentifier: new WeakSet(),
48
48
  lastArgNodes: new WeakSet(),
49
- lastImportDeclarationIfGen: null,
49
+ lastImportDeclaration: null,
50
50
  diagnosticsOnTopNodes: new WeakSet(),
51
51
  extraMappings: [],
52
52
  contentStartOffset: getContentStartOffset(sourceInfo.content),
@@ -61,7 +61,7 @@ export function transformForVolar(
61
61
  },
62
62
  });
63
63
  const newAst = walk(ast as AST.Node, state, gtsToTypingsWalker);
64
- // mark lastArgNodes
64
+ // mark lastArgNodes and lastImportDeclaration
65
65
  walk(newAst as AST.Node, state, {
66
66
  CallExpression(node, { state }) {
67
67
  const lastArg = node.arguments.at(-1);
@@ -70,11 +70,22 @@ export function transformForVolar(
70
70
  }
71
71
  },
72
72
  ImportDeclaration(node, { state }) {
73
- if (!state.sourceNodes.has(node)) {
74
- state.lastImportDeclarationIfGen = node;
73
+ state.lastImportDeclaration = [node, !state.sourceNodes.has(node)];
74
+ },
75
+ });
76
+ walk(newAst, state, {
77
+ Program(node, { state }) {
78
+ const lastImportDeclarationNode = state.lastImportDeclaration?.[0];
79
+ // break continuous gap between last import declaration and its next node
80
+ if (lastImportDeclarationNode) {
81
+ const index = node.body.indexOf(lastImportDeclarationNode);
82
+ if (index >= 0) {
83
+ node.body.splice(index + 1, 0, { type: "EmptyStatement" });
84
+ }
75
85
  }
76
86
  },
77
87
  });
88
+
78
89
  const printOptions = getPrintOptions(sourceInfo.content, state);
79
90
  let { code, mappings } = print(newAst, printOptions);
80
91
  code = applyReplacements(state, code, mappings);
@@ -88,20 +99,6 @@ export function transformForVolar(
88
99
  data: VERIFICATION_ONLY_MAPPING_DATA,
89
100
  });
90
101
  }
91
- walk(newAst, null, {
92
- ImportDeclaration(node) {
93
- if (!node.range) {
94
- return;
95
- }
96
- const endOffset = node.range[1];
97
- const mappingEndsWithThisImport = mappings.find(
98
- (m) => m.sourceOffsets[0] + m.lengths[0] === endOffset,
99
- );
100
- if (mappingEndsWithThisImport?.lengths[0]) {
101
- mappingEndsWithThisImport.lengths[0] += 1; // include the newline after the import
102
- }
103
- },
104
- });
105
102
  return {
106
103
  code,
107
104
  mappings,
@@ -17,7 +17,6 @@ export const DEFAULT_VOLAR_MAPPING_DATA: CodeInformation = {
17
17
  completion: true,
18
18
  format: true,
19
19
  navigation: true,
20
- semantic: true,
21
20
  structure: true,
22
21
  verification: true,
23
22
  };
@@ -30,7 +29,7 @@ export const LITERAL_FROM_ID_MAPPING_DATA: CodeInformation = {
30
29
  literalFromId: true,
31
30
  }
32
31
  export const DIRECT_ACTION_STUB_MAPPING_DATA: CodeInformation = {
33
- ...DEFAULT_VOLAR_MAPPING_DATA,
32
+ semantic: true,
34
33
  directActionStub: true,
35
34
  }
36
35
  export const VERIFICATION_ONLY_MAPPING_DATA: CodeInformation = {
@@ -20,7 +20,10 @@ import {
20
20
  LITERAL_FROM_ID_MAPPING_DATA,
21
21
  VERIFICATION_ONLY_MAPPING_DATA,
22
22
  } from "./mappings.ts";
23
- import type { TypingTranspileState, GTSAttributeNameHintStatement } from "./walker.ts";
23
+ import type {
24
+ TypingTranspileState,
25
+ GTSAttributeNameHintStatement,
26
+ } from "./walker.ts";
24
27
 
25
28
  export function getPrintOptions(
26
29
  source: string,
@@ -37,23 +40,61 @@ export function getPrintOptions(
37
40
  }
38
41
  return state.sourceNodes.has(node as Node);
39
42
  },
43
+
40
44
  printCommentsOnUntouchedNodes: true,
41
45
  getLeadingComments: (node) => (node as Node).leadingComments,
42
46
  getTrailingComments: (node) => (node as Node).trailingComments,
43
47
  getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
44
48
  // Add a 0-length mapping before and after each touched node with verification only,
45
49
  // so that error squiggles start/ends at those positions can be reflected.
46
- beforeWriteNode: ({ range, isUntouched, context }) => {
47
- if (isUntouched || !range) {
50
+ beforeWriteNode: ({ range, node, isUntouched, context }) => {
51
+ if (isUntouched || !range || node.type === "ImportDeclaration") {
52
+ // Don't do that for ImportDeclaration -- it mess up auto-import insertion point
48
53
  return;
49
54
  }
50
- context.writeMapped("", range.start, range.start, VERIFICATION_ONLY_MAPPING_DATA);
55
+ context.writeMapped(
56
+ "",
57
+ range.start,
58
+ range.start,
59
+ VERIFICATION_ONLY_MAPPING_DATA,
60
+ );
51
61
  },
52
- afterWriteNode: ({ range, isUntouched, context }) => {
53
- if (isUntouched || !range) {
62
+ afterWriteNode: ({ range, node, isUntouched, context }) => {
63
+ const [lastImportDecl, lastImportGenerated] =
64
+ state.lastImportDeclaration ?? [];
65
+ if (node.type === "ImportDeclaration" && lastImportDecl === node) {
66
+ // If the last import declaration is a generated one, because of we ensured that
67
+ // the generated import declarations are always unsorted, so TSServer will set the
68
+ // auto-insertion point next to this last import declaration.
69
+ // Add a mapping to that position (a written newline character) to the top-of-file,
70
+ // after skipping hashbang and leading comments.
71
+ context.write("\n");
72
+ let sourceOffsetBaseBase = lastImportGenerated
73
+ ? state.contentStartOffset
74
+ : (node.range?.[1] ?? 0);
75
+ const sourceOffset =
76
+ sourceOffsetBaseBase +
77
+ Math.max(0, context.source.slice(sourceOffsetBaseBase).search(/\n/));
78
+ // These +1s below is magic and I don't know why, but it works.
79
+ context.createExtraMapping(
80
+ {
81
+ start: sourceOffset + 1,
82
+ end: sourceOffset + 1,
83
+ },
84
+ context.generatedOffset,
85
+ context.generatedOffset,
86
+ DEFAULT_VOLAR_MAPPING_DATA,
87
+ );
88
+ } else if (isUntouched || !range) {
54
89
  return;
90
+ } else {
91
+ context.writeMapped(
92
+ "",
93
+ range.end,
94
+ range.end,
95
+ VERIFICATION_ONLY_MAPPING_DATA,
96
+ );
55
97
  }
56
- context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
57
98
  },
58
99
  printers: {
59
100
  // 1) Make the print of dummy identifier print nothing.
@@ -115,7 +156,9 @@ export function getPrintOptions(
115
156
  node.range[1],
116
157
  ATTRIBUTE_NAME_MAPPING_DATA,
117
158
  );
118
- } else if ((directActionStubRange = state.directActionStubRange.get(node))) {
159
+ } else if (
160
+ (directActionStubRange = state.directActionStubRange.get(node))
161
+ ) {
119
162
  // For direct action stubs, add mappings from this expression statement line to the
120
163
  // start of original direct action start position. Add `directActionStub` data
121
164
  // for recognizing them in language service plugin.
@@ -124,7 +167,7 @@ export function getPrintOptions(
124
167
  directActionStubRange.start,
125
168
  directActionStubRange.start + 1,
126
169
  DIRECT_ACTION_STUB_MAPPING_DATA,
127
- )
170
+ );
128
171
  } else {
129
172
  defaultPrinters.Literal(node, context);
130
173
  }
@@ -168,37 +211,17 @@ export function getPrintOptions(
168
211
  );
169
212
  }
170
213
  },
171
- // If the last import declaration is a generated one, because of we ensured that
172
- // the generated import declarations are always unsorted, so TSServer will set the
173
- // auto-insertion point next to this last import declaration.
174
- // Add a mapping to that position (a written newline character) to the top-of-file,
175
- // after skipping hashbang and leading comments.
176
- // NOTE: since the insertion derived from here won't add additional newline *before*
177
- // the inserted text, so here is a difference behavior from standard TSServer and our
178
- // language server. We'd try our best.
179
- ImportDeclaration(node, context) {
180
- defaultPrinters.ImportDeclaration(node, context);
181
- if (state.lastImportDeclarationIfGen === node) {
182
- context.write("\n");
183
- context.createExtraMapping(
184
- {
185
- start: state.contentStartOffset,
186
- end: state.contentStartOffset + 1,
187
- },
188
- context.generatedOffset,
189
- context.generatedOffset + 1,
190
- DEFAULT_VOLAR_MAPPING_DATA,
191
- );
192
- }
193
- },
194
214
  // @ts-expect-error This is a custom node type that don't have typing.
195
215
  // @see `GTSAttributeNameHintStatement`
196
- GTSAttributeNameHintStatement(node: GTSAttributeNameHintStatement, context: PrinterContext<CodeInformation>) {
216
+ GTSAttributeNameHintStatement(
217
+ node: GTSAttributeNameHintStatement,
218
+ context: PrinterContext<CodeInformation>,
219
+ ) {
197
220
  context.writeNode(node.object as EspolarAST.Node);
198
221
  context.write(".");
199
222
  context.writeSource(node.whiteSpaceStart, node.whiteSpaceEnd);
200
223
  context.write(";");
201
- }
224
+ },
202
225
  },
203
226
  // Enable triggering signature completion
204
227
  experimentalGetLeftParenSourceRange: (node) => {
@@ -76,10 +76,10 @@ export interface TypingTranspileState extends TranspileState {
76
76
  /** Nodes that are last arguments of a CallExpression */
77
77
  lastArgNodes: WeakSet<Node>;
78
78
  /**
79
- * The last import declaration, record if it is a generated one.
80
- * This declaration marks the TS auto-import insertion point.
79
+ * The last import declaration and whether it is a generated one.
80
+ * This declaration marks the TS auto-import insertion point if it's generated.
81
81
  */
82
- lastImportDeclarationIfGen: ImportDeclaration | null;
82
+ lastImportDeclaration: [node: ImportDeclaration, generated: boolean] | null;
83
83
  /** Nodes that have a diagnostic mappings to the top of the file */
84
84
  diagnosticsOnTopNodes: WeakSet<Node>;
85
85
  /** Extra mappings, the generated range will be found by the needle after replacement */