@ethlete/query 5.43.1 ā 6.0.0-next.0
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/CHANGELOG.md +42 -0
- package/fesm2022/ethlete-query-testing.mjs +178 -0
- package/fesm2022/ethlete-query-testing.mjs.map +1 -0
- package/fesm2022/ethlete-query.mjs +4289 -3521
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/generators.json +5 -0
- package/generators/migrate-to-query-v3/migration.js +211 -218
- package/generators/prep-for-query-v3/migration.js +329 -0
- package/generators/prep-for-query-v3/schema.json +14 -0
- package/package.json +18 -11
- package/types/ethlete-query-testing.d.ts +167 -0
- package/{index.d.ts ā types/ethlete-query.d.ts} +3219 -2968
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const devkit_1 = require("@nx/devkit");
|
|
6
|
-
const ts = tslib_1.__importStar(require("typescript"));
|
|
7
|
-
async function migrate(tree, schema) {
|
|
1
|
+
import { formatFiles, getProjects, visitNotIgnoredFiles } from '@nx/devkit';
|
|
2
|
+
import * as ts from 'typescript';
|
|
3
|
+
export default async function migrate(tree, schema) {
|
|
8
4
|
const queryClientFiles = new Map(); // filepath -> config names
|
|
9
5
|
const variableRenames = new Map(); // old name -> new name
|
|
10
|
-
|
|
6
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
11
7
|
if (!filePath.endsWith('.ts'))
|
|
12
8
|
return;
|
|
13
9
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -15,10 +11,6 @@ async function migrate(tree, schema) {
|
|
|
15
11
|
return;
|
|
16
12
|
let modified = false;
|
|
17
13
|
let newContent = content;
|
|
18
|
-
if (needsExperimentalQueryImport(content)) {
|
|
19
|
-
newContent = addExperimentalQueryImport(newContent);
|
|
20
|
-
modified = true;
|
|
21
|
-
}
|
|
22
14
|
if (hasQueryClientInstantiation(content)) {
|
|
23
15
|
const renames = new Map();
|
|
24
16
|
newContent = migrateQueryClientToConfig(newContent, renames);
|
|
@@ -56,7 +48,7 @@ async function migrate(tree, schema) {
|
|
|
56
48
|
if (variableRenames.size > 0) {
|
|
57
49
|
updateImportsAcrossWorkspace(tree, variableRenames);
|
|
58
50
|
}
|
|
59
|
-
// Replace
|
|
51
|
+
// Replace AnyV2Query with AnyLegacyQuery everywhere
|
|
60
52
|
replaceAnyQueryWithLegacy(tree);
|
|
61
53
|
// Remove devtools usage
|
|
62
54
|
removeDevtoolsUsage(tree);
|
|
@@ -65,43 +57,10 @@ async function migrate(tree, schema) {
|
|
|
65
57
|
// Check for legacy query creator usage (step 1: just collect and report)
|
|
66
58
|
checkLegacyQueryCreatorUsage(tree);
|
|
67
59
|
if (!schema.skipFormat) {
|
|
68
|
-
await
|
|
60
|
+
await formatFiles(tree);
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
63
|
//#endregion
|
|
72
|
-
//#region import ExperimentalQuery as E
|
|
73
|
-
function needsExperimentalQueryImport(content) {
|
|
74
|
-
// Check if file imports from @ethlete/query
|
|
75
|
-
const hasQueryImport = /from\s+['"]@ethlete\/query['"]/.test(content);
|
|
76
|
-
// Check if already has ExperimentalQuery import
|
|
77
|
-
const hasExperimentalQueryImport = /import\s*{[^}]*ExperimentalQuery/.test(content);
|
|
78
|
-
return hasQueryImport && !hasExperimentalQueryImport;
|
|
79
|
-
}
|
|
80
|
-
function addExperimentalQueryImport(content) {
|
|
81
|
-
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
82
|
-
let queryImportNode;
|
|
83
|
-
ts.forEachChild(sourceFile, (node) => {
|
|
84
|
-
if (ts.isImportDeclaration(node) &&
|
|
85
|
-
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
86
|
-
node.moduleSpecifier.text === '@ethlete/query') {
|
|
87
|
-
queryImportNode = node;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
if (!queryImportNode || !queryImportNode.importClause?.namedBindings) {
|
|
91
|
-
return content;
|
|
92
|
-
}
|
|
93
|
-
const namedBindings = queryImportNode.importClause.namedBindings;
|
|
94
|
-
if (!ts.isNamedImports(namedBindings)) {
|
|
95
|
-
return content;
|
|
96
|
-
}
|
|
97
|
-
const importStart = queryImportNode.getStart(sourceFile);
|
|
98
|
-
const importEnd = queryImportNode.getEnd();
|
|
99
|
-
const existingImports = namedBindings.elements.map((el) => el.getText(sourceFile));
|
|
100
|
-
const newImports = [...existingImports, 'ExperimentalQuery as E'];
|
|
101
|
-
const newImportStatement = `import { ${newImports.join(', ')} } from '@ethlete/query';`;
|
|
102
|
-
return content.slice(0, importStart) + newImportStatement + content.slice(importEnd);
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
64
|
//#region Query client to config
|
|
106
65
|
function hasQueryClientInstantiation(content) {
|
|
107
66
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
@@ -113,12 +72,12 @@ function hasQueryClientInstantiation(content) {
|
|
|
113
72
|
node.moduleSpecifier.text === '@ethlete/query' &&
|
|
114
73
|
node.importClause?.namedBindings &&
|
|
115
74
|
ts.isNamedImports(node.importClause.namedBindings)) {
|
|
116
|
-
const hasQueryClient = node.importClause.namedBindings.elements.some((el) => el.name.text === '
|
|
75
|
+
const hasQueryClient = node.importClause.namedBindings.elements.some((el) => el.name.text === 'V2QueryClient');
|
|
117
76
|
if (hasQueryClient) {
|
|
118
77
|
hasQueryClientImport = true;
|
|
119
78
|
}
|
|
120
79
|
}
|
|
121
|
-
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === '
|
|
80
|
+
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'V2QueryClient') {
|
|
122
81
|
hasNewQueryClient = true;
|
|
123
82
|
}
|
|
124
83
|
ts.forEachChild(node, visit);
|
|
@@ -134,7 +93,7 @@ function migrateQueryClientToConfig(content, renamesOut) {
|
|
|
134
93
|
// Find: new QueryClient({ baseRoute: '...' })
|
|
135
94
|
if (ts.isNewExpression(node) &&
|
|
136
95
|
ts.isIdentifier(node.expression) &&
|
|
137
|
-
node.expression.text === '
|
|
96
|
+
node.expression.text === 'V2QueryClient' &&
|
|
138
97
|
node.arguments &&
|
|
139
98
|
node.arguments.length > 0) {
|
|
140
99
|
const configArg = node.arguments[0];
|
|
@@ -188,25 +147,68 @@ function removeQueryClientImport(content) {
|
|
|
188
147
|
}
|
|
189
148
|
});
|
|
190
149
|
if (!queryImportNode?.importClause?.namedBindings || !ts.isNamedImports(queryImportNode.importClause.namedBindings)) {
|
|
191
|
-
|
|
150
|
+
// No @ethlete/query import exists - create one with necessary imports
|
|
151
|
+
const newImportsNeeded = [
|
|
152
|
+
'createQueryClientConfig',
|
|
153
|
+
'createGetQuery',
|
|
154
|
+
'createPostQuery',
|
|
155
|
+
'createPutQuery',
|
|
156
|
+
'createPatchQuery',
|
|
157
|
+
'createDeleteQuery',
|
|
158
|
+
];
|
|
159
|
+
// Find last import to insert after it
|
|
160
|
+
let lastImportEnd = 0;
|
|
161
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
162
|
+
if (ts.isImportDeclaration(node)) {
|
|
163
|
+
const end = node.getEnd();
|
|
164
|
+
if (end > lastImportEnd) {
|
|
165
|
+
lastImportEnd = end;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const newImportStatement = `\nimport { ${newImportsNeeded.join(', ')} } from '@ethlete/query';`;
|
|
170
|
+
if (lastImportEnd > 0) {
|
|
171
|
+
return content.slice(0, lastImportEnd) + newImportStatement + content.slice(lastImportEnd);
|
|
172
|
+
}
|
|
173
|
+
return `import { ${newImportsNeeded.join(', ')} } from '@ethlete/query';\n\n${content}`;
|
|
192
174
|
}
|
|
193
175
|
const namedBindings = queryImportNode.importClause.namedBindings;
|
|
194
|
-
const elements = namedBindings.elements.filter((el) => el.name.text !== '
|
|
195
|
-
//
|
|
196
|
-
|
|
176
|
+
const elements = namedBindings.elements.filter((el) => el.name.text !== 'V2QueryClient');
|
|
177
|
+
// Add the new imports we need
|
|
178
|
+
const newImportsNeeded = new Set([
|
|
179
|
+
'createQueryClientConfig',
|
|
180
|
+
'createGetQuery',
|
|
181
|
+
'createPostQuery',
|
|
182
|
+
'createPutQuery',
|
|
183
|
+
'createPatchQuery',
|
|
184
|
+
'createDeleteQuery',
|
|
185
|
+
]);
|
|
186
|
+
// Check which imports already exist
|
|
187
|
+
elements.forEach((el) => {
|
|
188
|
+
newImportsNeeded.delete(el.name.text);
|
|
189
|
+
});
|
|
190
|
+
// Combine existing imports with new ones
|
|
191
|
+
const allImports = [...elements.map((el) => el.getText(sourceFile)), ...Array.from(newImportsNeeded).sort()].sort();
|
|
192
|
+
// If no imports left after removing V2QueryClient, we still need to add the new ones
|
|
193
|
+
if (elements.length === 0 && newImportsNeeded.size > 0) {
|
|
194
|
+
const newImportStatement = `import { ${Array.from(newImportsNeeded).sort().join(', ')} } from '@ethlete/query';`;
|
|
197
195
|
const importStart = queryImportNode.getStart(sourceFile);
|
|
198
196
|
const importEnd = queryImportNode.getEnd();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
return content.slice(0, importStart) + newImportStatement + content.slice(importEnd);
|
|
198
|
+
}
|
|
199
|
+
// If we removed V2QueryClient but have other imports, reconstruct with new ones
|
|
200
|
+
if (elements.length > 0 || newImportsNeeded.size > 0) {
|
|
201
|
+
const importStart = queryImportNode.getStart(sourceFile);
|
|
202
|
+
const importEnd = queryImportNode.getEnd();
|
|
203
|
+
const newImportStatement = `import { ${allImports.join(', ')} } from '@ethlete/query';`;
|
|
204
|
+
return content.slice(0, importStart) + newImportStatement + content.slice(importEnd);
|
|
203
205
|
}
|
|
204
|
-
//
|
|
206
|
+
// If truly no imports needed, remove the import line
|
|
205
207
|
const importStart = queryImportNode.getStart(sourceFile);
|
|
206
208
|
const importEnd = queryImportNode.getEnd();
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
return content.slice(0, importStart) +
|
|
209
|
+
const nextChar = content[importEnd];
|
|
210
|
+
const endPos = nextChar === '\n' ? importEnd + 1 : importEnd;
|
|
211
|
+
return content.slice(0, importStart) + content.slice(endPos);
|
|
210
212
|
}
|
|
211
213
|
function renameVariables(content, renames) {
|
|
212
214
|
if (renames.size === 0)
|
|
@@ -293,7 +295,7 @@ function migrateConfigObject(configArg, node, sourceFile) {
|
|
|
293
295
|
newConfig.push(`retryFn: ${retryFnValue}`);
|
|
294
296
|
}
|
|
295
297
|
}
|
|
296
|
-
return `
|
|
298
|
+
return `createQueryClientConfig({\n ${newConfig.join(',\n ')}\n})`;
|
|
297
299
|
}
|
|
298
300
|
function getVariableNameForQueryClient(node, sourceFile) {
|
|
299
301
|
let parent = node.parent;
|
|
@@ -310,17 +312,13 @@ function extractClientConfigNames(content) {
|
|
|
310
312
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
311
313
|
const configNames = [];
|
|
312
314
|
function visit(node) {
|
|
313
|
-
// Find: const XXX =
|
|
315
|
+
// Find: const XXX = createQueryClientConfig(...)
|
|
314
316
|
if (ts.isVariableDeclaration(node) &&
|
|
315
317
|
ts.isIdentifier(node.name) &&
|
|
316
318
|
node.initializer &&
|
|
317
319
|
ts.isCallExpression(node.initializer)) {
|
|
318
320
|
const callExpr = node.initializer;
|
|
319
|
-
if (ts.
|
|
320
|
-
ts.isIdentifier(callExpr.expression.expression) &&
|
|
321
|
-
callExpr.expression.expression.text === 'E' &&
|
|
322
|
-
ts.isIdentifier(callExpr.expression.name) &&
|
|
323
|
-
callExpr.expression.name.text === 'createQueryClientConfig') {
|
|
321
|
+
if (ts.isIdentifier(callExpr.expression) && callExpr.expression.text === 'createQueryClientConfig') {
|
|
324
322
|
// This extracts the NEW variable name (apiClientConfig)
|
|
325
323
|
// But we should extract the name from the config object instead!
|
|
326
324
|
const nameArg = callExpr.arguments[0];
|
|
@@ -340,7 +338,7 @@ function extractClientConfigNames(content) {
|
|
|
340
338
|
//#endregion
|
|
341
339
|
//#region Add query client providers to apps
|
|
342
340
|
function updateDependentApps(tree, queryClientFiles) {
|
|
343
|
-
const projects =
|
|
341
|
+
const projects = getProjects(tree);
|
|
344
342
|
const updatedApps = [];
|
|
345
343
|
const warnedApps = [];
|
|
346
344
|
// Find all apps
|
|
@@ -397,6 +395,8 @@ function findImportedClientConfigs(content, queryClientFiles) {
|
|
|
397
395
|
return importedConfigs;
|
|
398
396
|
}
|
|
399
397
|
function addQueryClientProviders(content, clientConfigs) {
|
|
398
|
+
// Ensure provideQueryClient is imported
|
|
399
|
+
content = ensureImportFromQuery(content, ['provideQueryClient']);
|
|
400
400
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
401
401
|
let providersArrayNode;
|
|
402
402
|
function visit(node) {
|
|
@@ -411,7 +411,7 @@ function addQueryClientProviders(content, clientConfigs) {
|
|
|
411
411
|
visit(sourceFile);
|
|
412
412
|
if (!providersArrayNode)
|
|
413
413
|
return content;
|
|
414
|
-
const newProviders = clientConfigs.map((config) => `
|
|
414
|
+
const newProviders = clientConfigs.map((config) => `provideQueryClient(${config})`);
|
|
415
415
|
const elements = providersArrayNode.elements;
|
|
416
416
|
if (elements.length > 0) {
|
|
417
417
|
const insertPosition = elements[elements.length - 1].getEnd();
|
|
@@ -428,7 +428,7 @@ function addQueryClientProviders(content, clientConfigs) {
|
|
|
428
428
|
//#region Update imports across workspace
|
|
429
429
|
function updateImportsAcrossWorkspace(tree, renames) {
|
|
430
430
|
const updatedFiles = [];
|
|
431
|
-
|
|
431
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
432
432
|
if (!filePath.endsWith('.ts'))
|
|
433
433
|
return;
|
|
434
434
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -520,11 +520,7 @@ function addQueryCreatorsToFile(content, configNames) {
|
|
|
520
520
|
node.initializer &&
|
|
521
521
|
ts.isCallExpression(node.initializer)) {
|
|
522
522
|
const callExpr = node.initializer;
|
|
523
|
-
if (ts.
|
|
524
|
-
ts.isIdentifier(callExpr.expression.expression) &&
|
|
525
|
-
callExpr.expression.expression.text === 'E' &&
|
|
526
|
-
ts.isIdentifier(callExpr.expression.name) &&
|
|
527
|
-
callExpr.expression.name.text === 'createQueryClientConfig') {
|
|
523
|
+
if (ts.isIdentifier(callExpr.expression) && callExpr.expression.text === 'createQueryClientConfig') {
|
|
528
524
|
const configName = node.name.text;
|
|
529
525
|
// Find the variable statement (const/let/var line)
|
|
530
526
|
let parent = node.parent;
|
|
@@ -559,11 +555,11 @@ function addQueryCreatorsToFile(content, configNames) {
|
|
|
559
555
|
function generateCreatorsForConfig(configName) {
|
|
560
556
|
const configNameWithoutClientSuffix = configName.replace('Client', '');
|
|
561
557
|
const creators = [
|
|
562
|
-
`export const ${configNameWithoutClientSuffix}Get =
|
|
563
|
-
`export const ${configNameWithoutClientSuffix}Post =
|
|
564
|
-
`export const ${configNameWithoutClientSuffix}Put =
|
|
565
|
-
`export const ${configNameWithoutClientSuffix}Patch =
|
|
566
|
-
`export const ${configNameWithoutClientSuffix}Delete =
|
|
558
|
+
`export const ${configNameWithoutClientSuffix}Get = createGetQuery(${configName}Config);`,
|
|
559
|
+
`export const ${configNameWithoutClientSuffix}Post = createPostQuery(${configName}Config);`,
|
|
560
|
+
`export const ${configNameWithoutClientSuffix}Put = createPutQuery(${configName}Config);`,
|
|
561
|
+
`export const ${configNameWithoutClientSuffix}Patch = createPatchQuery(${configName}Config);`,
|
|
562
|
+
`export const ${configNameWithoutClientSuffix}Delete = createDeleteQuery(${configName}Config);`,
|
|
567
563
|
];
|
|
568
564
|
return creators.join('\n');
|
|
569
565
|
}
|
|
@@ -583,7 +579,7 @@ function createNewQueryCreators(tree, queryClientFiles) {
|
|
|
583
579
|
});
|
|
584
580
|
});
|
|
585
581
|
// Step 1: Find all legacy query creators and analyze them
|
|
586
|
-
|
|
582
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
587
583
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
588
584
|
return;
|
|
589
585
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -748,6 +744,8 @@ function transformLegacyQueryCreators(content, legacyCreators, queryClientFiles)
|
|
|
748
744
|
for (const { start, end, replacement } of replacements) {
|
|
749
745
|
result = result.slice(0, start) + replacement + result.slice(end);
|
|
750
746
|
}
|
|
747
|
+
// Ensure createLegacyQueryCreator is imported
|
|
748
|
+
result = ensureImportFromQuery(result, ['createLegacyQueryCreator']);
|
|
751
749
|
// Update imports to include necessary creator functions
|
|
752
750
|
result = addCreatorImports(result, creatorsByClient);
|
|
753
751
|
return result;
|
|
@@ -895,7 +893,7 @@ function generateNewQueryCreator(creator, sourceFile) {
|
|
|
895
893
|
}
|
|
896
894
|
function generateLegacyWrapper(creator) {
|
|
897
895
|
const legacyName = toLegacyName(creator.name);
|
|
898
|
-
return `export const ${legacyName} =
|
|
896
|
+
return `export const ${legacyName} = createLegacyQueryCreator({ creator: ${creator.name} });`;
|
|
899
897
|
}
|
|
900
898
|
function createAuthProviders(tree, authProvidersNeeded, queryClientFiles) {
|
|
901
899
|
const createdProviders = [];
|
|
@@ -922,7 +920,7 @@ function createAuthProviders(tree, authProvidersNeeded, queryClientFiles) {
|
|
|
922
920
|
if (createdProviders.length > 0) {
|
|
923
921
|
console.log('\nā
Created auth providers in:');
|
|
924
922
|
createdProviders.forEach((file) => console.log(` - ${file}`));
|
|
925
|
-
console.warn('\nā ļø Make sure to provide them in the respective app.config/main.ts providers array using
|
|
923
|
+
console.warn('\nā ļø Make sure to provide them in the respective app.config/main.ts providers array using provideBearerAuthProvider(yourConfigName)');
|
|
926
924
|
}
|
|
927
925
|
}
|
|
928
926
|
function addAuthProviderInjectFunction(content, clientName) {
|
|
@@ -965,6 +963,8 @@ function addAuthProviderInjectFunction(content, clientName) {
|
|
|
965
963
|
return result.slice(0, authProviderPosition) + injectFunction + result.slice(authProviderPosition);
|
|
966
964
|
}
|
|
967
965
|
function addAuthProviderToFile(content, clientName, configName) {
|
|
966
|
+
// Ensure createBearerAuthProviderConfig is imported
|
|
967
|
+
content = ensureImportFromQuery(content, ['createBearerAuthProviderConfig']);
|
|
968
968
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
969
969
|
// Find where the config is declared
|
|
970
970
|
let configPosition;
|
|
@@ -974,7 +974,6 @@ function addAuthProviderToFile(content, clientName, configName) {
|
|
|
974
974
|
node.name.text === configName &&
|
|
975
975
|
node.initializer &&
|
|
976
976
|
ts.isCallExpression(node.initializer)) {
|
|
977
|
-
// Find the variable statement
|
|
978
977
|
let parent = node.parent;
|
|
979
978
|
while (parent && !ts.isVariableStatement(parent)) {
|
|
980
979
|
parent = parent.parent;
|
|
@@ -990,13 +989,21 @@ function addAuthProviderToFile(content, clientName, configName) {
|
|
|
990
989
|
return content;
|
|
991
990
|
const authProviderCode = `
|
|
992
991
|
|
|
993
|
-
export const ${clientName}AuthProviderConfig =
|
|
992
|
+
export const ${clientName}AuthProviderConfig = createBearerAuthProviderConfig({
|
|
994
993
|
name: '${clientName}',
|
|
995
994
|
queryClientRef: ${configName}.token,
|
|
996
995
|
});`;
|
|
997
996
|
return content.slice(0, configPosition) + authProviderCode + content.slice(configPosition);
|
|
998
997
|
}
|
|
999
998
|
function generateSecureQueryCreators(content, clientName) {
|
|
999
|
+
// Ensure secure query creator functions are imported
|
|
1000
|
+
content = ensureImportFromQuery(content, [
|
|
1001
|
+
'createSecureGetQuery',
|
|
1002
|
+
'createSecurePostQuery',
|
|
1003
|
+
'createSecurePutQuery',
|
|
1004
|
+
'createSecurePatchQuery',
|
|
1005
|
+
'createSecureDeleteQuery',
|
|
1006
|
+
]);
|
|
1000
1007
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
1001
1008
|
// Find where the auth provider is declared
|
|
1002
1009
|
let authProviderPosition;
|
|
@@ -1023,11 +1030,11 @@ function generateSecureQueryCreators(content, clientName) {
|
|
|
1023
1030
|
const clientNameWithoutClient = clientName.replace('Client', '');
|
|
1024
1031
|
const configName = `${clientName}Config`;
|
|
1025
1032
|
const secureCreators = [
|
|
1026
|
-
`export const ${clientNameWithoutClient}GetSecure =
|
|
1027
|
-
`export const ${clientNameWithoutClient}PostSecure =
|
|
1028
|
-
`export const ${clientNameWithoutClient}PutSecure =
|
|
1029
|
-
`export const ${clientNameWithoutClient}PatchSecure =
|
|
1030
|
-
`export const ${clientNameWithoutClient}DeleteSecure =
|
|
1033
|
+
`export const ${clientNameWithoutClient}GetSecure = createSecureGetQuery(${configName}, ${authProviderName});`,
|
|
1034
|
+
`export const ${clientNameWithoutClient}PostSecure = createSecurePostQuery(${configName}, ${authProviderName});`,
|
|
1035
|
+
`export const ${clientNameWithoutClient}PutSecure = createSecurePutQuery(${configName}, ${authProviderName});`,
|
|
1036
|
+
`export const ${clientNameWithoutClient}PatchSecure = createSecurePatchQuery(${configName}, ${authProviderName});`,
|
|
1037
|
+
`export const ${clientNameWithoutClient}DeleteSecure = createSecureDeleteQuery(${configName}, ${authProviderName});`,
|
|
1031
1038
|
].join('\n');
|
|
1032
1039
|
return content.slice(0, authProviderPosition) + '\n\n' + secureCreators + content.slice(authProviderPosition);
|
|
1033
1040
|
}
|
|
@@ -1037,7 +1044,7 @@ function updateLegacyCreatorImportsAndUsages(tree, queryClientFiles) {
|
|
|
1037
1044
|
const legacyCreators = new Map(); // original name -> legacy name
|
|
1038
1045
|
const updatedFiles = [];
|
|
1039
1046
|
// Step 1: Find all legacy wrappers that were created
|
|
1040
|
-
|
|
1047
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1041
1048
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
1042
1049
|
return;
|
|
1043
1050
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -1052,7 +1059,7 @@ function updateLegacyCreatorImportsAndUsages(tree, queryClientFiles) {
|
|
|
1052
1059
|
return;
|
|
1053
1060
|
console.log(`\nā
Found ${legacyCreators.size} legacy query creator wrappers`);
|
|
1054
1061
|
// Step 2: Update imports and usages across the workspace
|
|
1055
|
-
|
|
1062
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1056
1063
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
1057
1064
|
return;
|
|
1058
1065
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -1078,25 +1085,21 @@ function updateLegacyCreatorImportsAndUsages(tree, queryClientFiles) {
|
|
|
1078
1085
|
}
|
|
1079
1086
|
}
|
|
1080
1087
|
function containsLegacyWrapperDefinitions(content) {
|
|
1081
|
-
return content.includes('
|
|
1088
|
+
return content.includes('createLegacyQueryCreator');
|
|
1082
1089
|
}
|
|
1083
1090
|
function findLegacyWrappers(content) {
|
|
1084
1091
|
const wrappers = new Map(); // original name -> legacy name
|
|
1085
1092
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
1086
1093
|
function visit(node) {
|
|
1087
|
-
// Find: export const legacyGetUsers =
|
|
1094
|
+
// Find: export const legacyGetUsers = createLegacyQueryCreator({ creator: getUsers });
|
|
1088
1095
|
if (ts.isVariableDeclaration(node) &&
|
|
1089
1096
|
ts.isIdentifier(node.name) &&
|
|
1090
1097
|
node.name.text.startsWith('legacy') &&
|
|
1091
1098
|
node.initializer &&
|
|
1092
1099
|
ts.isCallExpression(node.initializer)) {
|
|
1093
1100
|
const callExpr = node.initializer;
|
|
1094
|
-
// Check if it's
|
|
1095
|
-
if (ts.
|
|
1096
|
-
ts.isIdentifier(callExpr.expression.expression) &&
|
|
1097
|
-
callExpr.expression.expression.text === 'E' &&
|
|
1098
|
-
ts.isIdentifier(callExpr.expression.name) &&
|
|
1099
|
-
callExpr.expression.name.text === 'createLegacyQueryCreator') {
|
|
1101
|
+
// Check if it's createLegacyQueryCreator
|
|
1102
|
+
if (ts.isIdentifier(callExpr.expression) && callExpr.expression.text === 'createLegacyQueryCreator') {
|
|
1100
1103
|
// Extract the original creator name from the config object
|
|
1101
1104
|
if (callExpr.arguments.length > 0 && ts.isObjectLiteralExpression(callExpr.arguments[0])) {
|
|
1102
1105
|
const configObj = callExpr.arguments[0];
|
|
@@ -1274,7 +1277,7 @@ function updateLegacyCreatorUsages(content, legacyCreators) {
|
|
|
1274
1277
|
//#endregion
|
|
1275
1278
|
//#region Remove provideQueryClientForDevtools and QueryDevtoolsComponent in ts / et-query-devtools in html usage
|
|
1276
1279
|
function removeDevtoolsUsage(tree) {
|
|
1277
|
-
const projects =
|
|
1280
|
+
const projects = getProjects(tree);
|
|
1278
1281
|
const removedFromFiles = [];
|
|
1279
1282
|
// Only check app config files for provideQueryClientForDevtools
|
|
1280
1283
|
for (const [, projectConfig] of projects.entries()) {
|
|
@@ -1295,7 +1298,7 @@ function removeDevtoolsUsage(tree) {
|
|
|
1295
1298
|
}
|
|
1296
1299
|
}
|
|
1297
1300
|
// Check all TypeScript files for QueryDevtoolsComponent imports
|
|
1298
|
-
|
|
1301
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1299
1302
|
if (!filePath.endsWith('.ts'))
|
|
1300
1303
|
return;
|
|
1301
1304
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -1313,7 +1316,7 @@ function removeDevtoolsUsage(tree) {
|
|
|
1313
1316
|
}
|
|
1314
1317
|
});
|
|
1315
1318
|
// Check all HTML files for et-query-devtools
|
|
1316
|
-
|
|
1319
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1317
1320
|
if (!filePath.endsWith('.html'))
|
|
1318
1321
|
return;
|
|
1319
1322
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -1336,80 +1339,33 @@ function removeDevtoolsUsage(tree) {
|
|
|
1336
1339
|
}
|
|
1337
1340
|
}
|
|
1338
1341
|
function removeProvideQueryClientForDevtools(content) {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
// Remove provideQueryClientForDevtools from provider arrays
|
|
1343
|
-
if (ts.isCallExpression(node)) {
|
|
1344
|
-
if (ts.isIdentifier(node.expression) && node.expression.text === 'provideQueryClientForDevtools') {
|
|
1345
|
-
// Find the array this call is in
|
|
1346
|
-
let parent = node.parent;
|
|
1347
|
-
// Walk up until we find an array literal expression
|
|
1348
|
-
while (parent) {
|
|
1349
|
-
if (ts.isArrayLiteralExpression(parent)) {
|
|
1350
|
-
// Find which element contains our call expression
|
|
1351
|
-
const elementIndex = parent.elements.findIndex((el) => {
|
|
1352
|
-
// Check if this element or any of its descendants is our node
|
|
1353
|
-
let found = false;
|
|
1354
|
-
function search(n) {
|
|
1355
|
-
if (n === node) {
|
|
1356
|
-
found = true;
|
|
1357
|
-
return;
|
|
1358
|
-
}
|
|
1359
|
-
ts.forEachChild(n, search);
|
|
1360
|
-
}
|
|
1361
|
-
search(el);
|
|
1362
|
-
return found;
|
|
1363
|
-
});
|
|
1364
|
-
if (elementIndex !== -1) {
|
|
1365
|
-
const element = parent.elements[elementIndex];
|
|
1366
|
-
let start = element.getStart(sourceFile);
|
|
1367
|
-
let end = element.getEnd();
|
|
1368
|
-
// Handle comma and whitespace removal
|
|
1369
|
-
if (elementIndex < parent.elements.length - 1) {
|
|
1370
|
-
// Not the last element - remove trailing comma and whitespace
|
|
1371
|
-
const nextElement = parent.elements[elementIndex + 1];
|
|
1372
|
-
const textBetween = content.slice(end, nextElement.getStart(sourceFile));
|
|
1373
|
-
const commaIndex = textBetween.indexOf(',');
|
|
1374
|
-
if (commaIndex !== -1) {
|
|
1375
|
-
end += commaIndex + 1;
|
|
1376
|
-
// Also remove whitespace after comma
|
|
1377
|
-
while (end < content.length && /\s/.test(content[end])) {
|
|
1378
|
-
end++;
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
else if (elementIndex > 0) {
|
|
1383
|
-
// Last element - remove leading comma and whitespace
|
|
1384
|
-
const prevElement = parent.elements[elementIndex - 1];
|
|
1385
|
-
const textBetween = content.slice(prevElement.getEnd(), start);
|
|
1386
|
-
const commaIndex = textBetween.lastIndexOf(',');
|
|
1387
|
-
if (commaIndex !== -1) {
|
|
1388
|
-
start = prevElement.getEnd() + commaIndex;
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
// Remove leading whitespace/newlines
|
|
1392
|
-
while (start > 0 && /\s/.test(content[start - 1])) {
|
|
1393
|
-
start--;
|
|
1394
|
-
}
|
|
1395
|
-
replacements.push({ start, end, replacement: '' });
|
|
1396
|
-
}
|
|
1397
|
-
break;
|
|
1398
|
-
}
|
|
1399
|
-
parent = parent.parent;
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
ts.forEachChild(node, visit);
|
|
1404
|
-
}
|
|
1405
|
-
visit(sourceFile);
|
|
1406
|
-
// Apply replacements in reverse order
|
|
1342
|
+
// Simple regex approach to handle the common case
|
|
1343
|
+
// Match: ...(condition ? [] : [provideQueryClientForDevtools(...), ...])
|
|
1344
|
+
// Pattern 1: Remove entire spread when it only contains devtools
|
|
1407
1345
|
let result = content;
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1346
|
+
// Match spread expressions that contain only provideQueryClientForDevtools calls
|
|
1347
|
+
// This handles: ...(env.production ? [] : [devtools, devtools])
|
|
1348
|
+
const spreadPattern = /\.\.\.\([^)]+\?\s*\[\]\s*:\s*\[([\s\S]*?)\]\),?\s*/g;
|
|
1349
|
+
result = result.replace(spreadPattern, (match, innerContent) => {
|
|
1350
|
+
// Check if innerContent only has provideQueryClientForDevtools calls
|
|
1351
|
+
const lines = innerContent.split('\n').filter((line) => line.trim());
|
|
1352
|
+
const hasOnlyDevtools = lines.every((line) => line.trim().startsWith('provideQueryClientForDevtools') || line.trim() === '' || line.trim() === ',');
|
|
1353
|
+
if (hasOnlyDevtools) {
|
|
1354
|
+
return ''; // Remove the entire spread
|
|
1355
|
+
}
|
|
1356
|
+
// Otherwise, remove individual provideQueryClientForDevtools calls
|
|
1357
|
+
const cleaned = innerContent
|
|
1358
|
+
.split('\n')
|
|
1359
|
+
.filter((line) => !line.includes('provideQueryClientForDevtools'))
|
|
1360
|
+
.join('\n');
|
|
1361
|
+
return match.replace(innerContent, cleaned);
|
|
1362
|
+
});
|
|
1363
|
+
// Pattern 2: Remove standalone provideQueryClientForDevtools in regular arrays
|
|
1364
|
+
result = result.replace(/^\s*provideQueryClientForDevtools\([^)]*\),?\s*$/gm, '');
|
|
1365
|
+
// Clean up empty lines and trailing commas
|
|
1366
|
+
result = result.replace(/,\s*,/g, ','); // Double commas
|
|
1367
|
+
result = result.replace(/\[\s*,/g, '['); // Leading comma in array
|
|
1368
|
+
result = result.replace(/,\s*\]/g, ']'); // Trailing comma before closing bracket
|
|
1413
1369
|
return removeDevtoolsImports(result);
|
|
1414
1370
|
}
|
|
1415
1371
|
function removeQueryDevtoolsComponent(content) {
|
|
@@ -1515,17 +1471,17 @@ function removeDevtoolsFromHtml(content) {
|
|
|
1515
1471
|
return result;
|
|
1516
1472
|
}
|
|
1517
1473
|
//#endregion
|
|
1518
|
-
//#region Turn
|
|
1474
|
+
//#region Turn AnyV2Query into AnyLegacyQuery everywhere and do the same with AnyV2QueryCreator
|
|
1519
1475
|
function replaceAnyQueryWithLegacy(tree) {
|
|
1520
1476
|
const updatedFiles = [];
|
|
1521
|
-
|
|
1477
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1522
1478
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
1523
1479
|
return;
|
|
1524
1480
|
const content = tree.read(filePath, 'utf-8');
|
|
1525
1481
|
if (!content)
|
|
1526
1482
|
return;
|
|
1527
|
-
// Only process if it contains
|
|
1528
|
-
if (!content.includes('
|
|
1483
|
+
// Only process if it contains AnyV2Query or AnyV2QueryCreator
|
|
1484
|
+
if (!content.includes('AnyV2Query') && !content.includes('AnyV2QueryCreator'))
|
|
1529
1485
|
return;
|
|
1530
1486
|
const newContent = replaceAnyQueryInFile(content);
|
|
1531
1487
|
if (newContent !== content) {
|
|
@@ -1534,7 +1490,7 @@ function replaceAnyQueryWithLegacy(tree) {
|
|
|
1534
1490
|
}
|
|
1535
1491
|
});
|
|
1536
1492
|
if (updatedFiles.length > 0) {
|
|
1537
|
-
console.log('\nā
Replaced
|
|
1493
|
+
console.log('\nā
Replaced AnyV2Query and AnyV2QueryCreator with AnyLegacyQuery and AnyLegacyQueryCreator in:');
|
|
1538
1494
|
updatedFiles.forEach((file) => console.log(` - ${file}`));
|
|
1539
1495
|
}
|
|
1540
1496
|
}
|
|
@@ -1542,25 +1498,25 @@ function replaceAnyQueryInFile(content) {
|
|
|
1542
1498
|
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
1543
1499
|
const replacements = [];
|
|
1544
1500
|
function visit(node) {
|
|
1545
|
-
// Find type references to
|
|
1501
|
+
// Find type references to AnyV2Query and AnyV2QueryCreator
|
|
1546
1502
|
if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
|
|
1547
|
-
if (node.typeName.text === '
|
|
1503
|
+
if (node.typeName.text === 'AnyV2Query') {
|
|
1548
1504
|
replacements.push({
|
|
1549
1505
|
start: node.getStart(sourceFile),
|
|
1550
1506
|
end: node.getEnd(),
|
|
1551
|
-
replacement: '
|
|
1507
|
+
replacement: 'AnyLegacyQuery',
|
|
1552
1508
|
});
|
|
1553
1509
|
}
|
|
1554
|
-
else if (node.typeName.text === '
|
|
1510
|
+
else if (node.typeName.text === 'AnyV2QueryCreator') {
|
|
1555
1511
|
replacements.push({
|
|
1556
1512
|
start: node.getStart(sourceFile),
|
|
1557
1513
|
end: node.getEnd(),
|
|
1558
|
-
replacement: '
|
|
1514
|
+
replacement: 'AnyLegacyQueryCreator',
|
|
1559
1515
|
});
|
|
1560
1516
|
}
|
|
1561
1517
|
}
|
|
1562
1518
|
// Find identifier references (for runtime usage)
|
|
1563
|
-
if (ts.isIdentifier(node) && (node.text === '
|
|
1519
|
+
if (ts.isIdentifier(node) && (node.text === 'AnyV2Query' || node.text === 'AnyV2QueryCreator')) {
|
|
1564
1520
|
// Check if this is part of a type reference (already handled above)
|
|
1565
1521
|
const parent = node.parent;
|
|
1566
1522
|
if (ts.isTypeReferenceNode(parent) && parent.typeName === node) {
|
|
@@ -1573,7 +1529,7 @@ function replaceAnyQueryInFile(content) {
|
|
|
1573
1529
|
return;
|
|
1574
1530
|
}
|
|
1575
1531
|
// Replace standalone references
|
|
1576
|
-
const replacement = node.text === '
|
|
1532
|
+
const replacement = node.text === 'AnyV2Query' ? 'AnyLegacyQuery' : 'AnyLegacyQueryCreator';
|
|
1577
1533
|
replacements.push({
|
|
1578
1534
|
start: node.getStart(sourceFile),
|
|
1579
1535
|
end: node.getEnd(),
|
|
@@ -1589,11 +1545,18 @@ function replaceAnyQueryInFile(content) {
|
|
|
1589
1545
|
for (const { start, end, replacement } of replacements) {
|
|
1590
1546
|
result = result.slice(0, start) + replacement + result.slice(end);
|
|
1591
1547
|
}
|
|
1592
|
-
// Remove
|
|
1548
|
+
// Remove AnyV2Query and AnyV2QueryCreator from imports
|
|
1593
1549
|
result = removeAnyQueryFromImports(result);
|
|
1594
|
-
//
|
|
1595
|
-
if (
|
|
1596
|
-
|
|
1550
|
+
// Add AnyLegacyQuery and AnyLegacyQueryCreator imports if needed
|
|
1551
|
+
if (result.includes('AnyLegacyQuery') || result.includes('AnyLegacyQueryCreator')) {
|
|
1552
|
+
const importsToAdd = [];
|
|
1553
|
+
if (result.includes('AnyLegacyQuery')) {
|
|
1554
|
+
importsToAdd.push('AnyLegacyQuery');
|
|
1555
|
+
}
|
|
1556
|
+
if (result.includes('AnyLegacyQueryCreator')) {
|
|
1557
|
+
importsToAdd.push('AnyLegacyQueryCreator');
|
|
1558
|
+
}
|
|
1559
|
+
result = ensureImportFromQuery(result, importsToAdd);
|
|
1597
1560
|
}
|
|
1598
1561
|
return result;
|
|
1599
1562
|
}
|
|
@@ -1613,7 +1576,7 @@ function removeAnyQueryFromImports(content) {
|
|
|
1613
1576
|
return content;
|
|
1614
1577
|
}
|
|
1615
1578
|
const namedBindings = queryImportNode.importClause.namedBindings;
|
|
1616
|
-
const elementsToKeep = namedBindings.elements.filter((el) => el.name.text !== '
|
|
1579
|
+
const elementsToKeep = namedBindings.elements.filter((el) => el.name.text !== 'AnyV2Query' && el.name.text !== 'AnyV2QueryCreator');
|
|
1617
1580
|
if (elementsToKeep.length === namedBindings.elements.length) {
|
|
1618
1581
|
// Nothing to remove
|
|
1619
1582
|
return content;
|
|
@@ -1629,7 +1592,7 @@ function removeAnyQueryFromImports(content) {
|
|
|
1629
1592
|
end++;
|
|
1630
1593
|
return content.slice(0, start) + content.slice(end);
|
|
1631
1594
|
}
|
|
1632
|
-
// Reconstruct import without
|
|
1595
|
+
// Reconstruct import without AnyV2Query and AnyV2QueryCreator
|
|
1633
1596
|
const newImports = elementsToKeep.map((el) => el.getText(sourceFile));
|
|
1634
1597
|
const moduleSpecifier = queryImportNode.moduleSpecifier.text;
|
|
1635
1598
|
const newImportStatement = `import { ${newImports.join(', ')} } from '${moduleSpecifier}';`;
|
|
@@ -1671,11 +1634,7 @@ function addInjectFunctionsToFile(content, configNames) {
|
|
|
1671
1634
|
node.initializer &&
|
|
1672
1635
|
ts.isCallExpression(node.initializer)) {
|
|
1673
1636
|
const callExpr = node.initializer;
|
|
1674
|
-
if (ts.
|
|
1675
|
-
ts.isIdentifier(callExpr.expression.expression) &&
|
|
1676
|
-
callExpr.expression.expression.text === 'E' &&
|
|
1677
|
-
ts.isIdentifier(callExpr.expression.name) &&
|
|
1678
|
-
callExpr.expression.name.text === 'createQueryClientConfig') {
|
|
1637
|
+
if (ts.isIdentifier(callExpr.expression) && callExpr.expression.text === 'createQueryClientConfig') {
|
|
1679
1638
|
const configName = node.name.text;
|
|
1680
1639
|
// Find the variable statement
|
|
1681
1640
|
let parent = node.parent;
|
|
@@ -1769,7 +1728,7 @@ function checkLegacyQueryCreatorUsage(tree) {
|
|
|
1769
1728
|
console.log('\nš Checking for legacy query creator usages...');
|
|
1770
1729
|
// Step 1: Collect all usages BEFORE any transformations
|
|
1771
1730
|
const allUsages = [];
|
|
1772
|
-
|
|
1731
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
1773
1732
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
1774
1733
|
return;
|
|
1775
1734
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -1873,11 +1832,7 @@ function findLegacyCreatorNames(sourceFile, content) {
|
|
|
1873
1832
|
node.initializer &&
|
|
1874
1833
|
ts.isCallExpression(node.initializer)) {
|
|
1875
1834
|
const callExpr = node.initializer;
|
|
1876
|
-
if (ts.
|
|
1877
|
-
ts.isIdentifier(callExpr.expression.expression) &&
|
|
1878
|
-
callExpr.expression.expression.text === 'E' &&
|
|
1879
|
-
ts.isIdentifier(callExpr.expression.name) &&
|
|
1880
|
-
callExpr.expression.name.text === 'createLegacyQueryCreator') {
|
|
1835
|
+
if (ts.isIdentifier(callExpr.expression) && callExpr.expression.text === 'createLegacyQueryCreator') {
|
|
1881
1836
|
names.add(node.name.text);
|
|
1882
1837
|
}
|
|
1883
1838
|
}
|
|
@@ -1900,14 +1855,6 @@ function determineUsageContext(node, sourceFile) {
|
|
|
1900
1855
|
if (ts.isIdentifier(expr) && expr.text === 'queryComputed') {
|
|
1901
1856
|
return 'queryComputed';
|
|
1902
1857
|
}
|
|
1903
|
-
// Check for E.queryComputed()
|
|
1904
|
-
if (ts.isPropertyAccessExpression(expr) &&
|
|
1905
|
-
ts.isIdentifier(expr.expression) &&
|
|
1906
|
-
expr.expression.text === 'E' &&
|
|
1907
|
-
ts.isIdentifier(expr.name) &&
|
|
1908
|
-
expr.name.text === 'queryComputed') {
|
|
1909
|
-
return 'queryComputed';
|
|
1910
|
-
}
|
|
1911
1858
|
}
|
|
1912
1859
|
}
|
|
1913
1860
|
// Check for constructor
|
|
@@ -2217,7 +2164,7 @@ function transformLegacyCreatorPrepareCall(tree, classInjectors, pollingInfo) {
|
|
|
2217
2164
|
filesByPath.get(classInfo.filePath).push(classInfo);
|
|
2218
2165
|
});
|
|
2219
2166
|
// Also check files with standalone function usages
|
|
2220
|
-
|
|
2167
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
2221
2168
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
2222
2169
|
return;
|
|
2223
2170
|
if (filesByPath.has(filePath))
|
|
@@ -2764,7 +2711,7 @@ function containsInjectCall(node) {
|
|
|
2764
2711
|
//#region Migrate empty .prepare() calls to .prepare({})
|
|
2765
2712
|
function migrateEmptyPrepareCalls(tree) {
|
|
2766
2713
|
const updatedFiles = [];
|
|
2767
|
-
|
|
2714
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
2768
2715
|
if (!filePath.endsWith('.ts') || filePath.endsWith('.spec.ts'))
|
|
2769
2716
|
return;
|
|
2770
2717
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -2820,7 +2767,7 @@ function transformEmptyPrepareCalls(content) {
|
|
|
2820
2767
|
}
|
|
2821
2768
|
function detectPollingUsage(tree) {
|
|
2822
2769
|
const pollingInfo = new Map();
|
|
2823
|
-
|
|
2770
|
+
visitNotIgnoredFiles(tree, '', (filePath) => {
|
|
2824
2771
|
if (filePath.endsWith('.spec.ts'))
|
|
2825
2772
|
return;
|
|
2826
2773
|
const content = tree.read(filePath, 'utf-8');
|
|
@@ -2947,4 +2894,50 @@ function shouldAddDestroyOnResponse(queryVariableName, pollingInfo) {
|
|
|
2947
2894
|
return true;
|
|
2948
2895
|
}
|
|
2949
2896
|
//#endregion
|
|
2897
|
+
//#region Helper function to ensure imports from @ethlete/query
|
|
2898
|
+
function ensureImportFromQuery(content, importsNeeded) {
|
|
2899
|
+
const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
|
|
2900
|
+
let queryImportNode;
|
|
2901
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
2902
|
+
if (ts.isImportDeclaration(node) &&
|
|
2903
|
+
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
2904
|
+
node.moduleSpecifier.text === '@ethlete/query') {
|
|
2905
|
+
queryImportNode = node;
|
|
2906
|
+
}
|
|
2907
|
+
});
|
|
2908
|
+
const missingImports = new Set(importsNeeded);
|
|
2909
|
+
if (queryImportNode?.importClause?.namedBindings && ts.isNamedImports(queryImportNode.importClause.namedBindings)) {
|
|
2910
|
+
const namedBindings = queryImportNode.importClause.namedBindings;
|
|
2911
|
+
// Check which imports already exist
|
|
2912
|
+
namedBindings.elements.forEach((el) => {
|
|
2913
|
+
missingImports.delete(el.name.text);
|
|
2914
|
+
});
|
|
2915
|
+
if (missingImports.size === 0) {
|
|
2916
|
+
return content; // All needed imports already exist
|
|
2917
|
+
}
|
|
2918
|
+
// Add missing imports to existing import statement
|
|
2919
|
+
const existingImports = namedBindings.elements.map((el) => el.getText(sourceFile));
|
|
2920
|
+
const allImports = [...existingImports, ...Array.from(missingImports).sort()].sort();
|
|
2921
|
+
const newImportStatement = `import { ${allImports.join(', ')} } from '@ethlete/query';`;
|
|
2922
|
+
const importStart = queryImportNode.getStart(sourceFile);
|
|
2923
|
+
const importEnd = queryImportNode.getEnd();
|
|
2924
|
+
return content.slice(0, importStart) + newImportStatement + content.slice(importEnd);
|
|
2925
|
+
}
|
|
2926
|
+
// No @ethlete/query import exists - create one
|
|
2927
|
+
let lastImportEnd = 0;
|
|
2928
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
2929
|
+
if (ts.isImportDeclaration(node)) {
|
|
2930
|
+
const end = node.getEnd();
|
|
2931
|
+
if (end > lastImportEnd) {
|
|
2932
|
+
lastImportEnd = end;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
});
|
|
2936
|
+
const newImportStatement = `\nimport { ${Array.from(missingImports).sort().join(', ')} } from '@ethlete/query';`;
|
|
2937
|
+
if (lastImportEnd > 0) {
|
|
2938
|
+
return content.slice(0, lastImportEnd) + newImportStatement + content.slice(lastImportEnd);
|
|
2939
|
+
}
|
|
2940
|
+
return `import { ${Array.from(missingImports).sort().join(', ')} } from '@ethlete/query';\n\n${content}`;
|
|
2941
|
+
}
|
|
2942
|
+
//#endregion
|
|
2950
2943
|
//# sourceMappingURL=migration.js.map
|