@yahoo/uds 3.162.0 → 3.162.2

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 (51) hide show
  1. package/dist/cli/commands/purge.cjs +8 -1
  2. package/dist/cli/commands/purge.helpers.cjs +7 -0
  3. package/dist/cli/commands/purge.helpers.d.cts +3 -0
  4. package/dist/cli/commands/purge.helpers.d.ts +3 -0
  5. package/dist/cli/commands/purge.helpers.js +7 -0
  6. package/dist/cli/commands/purge.js +8 -1
  7. package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
  8. package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
  9. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.cts +1 -1
  10. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.ts +1 -1
  11. package/dist/components/client/Switch/Switch.cjs +5 -2
  12. package/dist/components/client/Switch/Switch.js +5 -2
  13. package/dist/components/client/Switch/switchStyles.cjs +2 -2
  14. package/dist/components/client/Switch/switchStyles.js +2 -2
  15. package/dist/css/dist/commands/css.cjs +2 -0
  16. package/dist/css/dist/commands/css.helpers.cjs +2 -0
  17. package/dist/css/dist/commands/css.helpers.js +2 -0
  18. package/dist/css/dist/commands/css.js +2 -0
  19. package/dist/css/dist/css/nodeUtils.cjs +28 -11
  20. package/dist/css/dist/css/nodeUtils.js +29 -12
  21. package/dist/css/dist/css/runner.cjs +8 -3
  22. package/dist/css/dist/css/runner.js +8 -3
  23. package/dist/css/dist/css/theme.d.cts +16 -0
  24. package/dist/css/dist/css/theme.d.ts +16 -0
  25. package/dist/css/dist/css/workerPool.cjs +2 -1
  26. package/dist/css/dist/css/workerPool.js +2 -1
  27. package/dist/css/dist/purger/optimized/ast/expressions.cjs +104 -11
  28. package/dist/css/dist/purger/optimized/ast/expressions.js +104 -11
  29. package/dist/css/dist/purger/optimized/ast/jsx.cjs +74 -0
  30. package/dist/css/dist/purger/optimized/ast/jsx.js +73 -0
  31. package/dist/css/dist/purger/optimized/ast/props.cjs +47 -0
  32. package/dist/css/dist/purger/optimized/ast/props.js +46 -0
  33. package/dist/css/dist/purger/optimized/ast/spread.cjs +87 -0
  34. package/dist/css/dist/purger/optimized/ast/spread.js +86 -0
  35. package/dist/css/dist/purger/optimized/purge.cjs +14 -8
  36. package/dist/css/dist/purger/optimized/purge.js +15 -9
  37. package/dist/css/dist/purger/optimized/purgeFromCode.cjs +176 -18
  38. package/dist/css/dist/purger/optimized/purgeFromCode.js +176 -19
  39. package/dist/css/dist/purger/optimized/utils/files.cjs +22 -2
  40. package/dist/css/dist/purger/optimized/utils/files.js +21 -3
  41. package/dist/hooks/useRtl.cjs +4 -8
  42. package/dist/hooks/useRtl.js +4 -8
  43. package/dist/styles/styler.d.cts +25 -25
  44. package/dist/styles/styler.d.ts +25 -25
  45. package/dist/uds/generated/componentData.cjs +2555 -2553
  46. package/dist/uds/generated/componentData.js +2555 -2553
  47. package/dist/uds/generated/tailwindPurge.cjs +1 -1
  48. package/dist/uds/generated/tailwindPurge.js +1 -1
  49. package/generated/componentData.json +3340 -3338
  50. package/generated/tailwindPurge.ts +1 -1
  51. package/package.json +1 -1
