@esportsplus/typescript 0.28.2 → 0.28.3

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.
@@ -6,7 +6,11 @@ type CoordinatorResult = {
6
6
  sourceFile: ts.SourceFile;
7
7
  };
8
8
  declare const _default: {
9
- transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, shared: SharedContext) => CoordinatorResult;
9
+ transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, shared: SharedContext) => {
10
+ changed: boolean;
11
+ code: string;
12
+ sourceFile: ts.SourceFile;
13
+ };
10
14
  };
11
15
  export default _default;
12
16
  export type { CoordinatorResult };
@@ -117,32 +117,49 @@ const transform = (plugins, code, file, program, shared) => {
117
117
  if (plugins.length === 0) {
118
118
  return { changed: false, code, sourceFile: file };
119
119
  }
120
- let checker = program.getTypeChecker(), currentCode = code, currentFile = file, fileName = file.fileName;
120
+ let allImports = [], allPrepend = [], allReplacements = [], checker = program.getTypeChecker(), fileName = file.fileName, originalFile = file;
121
121
  for (let i = 0, n = plugins.length; i < n; i++) {
122
122
  let plugin = plugins[i];
123
- if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
123
+ if (plugin.patterns && !hasPattern(code, plugin.patterns)) {
124
124
  continue;
125
125
  }
126
126
  let { imports, prepend, replacements } = plugin.transform({
127
127
  checker,
128
- code: currentCode,
128
+ code,
129
129
  program,
130
130
  shared,
131
- sourceFile: currentFile
131
+ sourceFile: originalFile
132
132
  });
133
133
  if (replacements?.length) {
134
- currentCode = applyIntents(currentCode, currentFile, replacements);
135
- currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
134
+ allReplacements.push(...replacements);
136
135
  }
137
136
  if (prepend?.length) {
138
- currentCode = applyPrepend(currentCode, currentFile, prepend);
139
- currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
137
+ allPrepend.push(...prepend);
140
138
  }
141
139
  if (imports?.length) {
142
- currentCode = applyImports(currentCode, currentFile, imports);
143
- currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
140
+ allImports.push(...imports);
144
141
  }
145
142
  }
143
+ let currentCode = code, currentFile = originalFile;
144
+ if (allReplacements.length > 0) {
145
+ allReplacements.sort((a, b) => a.node.getStart(originalFile) - b.node.getStart(originalFile));
146
+ for (let i = 1, n = allReplacements.length; i < n; i++) {
147
+ let prev = allReplacements[i - 1], curr = allReplacements[i], prevEnd = prev.node.end, currStart = curr.node.getStart(originalFile);
148
+ if (currStart < prevEnd) {
149
+ console.warn(`[coordinator] Overlapping replacements detected at ${fileName}:`, `[${prev.node.getStart(originalFile)}-${prevEnd}] overlaps [${currStart}-${curr.node.end}]`);
150
+ }
151
+ }
152
+ currentCode = applyIntents(currentCode, currentFile, allReplacements);
153
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
154
+ }
155
+ if (allPrepend.length > 0) {
156
+ currentCode = applyPrepend(currentCode, currentFile, allPrepend);
157
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
158
+ }
159
+ if (allImports.length > 0) {
160
+ currentCode = applyImports(currentCode, currentFile, allImports);
161
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
162
+ }
146
163
  return {
147
164
  changed: currentCode !== code,
148
165
  code: currentCode,
@@ -3,6 +3,7 @@ import coordinator from '../coordinator.js';
3
3
  import program from '../program.js';
4
4
  const FILE_REGEX = /\.[tj]sx?$/;
5
5
  const DIRECTORY_SEPARATOR_REGEX = /\\/g;
6
+ const LINE_ENDINGS_REGEX = /\r\n/g;
6
7
  let contexts = new Map();
7
8
  export default ({ name, onWatchChange, plugins }) => {
8
9
  return ({ root } = {}) => {
@@ -18,7 +19,8 @@ export default ({ name, onWatchChange, plugins }) => {
18
19
  }
19
20
  try {
20
21
  let prog = program.get(root || ''), sourceFile = prog.getSourceFile(id.replace(DIRECTORY_SEPARATOR_REGEX, '/')) || prog.getSourceFile(id);
21
- if (!sourceFile || sourceFile.getText() !== code) {
22
+ if (!sourceFile ||
23
+ sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
22
24
  sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
23
25
  }
24
26
  let result = coordinator.transform(plugins, code, sourceFile, prog, contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || ''));
package/package.json CHANGED
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "type": "module",
41
41
  "types": "build/index.d.ts",
42
- "version": "0.28.2",
42
+ "version": "0.28.3",
43
43
  "scripts": {
44
44
  "build": "tsc && tsc-alias",
45
45
  "-": "-"
@@ -169,73 +169,94 @@ function replaceReverse(code: string, replacements: Replacement[]): string {
169
169
  };
170
170
 
171
171
 
172
- /**
173
- * Transform source through all plugins sequentially.
174
- * Each plugin receives fresh AST with accurate positions.
175
- * All plugins share the original program type checker for import resolution.
176
- */
177
172
  const transform = (
178
173
  plugins: Plugin[],
179
174
  code: string,
180
175
  file: ts.SourceFile,
181
176
  program: ts.Program,
182
177
  shared: SharedContext
183
- ): CoordinatorResult => {
178
+ ) => {
184
179
  if (plugins.length === 0) {
185
180
  return { changed: false, code, sourceFile: file };
186
181
  }
187
182
 
188
- let checker = program.getTypeChecker(),
189
- currentCode = code,
190
- currentFile = file,
191
- fileName = file.fileName;
192
-
183
+ let allImports = [],
184
+ allPrepend = [],
185
+ allReplacements = [],
186
+ checker = program.getTypeChecker(),
187
+ fileName = file.fileName,
188
+ // Keep original source file for symbol resolution - checker operations
189
+ // require nodes from a file that's part of the program's module graph
190
+ originalFile = file;
191
+
192
+ // Phase 1: Collect intents from all plugins using original source file
193
+ // This ensures checker.getSymbolAtLocation() and getAliasedSymbol() work
194
+ // correctly for re-exports and module resolution
193
195
  for (let i = 0, n = plugins.length; i < n; i++) {
194
196
  let plugin = plugins[i];
195
197
 
196
- if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
198
+ if (plugin.patterns && !hasPattern(code, plugin.patterns)) {
197
199
  continue;
198
200
  }
199
201
 
200
202
  let { imports, prepend, replacements } = plugin.transform({
201
- checker,
202
- code: currentCode,
203
- program,
204
- shared,
205
- sourceFile: currentFile
206
- });
203
+ checker,
204
+ code,
205
+ program,
206
+ shared,
207
+ sourceFile: originalFile
208
+ });
207
209
 
208
210
  if (replacements?.length) {
209
- currentCode = applyIntents(currentCode, currentFile, replacements);
210
- currentFile = ts.createSourceFile(
211
- fileName,
212
- currentCode,
213
- currentFile.languageVersion,
214
- true
215
- );
211
+ allReplacements.push(...replacements);
216
212
  }
217
213
 
218
214
  if (prepend?.length) {
219
- currentCode = applyPrepend(currentCode, currentFile, prepend);
220
- currentFile = ts.createSourceFile(
221
- fileName,
222
- currentCode,
223
- currentFile.languageVersion,
224
- true
225
- );
215
+ allPrepend.push(...prepend);
226
216
  }
227
217
 
228
218
  if (imports?.length) {
229
- currentCode = applyImports(currentCode, currentFile, imports);
230
- currentFile = ts.createSourceFile(
231
- fileName,
232
- currentCode,
233
- currentFile.languageVersion,
234
- true
235
- );
219
+ allImports.push(...imports);
236
220
  }
237
221
  }
238
222
 
223
+ // Phase 2: Apply all collected intents
224
+ let currentCode = code,
225
+ currentFile = originalFile;
226
+
227
+ if (allReplacements.length > 0) {
228
+ // Sort by start position to detect overlaps
229
+ allReplacements.sort((a, b) => a.node.getStart(originalFile) - b.node.getStart(originalFile));
230
+
231
+ // Check for overlapping replacements
232
+ for (let i = 1, n = allReplacements.length; i < n; i++) {
233
+ let prev = allReplacements[i - 1],
234
+ curr = allReplacements[i],
235
+ prevEnd = prev.node.end,
236
+ currStart = curr.node.getStart(originalFile);
237
+
238
+ if (currStart < prevEnd) {
239
+ console.warn(
240
+ `[coordinator] Overlapping replacements detected at ${fileName}:`,
241
+ `[${prev.node.getStart(originalFile)}-${prevEnd}] overlaps [${currStart}-${curr.node.end}]`
242
+ );
243
+ }
244
+ }
245
+
246
+ currentCode = applyIntents(currentCode, currentFile, allReplacements);
247
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
248
+ }
249
+
250
+ if (allPrepend.length > 0) {
251
+ currentCode = applyPrepend(currentCode, currentFile, allPrepend);
252
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
253
+ }
254
+
255
+ if (allImports.length > 0) {
256
+ currentCode = applyImports(currentCode, currentFile, allImports);
257
+ currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
258
+ }
259
+
239
260
  return {
240
261
  changed: currentCode !== code,
241
262
  code: currentCode,
@@ -24,6 +24,8 @@ const FILE_REGEX = /\.[tj]sx?$/;
24
24
 
25
25
  const DIRECTORY_SEPARATOR_REGEX = /\\/g;
26
26
 
27
+ const LINE_ENDINGS_REGEX = /\r\n/g;
28
+
27
29
 
28
30
  let contexts = new Map<string, SharedContext>();
29
31
 
@@ -45,7 +47,10 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
45
47
  let prog = program.get(root || ''),
46
48
  sourceFile = prog.getSourceFile(id.replace(DIRECTORY_SEPARATOR_REGEX, '/')) || prog.getSourceFile(id);
47
49
 
48
- if (!sourceFile || sourceFile.getText() !== code) {
50
+ if (
51
+ !sourceFile ||
52
+ sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')
53
+ ) {
49
54
  sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
50
55
  }
51
56