@yahoo/uds 3.171.1 → 3.172.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.
Files changed (28) hide show
  1. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +2 -2
  2. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +2 -2
  3. package/dist/components/Link.cjs +3 -3
  4. package/dist/components/Link.js +3 -3
  5. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.cts +1 -1
  6. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.ts +1 -1
  7. package/dist/css/dist/purger/optimized/ast/expressions.cjs +278 -278
  8. package/dist/css/dist/purger/optimized/ast/expressions.js +278 -278
  9. package/dist/css/dist/purger/optimized/ast/jsx.cjs +67 -36
  10. package/dist/css/dist/purger/optimized/ast/jsx.js +67 -35
  11. package/dist/css/dist/purger/optimized/ast/oxc.cjs +265 -0
  12. package/dist/css/dist/purger/optimized/ast/oxc.js +253 -0
  13. package/dist/css/dist/purger/optimized/ast/props.cjs +21 -15
  14. package/dist/css/dist/purger/optimized/ast/props.js +21 -14
  15. package/dist/css/dist/purger/optimized/ast/spread.cjs +19 -19
  16. package/dist/css/dist/purger/optimized/ast/spread.js +19 -18
  17. package/dist/css/dist/purger/optimized/purgeFromCode.cjs +86 -101
  18. package/dist/css/dist/purger/optimized/purgeFromCode.js +86 -100
  19. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.cts +2 -2
  20. package/dist/tailwind-internal/dist/utils/getShadowStyles.d.ts +2 -2
  21. package/dist/tailwind-v3/dist/purger/legacy/purgeCSS.cjs +1 -1
  22. package/dist/tailwind-v3/dist/purger/legacy/purgeCSS.js +1 -1
  23. package/dist/uds/generated/componentData.cjs +340 -340
  24. package/dist/uds/generated/componentData.js +340 -340
  25. package/dist/uds/package.cjs +2 -0
  26. package/dist/uds/package.js +2 -0
  27. package/generated/componentData.json +783 -783
  28. package/package.json +3 -1
@@ -1,29 +1,14 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
+ import { findLocalDefinitions, forEachDescendant, getParent, getPropertyName, getStringLiteralValue, getText, isNoSubstitutionTemplate, isStringLiteral, parseSource } from "./oxc.js";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
- import { Node, Project, SyntaxKind, ts } from "ts-morph";
5
+ import { ResolverFactory } from "oxc-resolver";
5
6
  //#region ../css/dist/purger/optimized/ast/expressions.mjs
6
7
  /*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
7
- const importedSourceProject = new Project({ useInMemoryFileSystem: true });
8
- const importedSourceFileCache = /* @__PURE__ */ new Map();
8
+ const importedSourceCache = /* @__PURE__ */ new Map();
9
9
  const tsConfigPathCache = /* @__PURE__ */ new Map();
10
- const compilerOptionsCache = /* @__PURE__ */ new Map();
10
+ const resolverCache = /* @__PURE__ */ new Map();
11
11
  const hasImportQuery = (moduleSpecifier) => moduleSpecifier.includes("?");