@@ -55,6 +55,22 @@ interface UDSThemeConfig {
55
55
  config?: string;
56
56
  /** Entry directory path or .tsx file path, or a list of those paths (default: './src') */
57
57
  entry?: string | string[];
58
+ /**
59
+ * Additional glob patterns to exclude from the safelist scan (e.g. dev-only
60
+ * pages not detectable by filename). Test/spec/story files and
61
+ * __tests__/__mocks__ directories are always excluded.
62
+ */
63
+ ignore?: string[];
64
+ /**
65
+ * Also scan test/spec/story files and __tests__/__mocks__ directories
66
+ * (default: false). Useful when a Storybook build shares this CSS output.
67
+ */
68
+ includeDevFiles?: boolean;
69
+ /**
70
+ * Also scan story files (default: false) while keeping test/spec files
71
+ * excluded. Use when a Storybook build consumes the generated CSS.
72
+ */
73
+ includeStories?: boolean;
58
74
  /** Suppress log output during generation (default: false) */
59
75
  silent?: boolean;
60
76
  /**
@@ -55,6 +55,22 @@ interface UDSThemeConfig {
55
55
  config?: string;
56
56
  /** Entry directory path or .tsx file path, or a list of those paths (default: './src') */
57
57
  entry?: string | string[];
58
+ /**
59
+ * Additional glob patterns to exclude from the safelist scan (e.g. dev-only
60
+ * pages not detectable by filename). Test/spec/story files and
61
+ * __tests__/__mocks__ directories are always excluded.
62
+ */
63
+ ignore?: string[];
64
+ /**
65
+ * Also scan test/spec/story files and __tests__/__mocks__ directories
66
+ * (default: false). Useful when a Storybook build shares this CSS output.
67
+ */
68
+ includeDevFiles?: boolean;
69
+ /**
70
+ * Also scan story files (default: false) while keeping test/spec files
71
+ * excluded. Use when a Storybook build consumes the generated CSS.
72
+ */
73
+ includeStories?: boolean;
58
74
  /** Suppress log output during generation (default: false) */
59
75
  silent?: boolean;
60
76
  /**
@@ -60,7 +60,8 @@ const createWorkerPool = async (config, numWorkers) => {
60
60
  colorModes: options.colorModes,
61
61
  variantDefaults: options.variantDefaults,
62
62
  runtimeConfigValues: options.runtimeConfigValues,
63
- includeAllClassNamePrimitives: options.includeAllClassNamePrimitives
63
+ includeAllClassNamePrimitives: options.includeAllClassNamePrimitives,
64
+ deferWrapperSpreadResolution: options.deferWrapperSpreadResolution
64
65
  };
65
66
  const task = {
66
67
  resolve,
@@ -59,7 +59,8 @@ const createWorkerPool = async (config, numWorkers) => {
59
59
  colorModes: options.colorModes,
60
60
  variantDefaults: options.variantDefaults,
61
61
  runtimeConfigValues: options.runtimeConfigValues,
62
- includeAllClassNamePrimitives: options.includeAllClassNamePrimitives
62
+ includeAllClassNamePrimitives: options.includeAllClassNamePrimitives,
63
+ deferWrapperSpreadResolution: options.deferWrapperSpreadResolution
63
64
  };
64
65
  const task = {
65
66
  resolve,
@@ -223,30 +223,114 @@ const extractCallExpressionValues = (node, visited) => {
223
223
  const fromArguments = node.getArguments().flatMap((arg) => extractStringLiterals(arg, visited));
224
224
  return [...fromDefinitions, ...fromArguments];
225
225
  };
226
+ /** Array methods that return (a subset of) the receiver's elements. */
227
+ const ARRAY_CHAIN_METHODS = new Set([
228
+ "concat",
229
+ "filter",
230
+ "flat",
231
+ "reverse",
232
+ "slice",
233
+ "sort",
234
+ "toReversed",
235
+ "toSorted"
236
+ ]);
237
+ /**
238
+ * If the definition is the first parameter of a `.map()`/`.flatMap()` callback,
239
+ * return the expression being mapped over (the array source).
240
+ */
241
+ const getMappedArraySource = (definition) => {
242
+ if (!ts_morph.Node.isParameterDeclaration(definition)) return null;
243
+ const callback = definition.getParentIfKind(ts_morph.SyntaxKind.ArrowFunction);
244
+ if (!callback) return null;
245
+ const callExpression = callback.getParentIfKind(ts_morph.SyntaxKind.CallExpression);
246
+ if (!callExpression) return null;
247
+ const expression = callExpression.getExpression();
248
+ if (!ts_morph.Node.isPropertyAccessExpression(expression)) return null;
249
+ if (!["map", "flatMap"].includes(expression.getName())) return null;
250
+ if (callback.getParameters().findIndex((parameter) => {
251
+ return parameter.getNameNode().getText() === definition.getNameNode().getText();
252
+ }) !== 0) return null;
253
+ return expression.getExpression();
254
+ };
255
+ /**
256
+ * Resolve a node to the object-literal AST nodes it may evaluate to.
257
+ * Handles arrays of objects (each element is a candidate), element access,
258
+ * array-method chains, and `.map()` callback parameters (UDS-2557 follow-up:
259
+ * variant arrays nested inside const structures).
260
+ */
261
+ const resolveObjectLiteralNodes = (node, visited) => {
262
+ if (visited.has(node)) return [];
263
+ visited.add(node);
264
+ if (ts_morph.Node.isObjectLiteralExpression(node)) return [node];
265
+ if (ts_morph.Node.isParenthesizedExpression(node) || ts_morph.Node.isAsExpression(node) || ts_morph.Node.isTypeAssertion(node) || ts_morph.Node.isSatisfiesExpression(node)) return resolveObjectLiteralNodes(node.getExpression(), visited);
266
+ if (ts_morph.Node.isArrayLiteralExpression(node)) return node.getElements().flatMap((element) => resolveObjectLiteralNodes(element, visited));
267
+ if (ts_morph.Node.isElementAccessExpression(node)) return resolveObjectLiteralNodes(node.getExpression(), visited);
268
+ if (ts_morph.Node.isCallExpression(node)) {
269
+ const expression = node.getExpression();
270
+ if (ts_morph.Node.isPropertyAccessExpression(expression) && ARRAY_CHAIN_METHODS.has(expression.getName())) return resolveObjectLiteralNodes(expression.getExpression(), visited);
271
+ return [];
272
+ }
273
+ if (ts_morph.Node.isIdentifier(node)) return getLocalDefinitionNodes(node).flatMap((definition) => {
274
+ if (ts_morph.Node.isVariableDeclaration(definition)) {
275
+ const initializer = definition.getInitializer();
276
+ return initializer ? resolveObjectLiteralNodes(initializer, visited) : [];
277
+ }
278
+ const mappedSource = getMappedArraySource(definition);
279
+ if (mappedSource) return resolveObjectLiteralNodes(mappedSource, visited);
280
+ return [];
281
+ });
282
+ return [];
283
+ };
284
+ /**
285
+ * Collect the initializers of a named property across object-literal candidates.
286
+ */
287
+ const getPropertyInitializers = (objectLiterals, propertyName) => objectLiterals.flatMap((obj) => {
288
+ if (!ts_morph.Node.isObjectLiteralExpression(obj)) return [];
289
+ return obj.getProperties().flatMap((prop) => {
290
+ if (!ts_morph.Node.isPropertyAssignment(prop) || prop.getName() !== propertyName) return [];
291
+ const initializer = prop.getInitializer();
292
+ return initializer ? [initializer] : [];
293
+ });
294
+ });
295
+ /**
296
+ * For a destructured binding (e.g. `({ variants }) =>` map param or
297
+ * `const { variants } = GROUPS[0]`), resolve the bound property's initializers.
298
+ */
299
+ const getBindingElementSources = (definition) => {
300
+ if (!ts_morph.Node.isBindingElement(definition)) return [];
301
+ const bindingPattern = definition.getParent();
302
+ if (!ts_morph.Node.isObjectBindingPattern(bindingPattern)) return [];
303
+ const propertyName = definition.getPropertyNameNode()?.getText() ?? definition.getName();
304
+ const holder = bindingPattern.getParent();
305
+ let source = null;
306
+ if (ts_morph.Node.isParameterDeclaration(holder)) source = getMappedArraySource(holder);
307
+ else if (ts_morph.Node.isVariableDeclaration(holder)) source = holder.getInitializer() ?? null;
308
+ if (!source) return [];
309
+ return getPropertyInitializers(resolveObjectLiteralNodes(source, /* @__PURE__ */ new Set()), propertyName);
310
+ };
226
311
  const extractArrayElementValues = (node, visited) => {
227
312
  if (ts_morph.Node.isArrayLiteralExpression(node)) return node.getElements().flatMap((element) => extractStringLiterals(element, visited)).filter((value, index, values) => values.indexOf(value) === index);
228
313
  if (ts_morph.Node.isParenthesizedExpression(node)) return extractArrayElementValues(node.getExpression(), visited);
229
314
  if (ts_morph.Node.isAsExpression(node) || ts_morph.Node.isTypeAssertion(node) || ts_morph.Node.isSatisfiesExpression(node)) return extractArrayElementValues(node.getExpression(), visited);
315
+ if (ts_morph.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);
316
+ if (ts_morph.Node.isCallExpression(node)) {
317
+ const expression = node.getExpression();
318
+ if (ts_morph.Node.isPropertyAccessExpression(expression) && ARRAY_CHAIN_METHODS.has(expression.getName())) return extractArrayElementValues(expression.getExpression(), visited);
319
+ return [];
320
+ }
230
321
  if (ts_morph.Node.isIdentifier(node)) return getLocalDefinitionNodes(node).flatMap((definition) => {
231
322
  if (ts_morph.Node.isVariableDeclaration(definition)) {
232
323
  const initializer = definition.getInitializer();
233
324
  return initializer ? extractArrayElementValues(initializer, visited) : [];
234
325
  }
235
- return [];
326
+ return getBindingElementSources(definition).flatMap((source) => extractArrayElementValues(source, visited));
236
327
  }).filter((value, index, values) => values.indexOf(value) === index);
237
328
  return [];
238
329
  };
239
330
  const extractMappedParameterValues = (definition, visited) => {
240
- if (!ts_morph.Node.isParameterDeclaration(definition)) return [];
241
- const callback = definition.getParentIfKind(ts_morph.SyntaxKind.ArrowFunction);
242
- if (!callback) return [];
243
- const callExpression = callback.getParentIfKind(ts_morph.SyntaxKind.CallExpression);
244
- if (!callExpression) return [];
245
- const expression = callExpression.getExpression();
246
- if (!ts_morph.Node.isPropertyAccessExpression(expression)) return [];
247
- if (!["map", "flatMap"].includes(expression.getName())) return [];
248
- if (callback.getParameters().findIndex((parameter) => parameter.getNameNode().getText() === definition.getNameNode().getText()) !== 0) return [];
249
- return extractArrayElementValues(expression.getExpression(), visited);
331
+ const mappedSource = getMappedArraySource(definition);
332
+ if (!mappedSource) return [];
333
+ return extractArrayElementValues(mappedSource, visited);
250
334
  };
251
335
  const extractIdentifierValues = (node, visited) => {
252
336
  if (!ts_morph.Node.isIdentifier(node)) return null;
@@ -331,6 +415,15 @@ const extractObjectValues = (node, visited) => {
331
415
  } else values.push(...extractObjectValues(initializer, visited));
332
416
  }
333
417
  });
