@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) =>
|
|
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
|
|
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(
|
|
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
|
|
128
|
+
code,
|
|
129
129
|
program,
|
|
130
130
|
shared,
|
|
131
|
-
sourceFile:
|
|
131
|
+
sourceFile: originalFile
|
|
132
132
|
});
|
|
133
133
|
if (replacements?.length) {
|
|
134
|
-
|
|
135
|
-
currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
|
|
134
|
+
allReplacements.push(...replacements);
|
|
136
135
|
}
|
|
137
136
|
if (prepend?.length) {
|
|
138
|
-
|
|
139
|
-
currentFile = ts.createSourceFile(fileName, currentCode, currentFile.languageVersion, true);
|
|
137
|
+
allPrepend.push(...prepend);
|
|
140
138
|
}
|
|
141
139
|
if (imports?.length) {
|
|
142
|
-
|
|
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 ||
|
|
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
|
@@ -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
|
-
)
|
|
178
|
+
) => {
|
|
184
179
|
if (plugins.length === 0) {
|
|
185
180
|
return { changed: false, code, sourceFile: file };
|
|
186
181
|
}
|
|
187
182
|
|
|
188
|
-
let
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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(
|
|
198
|
+
if (plugin.patterns && !hasPattern(code, plugin.patterns)) {
|
|
197
199
|
continue;
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
let { imports, prepend, replacements } = plugin.transform({
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
checker,
|
|
204
|
+
code,
|
|
205
|
+
program,
|
|
206
|
+
shared,
|
|
207
|
+
sourceFile: originalFile
|
|
208
|
+
});
|
|
207
209
|
|
|
208
210
|
if (replacements?.length) {
|
|
209
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|