@esportsplus/typescript 0.28.3 → 0.28.5

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,6 +6,7 @@ type CoordinatorResult = {
6
6
  sourceFile: ts.SourceFile;
7
7
  };
8
8
  declare const _default: {
9
+ createPatchedProgram: (baseProgram: ts.Program, fileName: string, newContent: string) => ts.Program;
9
10
  transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, shared: SharedContext) => {
10
11
  changed: boolean;
11
12
  code: string;
@@ -99,7 +99,6 @@ function modify(code, file, pkg, options) {
99
99
  }
100
100
  return replaceReverse(code, replacements);
101
101
  }
102
- ;
103
102
  function replaceReverse(code, replacements) {
104
103
  if (replacements.length === 0) {
105
104
  return code;
@@ -112,58 +111,61 @@ function replaceReverse(code, replacements) {
112
111
  }
113
112
  return result;
114
113
  }
115
- ;
114
+ const createPatchedProgram = (baseProgram, fileName, newContent) => {
115
+ let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()), options = baseProgram.getCompilerOptions();
116
+ return ts.createProgram(baseProgram.getRootFileNames(), options, {
117
+ ...baseHost,
118
+ getSourceFile: (name, languageVersion) => {
119
+ if (name === fileName || name === fileName.replace(/\\/g, '/')) {
120
+ return ts.createSourceFile(name, newContent, languageVersion, true);
121
+ }
122
+ return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
123
+ },
124
+ fileExists: (name) => baseHost.fileExists(name),
125
+ readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
126
+ }, baseProgram);
127
+ };
116
128
  const transform = (plugins, code, file, program, shared) => {
117
129
  if (plugins.length === 0) {
118
130
  return { changed: false, code, sourceFile: file };
119
131
  }
120
- let allImports = [], allPrepend = [], allReplacements = [], checker = program.getTypeChecker(), fileName = file.fileName, originalFile = file;
132
+ let changed = false, currentCode = code, currentFile = file, currentProgram = program, fileName = file.fileName;
121
133
  for (let i = 0, n = plugins.length; i < n; i++) {
122
134
  let plugin = plugins[i];
123
- if (plugin.patterns && !hasPattern(code, plugin.patterns)) {
135
+ if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
124
136
  continue;
125
137
  }
126
138
  let { imports, prepend, replacements } = plugin.transform({
127
- checker,
128
- code,
129
- program,
139
+ checker: currentProgram.getTypeChecker(),
140
+ code: currentCode,
141
+ program: currentProgram,
130
142
  shared,
131
- sourceFile: originalFile
132
- });
143
+ sourceFile: currentFile
144
+ }), pluginChanged = false;
133
145
  if (replacements?.length) {
134
- allReplacements.push(...replacements);
146
+ currentCode = applyIntents(currentCode, currentFile, replacements);
147
+ pluginChanged = true;
135
148
  }
136
149
  if (prepend?.length) {
137
- allPrepend.push(...prepend);
150
+ currentCode = applyPrepend(currentCode, currentFile, prepend);
151
+ pluginChanged = true;
138
152
  }
