@esportsplus/reactivity 0.23.0 → 0.23.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/build/transformer/detector.js +38 -0
- package/build/transformer/{core/index.d.ts → index.d.ts} +1 -1
- package/build/transformer/plugins/esbuild.js +3 -2
- package/build/transformer/plugins/tsc.js +1 -1
- package/build/transformer/plugins/vite.js +2 -2
- package/build/transformer/transforms/auto-dispose.js +119 -0
- package/build/transformer/{core/transforms → transforms}/reactive-array.d.ts +1 -1
- package/build/transformer/transforms/reactive-array.js +93 -0
- package/build/transformer/{core/transforms → transforms}/reactive-object.d.ts +1 -1
- package/build/transformer/transforms/reactive-object.js +164 -0
- package/build/transformer/{core/transforms → transforms}/reactive-primitives.d.ts +1 -1
- package/build/transformer/transforms/reactive-primitives.js +335 -0
- package/build/transformer/{core/transforms → transforms}/utilities.d.ts +1 -2
- package/build/transformer/transforms/utilities.js +73 -0
- package/package.json +8 -12
- package/src/transformer/detector.ts +65 -0
- package/src/transformer/{core/index.ts → index.ts} +1 -5
- package/src/transformer/plugins/esbuild.ts +3 -2
- package/src/transformer/plugins/tsc.ts +1 -1
- package/src/transformer/plugins/vite.ts +2 -4
- package/src/transformer/transforms/auto-dispose.ts +191 -0
- package/src/transformer/transforms/reactive-array.ts +143 -0
- package/src/transformer/{core/transforms → transforms}/reactive-object.ts +101 -92
- package/src/transformer/transforms/reactive-primitives.ts +461 -0
- package/src/transformer/transforms/utilities.ts +119 -0
- package/build/transformer/core/detector.js +0 -6
- package/build/transformer/core/transforms/auto-dispose.js +0 -116
- package/build/transformer/core/transforms/reactive-array.js +0 -89
- package/build/transformer/core/transforms/reactive-object.js +0 -155
- package/build/transformer/core/transforms/reactive-primitives.js +0 -325
- package/build/transformer/core/transforms/utilities.js +0 -57
- package/src/transformer/core/detector.ts +0 -12
- package/src/transformer/core/transforms/auto-dispose.ts +0 -194
- package/src/transformer/core/transforms/reactive-array.ts +0 -140
- package/src/transformer/core/transforms/reactive-primitives.ts +0 -459
- package/src/transformer/core/transforms/utilities.ts +0 -95
- /package/build/transformer/{core/detector.d.ts → detector.d.ts} +0 -0
- /package/build/transformer/{core/index.js → index.js} +0 -0
- /package/build/transformer/{core/transforms → transforms}/auto-dispose.d.ts +0 -0
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
import type { BindingType, Bindings } from '~/types';
|
|
2
|
-
import { uid } from '@esportsplus/typescript/transformer';
|
|
3
|
-
import ts from 'typescript';
|
|
4
|
-
import { addMissingImports, applyReplacements, Replacement } from './utilities';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
interface ComputedArgRange {
|
|
8
|
-
end: number;
|
|
9
|
-
start: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface ScopeBinding {
|
|
13
|
-
name: string;
|
|
14
|
-
scope: ts.Node;
|
|
15
|
-
type: BindingType;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function findEnclosingScope(node: ts.Node): ts.Node {
|
|
20
|
-
let current = node.parent;
|
|
21
|
-
|
|
22
|
-
while (current) {
|
|
23
|
-
if (
|
|
24
|
-
ts.isBlock(current) ||
|
|
25
|
-
ts.isSourceFile(current) ||
|
|
26
|
-
ts.isFunctionDeclaration(current) ||
|
|
27
|
-
ts.isFunctionExpression(current) ||
|
|
28
|
-
ts.isArrowFunction(current) ||
|
|
29
|
-
ts.isForStatement(current) ||
|
|
30
|
-
ts.isForInStatement(current) ||
|
|
31
|
-
ts.isForOfStatement(current)
|
|
32
|
-
) {
|
|
33
|
-
return current;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
current = current.parent;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return node.getSourceFile();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function findBinding(bindings: ScopeBinding[], name: string, node: ts.Node): ScopeBinding | undefined {
|
|
43
|
-
for (let i = 0, n = bindings.length; i < n; i++) {
|
|
44
|
-
let b = bindings[i];
|
|
45
|
-
|
|
46
|
-
if (b.name === name && isInScope(node, b)) {
|
|
47
|
-
return b;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function isInComputedRange(ranges: ComputedArgRange[], start: number, end: number): boolean {
|
|
55
|
-
for (let i = 0, n = ranges.length; i < n; i++) {
|
|
56
|
-
let r = ranges[i];
|
|
57
|
-
|
|
58
|
-
if (start >= r.start && end <= r.end) {
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function isInScope(reference: ts.Node, binding: ScopeBinding): boolean {
|
|
67
|
-
let current: ts.Node | undefined = reference;
|
|
68
|
-
|
|
69
|
-
while (current) {
|
|
70
|
-
if (current === binding.scope) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
current = current.parent;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function classifyReactiveArg(arg: ts.Expression): 'computed' | 'signal' | null {
|
|
81
|
-
if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
82
|
-
return 'computed';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (ts.isObjectLiteralExpression(arg) || ts.isArrayLiteralExpression(arg)) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return 'signal';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function isInDeclarationInit(node: ts.Node): boolean {
|
|
93
|
-
let parent = node.parent;
|
|
94
|
-
|
|
95
|
-
if (ts.isVariableDeclaration(parent) && parent.initializer === node) {
|
|
96
|
-
return true;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function isReactiveReassignment(node: ts.Node): boolean {
|
|
103
|
-
let parent = node.parent;
|
|
104
|
-
|
|
105
|
-
if (ts.isBinaryExpression(parent) &&
|
|
106
|
-
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
107
|
-
parent.right === node &&
|
|
108
|
-
ts.isCallExpression(node) &&
|
|
109
|
-
ts.isIdentifier((node as ts.CallExpression).expression) &&
|
|
110
|
-
((node as ts.CallExpression).expression as ts.Identifier).text === 'reactive') {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isWriteContext(node: ts.Identifier): 'simple' | 'compound' | 'increment' | false {
|
|
118
|
-
let parent = node.parent;
|
|
119
|
-
|
|
120
|
-
if (ts.isBinaryExpression(parent) && parent.left === node) {
|
|
121
|
-
let op = parent.operatorToken.kind;
|
|
122
|
-
|
|
123
|
-
if (op === ts.SyntaxKind.EqualsToken) {
|
|
124
|
-
return 'simple';
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (op >= ts.SyntaxKind.PlusEqualsToken && op <= ts.SyntaxKind.CaretEqualsToken) {
|
|
128
|
-
return 'compound';
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (
|
|
132
|
-
op === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
133
|
-
op === ts.SyntaxKind.BarBarEqualsToken ||
|
|
134
|
-
op === ts.SyntaxKind.QuestionQuestionEqualsToken
|
|
135
|
-
) {
|
|
136
|
-
return 'compound';
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (ts.isPostfixUnaryExpression(parent) || ts.isPrefixUnaryExpression(parent)) {
|
|
141
|
-
let op = parent.operator;
|
|
142
|
-
|
|
143
|
-
if (op === ts.SyntaxKind.PlusPlusToken || op === ts.SyntaxKind.MinusMinusToken) {
|
|
144
|
-
return 'increment';
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function getCompoundOperator(kind: ts.SyntaxKind): string {
|
|
152
|
-
if (kind === ts.SyntaxKind.PlusEqualsToken) {
|
|
153
|
-
return '+';
|
|
154
|
-
}
|
|
155
|
-
else if (kind === ts.SyntaxKind.MinusEqualsToken) {
|
|
156
|
-
return '-';
|
|
157
|
-
}
|
|
158
|
-
else if (kind === ts.SyntaxKind.AsteriskEqualsToken) {
|
|
159
|
-
return '*';
|
|
160
|
-
}
|
|
161
|
-
else if (kind === ts.SyntaxKind.SlashEqualsToken) {
|
|
162
|
-
return '/';
|
|
163
|
-
}
|
|
164
|
-
else if (kind === ts.SyntaxKind.PercentEqualsToken) {
|
|
165
|
-
return '%';
|
|
166
|
-
}
|
|
167
|
-
else if (kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
|
|
168
|
-
return '**';
|
|
169
|
-
}
|
|
170
|
-
else if (kind === ts.SyntaxKind.AmpersandEqualsToken) {
|
|
171
|
-
return '&';
|
|
172
|
-
}
|
|
173
|
-
else if (kind === ts.SyntaxKind.BarEqualsToken) {
|
|
174
|
-
return '|';
|
|
175
|
-
}
|
|
176
|
-
else if (kind === ts.SyntaxKind.CaretEqualsToken) {
|
|
177
|
-
return '^';
|
|
178
|
-
}
|
|
179
|
-
else if (kind === ts.SyntaxKind.LessThanLessThanEqualsToken) {
|
|
180
|
-
return '<<';
|
|
181
|
-
}
|
|
182
|
-
else if (kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken) {
|
|
183
|
-
return '>>';
|
|
184
|
-
}
|
|
185
|
-
else if (kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
186
|
-
return '>>>';
|
|
187
|
-
}
|
|
188
|
-
else if (kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
|
|
189
|
-
return '&&';
|
|
190
|
-
}
|
|
191
|
-
else if (kind === ts.SyntaxKind.BarBarEqualsToken) {
|
|
192
|
-
return '||';
|
|
193
|
-
}
|
|
194
|
-
else if (kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
195
|
-
return '??';
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
return '+';
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function transformComputedArg(
|
|
203
|
-
arg: ts.Expression,
|
|
204
|
-
scopedBindings: ScopeBinding[],
|
|
205
|
-
sourceFile: ts.SourceFile,
|
|
206
|
-
neededImports: Set<string>
|
|
207
|
-
): string {
|
|
208
|
-
let argStart = arg.getStart(sourceFile),
|
|
209
|
-
innerReplacements: Replacement[] = [],
|
|
210
|
-
text = arg.getText(sourceFile);
|
|
211
|
-
|
|
212
|
-
function visitArg(node: ts.Node): void {
|
|
213
|
-
// Only transform identifiers that are signal bindings
|
|
214
|
-
if (ts.isIdentifier(node)) {
|
|
215
|
-
// Skip if it's a property name in property access (obj.prop - skip prop)
|
|
216
|
-
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
|
217
|
-
ts.forEachChild(node, visitArg);
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Skip if it's the function name in a call expression
|
|
222
|
-
if (ts.isCallExpression(node.parent) && node.parent.expression === node) {
|
|
223
|
-
ts.forEachChild(node, visitArg);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
let binding = findBinding(scopedBindings, node.text, node);
|
|
228
|
-
|
|
229
|
-
if (binding) {
|
|
230
|
-
neededImports.add('read');
|
|
231
|
-
|
|
232
|
-
innerReplacements.push({
|
|
233
|
-
end: node.end - argStart,
|
|
234
|
-
newText: `read(${node.text})`,
|
|
235
|
-
start: node.getStart(sourceFile) - argStart
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
ts.forEachChild(node, visitArg);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
visitArg(arg);
|
|
244
|
-
|
|
245
|
-
return applyReplacements(text, innerReplacements);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const transformReactivePrimitives = (
|
|
250
|
-
sourceFile: ts.SourceFile,
|
|
251
|
-
bindings: Bindings
|
|
252
|
-
): string => {
|
|
253
|
-
let code = sourceFile.getFullText(),
|
|
254
|
-
computedArgRanges: ComputedArgRange[] = [],
|
|
255
|
-
hasReactiveImport = false,
|
|
256
|
-
neededImports = new Set<string>(),
|
|
257
|
-
replacements: Replacement[] = [],
|
|
258
|
-
scopedBindings: ScopeBinding[] = [];
|
|
259
|
-
|
|
260
|
-
// Single-pass visitor: detect imports, bindings, and usages together
|
|
261
|
-
function visit(node: ts.Node): void {
|
|
262
|
-
if (
|
|
263
|
-
ts.isImportDeclaration(node) &&
|
|
264
|
-
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
265
|
-
node.moduleSpecifier.text.includes('@esportsplus/reactivity')
|
|
266
|
-
) {
|
|
267
|
-
let clause = node.importClause;
|
|
268
|
-
|
|
269
|
-
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
270
|
-
for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
|
|
271
|
-
if (clause.namedBindings.elements[i].name.text === 'reactive') {
|
|
272
|
-
hasReactiveImport = true;
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (
|
|
280
|
-
hasReactiveImport &&
|
|
281
|
-
ts.isCallExpression(node) &&
|
|
282
|
-
ts.isIdentifier(node.expression) &&
|
|
283
|
-
node.expression.text === 'reactive' &&
|
|
284
|
-
node.arguments.length > 0
|
|
285
|
-
) {
|
|
286
|
-
|
|
287
|
-
let arg = node.arguments[0],
|
|
288
|
-
classification = classifyReactiveArg(arg);
|
|
289
|
-
|
|
290
|
-
if (classification) {
|
|
291
|
-
let varName: string | null = null;
|
|
292
|
-
|
|
293
|
-
if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
294
|
-
varName = node.parent.name.text;
|
|
295
|
-
}
|
|
296
|
-
else if (
|
|
297
|
-
ts.isBinaryExpression(node.parent) &&
|
|
298
|
-
node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
299
|
-
ts.isIdentifier(node.parent.left)
|
|
300
|
-
) {
|
|
301
|
-
varName = node.parent.left.text;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (varName) {
|
|
305
|
-
let scope = findEnclosingScope(node);
|
|
306
|
-
|
|
307
|
-
scopedBindings.push({ name: varName, scope, type: classification });
|
|
308
|
-
bindings.set(varName, classification);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (classification === 'computed') {
|
|
312
|
-
// Track range to skip identifiers inside when visitor continues
|
|
313
|
-
computedArgRanges.push({
|
|
314
|
-
end: arg.end,
|
|
315
|
-
start: arg.getStart(sourceFile)
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// Transform signal references inside the computed arg
|
|
319
|
-
let argText = transformComputedArg(arg, scopedBindings, sourceFile, neededImports);
|
|
320
|
-
|
|
321
|
-
replacements.push({
|
|
322
|
-
end: node.end,
|
|
323
|
-
newText: `computed(${argText})`,
|
|
324
|
-
start: node.pos
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
neededImports.add('computed');
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
let argText = arg.getText(sourceFile);
|
|
331
|
-
|
|
332
|
-
replacements.push({
|
|
333
|
-
end: node.end,
|
|
334
|
-
newText: `signal(${argText})`,
|
|
335
|
-
start: node.pos
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
neededImports.add('signal');
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Transform identifier usages
|
|
344
|
-
if (ts.isIdentifier(node) && !isInDeclarationInit(node.parent)) {
|
|
345
|
-
// Skip if it's a property name in property access (obj.prop - skip prop)
|
|
346
|
-
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
|
347
|
-
ts.forEachChild(node, visit);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
let nodeStart = node.getStart(sourceFile);
|
|
352
|
-
|
|
353
|
-
// Skip if inside a computed arg we already transformed
|
|
354
|
-
let insideComputedArg = isInComputedRange(computedArgRanges, nodeStart, node.end);
|
|
355
|
-
|
|
356
|
-
if (insideComputedArg) {
|
|
357
|
-
ts.forEachChild(node, visit);
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
let binding = findBinding(scopedBindings, node.text, node),
|
|
362
|
-
name = node.text;
|
|
363
|
-
|
|
364
|
-
if (binding) {
|
|
365
|
-
if (
|
|
366
|
-
!isReactiveReassignment(node.parent) &&
|
|
367
|
-
!(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)
|
|
368
|
-
) {
|
|
369
|
-
let writeCtx = isWriteContext(node);
|
|
370
|
-
|
|
371
|
-
if (writeCtx) {
|
|
372
|
-
if (binding.type !== 'computed') {
|
|
373
|
-
neededImports.add('set');
|
|
374
|
-
|
|
375
|
-
let parent = node.parent;
|
|
376
|
-
|
|
377
|
-
if (writeCtx === 'simple' && ts.isBinaryExpression(parent)) {
|
|
378
|
-
let valueText = parent.right.getText(sourceFile);
|
|
379
|
-
|
|
380
|
-
replacements.push({
|
|
381
|
-
end: parent.end,
|
|
382
|
-
newText: `set(${name}, ${valueText})`,
|
|
383
|
-
start: parent.pos
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
else if (writeCtx === 'compound' && ts.isBinaryExpression(parent)) {
|
|
387
|
-
let op = getCompoundOperator(parent.operatorToken.kind),
|
|
388
|
-
valueText = parent.right.getText(sourceFile);
|
|
389
|
-
|
|
390
|
-
replacements.push({
|
|
391
|
-
end: parent.end,
|
|
392
|
-
newText: `set(${name}, ${name}.value ${op} ${valueText})`,
|
|
393
|
-
start: parent.pos
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
else if (writeCtx === 'increment') {
|
|
397
|
-
let isPrefix = ts.isPrefixUnaryExpression(parent),
|
|
398
|
-
op = (parent as ts.PrefixUnaryExpression | ts.PostfixUnaryExpression).operator,
|
|
399
|
-
delta = op === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1';
|
|
400
|
-
|
|
401
|
-
if (ts.isExpressionStatement(parent.parent)) {
|
|
402
|
-
replacements.push({
|
|
403
|
-
end: parent.end,
|
|
404
|
-
newText: `set(${name}, ${name}.value ${delta})`,
|
|
405
|
-
start: parent.pos
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
else if (isPrefix) {
|
|
409
|
-
replacements.push({
|
|
410
|
-
end: parent.end,
|
|
411
|
-
newText: `(set(${name}, ${name}.value ${delta}), ${name}.value)`,
|
|
412
|
-
start: parent.pos
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
let tmp = uid('tmp');
|
|
417
|
-
|
|
418
|
-
replacements.push({
|
|
419
|
-
end: parent.end,
|
|
420
|
-
newText: `((${tmp}) => (set(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
|
|
421
|
-
start: parent.pos
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
neededImports.add('read');
|
|
429
|
-
|
|
430
|
-
replacements.push({
|
|
431
|
-
end: node.end,
|
|
432
|
-
newText: `read(${name})`,
|
|
433
|
-
start: node.pos
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
ts.forEachChild(node, visit);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
visit(sourceFile);
|
|
444
|
-
|
|
445
|
-
if (replacements.length === 0) {
|
|
446
|
-
return code;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
let result = applyReplacements(code, replacements);
|
|
450
|
-
|
|
451
|
-
if (neededImports.size > 0) {
|
|
452
|
-
result = addMissingImports(result, neededImports);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return result;
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
export { transformReactivePrimitives };
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { Replacement } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import { applyReplacements } from '@esportsplus/typescript/transformer';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type ExtraImport = {
|
|
6
|
-
module: string;
|
|
7
|
-
specifier: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const BRACES_CONTENT_REGEX = /\{([^}]*)\}/;
|
|
12
|
-
|
|
13
|
-
const REACTIVITY_IMPORT_REGEX = /(import\s*\{[^}]*\}\s*from\s*['"]@esportsplus\/reactivity['"])/;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const addMissingImports = (code: string, needed: Set<string>, extraImports?: ExtraImport[]): string => {
|
|
17
|
-
let reactivityImportMatch = code.match(REACTIVITY_IMPORT_REGEX);
|
|
18
|
-
|
|
19
|
-
if (!reactivityImportMatch) {
|
|
20
|
-
return code;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let bracesMatch = reactivityImportMatch[1].match(BRACES_CONTENT_REGEX),
|
|
24
|
-
existing = new Set<string>(),
|
|
25
|
-
existingImport = reactivityImportMatch[1],
|
|
26
|
-
extraSpecifiers = new Set<string>(),
|
|
27
|
-
toAdd: string[] = [];
|
|
28
|
-
|
|
29
|
-
if (bracesMatch?.[1]) {
|
|
30
|
-
let parts = bracesMatch[1].split(',');
|
|
31
|
-
|
|
32
|
-
for (let i = 0, n = parts.length; i < n; i++) {
|
|
33
|
-
let trimmed = parts[i].trim();
|
|
34
|
-
|
|
35
|
-
if (trimmed) {
|
|
36
|
-
existing.add(trimmed);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (extraImports) {
|
|
42
|
-
for (let i = 0, n = extraImports.length; i < n; i++) {
|
|
43
|
-
extraSpecifiers.add(extraImports[i].specifier);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
for (let imp of needed) {
|
|
48
|
-
if (!extraSpecifiers.has(imp) && !existing.has(imp)) {
|
|
49
|
-
toAdd.push(imp);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (toAdd.length > 0) {
|
|
54
|
-
let combined: string[] = [];
|
|
55
|
-
|
|
56
|
-
for (let item of existing) {
|
|
57
|
-
if (item) {
|
|
58
|
-
combined.push(item);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
for (let i = 0, n = toAdd.length; i < n; i++) {
|
|
63
|
-
if (toAdd[i]) {
|
|
64
|
-
combined.push(toAdd[i]);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
combined.sort();
|
|
69
|
-
|
|
70
|
-
code = code.replace(
|
|
71
|
-
existingImport,
|
|
72
|
-
existingImport.replace(BRACES_CONTENT_REGEX, `{ ${combined.join(', ')} }`)
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (extraImports) {
|
|
77
|
-
for (let i = 0, n = extraImports.length; i < n; i++) {
|
|
78
|
-
let extra = extraImports[i];
|
|
79
|
-
|
|
80
|
-
if (needed.has(extra.specifier) && !code.includes(extra.module)) {
|
|
81
|
-
let insertPos = code.indexOf('import');
|
|
82
|
-
|
|
83
|
-
code = code.substring(0, insertPos) +
|
|
84
|
-
`import { ${extra.specifier} } from '${extra.module}';\n` +
|
|
85
|
-
code.substring(insertPos);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return code;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
export { addMissingImports, applyReplacements };
|
|
95
|
-
export type { ExtraImport, Replacement };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|