418
+ const enumDecl = node.getSourceFile().getEnum(node.getText());
419
+ if (enumDecl) {
420
+ const obj = {};
421
+ enumDecl.getMembers().forEach((member) => {
422
+ const initializer = member.getInitializer();
423
+ if (initializer && ts_morph.Node.isStringLiteral(initializer)) obj[member.getName()] = initializer.getLiteralValue();
424
+ });
425
+ if (Object.keys(obj).length > 0) values.push(obj);
426
+ }
334
427
  return values;
335
428
  }
336
429
  if (ts_morph.Node.isCallExpression(node)) {
@@ -220,30 +220,114 @@ const extractCallExpressionValues = (node, visited) => {
220
220
  const fromArguments = node.getArguments().flatMap((arg) => extractStringLiterals(arg, visited));
221
221
  return [...fromDefinitions, ...fromArguments];
222
222
  };
223
+ /** Array methods that return (a subset of) the receiver's elements. */
224
+ const ARRAY_CHAIN_METHODS = new Set([
225
+ "concat",
226
+ "filter",
227
+ "flat",
228
+ "reverse",
229
+ "slice",
230
+ "sort",
231
+ "toReversed",
232
+ "toSorted"
233
+ ]);
234
+ /**
235
+ * If the definition is the first parameter of a `.map()`/`.flatMap()` callback,
236
+ * return the expression being mapped over (the array source).
237
+ */
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();
251
+ };
252
+ /**
253
+ * Resolve a node to the object-literal AST nodes it may evaluate to.
254
+ * Handles arrays of objects (each element is a candidate), element access,
255
+ * array-method chains, and `.map()` callback parameters (UDS-2557 follow-up:
256
+ * variant arrays nested inside const structures).
257
+ */
258
+ const resolveObjectLiteralNodes = (node, visited) => {
259
+ if (visited.has(node)) return [];
260
+ 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
+ return [];
269
+ }
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);
277
+ return [];
278
+ });
279
+ return [];
280
+ };
281
+ /**
282
+ * Collect the initializers of a named property across object-literal candidates.
283
+ */
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] : [];
290
+ });
291
+ });
292
+ /**
293
+ * For a destructured binding (e.g. `({ variants }) =>` map param or
294
+ * `const { variants } = GROUPS[0]`), resolve the bound property's initializers.
295
+ */
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);
307
+ };
223
308
  const extractArrayElementValues = (node, visited) => {
224
309
  if (Node.isArrayLiteralExpression(node)) return node.getElements().flatMap((element) => extractStringLiterals(element, visited)).filter((value, index, values) => values.indexOf(value) === index);
225
310
  if (Node.isParenthesizedExpression(node)) return extractArrayElementValues(node.getExpression(), visited);
226
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);
316
+ return [];
317
+ }
227
318
  if (Node.isIdentifier(node)) return getLocalDefinitionNodes(node).flatMap((definition) => {
228
319
  if (Node.isVariableDeclaration(definition)) {
229
320
  const initializer = definition.getInitializer();
230
321
  return initializer ? extractArrayElementValues(initializer, visited) : [];
231
322
  }
232
- return [];
323
+ return getBindingElementSources(definition).flatMap((source) => extractArrayElementValues(source, visited));
233
324
  }).filter((value, index, values) => values.indexOf(value) === index);