139
153
  if (imports?.length) {
140
- allImports.push(...imports);
154
+ currentCode = applyImports(currentCode, currentFile, imports);
155
+ pluginChanged = true;
141
156
  }
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}]`);
157
+ if (pluginChanged) {
158
+ changed = true;
159
+ if (i < n - 1) {
160
+ currentProgram = createPatchedProgram(program, fileName, currentCode);
161
+ currentFile = currentProgram.getSourceFile(fileName) ||
162
+ ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
163
+ }
164
+ else {
165
+ currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
150
166
  }
151
167
  }
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
- }
163
- return {
164
- changed: currentCode !== code,
165
- code: currentCode,
166
- sourceFile: currentFile
167
- };
168
+ }
169
+ return { changed, code: currentCode, sourceFile: currentFile };
168
170
  };
169
- export default { transform };
171
+ export default { createPatchedProgram, transform };
@@ -18,10 +18,13 @@ export default ({ name, onWatchChange, plugins }) => {
18
18
  return null;
19
19
  }
20
20
  try {
21
- let prog = program.get(root || ''), sourceFile = prog.getSourceFile(id.replace(DIRECTORY_SEPARATOR_REGEX, '/')) || prog.getSourceFile(id);
22
- if (!sourceFile ||
23
- sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
24
- sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
21
+ let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'), prog = program.get(root || ''), sourceFile = prog.getSourceFile(normalizedId) || prog.getSourceFile(id);
22
+ if (sourceFile && sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
23
+ sourceFile = undefined;
24
+ }
25
+ if (!sourceFile) {
26
+ prog = coordinator.createPatchedProgram(prog, normalizedId, code);
27
+ sourceFile = prog.getSourceFile(normalizedId) || ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
25
28
  }
26
29
  let result = coordinator.transform(plugins, code, sourceFile, prog, contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || ''));
27
30
  if (!result.changed) {
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.3",
42
+ "version": "0.28.5",
43
43
  "scripts": {
44
44
  "build": "tsc && tsc-alias",
45
45
  "-": "-"
@@ -148,7 +148,7 @@ function modify(code: string, file: ts.SourceFile, pkg: string, options: ModifyO
148
148
  }
149
149
 
150
150
  return replaceReverse(code, replacements);
151
- };
151
+ }
152
152
 
153
153
  function replaceReverse(code: string, replacements: Replacement[]): string {
154
154
  if (replacements.length === 0) {
@@ -166,9 +166,31 @@ function replaceReverse(code: string, replacements: Replacement[]): string {
166
166
  }
167
167
 
168
168
  return result;
169
- };
169
+ }
170
170
 
171
171
 
172
+ const createPatchedProgram = (baseProgram: ts.Program, fileName: string, newContent: string) => {
173
+ let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()),
174
+ options = baseProgram.getCompilerOptions();
175
+
176
+ return ts.createProgram(
177
+ baseProgram.getRootFileNames(),
178
+ options,
179
+ {
180
+ ...baseHost,
181
+ getSourceFile: (name, languageVersion) => {
182
+ if (name === fileName || name === fileName.replace(/\\/g, '/')) {
183
+ return ts.createSourceFile(name, newContent, languageVersion, true);
184
+ }
185
+ return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
186
+ },
187
+ fileExists: (name) => baseHost.fileExists(name),
188
+ readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
189
+ },
190
+ baseProgram
191
+ );
192
+ };
193
+
172
194
  const transform = (
173
195
  plugins: Plugin[],
174
196
  code: string,
@@ -180,90 +202,60 @@ const transform = (
180
202
  return { changed: false, code, sourceFile: file };
181
203
  }
182
204
 
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
205
+ let changed = false,
206
+ currentCode = code,
207
+ currentFile = file,
208
+ currentProgram = program,
209
+ fileName = file.fileName;
210
+
195
211
  for (let i = 0, n = plugins.length; i < n; i++) {
196
212
  let plugin = plugins[i];
197
213
 
198
- if (plugin.patterns && !hasPattern(code, plugin.patterns)) {
214
+ if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
199
215
  continue;
200
216
  }
201
217
 
202
218
  let { imports, prepend, replacements } = plugin.transform({
203
- checker,
204
- code,
205
- program,
206
- shared,
207
- sourceFile: originalFile
208
- });
219
+ checker: currentProgram.getTypeChecker(),
220
+ code: currentCode,
221
+ program: currentProgram,
222
+ shared,
223
+ sourceFile: currentFile
224
+ }),
225
+ pluginChanged = false;
209
226
 
210
227
  if (replacements?.length) {
211
- allReplacements.push(...replacements);
228
+ currentCode = applyIntents(currentCode, currentFile, replacements);
229
+ pluginChanged = true;
212
230
  }
213
231
 
214
232
  if (prepend?.length) {
215
- allPrepend.push(...prepend);
233
+ currentCode = applyPrepend(currentCode, currentFile, prepend);
234
+ pluginChanged = true;
216
235
  }
217
236
 
218
237
  if (imports?.length) {
219
- allImports.push(...imports);
238
+ currentCode = applyImports(currentCode, currentFile, imports);
239
+ pluginChanged = true;
220
240
  }
221
- }
222
241
 
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
- );
242
+ if (pluginChanged) {
243
+ changed = true;
244
+ // Create patched program for next plugin
245
+ if (i < n - 1) {
246
+ currentProgram = createPatchedProgram(program, fileName, currentCode);
247
+ currentFile = currentProgram.getSourceFile(fileName) ||
248
+ ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
249
+ }
250
+ else {
251
+ currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
243
252
  }
244
253
  }
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
254
  }
259
255
 
260
- return {
261
- changed: currentCode !== code,
262
- code: currentCode,
263
- sourceFile: currentFile
264
- };
256
+ return { changed, code: currentCode, sourceFile: currentFile };
265
257
  };
266
258
 
267
259
 
268
- export default { transform };
260
+ export default { createPatchedProgram, transform };
269
261
  export type { CoordinatorResult };
@@ -44,14 +44,18 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
44
44
  }
45
45
 
46
46
  try {
47
- let prog = program.get(root || ''),
48
- sourceFile = prog.getSourceFile(id.replace(DIRECTORY_SEPARATOR_REGEX, '/')) || prog.getSourceFile(id);
49
-
50
- if (
51
- !sourceFile ||
52
- sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')
53
- ) {
54
- sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
47
+ let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'),
48
+ prog = program.get(root || ''),
49
+ sourceFile = prog.getSourceFile(normalizedId) || prog.getSourceFile(id);
50
+
51
+ // Check if file content matches (existing file may have changed)
52
+ if (sourceFile && sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
53
+ sourceFile = undefined;
54
+ }
55
+
56
+ if (!sourceFile) {
57
+ prog = coordinator.createPatchedProgram(prog, normalizedId, code);
58
+ sourceFile = prog.getSourceFile(normalizedId) || ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
55
59
  }
56
60
 
57
61
  let result = coordinator.transform(