@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.
@@ -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) || ts.isExportSpecifier(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({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: nextName });
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, moduleSpecifiers) => {
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 (ts.isImportDeclaration(node) &&
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 { content, modified: false, replacementCount: 0 };
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
- // Apply replacements in reverse order
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.sort((a, b) => b.start - a.start);
319
- for (const { start, end, replacement } of replacements) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/query",
3
- "version": "6.0.0-next.46",
3
+ "version": "6.0.0-next.49",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -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;