234
325
  return [];
235
326
  };
236
327
  const extractMappedParameterValues = (definition, visited) => {
237
- if (!Node.isParameterDeclaration(definition)) return [];
238
- const callback = definition.getParentIfKind(SyntaxKind.ArrowFunction);
239
- if (!callback) return [];
240
- const callExpression = callback.getParentIfKind(SyntaxKind.CallExpression);
241
- if (!callExpression) return [];
242
- const expression = callExpression.getExpression();
243
- if (!Node.isPropertyAccessExpression(expression)) return [];
244
- if (!["map", "flatMap"].includes(expression.getName())) return [];
245
- if (callback.getParameters().findIndex((parameter) => parameter.getNameNode().getText() === definition.getNameNode().getText()) !== 0) return [];
246
- return extractArrayElementValues(expression.getExpression(), visited);
328
+ const mappedSource = getMappedArraySource(definition);
329
+ if (!mappedSource) return [];
330
+ return extractArrayElementValues(mappedSource, visited);
247
331
  };
248
332
  const extractIdentifierValues = (node, visited) => {
249
333
  if (!Node.isIdentifier(node)) return null;
@@ -328,6 +412,15 @@ const extractObjectValues = (node, visited) => {
328
412
  } else values.push(...extractObjectValues(initializer, visited));
329
413
  }
