@ethlete/query 6.0.0-next.46 → 6.0.0-next.49
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 +44 -0
- package/fesm2022/ethlete-query-testing.mjs +8 -0
- package/fesm2022/ethlete-query-testing.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +475 -150
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/migrate-query-opt-in-features/migration.js +13 -1
- package/generators/migrate-to-query-v3/auth-provider-scaffold.js +6 -4
- package/generators/migrate-to-query-v3/cleanup-migration.js +2 -42
- package/generators/migrate-to-query-v3/legacy-prepare-migration.js +9 -12
- package/generators/migrate-to-query-v3/legacy-query-creator-migration.js +81 -15
- package/generators/migrate-to-query-v3/migration-scope.js +0 -3
- package/generators/migrate-to-query-v3/query-client-migration.js +97 -47
- package/generators/migrate-to-query-v3/rename-symbols.js +19 -6
- package/generators/migrate-to-query-v3/shared.js +6 -2
- package/generators/prep-for-query-v3/migration.js +68 -11
- package/package.json +1 -1
- package/types/ethlete-query-testing.d.ts +2 -0
- package/types/ethlete-query.d.ts +250 -49
|
@@ -17,8 +17,6 @@ const isNamePosition = (node) => {
|
|
|
17
17
|
// Object literal / type member keys, enum members, JSX-ish attribute names.
|
|
18
18
|
if (ts.isPropertyAssignment(parent) && parent.name === node)
|
|
19
19
|
return true;
|
|
20
|
-
if (ts.isShorthandPropertyAssignment(parent) && parent.name === node)
|
|
21
|
-
return true;
|
|
22
20
|
if (ts.isPropertySignature(parent) && parent.name === node)
|
|
23
21
|
return true;
|
|
24
22
|
if (ts.isMethodSignature(parent) && parent.name === node)
|
|
@@ -57,12 +55,24 @@ const isNamePosition = (node) => {
|
|
|
57
55
|
if (ts.isLabeledStatement(parent) && parent.label === node)
|
|
58
56
|
return true;
|
|
59
57
|
// Import / export clauses are rewritten by the caller, never by the reference pass.
|
|
60
|
-
if (ts.isImportSpecifier(parent)
|
|
58
|
+
if (ts.isImportSpecifier(parent))
|
|
59
|
+
return true;
|
|
60
|
+
if (ts.isExportSpecifier(parent) &&
|
|
61
|
+
(parent.parent.parent.moduleSpecifier || (parent.propertyName && parent.name === node))) {
|
|
61
62
|
return true;
|
|
63
|
+
}
|
|
62
64
|
if (ts.isImportClause(parent) || ts.isNamespaceImport(parent))
|
|
63
65
|
return true;
|
|
64
66
|
return false;
|
|
65
67
|
};
|
|
68
|
+
const renamedReference = (node, nextName) => {
|
|
69
|
+
const parent = node.parent;
|
|
70
|
+
if (ts.isShorthandPropertyAssignment(parent))
|
|
71
|
+
return `${node.text}: ${nextName}`;
|
|
72
|
+
if (ts.isExportSpecifier(parent) && !parent.propertyName)
|
|
73
|
+
return `${nextName} as ${node.text}`;
|
|
74
|
+
return nextName;
|
|
75
|
+
};
|
|
66
76
|
/** Every name the file declares itself - a local by the same name means the import is shadowed. */
|
|
67
77
|
const collectLocalDeclarations = (sourceFile) => {
|
|
68
78
|
const declared = new Set();
|
|
@@ -115,7 +125,11 @@ export const renameImportedReferences = (content, renames) => {
|
|
|
115
125
|
if (ts.isIdentifier(node)) {
|
|
116
126
|
const nextName = applicable.get(node.text);
|
|
117
127
|
if (nextName && !isNamePosition(node)) {
|
|
118
|
-
replacements.push({
|
|
128
|
+
replacements.push({
|
|
129
|
+
start: node.getStart(sourceFile),
|
|
130
|
+
end: node.getEnd(),
|
|
131
|
+
replacement: renamedReference(node, nextName),
|
|
132
|
+
});
|
|
119
133
|
}
|
|
120
134
|
}
|
|
121
135
|
ts.forEachChild(node, visit);
|
|
@@ -136,7 +150,7 @@ export const renameImportedReferences = (content, renames) => {
|
|
|
136
150
|
* the same generator invocation so they land that way. Identifiers inside template strings count as
|
|
137
151
|
* usage too - a component referenced only from an inline template must not be pruned.
|
|
138
152
|
*/
|
|
139
|
-
export const pruneUnusedNamedImports = (content
|
|
153
|
+
export const pruneUnusedNamedImports = (content) => {
|
|
140
154
|
const sourceFile = createSourceFile(content);
|
|
141
155
|
const used = new Set();
|
|
142
156
|
const addWordsFrom = (text) => {
|
|
@@ -162,7 +176,6 @@ export const pruneUnusedNamedImports = (content, moduleSpecifiers) => {
|
|
|
162
176
|
for (const node of sourceFile.statements) {
|
|
163
177
|
if (!ts.isImportDeclaration(node) ||
|
|
164
178
|
!ts.isStringLiteral(node.moduleSpecifier) ||
|
|
165
|
-
(moduleSpecifiers !== 'all' && !moduleSpecifiers.includes(node.moduleSpecifier.text)) ||
|
|
166
179
|
!node.importClause?.namedBindings ||
|
|
167
180
|
!ts.isNamedImports(node.importClause.namedBindings)) {
|
|
168
181
|
continue;
|
|
@@ -17,9 +17,13 @@ export const ensureNamedImports = ({ content, importsNeeded, moduleSpecifier })
|
|
|
17
17
|
const sourceFile = createSourceFile(content);
|
|
18
18
|
let importNode;
|
|
19
19
|
ts.forEachChild(sourceFile, (node) => {
|
|
20
|
-
if (
|
|
20
|
+
if (!importNode &&
|
|
21
|
+
ts.isImportDeclaration(node) &&
|
|
21
22
|
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
22
|
-
node.moduleSpecifier.text === moduleSpecifier
|
|
23
|
+
node.moduleSpecifier.text === moduleSpecifier &&
|
|
24
|
+
!node.importClause?.isTypeOnly &&
|
|
25
|
+
node.importClause?.namedBindings &&
|
|
26
|
+
ts.isNamedImports(node.importClause.namedBindings)) {
|
|
23
27
|
importNode = node;
|
|
24
28
|
}
|
|
25
29
|
});
|
|
@@ -76,7 +76,18 @@ function renameSymbolsInFile(content, filePath, symbolUsageCounts) {
|
|
|
76
76
|
const replacements = [];
|
|
77
77
|
// Track which symbols are imported from @ethlete/query
|
|
78
78
|
const importedSymbols = new Set();
|
|
79
|
+
const namespaceAliases = collectQueryNamespaceAliases(sourceFile);
|
|
79
80
|
function visit(node) {
|
|
81
|
+
const namespaceMember = getNamespaceMember(node, namespaceAliases)?.member;
|
|
82
|
+
const renamedMember = namespaceMember && (TYPE_RENAMES.get(namespaceMember.text) || FUNCTION_RENAMES.get(namespaceMember.text));
|
|
83
|
+
if (namespaceMember && renamedMember) {
|
|
84
|
+
replacements.push({
|
|
85
|
+
start: namespaceMember.getStart(sourceFile),
|
|
86
|
+
end: namespaceMember.getEnd(),
|
|
87
|
+
replacement: renamedMember,
|
|
88
|
+
oldName: namespaceMember.text,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
80
91
|
// Track imports from @ethlete/query
|
|
81
92
|
if (ts.isImportDeclaration(node)) {
|
|
82
93
|
const moduleSpecifier = node.moduleSpecifier;
|
|
@@ -107,7 +118,9 @@ function renameSymbolsInFile(content, filePath, symbolUsageCounts) {
|
|
|
107
118
|
return;
|
|
108
119
|
}
|
|
109
120
|
// Skip if it's the imported name in an import specifier (we'll handle that separately)
|
|
110
|
-
if (ts.isImportSpecifier(parent) && (parent.propertyName === node || parent.name === node))
|
|
121
|
+
if ((ts.isImportSpecifier(parent) && (parent.propertyName === node || parent.name === node)) ||
|
|
122
|
+
(ts.isPropertyAccessExpression(parent) && parent.name === node) ||
|
|
123
|
+
(ts.isQualifiedName(parent) && parent.right === node)) {
|
|
111
124
|
ts.forEachChild(node, visit);
|
|
112
125
|
return;
|
|
113
126
|
}
|
|
@@ -138,6 +151,33 @@ function renameSymbolsInFile(content, filePath, symbolUsageCounts) {
|
|
|
138
151
|
}
|
|
139
152
|
return result;
|
|
140
153
|
}
|
|
154
|
+
function collectQueryNamespaceAliases(sourceFile) {
|
|
155
|
+
const aliases = new Set();
|
|
156
|
+
sourceFile.statements.forEach((statement) => {
|
|
157
|
+
if (!ts.isImportDeclaration(statement)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
161
|
+
if (namedBindings &&
|
|
162
|
+
ts.isNamespaceImport(namedBindings) &&
|
|
163
|
+
ts.isStringLiteral(statement.moduleSpecifier) &&
|
|
164
|
+
statement.moduleSpecifier.text === '@ethlete/query') {
|
|
165
|
+
aliases.add(namedBindings.name.text);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return aliases;
|
|
169
|
+
}
|
|
170
|
+
function getNamespaceMember(node, namespaceAliases) {
|
|
171
|
+
const [namespace, member] = ts.isPropertyAccessExpression(node)
|
|
172
|
+
? [node.expression, node.name]
|
|
173
|
+
: ts.isQualifiedName(node)
|
|
174
|
+
? [node.left, node.right]
|
|
175
|
+
: [];
|
|
176
|
+
if (!namespace || !member || !ts.isIdentifier(namespace) || !ts.isIdentifier(member)) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
return namespaceAliases.has(namespace.text) ? { namespace, member } : undefined;
|
|
180
|
+
}
|
|
141
181
|
function updateImports(sourceFile) {
|
|
142
182
|
const replacements = [];
|
|
143
183
|
function visit(node) {
|
|
@@ -232,9 +272,11 @@ function replaceNamespaceInFile(content, filePath) {
|
|
|
232
272
|
ts.forEachChild(node, collectImport);
|
|
233
273
|
}
|
|
234
274
|
collectImport(sourceFile);
|
|
275
|
+
const namespaceAliases = collectQueryNamespaceAliases(sourceFile);
|
|
276
|
+
const namespaceReplacements = collectNamespacedExperimentalQueryReplacements(sourceFile, namespaceAliases);
|
|
235
277
|
// If no ExperimentalQuery import found, return unchanged
|
|
236
278
|
if (!hasExperimentalQueryImport || !experimentalQueryAlias) {
|
|
237
|
-
return
|
|
279
|
+
return applyReplacements(content, namespaceReplacements, namespaceReplacements.length);
|
|
238
280
|
}
|
|
239
281
|
// Second pass: collect used symbols
|
|
240
282
|
function findUsages(node) {
|
|
@@ -313,17 +355,32 @@ function replaceNamespaceInFile(content, filePath) {
|
|
|
313
355
|
ts.forEachChild(node, createReplacements);
|
|
314
356
|
}
|
|
315
357
|
createReplacements(sourceFile);
|
|
316
|
-
//
|
|
358
|
+
// Subtract 1 for the import replacement
|
|
359
|
+
return applyReplacements(content, [...replacements, ...namespaceReplacements], replacements.length - 1 + namespaceReplacements.length);
|
|
360
|
+
}
|
|
361
|
+
function collectNamespacedExperimentalQueryReplacements(sourceFile, namespaceAliases) {
|
|
362
|
+
const replacements = [];
|
|
363
|
+
if (namespaceAliases.size === 0) {
|
|
364
|
+
return replacements;
|
|
365
|
+
}
|
|
366
|
+
function visit(node) {
|
|
367
|
+
const access = getNamespaceMember(node, namespaceAliases);
|
|
368
|
+
if (access?.member.text === 'ExperimentalQuery') {
|
|
369
|
+
replacements.push({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: access.namespace.text });
|
|
370
|
+
}
|
|
371
|
+
ts.forEachChild(node, visit);
|
|
372
|
+
}
|
|
373
|
+
visit(sourceFile);
|
|
374
|
+
return replacements;
|
|
375
|
+
}
|
|
376
|
+
function applyReplacements(content, replacements, replacementCount) {
|
|
317
377
|
let result = content;
|
|
318
|
-
replacements
|
|
319
|
-
|
|
378
|
+
[...replacements]
|
|
379
|
+
.sort((a, b) => b.start - a.start)
|
|
380
|
+
.forEach(({ start, end, replacement }) => {
|
|
320
381
|
result = result.slice(0, start) + replacement + result.slice(end);
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
content: result,
|
|
324
|
-
modified: replacements.length > 0,
|
|
325
|
-
replacementCount: replacements.length - 1, // Subtract 1 for the import replacement
|
|
326
|
-
};
|
|
382
|
+
});
|
|
383
|
+
return { content: result, modified: replacements.length > 0, replacementCount };
|
|
327
384
|
}
|
|
328
385
|
//#endregion
|
|
329
386
|
//# sourceMappingURL=migration.js.map
|
package/package.json
CHANGED
|
@@ -283,6 +283,8 @@ type WebSocketTestDouble = {
|
|
|
283
283
|
} | null;
|
|
284
284
|
/** The `withCredentials` the client asked the factory for, or `null` until it called it. */
|
|
285
285
|
withCredentials: () => boolean | null;
|
|
286
|
+
/** The auth payload of every handshake, oldest first - `null` for one made without `auth`. */
|
|
287
|
+
handshakes: () => (object | null)[];
|
|
286
288
|
/** Every message the client emitted, newest last - room joins and leaves included, buffered ones too. */
|
|
287
289
|
sent: () => {
|
|
288
290
|
event: string;
|