12
- const getLocalDefinitionNodes = (node) => {
13
- if (!Node.isIdentifier(node)) return [];
14
- const name = node.getText();
15
- const nodeStart = node.getStart();
16
- const sourceFile = node.getSourceFile();
17
- return [
18
- ...sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration).filter((definition) => definition.getName() === name && definition.getStart() <= nodeStart),
19
- ...sourceFile.getDescendantsOfKind(SyntaxKind.Parameter).filter((definition) => definition.getName() === name && definition.getStart() <= nodeStart),
20
- ...sourceFile.getDescendantsOfKind(SyntaxKind.BindingElement).filter((definition) => definition.getName() === name && definition.getStart() <= nodeStart),
21
- ...sourceFile.getFunctions().filter((definition) => definition.getName() === name && definition.getStart() <= nodeStart)
22
- ].sort((left, right) => right.getStart() - left.getStart()).slice(0, 1);
23
- };
24
- const getDefinitionNodesSafe = (node) => {
25
- return getLocalDefinitionNodes(node);
26
- };
27
12
  const isExistingFile = (candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isFile();
28
13
  const resolveRelativeImportPath = (sourceFilePath, moduleSpecifier) => {
29
14
  if (!path.isAbsolute(sourceFilePath) || !moduleSpecifier.startsWith(".") || hasImportQuery(moduleSpecifier)) return null;
@@ -68,55 +53,69 @@ const findNearestTypeScriptConfig = (sourceFilePath) => {
68
53
  currentDir = parentDir;
69
54
  }
70
55
  };
71
- const getCompilerOptionsForSourceFile = (sourceFilePath) => {
56
+ const getResolverForConfig = (configPath) => {
57
+ const cached = resolverCache.get(configPath);
58
+ if (cached) return cached;
59
+ const resolver = new ResolverFactory({
60
+ tsconfig: {
61
+ configFile: configPath,
62
+ references: "auto"
63
+ },
64
+ extensions: [
65
+ ".ts",
66
+ ".tsx",
67
+ ".mts",
68
+ ".cts",
69
+ ".js",
70
+ ".jsx",
71
+ ".mjs",
72
+ ".cjs"
73
+ ],
74
+ conditionNames: [
75
+ "import",
76
+ "require",
77
+ "node"
78
+ ]
79
+ });
80
+ resolverCache.set(configPath, resolver);
81
+ return resolver;
82
+ };
83
+ const resolveConfigImportPath = (sourceFilePath, moduleSpecifier) => {
84
+ if (hasImportQuery(moduleSpecifier)) return null;
72
85
  const configPath = findNearestTypeScriptConfig(sourceFilePath);
73
86
  if (!configPath) return null;
74
- const cached = compilerOptionsCache.get(configPath);
75
- if (cached !== void 0) return cached;
76
- const readResult = ts.readConfigFile(configPath, ts.sys.readFile);
77
- if (readResult.error) {
78
- compilerOptionsCache.set(configPath, null);
87
+ try {
88
+ const resolved = getResolverForConfig(configPath).sync(path.dirname(sourceFilePath), moduleSpecifier).path;
89
+ if (!resolved) return null;
90
+ if (resolved.includes(`${path.sep}node_modules${path.sep}`)) return null;
91
+ return isExistingFile(resolved) ? resolved : null;
92
+ } catch {
79
93
  return null;
80
94
  }
81
- const parsed = ts.parseJsonConfigFileContent(readResult.config, ts.sys, path.dirname(configPath));
82
- const compilerOptions = parsed.options.paths && !parsed.options.baseUrl ? {
83
- ...parsed.options,
84
- baseUrl: path.dirname(configPath)
85
- } : parsed.options;
86
- compilerOptionsCache.set(configPath, compilerOptions);
87
- return compilerOptions;
88
- };
89
- const resolveConfigImportPath = (sourceFilePath, moduleSpecifier) => {
90
- if (hasImportQuery(moduleSpecifier)) return null;
91
- const compilerOptions = getCompilerOptionsForSourceFile(sourceFilePath);
92
- if (!compilerOptions) return null;
93
- const resolvedModule = ts.resolveModuleName(moduleSpecifier, sourceFilePath, compilerOptions, ts.sys).resolvedModule;
94
- if (!resolvedModule) return null;
95
- return isExistingFile(resolvedModule.resolvedFileName) ? resolvedModule.resolvedFileName : null;
96
95
  };
97
96
  const resolveImportPath = (sourceFilePath, moduleSpecifier) => moduleSpecifier.startsWith(".") ? resolveRelativeImportPath(sourceFilePath, moduleSpecifier) : resolveConfigImportPath(sourceFilePath, moduleSpecifier);
98
- const getImportedSourceFile = (filePath) => {
99
- const cached = importedSourceFileCache.get(filePath);
97
+ const getImportedSource = (filePath) => {
98
+ const cached = importedSourceCache.get(filePath);
100
99
  if (cached) return cached;
101
100
  if (!fs.existsSync(filePath)) return null;
102
- const sourceFile = importedSourceProject.createSourceFile(filePath, fs.readFileSync(filePath, "utf-8"), { overwrite: true });
103
- importedSourceFileCache.set(filePath, sourceFile);
104
- return sourceFile;
101
+ const source = parseSource(filePath, fs.readFileSync(filePath, "utf-8"));
102
+ importedSourceCache.set(filePath, source);
103
+ return source;
105
104
  };
106
- const extractImportedIdentifierValues = (node, visited) => {
107
- if (!Node.isIdentifier(node)) return [];
108
- const sourceFile = node.getSourceFile();
109
- const sourceFilePath = sourceFile.getFilePath();
110
- const importMatch = sourceFile.getImportDeclarations().find((importDecl) => importDecl.getNamedImports().some((namedImport) => (namedImport.getAliasNode()?.getText() ?? namedImport.getName()) === node.getText()));
111
- if (!importMatch) return [];
112
- const namedImport = importMatch.getNamedImports().find((candidate) => (candidate.getAliasNode()?.getText() ?? candidate.getName()) === node.getText());
113
- if (!namedImport) return [];
114
- const resolvedPath = resolveImportPath(sourceFilePath, importMatch.getModuleSpecifierValue());
105
+ const extractImportedIdentifierValues = (node, source, visited) => {
106
+ if (node.type !== "Identifier") return [];
107
+ const localName = node.name;
108
+ const entry = source.staticImports.flatMap((staticImport) => staticImport.entries.map((importEntry) => ({
109
+ staticImport,
110
+ importEntry
111
+ }))).find(({ importEntry }) => importEntry.importName.kind === "Name" && importEntry.localName.value === localName);
112
+ if (!entry || !entry.importEntry.importName.name) return [];
113
+ const resolvedPath = resolveImportPath(source.filePath, entry.staticImport.moduleRequest.value);
115
114
  if (!resolvedPath) return [];
116
- const importedSourceFile = getImportedSourceFile(resolvedPath);
117
- if (!importedSourceFile) return [];
118
- const initializer = importedSourceFile.getVariableDeclaration(namedImport.getName())?.getInitializer();
119
- return initializer ? extractStringLiterals(initializer, visited) : [];
115
+ const importedSource = getImportedSource(resolvedPath);
116
+ if (!importedSource) return [];
117
+ const initializer = importedSource.topLevelVariables.get(entry.importEntry.importName.name)?.init;
118
+ return initializer ? extractStringLiterals(initializer, importedSource, visited) : [];
120
119
  };
121
120
  /**
122
121
  * Extracts string literal values from an expression.
@@ -131,93 +130,102 @@ const extractImportedIdentifierValues = (node, visited) => {
131
130
  * - As expressions: value as Type
132
131
  *
133
132
  * @param node The expression node to extract values from
133
+ * @param source The parsed source containing the node
134
134
  * @param visited Set of visited nodes to prevent infinite recursion
135
135
  * @returns Array of extracted string literal values
136
136
  */
137
- const extractStringLiterals = (node, visited = /* @__PURE__ */ new Set()) => {
137
+ const extractStringLiterals = (node, source, visited = /* @__PURE__ */ new Set()) => {
138
138
  if (visited.has(node)) return [];
139
139
  visited.add(node);
140
- const directValues = extractDirectLiteralValues(node);
140
+ if (node.type === "ChainExpression") return extractStringLiterals(node.expression, source, visited);
141
+ const directValues = extractDirectLiteralValues(node, source);
141
142
  if (directValues) return directValues;
142
- const templateValues = extractTemplateExpressionValues(node, visited);
143
+ const templateValues = extractTemplateExpressionValues(node, source, visited);
143
144
  if (templateValues) return templateValues;
144
- if (Node.isConditionalExpression(node)) return [...extractStringLiterals(node.getWhenTrue(), visited), ...extractStringLiterals(node.getWhenFalse(), visited)];
145
- const binaryValues = extractBinaryExpressionValues(node, visited);
145
+ if (node.type === "ConditionalExpression") return [...extractStringLiterals(node.consequent, source, visited), ...extractStringLiterals(node.alternate, source, visited)];
146
+ const binaryValues = extractBinaryExpressionValues(node, source, visited);
146
147
  if (binaryValues) return binaryValues;
147
- const wrappedExpressionValues = extractWrappedExpressionValues(node, visited);
148
+ const wrappedExpressionValues = extractWrappedExpressionValues(node, source, visited);
148
149
  if (wrappedExpressionValues) return wrappedExpressionValues;
149
- const propertyAccessValues = extractPropertyAccessValues(node, visited);
150
+ const propertyAccessValues = extractPropertyAccessValues(node, source, visited);
150
151
  if (propertyAccessValues) return propertyAccessValues;
151
- const elementAccessValues = extractElementAccessValues(node, visited);
152
+ const elementAccessValues = extractElementAccessValues(node, source, visited);
152
153
  if (elementAccessValues) return elementAccessValues;
153
- const callExpressionValues = extractCallExpressionValues(node, visited);
154
+ const callExpressionValues = extractCallExpressionValues(node, source, visited);
154
155
  if (callExpressionValues) return callExpressionValues;
155
- const identifierValues = extractIdentifierValues(node, visited);
156
+ const identifierValues = extractIdentifierValues(node, source, visited);
156
157
  if (identifierValues) return identifierValues;
157
158
  return [];
158
159
  };
159
- const extractDirectLiteralValues = (node) => {
160
- if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) return [node.getLiteralValue()];
160
+ const extractDirectLiteralValues = (node, _source) => {
161
+ if (isStringLiteral(node)) return [getStringLiteralValue(node)];
162
+ if (isNoSubstitutionTemplate(node) && node.type === "TemplateLiteral") return [node.quasis[0]?.value.cooked ?? ""];
161
163
  return null;
162
164
  };
163
- const extractTemplateExpressionValues = (node, visited) => {
164
- if (!Node.isTemplateExpression(node)) return null;
165
- const parts = [[node.getHead().getLiteralText()]];
166
- node.getTemplateSpans().forEach((span) => {
167
- const exprValues = extractStringLiterals(span.getExpression(), visited);
168
- const literalText = span.getLiteral().getLiteralText();
165
+ const extractTemplateExpressionValues = (node, source, visited) => {
166
+ if (node.type !== "TemplateLiteral" || node.expressions.length === 0) return null;
167
+ const parts = [[node.quasis[0]?.value.cooked ?? ""]];
168
+ node.expressions.forEach((expression, index) => {
169
+ const exprValues = extractStringLiterals(expression, source, visited);
170
+ const literalText = node.quasis[index + 1]?.value.cooked ?? "";
169
171
  parts.push(exprValues.length > 0 ? exprValues.map((value) => `${value}${literalText}`) : ["", literalText]);
170
172
  });
171
173
  return parts.reduce((acc, segment) => acc.flatMap((base) => segment.map((frag) => `${base}${frag}`)), [""]).filter((value) => value.length > 0);
172
174
  };
173
- const extractBinaryExpressionValues = (node, visited) => {
174
- if (!Node.isBinaryExpression(node)) return null;
175
- const operator = node.getOperatorToken().getText();
176
- if (operator === "+") {
177
- const left = extractStringLiterals(node.getLeft(), visited);
178
- const right = extractStringLiterals(node.getRight(), visited);
179
- const combined = left.flatMap((l) => right.map((r) => `${l}${r}`));
180
- return combined.length > 0 ? combined : [];
175
+ const extractBinaryExpressionValues = (node, source, visited) => {
176
+ if (node.type === "BinaryExpression") {
177
+ if (node.operator === "+") {
178
+ const left = extractStringLiterals(node.left, source, visited);
179
+ const right = extractStringLiterals(node.right, source, visited);
180
+ const combined = left.flatMap((l) => right.map((r) => `${l}${r}`));
181
+ return combined.length > 0 ? combined : [];
182
+ }
183
+ return [];
181
184
  }
182
- if (operator === "||" || operator === "??") return [...extractStringLiterals(node.getLeft(), visited), ...extractStringLiterals(node.getRight(), visited)];
183
- return [];
185
+ if (node.type === "LogicalExpression") {
186
+ if (node.operator === "||" || node.operator === "??") return [...extractStringLiterals(node.left, source, visited), ...extractStringLiterals(node.right, source, visited)];
187
+ return [];
188
+ }
189
+ return null;
184
190
  };
185
- const extractWrappedExpressionValues = (node, visited) => {
186
- if (Node.isParenthesizedExpression(node) || Node.isAsExpression(node)) return extractStringLiterals(node.getExpression(), visited);
191
+ const extractWrappedExpressionValues = (node, source, visited) => {
192
+ if (node.type === "ParenthesizedExpression" || node.type === "TSAsExpression") return extractStringLiterals(node.expression, source, visited);
187
193
  return null;
188
194
  };
189
- const extractPropertyAccessValues = (node, visited) => {
190
- if (!Node.isPropertyAccessExpression(node)) return null;
191
- const typeValues = extractLiteralValuesFromType(node);
195
+ const extractPropertyAccessValues = (node, source, visited) => {
196
+ if (node.type !== "MemberExpression" || node.computed) return null;
197
+ if (node.property.type !== "Identifier") return null;
198
+ const typeValues = extractLiteralValuesFromType(node, source);
192
199
  if (typeValues.length > 0) return typeValues;
193
- const propertyName = node.getName();
194
- return extractObjectValues(node.getExpression(), visited).filter((value) => typeof value === "object" && value !== null && propertyName in value).map((value) => value[propertyName]).filter((value) => typeof value === "string");
200
+ const propertyName = node.property.name;
201
+ return extractObjectValues(node.object, source, visited).filter((value) => typeof value === "object" && value !== null && propertyName in value).map((value) => value[propertyName]).filter((value) => typeof value === "string");
195
202
  };
196
- const extractElementAccessValues = (node, visited) => {
197
- if (!Node.isElementAccessExpression(node)) return null;
198
- const typeValues = extractLiteralValuesFromType(node);
203
+ const extractElementAccessValues = (node, source, visited) => {
204
+ if (node.type !== "MemberExpression" || !node.computed) return null;
205
+ const typeValues = extractLiteralValuesFromType(node, source);
199
206
  if (typeValues.length > 0) return typeValues;
200
- return extractObjectValues(node.getExpression(), visited).flatMap((value) => {
207
+ return extractObjectValues(node.object, source, visited).flatMap((value) => {
201
208
  if (typeof value === "string") return [value];
202
209
  if (typeof value === "object" && value !== null) return Object.values(value).filter((entry) => typeof entry === "string");
203
210
  return [];
204
211
  });
205
212
  };
206
- const extractCallExpressionValues = (node, visited) => {
207
- if (!Node.isCallExpression(node)) return null;
208
- const expression = node.getExpression();
209
- const fromDefinitions = Node.isIdentifier(expression) ? getDefinitionNodesSafe(expression).flatMap((definition) => {
210
- if (Node.isFunctionDeclaration(definition)) return definition.getDescendantsOfKind(SyntaxKind.ReturnStatement).flatMap((returnStmt) => {
211
- const expression = returnStmt.getExpression();
212
- return expression ? extractStringLiterals(expression, visited) : [];
213
- });
214
- if (Node.isVariableDeclaration(definition)) {
215
- const initializer = definition.getInitializer();
216
- return initializer ? extractFromFunctionLike(initializer, visited) : [];
217
- }
213
+ const collectReturnExpressions = (node) => {
214
+ const returns = [];
215
+ forEachDescendant(node, (descendant) => {
216
+ if (descendant.type === "ReturnStatement" && descendant.argument) returns.push(descendant.argument);
217
+ });
218
+ return returns;
219
+ };
220
+ const extractCallExpressionValues = (node, source, visited) => {
221
+ if (node.type !== "CallExpression") return null;
222
+ const callee = node.callee;
223
+ const fromDefinitions = callee.type === "Identifier" ? findLocalDefinitions(source, callee).flatMap((definition) => {
224
+ if (definition.kind === "function") return collectReturnExpressions(definition.node).flatMap((expression) => extractStringLiterals(expression, source, visited));
225
+ if (definition.kind === "variable") return definition.init ? extractFromFunctionLike(definition.init, source, visited) : [];
218
226
  return [];
219
227
  }) : [];
220
- const fromArguments = node.getArguments().flatMap((arg) => extractStringLiterals(arg, visited));
228
+ const fromArguments = node.arguments.flatMap((arg) => extractStringLiterals(arg, source, visited));
221
229
  return [...fromDefinitions, ...fromArguments];
222
230
  };
223
231
  /** Array methods that return (a subset of) the receiver's elements. */
@@ -235,19 +243,18 @@ const ARRAY_CHAIN_METHODS = new Set([
235
243
  * If the definition is the first parameter of a `.map()`/`.flatMap()` callback,
236
244
  * return the expression being mapped over (the array source).
237
245
  */
238
- const getMappedArraySource = (definition) => {
239
- if (!Node.isParameterDeclaration(definition)) return null;
240
- const callback = definition.getParentIfKind(SyntaxKind.ArrowFunction);
241
- if (!callback) return null;
242
- const callExpression = callback.getParentIfKind(SyntaxKind.CallExpression);
243
- if (!callExpression) return null;
244
- const expression = callExpression.getExpression();
245
- if (!Node.isPropertyAccessExpression(expression)) return null;
246
- if (!["map", "flatMap"].includes(expression.getName())) return null;
247
- if (callback.getParameters().findIndex((parameter) => {
248
- return parameter.getNameNode().getText() === definition.getNameNode().getText();
249
- }) !== 0) return null;
250
- return expression.getExpression();
246
+ const getMappedArraySource = (definition, source) => {
247
+ if (definition.kind !== "parameter" || !definition.paramFunction) return null;
248
+ const callback = definition.paramFunction;
249
+ if (callback.type !== "ArrowFunctionExpression") return null;
250
+ const callExpression = getParent(source, callback);
251
+ if (!callExpression || callExpression.type !== "CallExpression") return null;
252
+ const callee = callExpression.callee;
253
+ if (callee.type !== "MemberExpression" || callee.computed) return null;
254
+ if (callee.property.type !== "Identifier") return null;
255
+ if (!["map", "flatMap"].includes(callee.property.name)) return null;
256
+ if (definition.paramIndex !== 0) return null;
257
+ return callee.object;
251
258
  };
252
259
  /**
253
260
  * Resolve a node to the object-literal AST nodes it may evaluate to.
@@ -255,25 +262,23 @@ const getMappedArraySource = (definition) => {
255
262
  * array-method chains, and `.map()` callback parameters (UDS-2557 follow-up:
256
263
  * variant arrays nested inside const structures).
257
264
  */
258
- const resolveObjectLiteralNodes = (node, visited) => {
265
+ const resolveObjectLiteralNodes = (node, source, visited) => {
259
266
  if (visited.has(node)) return [];
260
267
  visited.add(node);
261
- if (Node.isObjectLiteralExpression(node)) return [node];
262
- if (Node.isParenthesizedExpression(node) || Node.isAsExpression(node) || Node.isTypeAssertion(node) || Node.isSatisfiesExpression(node)) return resolveObjectLiteralNodes(node.getExpression(), visited);
263
- if (Node.isArrayLiteralExpression(node)) return node.getElements().flatMap((element) => resolveObjectLiteralNodes(element, visited));
264
- if (Node.isElementAccessExpression(node)) return resolveObjectLiteralNodes(node.getExpression(), visited);
265
- if (Node.isCallExpression(node)) {
266
- const expression = node.getExpression();
267
- if (Node.isPropertyAccessExpression(expression) && ARRAY_CHAIN_METHODS.has(expression.getName())) return resolveObjectLiteralNodes(expression.getExpression(), visited);
268
+ if (node.type === "ChainExpression") return resolveObjectLiteralNodes(node.expression, source, visited);
269
+ if (node.type === "ObjectExpression") return [node];
270
+ if (node.type === "ParenthesizedExpression" || node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSSatisfiesExpression") return resolveObjectLiteralNodes(node.expression, source, visited);
271
+ if (node.type === "ArrayExpression") return node.elements.flatMap((element) => element ? resolveObjectLiteralNodes(element, source, visited) : []);
272
+ if (node.type === "MemberExpression" && node.computed) return resolveObjectLiteralNodes(node.object, source, visited);
273
+ if (node.type === "CallExpression") {
274
+ const callee = node.callee;
275
+ if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && ARRAY_CHAIN_METHODS.has(callee.property.name)) return resolveObjectLiteralNodes(callee.object, source, visited);
268
276
  return [];
269
277
  }
270
- if (Node.isIdentifier(node)) return getLocalDefinitionNodes(node).flatMap((definition) => {
271
- if (Node.isVariableDeclaration(definition)) {
272
- const initializer = definition.getInitializer();
273
- return initializer ? resolveObjectLiteralNodes(initializer, visited) : [];
274
- }
275
- const mappedSource = getMappedArraySource(definition);
276
- if (mappedSource) return resolveObjectLiteralNodes(mappedSource, visited);
278
+ if (node.type === "Identifier") return findLocalDefinitions(source, node).flatMap((definition) => {
279
+ if (definition.kind === "variable") return definition.init ? resolveObjectLiteralNodes(definition.init, source, visited) : [];
280
+ const mappedSource = getMappedArraySource(definition, source);
281
+ if (mappedSource) return resolveObjectLiteralNodes(mappedSource, source, visited);
277
282
  return [];
278
283
  });
279
284
  return [];
@@ -281,74 +286,82 @@ const resolveObjectLiteralNodes = (node, visited) => {
281
286
  /**
282
287
  * Collect the initializers of a named property across object-literal candidates.
283
288
  */
284
- const getPropertyInitializers = (objectLiterals, propertyName) => objectLiterals.flatMap((obj) => {
285
- if (!Node.isObjectLiteralExpression(obj)) return [];
286
- return obj.getProperties().flatMap((prop) => {
287
- if (!Node.isPropertyAssignment(prop) || prop.getName() !== propertyName) return [];
288
- const initializer = prop.getInitializer();
289
- return initializer ? [initializer] : [];
289
+ const getPropertyInitializers = (objectLiterals, propertyName, source) => objectLiterals.flatMap((obj) => {
290
+ if (obj.type !== "ObjectExpression") return [];
291
+ return obj.properties.flatMap((prop) => {
292
+ if (prop.type !== "Property" || prop.shorthand || getPropertyName(source, prop) !== propertyName) return [];
293
+ return prop.value ? [prop.value] : [];
290
294
  });
291
295
  });
292
296
  /**
293
297
  * For a destructured binding (e.g. `({ variants }) =>` map param or
294
298
  * `const { variants } = GROUPS[0]`), resolve the bound property's initializers.
295
299
  */
296
- const getBindingElementSources = (definition) => {
297
- if (!Node.isBindingElement(definition)) return [];
298
- const bindingPattern = definition.getParent();
299
- if (!Node.isObjectBindingPattern(bindingPattern)) return [];
300
- const propertyName = definition.getPropertyNameNode()?.getText() ?? definition.getName();
301
- const holder = bindingPattern.getParent();
302
- let source = null;
303
- if (Node.isParameterDeclaration(holder)) source = getMappedArraySource(holder);
304
- else if (Node.isVariableDeclaration(holder)) source = holder.getInitializer() ?? null;
305
- if (!source) return [];
306
- return getPropertyInitializers(resolveObjectLiteralNodes(source, /* @__PURE__ */ new Set()), propertyName);
300
+ const getBindingElementSources = (definition, source) => {
301
+ if (definition.kind !== "binding" || definition.bindingPattern?.type !== "ObjectPattern") return [];
302
+ const propertyName = definition.bindingPropertyName ?? definition.name;
303
+ const pattern = definition.bindingPattern;
304
+ const holder = getParent(source, pattern);
305
+ let arraySource = null;
306
+ if (holder && holder.type === "VariableDeclarator") arraySource = holder.init ?? null;
307
+ else {
308
+ const paramNode = holder && holder.type === "AssignmentPattern" ? holder : pattern;
309
+ const fn = holder && holder.type === "AssignmentPattern" ? getParent(source, holder) : holder;
310
+ if (fn && (fn.type === "ArrowFunctionExpression" || fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression")) {
311
+ const paramIndex = fn.params.indexOf(paramNode);
312
+ if (paramIndex !== -1) arraySource = getMappedArraySource({
313
+ kind: "parameter",
314
+ name: propertyName,
315
+ start: pattern.start,
316
+ node: paramNode,
317
+ init: null,
318
+ typeNode: null,
319
+ paramFunction: fn,
320
+ paramIndex
321
+ }, source);
322
+ }
323
+ }
324
+ if (!arraySource) return [];
325
+ return getPropertyInitializers(resolveObjectLiteralNodes(arraySource, source, /* @__PURE__ */ new Set()), propertyName, source);
307
326
  };
308
- const extractArrayElementValues = (node, visited) => {
309
- if (Node.isArrayLiteralExpression(node)) return node.getElements().flatMap((element) => extractStringLiterals(element, visited)).filter((value, index, values) => values.indexOf(value) === index);
310
- if (Node.isParenthesizedExpression(node)) return extractArrayElementValues(node.getExpression(), visited);
311
- if (Node.isAsExpression(node) || Node.isTypeAssertion(node) || Node.isSatisfiesExpression(node)) return extractArrayElementValues(node.getExpression(), visited);
312
- if (Node.isPropertyAccessExpression(node)) return getPropertyInitializers(resolveObjectLiteralNodes(node.getExpression(), /* @__PURE__ */ new Set()), node.getName()).flatMap((initializer) => extractArrayElementValues(initializer, visited)).filter((value, index, values) => values.indexOf(value) === index);
313
- if (Node.isCallExpression(node)) {
314
- const expression = node.getExpression();
315
- if (Node.isPropertyAccessExpression(expression) && ARRAY_CHAIN_METHODS.has(expression.getName())) return extractArrayElementValues(expression.getExpression(), visited);
327
+ const extractArrayElementValues = (node, source, visited) => {
328
+ if (node.type === "ChainExpression") return extractArrayElementValues(node.expression, source, visited);
329
+ if (node.type === "ArrayExpression") return node.elements.flatMap((element) => element ? extractStringLiterals(element, source, visited) : []).filter((value, index, values) => values.indexOf(value) === index);
330
+ if (node.type === "ParenthesizedExpression") return extractArrayElementValues(node.expression, source, visited);
331
+ if (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSSatisfiesExpression") return extractArrayElementValues(node.expression, source, visited);
332
+ if (node.type === "MemberExpression" && !node.computed) {
333
+ if (node.property.type !== "Identifier") return [];
334
+ return getPropertyInitializers(resolveObjectLiteralNodes(node.object, source, /* @__PURE__ */ new Set()), node.property.name, source).flatMap((initializer) => extractArrayElementValues(initializer, source, visited)).filter((value, index, values) => values.indexOf(value) === index);
335
+ }
336
+ if (node.type === "CallExpression") {
337
+ const callee = node.callee;
338
+ if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && ARRAY_CHAIN_METHODS.has(callee.property.name)) return extractArrayElementValues(callee.object, source, visited);
316
339
  return [];
317
340
  }
318
- if (Node.isIdentifier(node)) return getLocalDefinitionNodes(node).flatMap((definition) => {
319
- if (Node.isVariableDeclaration(definition)) {
320
- const initializer = definition.getInitializer();
321
- return initializer ? extractArrayElementValues(initializer, visited) : [];
322
- }
323
- return getBindingElementSources(definition).flatMap((source) => extractArrayElementValues(source, visited));
341
+ if (node.type === "Identifier") return findLocalDefinitions(source, node).flatMap((definition) => {
342
+ if (definition.kind === "variable") return definition.init ? extractArrayElementValues(definition.init, source, visited) : [];
343
+ return getBindingElementSources(definition, source).flatMap((elementSource) => extractArrayElementValues(elementSource, source, visited));
324
344
  }).filter((value, index, values) => values.indexOf(value) === index);
325
345
  return [];
326
346
  };
327
- const extractMappedParameterValues = (definition, visited) => {
328
- const mappedSource = getMappedArraySource(definition);
347
+ const extractMappedParameterValues = (definition, source, visited) => {
348
+ const mappedSource = getMappedArraySource(definition, source);
329
349
  if (!mappedSource) return [];
330
- return extractArrayElementValues(mappedSource, visited);
350
+ return extractArrayElementValues(mappedSource, source, visited);
331
351
  };
332
- const extractIdentifierValues = (node, visited) => {
333
- if (!Node.isIdentifier(node)) return null;
334
- const values = getDefinitionNodesSafe(node).flatMap((definition) => {
335
- const mappedParameterValues = extractMappedParameterValues(definition, visited);
352
+ const extractIdentifierValues = (node, source, visited) => {
353
+ if (node.type !== "Identifier") return null;
354
+ const values = findLocalDefinitions(source, node).flatMap((definition) => {
355
+ const mappedParameterValues = extractMappedParameterValues(definition, source, visited);
336
356
  if (mappedParameterValues.length > 0) return mappedParameterValues;
337
- if (Node.isVariableDeclaration(definition) || Node.isParameterDeclaration(definition) || Node.isBindingElement(definition)) {
338
- const initializer = definition.getInitializer();
339
- if (initializer) return extractStringLiterals(initializer, visited);
340
- if (Node.isBindingElement(definition)) {
341
- const bindingPattern = definition.getParent();
342
- if (Node.isObjectBindingPattern(bindingPattern)) {
343
- const parentDecl = bindingPattern.getParent();
344
- if (Node.isVariableDeclaration(parentDecl)) {
345
- const parentInit = parentDecl.getInitializer();
346
- if (parentInit) {
347
- const propName = definition.getNameNode().getText();
348
- const propValues = extractObjectValues(parentInit, new Set(visited)).filter((obj) => typeof obj === "object" && obj !== null && propName in obj).map((obj) => obj[propName]).filter((v) => typeof v === "string");
349
- if (propValues.length > 0) return propValues;
350
- }
351
- }
357
+ if (definition.kind === "variable" || definition.kind === "parameter" || definition.kind === "binding") {
358
+ if (definition.init) return extractStringLiterals(definition.init, source, visited);
359
+ if (definition.kind === "binding" && definition.bindingPattern?.type === "ObjectPattern") {
360
+ const holder = getParent(source, definition.bindingPattern);
361
+ if (holder && holder.type === "VariableDeclarator" && holder.init) {
362
+ const propName = definition.name;
363
+ const propValues = extractObjectValues(holder.init, source, new Set(visited)).filter((obj) => typeof obj === "object" && obj !== null && propName in obj).map((obj) => obj[propName]).filter((v) => typeof v === "string");
364
+ if (propValues.length > 0) return propValues;
352
365
  }
353
366
  }
354
367
  return [];
@@ -356,25 +369,23 @@ const extractIdentifierValues = (node, visited) => {
356
369
  return [];
357
370
  });
358
371
  if (values.length > 0) return values;
359
- const importedValues = extractImportedIdentifierValues(node, visited);
372
+ const importedValues = extractImportedIdentifierValues(node, source, visited);
360
373
  if (importedValues.length > 0) return importedValues;
361
- return extractLiteralValuesFromType(node);
374
+ return extractLiteralValuesFromType(node, source);
362
375
  };
363
376
  /**
364
377
  * Extract string literals from arrow functions or function expressions
365
378
  */
366
- const extractFromFunctionLike = (node, visited) => {
379
+ const extractFromFunctionLike = (node, source, visited) => {
367
380
  const values = [];
368
- if (Node.isArrowFunction(node)) {
369
- const body = node.getBody();
370
- if (Node.isBlock(body)) body.getDescendantsOfKind(SyntaxKind.ReturnStatement).forEach((returnStmt) => {
371
- const returnExpr = returnStmt.getExpression();
372
- if (returnExpr) values.push(...extractStringLiterals(returnExpr, visited));
381
+ if (node.type === "ArrowFunctionExpression") {
382
+ const body = node.body;
383
+ if (body.type === "BlockStatement") collectReturnExpressions(body).forEach((returnExpr) => {
384
+ values.push(...extractStringLiterals(returnExpr, source, visited));
373
385
  });
374
- else values.push(...extractStringLiterals(body, visited));
375
- } else if (Node.isFunctionExpression(node)) node.getDescendantsOfKind(SyntaxKind.ReturnStatement).forEach((returnStmt) => {
376
- const returnExpr = returnStmt.getExpression();
377
- if (returnExpr) values.push(...extractStringLiterals(returnExpr, visited));
386
+ else values.push(...extractStringLiterals(body, source, visited));
387
+ } else if (node.type === "FunctionExpression") collectReturnExpressions(node).forEach((returnExpr) => {
388
+ values.push(...extractStringLiterals(returnExpr, source, visited));
378
389
  });
379
390
  return values;
380
391
  };
@@ -382,19 +393,20 @@ const extractFromFunctionLike = (node, visited) => {
382
393
  * Extract object literal values from an expression.
383
394
  * Returns an array of all possible object values (for union types or indexed access).
384
395
  */
385
- const extractObjectValues = (node, visited) => {
396
+ const extractObjectValues = (node, source, visited) => {
386
397
  if (visited.has(node)) return [];
387
398
  visited.add(node);
399
+ if (node.type === "ChainExpression") return extractObjectValues(node.expression, source, visited);
388
400
  const values = [];
389
- if (Node.isObjectLiteralExpression(node)) {
401
+ if (node.type === "ObjectExpression") {
390
402
  const obj = {};
391
- node.getProperties().forEach((prop) => {
392
- if (Node.isPropertyAssignment(prop)) {
393
- const name = prop.getName();
394
- const init = prop.getInitializer();
395
- if (init && Node.isStringLiteral(init)) obj[name] = init.getLiteralValue();
396
- else if (init && Node.isObjectLiteralExpression(init)) {
397
- const nestedValues = extractObjectValues(init, visited);
403
+ node.properties.forEach((prop) => {
404
+ if (prop.type === "Property" && !prop.shorthand) {
405
+ const name = getPropertyName(source, prop);
406
+ const init = prop.value;
407
+ if (init && isStringLiteral(init)) obj[name] = getStringLiteralValue(init);
408
+ else if (init && init.type === "ObjectExpression") {
409
+ const nestedValues = extractObjectValues(init, source, visited);
398
410
  if (nestedValues.length > 0) obj[name] = nestedValues[0];
399
411
  }
400
412
  }
@@ -402,58 +414,51 @@ const extractObjectValues = (node, visited) => {
402
414
  values.push(obj);
403
415
  return values;
404
416
  }
405
- if (Node.isIdentifier(node)) {
406
- getDefinitionNodesSafe(node).forEach((definition) => {
407
- if (Node.isVariableDeclaration(definition)) {
408
- const initializer = definition.getInitializer();
409
- if (initializer) if (Node.isAsExpression(initializer)) {
410
- const inner = initializer.getExpression();
411
- values.push(...extractObjectValues(inner, visited));
412
- } else values.push(...extractObjectValues(initializer, visited));
417
+ if (node.type === "Identifier") {
418
+ findLocalDefinitions(source, node).forEach((definition) => {
419
+ if (definition.kind === "variable" && definition.init) {
420
+ const initializer = definition.init;
421
+ if (initializer.type === "TSAsExpression") values.push(...extractObjectValues(initializer.expression, source, visited));
422
+ else values.push(...extractObjectValues(initializer, source, visited));
413
423
  }
414
424
  });
415
- const enumDecl = node.getSourceFile().getEnum(node.getText());
425
+ const enumDecl = source.topLevelEnums.get(node.name);
416
426
  if (enumDecl) {
417
427
  const obj = {};
418
- enumDecl.getMembers().forEach((member) => {
419
- const initializer = member.getInitializer();
420
- if (initializer && Node.isStringLiteral(initializer)) obj[member.getName()] = initializer.getLiteralValue();
428
+ enumDecl.body.members.forEach((member) => {
429
+ const initializer = member.initializer;
430
+ if (initializer && isStringLiteral(initializer)) {
431
+ const memberName = member.id.type === "Identifier" ? member.id.name : isStringLiteral(member.id) ? getStringLiteralValue(member.id) : getText(source, member.id);
432
+ obj[memberName] = getStringLiteralValue(initializer);
433
+ }
421
434
  });
422
435
  if (Object.keys(obj).length > 0) values.push(obj);
423
436
  }
424
437
  return values;
425
438
  }
426
- if (Node.isCallExpression(node)) {
427
- const expression = node.getExpression();
428
- if (Node.isIdentifier(expression)) getDefinitionNodesSafe(expression).forEach((definition) => {
429
- if (Node.isFunctionDeclaration(definition)) definition.getDescendantsOfKind(SyntaxKind.ReturnStatement).forEach((returnStmt) => {
430
- const returnExpr = returnStmt.getExpression();
431
- if (returnExpr) values.push(...extractObjectValues(returnExpr, visited));
439
+ if (node.type === "CallExpression") {
440
+ const callee = node.callee;
441
+ if (callee.type === "Identifier") findLocalDefinitions(source, callee).forEach((definition) => {
442
+ if (definition.kind === "function") collectReturnExpressions(definition.node).forEach((returnExpr) => {
443
+ values.push(...extractObjectValues(returnExpr, source, visited));
432
444
  });
433
- if (Node.isVariableDeclaration(definition)) {
434
- const initializer = definition.getInitializer();
435
- if (initializer) {
436
- const extractFromFn = (fn) => {
437
- if (Node.isArrowFunction(fn)) {
438
- const body = fn.getBody();
439
- if (Node.isBlock(body)) body.getDescendantsOfKind(SyntaxKind.ReturnStatement).forEach((returnStmt) => {
440
- const returnExpr = returnStmt.getExpression();
441
- if (returnExpr) values.push(...extractObjectValues(returnExpr, visited));
442
- });
443
- else values.push(...extractObjectValues(body, visited));
444
- } else if (Node.isFunctionExpression(fn)) fn.getDescendantsOfKind(SyntaxKind.ReturnStatement).forEach((returnStmt) => {
445
- const returnExpr = returnStmt.getExpression();
446
- if (returnExpr) values.push(...extractObjectValues(returnExpr, visited));
447
- });
448
- };
449
- extractFromFn(initializer);
450
- }
445
+ if (definition.kind === "variable" && definition.init) {
446
+ const initializer = definition.init;
447
+ if (initializer.type === "ArrowFunctionExpression") {
448
+ const body = initializer.body;
449
+ if (body.type === "BlockStatement") collectReturnExpressions(body).forEach((returnExpr) => {
450
+ values.push(...extractObjectValues(returnExpr, source, visited));
451
+ });
452
+ else values.push(...extractObjectValues(body, source, visited));
453
+ } else if (initializer.type === "FunctionExpression") collectReturnExpressions(initializer).forEach((returnExpr) => {
454
+ values.push(...extractObjectValues(returnExpr, source, visited));
455
+ });
451
456
  }
452
457
  });
453
458
  return values;
454
459
  }
455
- if (Node.isElementAccessExpression(node)) {
456
- extractObjectValues(node.getExpression(), visited).forEach((obj) => {
460
+ if (node.type === "MemberExpression" && node.computed) {
461
+ extractObjectValues(node.object, source, visited).forEach((obj) => {
457
462
  if (typeof obj === "object" && obj !== null) Object.values(obj).forEach((value) => values.push(value));
458
463
  });
459
464
  return values;
@@ -462,46 +467,42 @@ const extractObjectValues = (node, visited) => {
462
467
  };
463
468
  /**
464
469
  * Extract string literal values from a TypeScript type annotation AST node.
465
- * Pure AST traversal — avoids expensive TS Language Service `getType()` calls.
470
+ * Pure AST traversal — no type checker involved.
466
471
  */
467
472
  const extractStringLiteralsFromTypeNode = (typeNode) => {
468
- if (Node.isLiteralTypeNode(typeNode)) {
469
- const literal = typeNode.getLiteral();
470
- if (Node.isStringLiteral(literal)) return [literal.getLiteralValue()];
473
+ if (typeNode.type === "TSLiteralType") {
474
+ const literal = typeNode.literal;
475
+ if (isStringLiteral(literal)) return [getStringLiteralValue(literal)];
471
476
  return [];
472
477
  }
473
- if (Node.isUnionTypeNode(typeNode)) return typeNode.getTypeNodes().flatMap(extractStringLiteralsFromTypeNode);
478
+ if (typeNode.type === "TSUnionType") return typeNode.types.flatMap(extractStringLiteralsFromTypeNode);
474
479
  return [];
475
480
  };
476
481
  /**
477
482
  * Extract literal values from a TypeScript type annotation (for union types like 'brand' | 'secondary').
478
- * Uses pure AST traversal instead of the TS type checker to avoid expensive LS initialization.
483
+ * Uses pure AST traversal instead of the TS type checker.
479
484
  */
480
- const extractLiteralValuesFromType = (node) => {
481
- if (Node.isIdentifier(node)) {
482
- const definitions = getLocalDefinitionNodes(node);
485
+ const extractLiteralValuesFromType = (node, source) => {
486
+ if (node.type === "Identifier") {
487
+ const definitions = findLocalDefinitions(source, node);
483
488
  for (const def of definitions) {
484
- if (Node.isParameterDeclaration(def) || Node.isVariableDeclaration(def) || Node.isPropertyDeclaration(def) || Node.isPropertySignature(def)) {
485
- const typeNode = def.getTypeNode?.();
486
- if (typeNode) {
487
- const values = extractStringLiteralsFromTypeNode(typeNode);
489
+ if (def.kind === "parameter" || def.kind === "variable") {
490
+ if (def.typeNode) {
491
+ const values = extractStringLiteralsFromTypeNode(def.typeNode);
488
492
  if (values.length > 0) return values;
489
493
  }
490
494
  }
491
- if (Node.isBindingElement(def)) {
492
- const bindingPattern = def.getParent();
493
- if (bindingPattern) {
494
- const parentDecl = bindingPattern.getParent();
495
- if (parentDecl && Node.isVariableDeclaration(parentDecl)) {
496
- const parentType = parentDecl.getTypeNode();
497
- if (parentType && Node.isTypeLiteral(parentType)) {
498
- const propName = def.getNameNode().getText();
499
- for (const member of parentType.getMembers()) if (Node.isPropertySignature(member) && member.getName() === propName) {
500
- const memberType = member.getTypeNode();
501
- if (memberType) {
502
- const values = extractStringLiteralsFromTypeNode(memberType);
503
- if (values.length > 0) return values;
504
- }
495
+ if (def.kind === "binding" && def.bindingPattern) {
496
+ const holder = getParent(source, def.bindingPattern);
497
+ if (holder && holder.type === "VariableDeclarator") {
498
+ const parentType = holder.id.typeAnnotation?.typeAnnotation;
499
+ if (parentType && parentType.type === "TSTypeLiteral") {
500
+ const propName = def.name;
501
+ for (const member of parentType.members) if (member.type === "TSPropertySignature" && member.key.type === "Identifier" && member.key.name === propName) {
502
+ const memberType = member.typeAnnotation?.typeAnnotation;
503
+ if (memberType) {
504
+ const values = extractStringLiteralsFromTypeNode(memberType);
505
+ if (values.length > 0) return values;
505
506
  }
506
507
  }
507
508
  }
@@ -509,7 +510,6 @@ const extractLiteralValuesFromType = (node) => {
509
510
  }
510
511
  }
511
512
  }
512
- if (Node.isPropertyAccessExpression(node) || Node.isElementAccessExpression(node)) return [];
513
513
  return [];
514
514
  };
515
515
  //#endregion