330
414
  });
415
+ const enumDecl = node.getSourceFile().getEnum(node.getText());
416
+ if (enumDecl) {
417
+ const obj = {};
418
+ enumDecl.getMembers().forEach((member) => {
419
+ const initializer = member.getInitializer();
420
+ if (initializer && Node.isStringLiteral(initializer)) obj[member.getName()] = initializer.getLiteralValue();
421
+ });
422
+ if (Object.keys(obj).length > 0) values.push(obj);
423
+ }
331
424
  return values;
332
425
  }
333
426
  if (Node.isCallExpression(node)) {
@@ -0,0 +1,74 @@
1
+ /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
+ require("../../../../../_virtual/_rolldown/runtime.cjs");
3
+ let ts_morph = require("ts-morph");
4
+ //#region ../css/dist/purger/optimized/ast/jsx.mjs
5
+ /*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
6
+ /**
7
+ * Check if an expression is using React.forwardRef
8
+ */
9
+ const isForwardRefExpression = (node) => {
10
+ if (!ts_morph.Node.isCallExpression(node)) return false;
11
+ const expression = node.getExpression();
12
+ if (ts_morph.Node.isIdentifier(expression) && expression.getText() === "forwardRef") return true;
13
+ if (ts_morph.Node.isPropertyAccessExpression(expression) && expression.getText() === "React.forwardRef") return true;
14
+ return false;
15
+ };
16
+ /**
17
+ * Check if a node is a JSX component (PascalCase name)
18
+ */
19
+ const isJsxComponent = (node) => {
20
+ let name;
21
+ if (ts_morph.Node.isVariableDeclaration(node) || ts_morph.Node.isFunctionDeclaration(node) || ts_morph.Node.isClassDeclaration(node)) name = node.getName();
22
+ else if (ts_morph.Node.isFunctionExpression(node) || ts_morph.Node.isArrowFunction(node)) name = node.getFirstAncestorByKind(ts_morph.SyntaxKind.VariableDeclaration)?.getName();
23
+ return name ? /^[A-Z]/.test(name) : false;
24
+ };
25
+ /**
26
+ * Get the function declaration from a component, unwrapping forwardRef if needed
27
+ */
28
+ const getReactFunctionDeclaration = (declaration) => {
29
+ if (!isJsxComponent(declaration)) return null;
30
+ if (ts_morph.Node.isFunctionDeclaration(declaration)) return declaration;
31
+ if (ts_morph.Node.isVariableDeclaration(declaration)) {
32
+ const initializer = declaration.getInitializer();
33
+ if (!initializer) return null;
34
+ if (isForwardRefExpression(initializer)) {
35
+ const [arg] = initializer.getArguments();
36
+ if (ts_morph.Node.isFunctionDeclaration(arg) || ts_morph.Node.isFunctionExpression(arg) || ts_morph.Node.isArrowFunction(arg)) return arg;
37
+ } else if (ts_morph.Node.isFunctionDeclaration(initializer) || ts_morph.Node.isFunctionExpression(initializer) || ts_morph.Node.isArrowFunction(initializer)) return initializer;
38
+ }
39
+ return null;
40
+ };
41
+ /**
42
+ * Get the parent component that contains a JSX reference.
43
+ * Returns information about the component including spread rest identifier.
44
+ */
45
+ const getParentComponentInfo = (reference) => {
46
+ const block = reference.getParentWhile((parent) => !getReactFunctionDeclaration(parent));
47
+ if (!block) return;
48
+ const blockParent = block.getParent();
49
+ if (!blockParent) return;
50
+ const reactComponent = getReactFunctionDeclaration(blockParent);
51
+ if (!reactComponent) return;
52
+ let componentName;
53
+ const variableDeclaration = reactComponent.getFirstAncestorByKind(ts_morph.SyntaxKind.VariableDeclaration);
54
+ if (variableDeclaration) componentName = variableDeclaration.getName();
55
+ else if (ts_morph.Node.isFunctionDeclaration(reactComponent)) componentName = reactComponent.getName();
56
+ if (!componentName) return;
57
+ let spreadRestIdentifier;
58
+ let paramIdentifier;
59
+ reactComponent.getParameters().forEach((parameter) => {
60
+ const objectBindingPattern = parameter.getChildrenOfKind(ts_morph.SyntaxKind.ObjectBindingPattern)[0];
61
+ const identifier = parameter.getChildrenOfKind(ts_morph.SyntaxKind.Identifier)[0];
62
+ if (objectBindingPattern) {
63
+ const dotDotToken = objectBindingPattern.getFirstDescendantByKind(ts_morph.SyntaxKind.DotDotDotToken);
64
+ if (dotDotToken) spreadRestIdentifier = dotDotToken.getParent()?.getFirstChildByKindOrThrow(ts_morph.SyntaxKind.Identifier).getText();
65
+ } else if (identifier) paramIdentifier = identifier.getText();
66
+ });
67
+ return {
68
+ componentName,
69
+ spreadRestIdentifier,
70
+ paramIdentifier
71
+ };
72
+ };
73
+ //#endregion
74
+ exports.getParentComponentInfo = getParentComponentInfo;
@@ -0,0 +1,73 @@
1
+ /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
+ import { Node, SyntaxKind } from "ts-morph";
3
+ //#region ../css/dist/purger/optimized/ast/jsx.mjs
4
+ /*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
5
+ /**
6
+ * Check if an expression is using React.forwardRef
7
+ */
8
+ const isForwardRefExpression = (node) => {
9
+ if (!Node.isCallExpression(node)) return false;
10
+ const expression = node.getExpression();
11
+ if (Node.isIdentifier(expression) && expression.getText() === "forwardRef") return true;
12
+ if (Node.isPropertyAccessExpression(expression) && expression.getText() === "React.forwardRef") return true;
13
+ return false;
14
+ };
15
+ /**
16
+ * Check if a node is a JSX component (PascalCase name)
17
+ */
18
+ const isJsxComponent = (node) => {
19
+ let name;
20
+ if (Node.isVariableDeclaration(node) || Node.isFunctionDeclaration(node) || Node.isClassDeclaration(node)) name = node.getName();
21
+ else if (Node.isFunctionExpression(node) || Node.isArrowFunction(node)) name = node.getFirstAncestorByKind(SyntaxKind.VariableDeclaration)?.getName();
22
+ return name ? /^[A-Z]/.test(name) : false;
23
+ };
24
+ /**
25
+ * Get the function declaration from a component, unwrapping forwardRef if needed
26
+ */
27
+ const getReactFunctionDeclaration = (declaration) => {
28
+ if (!isJsxComponent(declaration)) return null;
29
+ if (Node.isFunctionDeclaration(declaration)) return declaration;
30
+ if (Node.isVariableDeclaration(declaration)) {
31
+ const initializer = declaration.getInitializer();
32
+ if (!initializer) return null;
33
+ if (isForwardRefExpression(initializer)) {
34
+ const [arg] = initializer.getArguments();
35
+ if (Node.isFunctionDeclaration(arg) || Node.isFunctionExpression(arg) || Node.isArrowFunction(arg)) return arg;
36
+ } else if (Node.isFunctionDeclaration(initializer) || Node.isFunctionExpression(initializer) || Node.isArrowFunction(initializer)) return initializer;
37
+ }
38
+ return null;
39
+ };
40
+ /**
41
+ * Get the parent component that contains a JSX reference.
42
+ * Returns information about the component including spread rest identifier.
43
+ */
44
+ const getParentComponentInfo = (reference) => {
45
+ const block = reference.getParentWhile((parent) => !getReactFunctionDeclaration(parent));
46
+ if (!block) return;
47
+ const blockParent = block.getParent();
48
+ if (!blockParent) return;
49
+ const reactComponent = getReactFunctionDeclaration(blockParent);
50
+ if (!reactComponent) return;
51
+ let componentName;
52
+ const variableDeclaration = reactComponent.getFirstAncestorByKind(SyntaxKind.VariableDeclaration);
53
+ if (variableDeclaration) componentName = variableDeclaration.getName();
54
+ else if (Node.isFunctionDeclaration(reactComponent)) componentName = reactComponent.getName();
55
+ if (!componentName) return;
56
+ let spreadRestIdentifier;
57
+ let paramIdentifier;
58
+ reactComponent.getParameters().forEach((parameter) => {
59
+ const objectBindingPattern = parameter.getChildrenOfKind(SyntaxKind.ObjectBindingPattern)[0];
60
+ const identifier = parameter.getChildrenOfKind(SyntaxKind.Identifier)[0];
61
+ if (objectBindingPattern) {
62
+ const dotDotToken = objectBindingPattern.getFirstDescendantByKind(SyntaxKind.DotDotDotToken);
63
+ if (dotDotToken) spreadRestIdentifier = dotDotToken.getParent()?.getFirstChildByKindOrThrow(SyntaxKind.Identifier).getText();
64
+ } else if (identifier) paramIdentifier = identifier.getText();
65
+ });
66
+ return {
67
+ componentName,
68
+ spreadRestIdentifier,
69
+ paramIdentifier
70
+ };
71
+ };
72
+ //#endregion
73
+ export { getParentComponentInfo };
@@ -0,0 +1,47 @@
1
+ /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
+ require("../../../../../_virtual/_rolldown/runtime.cjs");
3
+ const require_expressions = require("./expressions.cjs");
4
+ let ts_morph = require("ts-morph");
5
+ //#region ../css/dist/purger/optimized/ast/props.mjs
6
+ /*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
7
+ /**
8
+ * Extract all props from a JSX element (both explicit props and spread props).
9
+ *
10
+ * For explicit props like `<Box color="brand" />`, extracts the prop name and value.
11
+ * For spread props like `<Box {...props} />`, marks them as fromSpread for later resolution.
12
+ *
13
+ * @param element The JSX element to extract props from
14
+ * @returns Array of extracted props with their values
15
+ */
16
+ const extractPropsFromElement = (element) => element.getAttributes().flatMap((attr) => {
17
+ if (ts_morph.Node.isJsxAttribute(attr)) {
18
+ const propName = attr.getNameNode().getText();
19
+ const stringLiterals = attr.getDescendantsOfKind(ts_morph.SyntaxKind.StringLiteral);
20
+ return [{
21
+ name: propName,
22
+ values: stringLiterals.length > 0 ? stringLiterals.map((lit) => lit.getLiteralText()) : (() => {
23
+ const initializer = attr.getInitializer();
24
+ if (!initializer || !ts_morph.Node.isJsxExpression(initializer)) return [];
25
+ const expression = initializer.getExpression();
26
+ return expression ? require_expressions.extractStringLiterals(expression) : [];
27
+ })(),
28
+ fromSpread: false
29
+ }];
30
+ }
31
+ if (ts_morph.Node.isJsxSpreadAttribute(attr)) {
32
+ const expression = attr.getExpression();
33
+ return [{
34
+ name: `__spread__:${ts_morph.Node.isIdentifier(expression) ? expression.getText() : expression.getChildren().pop()?.getText() ?? ""}`,
35
+ values: [],
36
+ fromSpread: true
37
+ }];
38
+ }
39
+ return [];
40
+ });
41
+ /**
42
+ * Extract only explicit (non-spread) props from a JSX element.
43
+ * Used when we want to avoid including spread-derived values.
44
+ */
45
+ const extractExplicitProps = (element) => extractPropsFromElement(element).filter((p) => !p.fromSpread);
46
+ //#endregion
47
+ exports.extractExplicitProps = extractExplicitProps;
@@ -0,0 +1,46 @@
1
+ /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
+ import { extractStringLiterals } from "./expressions.js";
3
+ import { Node, SyntaxKind } from "ts-morph";
4
+ //#region ../css/dist/purger/optimized/ast/props.mjs
5
+ /*! © 2026 Yahoo, Inc. UDS CSS v0.0.0-development */
6
+ /**
7
+ * Extract all props from a JSX element (both explicit props and spread props).
8
+ *
9
+ * For explicit props like `<Box color="brand" />`, extracts the prop name and value.
10
+ * For spread props like `<Box {...props} />`, marks them as fromSpread for later resolution.
11
+ *
12
+ * @param element The JSX element to extract props from
13
+ * @returns Array of extracted props with their values
14
+ */
15
+ const extractPropsFromElement = (element) => element.getAttributes().flatMap((attr) => {
16
+ if (Node.isJsxAttribute(attr)) {
17
+ const propName = attr.getNameNode().getText();
18
+ const stringLiterals = attr.getDescendantsOfKind(SyntaxKind.StringLiteral);
19
+ return [{
20
+ name: propName,
21
+ values: stringLiterals.length > 0 ? stringLiterals.map((lit) => lit.getLiteralText()) : (() => {
22
+ const initializer = attr.getInitializer();
23
+ if (!initializer || !Node.isJsxExpression(initializer)) return [];
24
+ const expression = initializer.getExpression();
25
+ return expression ? extractStringLiterals(expression) : [];
26
+ })(),
27
+ fromSpread: false
28
+ }];
29
+ }
30
+ if (Node.isJsxSpreadAttribute(attr)) {
31
+ const expression = attr.getExpression();
32
+ return [{
33
+ name: `__spread__:${Node.isIdentifier(expression) ? expression.getText() : expression.getChildren().pop()?.getText() ?? ""}`,
34
+ values: [],
35
+ fromSpread: true
36
+ }];
37
+ }
38
+ return [];
39
+ });
40
+ /**
41
+ * Extract only explicit (non-spread) props from a JSX element.
42
+ * Used when we want to avoid including spread-derived values.
43
+ */
44
+ const extractExplicitProps = (element) => extractPropsFromElement(element).filter((p) => !p.fromSpread);
45
+ //#endregion
46
+ export { extractExplicitProps };