@gi-tcg/gts-transpiler 0.6.0 → 0.6.2

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
@@ -1646,7 +1646,7 @@ const LITERAL_FROM_ID_MAPPING_DATA = {
1646
1646
  literalFromId: true
1647
1647
  };
1648
1648
  const DIRECT_ACTION_STUB_MAPPING_DATA = {
1649
- ...DEFAULT_VOLAR_MAPPING_DATA,
1649
+ semantic: true,
1650
1650
  directActionStub: true
1651
1651
  };
1652
1652
  const VERIFICATION_ONLY_MAPPING_DATA = { verification: true };
@@ -1666,13 +1666,22 @@ function getPrintOptions(source, state) {
1666
1666
  getLeadingComments: (node) => node.leadingComments,
1667
1667
  getTrailingComments: (node) => node.trailingComments,
1668
1668
  getMappingData: () => DEFAULT_VOLAR_MAPPING_DATA,
1669
- beforeWriteNode: ({ range, isUntouched, context }) => {
1670
- if (isUntouched || !range) return;
1669
+ beforeWriteNode: ({ range, node, isUntouched, context }) => {
1670
+ if (isUntouched || !range || node.type === "ImportDeclaration") return;
1671
1671
  context.writeMapped("", range.start, range.start, VERIFICATION_ONLY_MAPPING_DATA);
1672
1672
  },
1673
- afterWriteNode: ({ range, isUntouched, context }) => {
1674
- if (isUntouched || !range) return;
1675
- context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
1673
+ afterWriteNode: ({ range, node, isUntouched, context }) => {
1674
+ const [lastImportDecl, lastImportGenerated] = state.lastImportDeclaration ?? [];
1675
+ if (node.type === "ImportDeclaration" && lastImportDecl === node) {
1676
+ context.write("\n");
1677
+ let sourceOffsetBaseBase = lastImportGenerated ? state.contentStartOffset : node.range?.[1] ?? 0;
1678
+ const sourceOffset = sourceOffsetBaseBase + Math.max(0, context.source.slice(sourceOffsetBaseBase).search(/\n/));
1679
+ context.createExtraMapping({
1680
+ start: sourceOffset + 1,
1681
+ end: sourceOffset + 1
1682
+ }, context.generatedOffset, context.generatedOffset, DEFAULT_VOLAR_MAPPING_DATA);
1683
+ } else if (isUntouched || !range) return;
1684
+ else context.writeMapped("", range.end, range.end, VERIFICATION_ONLY_MAPPING_DATA);
1676
1685
  },
1677
1686
  printers: {
1678
1687
  Identifier(node, context) {
@@ -1726,16 +1735,6 @@ function getPrintOptions(source, state) {
1726
1735
  }, generatedStart, generatedEnd, VERIFICATION_ONLY_MAPPING_DATA);
1727
1736
  }
1728
1737
  },
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
1738
  GTSAttributeNameHintStatement(node, context) {
1740
1739
  context.writeNode(node.object);
1741
1740
  context.write(".");
@@ -1847,7 +1846,7 @@ function transformForVolar(ast, option, sourceInfo) {
1847
1846
  directActionStubRange: /* @__PURE__ */ new WeakMap(),
1848
1847
  literalFromIdentifier: /* @__PURE__ */ new WeakSet(),
1849
1848
  lastArgNodes: /* @__PURE__ */ new WeakSet(),
1850
- lastImportDeclarationIfGen: null,
1849
+ lastImportDeclaration: null,
1851
1850
  diagnosticsOnTopNodes: /* @__PURE__ */ new WeakSet(),
1852
1851
  extraMappings: [],
1853
1852
  contentStartOffset: getContentStartOffset(sourceInfo.content)
@@ -1863,9 +1862,16 @@ function transformForVolar(ast, option, sourceInfo) {
1863
1862
  if (lastArg) state.lastArgNodes.add(lastArg);
1864
1863
  },
1865
1864
  ImportDeclaration(node, { state }) {
1866
- if (!state.sourceNodes.has(node)) state.lastImportDeclarationIfGen = node;
1865
+ state.lastImportDeclaration = [node, !state.sourceNodes.has(node)];
1867
1866
  }
1868
1867
  });
1868
+ walk(newAst, state, { Program(node, { state }) {
1869
+ const lastImportDeclarationNode = state.lastImportDeclaration?.[0];
1870
+ if (lastImportDeclarationNode) {
1871
+ const index = node.body.indexOf(lastImportDeclarationNode);
1872
+ if (index >= 0) node.body.splice(index + 1, 0, { type: "EmptyStatement" });
1873
+ }
1874
+ } });
1869
1875
  let { code, mappings } = print$1(newAst, getPrintOptions(sourceInfo.content, state));
1870
1876
  code = applyReplacements(state, code, mappings);
1871
1877
  for (const extraMapping of state.extraMappings) {
@@ -1878,12 +1884,6 @@ function transformForVolar(ast, option, sourceInfo) {
1878
1884
  data: VERIFICATION_ONLY_MAPPING_DATA
1879
1885
  });
1880
1886
  }
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
1887
  return {
1888
1888
  code,
1889
1889
  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.2",
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,
@@ -30,7 +30,7 @@ export const LITERAL_FROM_ID_MAPPING_DATA: CodeInformation = {
30
30
  literalFromId: true,
31
31
  }
32
32
  export const DIRECT_ACTION_STUB_MAPPING_DATA: CodeInformation = {
33
- ...DEFAULT_VOLAR_MAPPING_DATA,
33
+ semantic: true,
34
34
  directActionStub: true,
35
35
  }
36
36
  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 */