@yahoo/uds 3.116.0 → 3.116.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 (37) hide show
  1. package/dist/components/client/BottomSheet/BottomSheet.cjs +37 -8
  2. package/dist/components/client/BottomSheet/BottomSheet.js +38 -9
  3. package/dist/components/client/BottomSheet/BottomSheetContent.cjs +4 -2
  4. package/dist/components/client/BottomSheet/BottomSheetContent.js +4 -2
  5. package/dist/components/client/BottomSheet/BottomSheetInternalContext.cjs +15 -0
  6. package/dist/components/client/BottomSheet/BottomSheetInternalContext.d.cts +12 -0
  7. package/dist/components/client/BottomSheet/BottomSheetInternalContext.d.ts +12 -0
  8. package/dist/components/client/BottomSheet/BottomSheetInternalContext.js +12 -0
  9. package/dist/styles/styler.d.cts +19 -19
  10. package/dist/styles/styler.d.ts +19 -19
  11. package/dist/tailwind/dist/css/generate.cjs +6 -0
  12. package/dist/tailwind/dist/css/generate.helpers.cjs +5 -1
  13. package/dist/tailwind/dist/css/generate.helpers.js +5 -1
  14. package/dist/tailwind/dist/css/generate.js +6 -0
  15. package/dist/tailwind/dist/css/nodeUtils.cjs +2 -1
  16. package/dist/tailwind/dist/css/nodeUtils.js +2 -1
  17. package/dist/tailwind/dist/css/postcss.cjs +1 -1
  18. package/dist/tailwind/dist/css/postcss.helpers.cjs +8 -6
  19. package/dist/tailwind/dist/css/postcss.helpers.js +8 -6
  20. package/dist/tailwind/dist/css/postcss.js +1 -1
  21. package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +103 -1
  22. package/dist/tailwind/dist/purger/optimized/ast/expressions.js +102 -2
  23. package/dist/tailwind/dist/purger/optimized/ast/jsx.cjs +7 -1
  24. package/dist/tailwind/dist/purger/optimized/ast/jsx.js +7 -1
  25. package/dist/tailwind/dist/purger/optimized/purgeFromCode.cjs +18 -13
  26. package/dist/tailwind/dist/purger/optimized/purgeFromCode.js +18 -13
  27. package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.cjs +2 -1
  28. package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.js +2 -1
  29. package/dist/uds/generated/componentData.cjs +825 -806
  30. package/dist/uds/generated/componentData.js +799 -786
  31. package/dist/uds/generated/tailwindPurge.cjs +7 -7
  32. package/dist/uds/generated/tailwindPurge.js +7 -7
  33. package/dist/uds/package.cjs +1 -1
  34. package/dist/uds/package.js +1 -1
  35. package/generated/componentData.json +1122 -1107
  36. package/generated/tailwindPurge.ts +2 -2
  37. package/package.json +2 -2
@@ -23,6 +23,11 @@ const normalizeScope = (scope) => {
23
23
  const trimmedScope = scope?.trim();
24
24
  return trimmedScope ? trimmedScope : void 0;
25
25
  };
26
+ const getArbitrarySafelistRawContent = (safelist) => {
27
+ const arbitraryClasses = safelist.filter((entry) => typeof entry === "string" && entry.includes("["));
28
+ if (arbitraryClasses.length === 0) return [];
29
+ return [`<div class="${arbitraryClasses.join(" ")}"></div>`];
30
+ };
26
31
  /**
27
32
  * Generate CSS from a safelist using Tailwind + PostCSS
28
33
  * @param safelist - UDS component classes to include
@@ -38,6 +43,7 @@ const generateCSS = async (safelist, config, options) => {
38
43
  let css = await require_generate_helpers.applyScopedColorModeFix((await (0, postcss.default)(require_generate_helpers.buildPostcssPlugins({
39
44
  tailwindPlugin: require_generate_helpers.createTailwindPlugin({
40
45
  contentDir,
46
+ rawContents: getArbitrarySafelistRawContent(safelist),
41
47
  safelist,
42
48
  config,
43
49
  enablePreflight: cssFlags.enablePreflight,
@@ -34,9 +34,13 @@ const getCssFeatureFlags = (cssOptions) => {
34
34
  const getContentGlobs = (contentDir) => {
35
35
  return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => require_entryPoints.hasAllowedEntryFileExtension(dir) ? dir : node_path.default.join(dir, "**/*.{js,jsx,ts,tsx}"));
36
36
  };
37
+ const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
38
+ raw: rawContent,
39
+ extension: "html"
40
+ }));
37
41
  const createTailwindPlugin = (options) => {
38
42
  return (0, tailwindcss.default)({
39
- content: getContentGlobs(options.contentDir),
43
+ content: [...getContentGlobs(options.contentDir), ...getRawContentEntries(options.rawContents ?? [])],
40
44
  safelist: options.safelist,
41
45
  corePlugins: { preflight: options.enablePreflight },
42
46
  plugins: [require_plugin.tailwindPlugin({
@@ -27,9 +27,13 @@ const getCssFeatureFlags = (cssOptions) => {
27
27
  const getContentGlobs = (contentDir) => {
28
28
  return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => hasAllowedEntryFileExtension(dir) ? dir : path.join(dir, "**/*.{js,jsx,ts,tsx}"));
29
29
  };
30
+ const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
31
+ raw: rawContent,
32
+ extension: "html"
33
+ }));
30
34
  const createTailwindPlugin = (options) => {
31
35
  return tailwindcss({
32
- content: getContentGlobs(options.contentDir),
36
+ content: [...getContentGlobs(options.contentDir), ...getRawContentEntries(options.rawContents ?? [])],
33
37
  safelist: options.safelist,
34
38
  corePlugins: { preflight: options.enablePreflight },
35
39
  plugins: [tailwindPlugin({
@@ -19,6 +19,11 @@ const normalizeScope = (scope) => {
19
19
  const trimmedScope = scope?.trim();
20
20
  return trimmedScope ? trimmedScope : void 0;
21
21
  };
22
+ const getArbitrarySafelistRawContent = (safelist) => {
23
+ const arbitraryClasses = safelist.filter((entry) => typeof entry === "string" && entry.includes("["));
24
+ if (arbitraryClasses.length === 0) return [];
25
+ return [`<div class="${arbitraryClasses.join(" ")}"></div>`];
26
+ };
22
27
  /**
23
28
  * Generate CSS from a safelist using Tailwind + PostCSS
24
29
  * @param safelist - UDS component classes to include
@@ -34,6 +39,7 @@ const generateCSS = async (safelist, config, options) => {
34
39
  let css = await applyScopedColorModeFix((await postcss(buildPostcssPlugins({
35
40
  tailwindPlugin: createTailwindPlugin({
36
41
  contentDir,
42
+ rawContents: getArbitrarySafelistRawContent(safelist),
37
43
  safelist,
38
44
  config,
39
45
  enablePreflight: cssFlags.enablePreflight,
@@ -37,7 +37,8 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
37
37
  variants,
38
38
  autoVariants,
39
39
  componentData,
40
- includeAllClassNamePrimitives
40
+ includeAllClassNamePrimitives,
41
+ filePath
41
42
  });
42
43
  }));
43
44
  return {
@@ -33,7 +33,8 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
33
33
  variants,
34
34
  autoVariants,
35
35
  componentData,
36
- includeAllClassNamePrimitives
36
+ includeAllClassNamePrimitives,
37
+ filePath
37
38
  });
38
39
  }));
39
40
  return {
@@ -13,7 +13,7 @@ const require_postcss_helpers = require('./postcss.helpers.cjs');
13
13
  * ANCESTOR of the scope, not a descendant. This plugin adds alternative
14
14
  * selectors so color modes work correctly:
15
15
  *
16
- * `.scope .uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo, .uds-color-mode-dark .scope .foo`
16
+ * `.scope .uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo, .uds-color-mode-dark .scope .foo, .uds-color-mode-dark.scope .foo`
17
17
  *
18
18
  * This ensures styles apply whether the color mode class is inside or outside the scope.
19
19
  */
@@ -4,22 +4,24 @@
4
4
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
5
5
  const COLOR_MODE_RE = /^(\.(uds-color-mode-(?:dark|light)))(\s+.+)?$/;
6
6
  const escapeForRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7
- const getScopedColorModeAlternativeSelector = (selector, scopeClass) => {
7
+ const getScopedColorModeAlternativeSelector = (selector, scopeClass, variant = "descendant") => {
8
8
  const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
9
9
  if (!scopeMatch) return null;
10
10
  const colorModeMatch = scopeMatch[2].match(COLOR_MODE_RE);
11
11
  if (!colorModeMatch) return null;
12
- return `${colorModeMatch[1]} ${scopeClass}${colorModeMatch[3] ?? ""}`;
12
+ const colorModeClass = colorModeMatch[1];
13
+ const rest = colorModeMatch[3] ?? "";
14
+ return variant === "same-element" ? `${colorModeClass}${scopeClass}${rest}` : `${colorModeClass} ${scopeClass}${rest}`;
13
15
  };
14
16
  const buildScopedColorModeSelectorList = (ruleSelector, scopeClass) => {
15
17
  const selectors = ruleSelector.split(",").map((value) => value.trim());
16
18
  return selectors.reduce((acc, selector) => {
17
- const altSelector = getScopedColorModeAlternativeSelector(selector, scopeClass);
18
- return altSelector && !selectors.includes(altSelector) && !acc.includes(altSelector) ? [
19
+ const nextAltSelectors = [getScopedColorModeAlternativeSelector(selector, scopeClass), getScopedColorModeAlternativeSelector(selector, scopeClass, "same-element")].filter((value) => Boolean(value)).filter((altSelector) => !selectors.includes(altSelector) && !acc.includes(altSelector));
20
+ return [
19
21
  ...acc,
20
22
  selector,
21
- altSelector
22
- ] : [...acc, selector];
23
+ ...nextAltSelectors
24
+ ];
23
25
  }, []).join(", ");
24
26
  };
25
27
 
@@ -3,22 +3,24 @@
3
3
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
4
4
  const COLOR_MODE_RE = /^(\.(uds-color-mode-(?:dark|light)))(\s+.+)?$/;
5
5
  const escapeForRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6
- const getScopedColorModeAlternativeSelector = (selector, scopeClass) => {
6
+ const getScopedColorModeAlternativeSelector = (selector, scopeClass, variant = "descendant") => {
7
7
  const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
8
8
  if (!scopeMatch) return null;
9
9
  const colorModeMatch = scopeMatch[2].match(COLOR_MODE_RE);
10
10
  if (!colorModeMatch) return null;
11
- return `${colorModeMatch[1]} ${scopeClass}${colorModeMatch[3] ?? ""}`;
11
+ const colorModeClass = colorModeMatch[1];
12
+ const rest = colorModeMatch[3] ?? "";
13
+ return variant === "same-element" ? `${colorModeClass}${scopeClass}${rest}` : `${colorModeClass} ${scopeClass}${rest}`;
12
14
  };
13
15
  const buildScopedColorModeSelectorList = (ruleSelector, scopeClass) => {
14
16
  const selectors = ruleSelector.split(",").map((value) => value.trim());
15
17
  return selectors.reduce((acc, selector) => {
16
- const altSelector = getScopedColorModeAlternativeSelector(selector, scopeClass);
17
- return altSelector && !selectors.includes(altSelector) && !acc.includes(altSelector) ? [
18
+ const nextAltSelectors = [getScopedColorModeAlternativeSelector(selector, scopeClass), getScopedColorModeAlternativeSelector(selector, scopeClass, "same-element")].filter((value) => Boolean(value)).filter((altSelector) => !selectors.includes(altSelector) && !acc.includes(altSelector));
19
+ return [
18
20
  ...acc,
19
21
  selector,
20
- altSelector
21
- ] : [...acc, selector];
22
+ ...nextAltSelectors
23
+ ];
22
24
  }, []).join(", ");
23
25
  };
24
26
 
@@ -13,7 +13,7 @@ import { buildScopedColorModeSelectorList } from "./postcss.helpers.js";
13
13
  * ANCESTOR of the scope, not a descendant. This plugin adds alternative
14
14
  * selectors so color modes work correctly:
15
15
  *
16
- * `.scope .uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo, .uds-color-mode-dark .scope .foo`
16
+ * `.scope .uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo, .uds-color-mode-dark .scope .foo, .uds-color-mode-dark.scope .foo`
17
17
  *
18
18
  * This ensures styles apply whether the color mode class is inside or outside the scope.
19
19
  */
@@ -1,9 +1,108 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
2
  const require_runtime = require('../../../../../_virtual/_rolldown/runtime.cjs');
3
+ let node_path = require("node:path");
4
+ node_path = require_runtime.__toESM(node_path);
5
+ let node_fs = require("node:fs");
6
+ node_fs = require_runtime.__toESM(node_fs);
3
7
  let ts_morph = require("ts-morph");
4
8
 
5
9
  //#region ../tailwind/dist/purger/optimized/ast/expressions.js
6
10
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
11
+ const importedSourceProject = new ts_morph.Project({ useInMemoryFileSystem: true });
12
+ const importedSourceFileCache = /* @__PURE__ */ new Map();
13
+ const tsConfigPathCache = /* @__PURE__ */ new Map();
14
+ const compilerOptionsCache = /* @__PURE__ */ new Map();
15
+ const hasImportQuery = (moduleSpecifier) => moduleSpecifier.includes("?");
16
+ const isExistingFile = (candidate) => node_fs.default.existsSync(candidate) && node_fs.default.statSync(candidate).isFile();
17
+ const resolveRelativeImportPath = (sourceFilePath, moduleSpecifier) => {
18
+ if (!node_path.default.isAbsolute(sourceFilePath) || !moduleSpecifier.startsWith(".") || hasImportQuery(moduleSpecifier)) return null;
19
+ const basePath = node_path.default.resolve(node_path.default.dirname(sourceFilePath), moduleSpecifier);
20
+ return [
21
+ basePath,
22
+ `${basePath}.ts`,
23
+ `${basePath}.tsx`,
24
+ `${basePath}.js`,
25
+ `${basePath}.jsx`,
26
+ node_path.default.join(basePath, "index.ts"),
27
+ node_path.default.join(basePath, "index.tsx"),
28
+ node_path.default.join(basePath, "index.js"),
29
+ node_path.default.join(basePath, "index.jsx")
30
+ ].find((candidate) => isExistingFile(candidate)) ?? null;
31
+ };
32
+ const findNearestTypeScriptConfig = (sourceFilePath) => {
33
+ const sourceDir = node_path.default.dirname(sourceFilePath);
34
+ const cached = tsConfigPathCache.get(sourceDir);
35
+ if (cached !== void 0) return cached;
36
+ let currentDir = sourceDir;
37
+ while (true) {
38
+ const tsConfigPath = node_path.default.join(currentDir, "tsconfig.json");
39
+ if (isExistingFile(tsConfigPath)) {
40
+ tsConfigPathCache.set(sourceDir, tsConfigPath);
41
+ return tsConfigPath;
42
+ }
43
+ const jsConfigPath = node_path.default.join(currentDir, "jsconfig.json");
44
+ if (isExistingFile(jsConfigPath)) {
45
+ tsConfigPathCache.set(sourceDir, jsConfigPath);
46
+ return jsConfigPath;
47
+ }
48
+ const parentDir = node_path.default.dirname(currentDir);
49
+ if (parentDir === currentDir) {
50
+ tsConfigPathCache.set(sourceDir, null);
51
+ return null;
52
+ }
53
+ currentDir = parentDir;
54
+ }
55
+ };
56
+ const getCompilerOptionsForSourceFile = (sourceFilePath) => {
57
+ const configPath = findNearestTypeScriptConfig(sourceFilePath);
58
+ if (!configPath) return null;
59
+ const cached = compilerOptionsCache.get(configPath);
60
+ if (cached !== void 0) return cached;
61
+ const readResult = ts_morph.ts.readConfigFile(configPath, ts_morph.ts.sys.readFile);
62
+ if (readResult.error) {
63
+ compilerOptionsCache.set(configPath, null);
64
+ return null;
65
+ }
66
+ const parsed = ts_morph.ts.parseJsonConfigFileContent(readResult.config, ts_morph.ts.sys, node_path.default.dirname(configPath));
67
+ const compilerOptions = parsed.options.paths && !parsed.options.baseUrl ? {
68
+ ...parsed.options,
69
+ baseUrl: node_path.default.dirname(configPath)
70
+ } : parsed.options;
71
+ compilerOptionsCache.set(configPath, compilerOptions);
72
+ return compilerOptions;
73
+ };
74
+ const resolveConfigImportPath = (sourceFilePath, moduleSpecifier) => {
75
+ if (hasImportQuery(moduleSpecifier)) return null;
76
+ const compilerOptions = getCompilerOptionsForSourceFile(sourceFilePath);
77
+ if (!compilerOptions) return null;
78
+ const resolvedModule = ts_morph.ts.resolveModuleName(moduleSpecifier, sourceFilePath, compilerOptions, ts_morph.ts.sys).resolvedModule;
79
+ if (!resolvedModule) return null;
80
+ return isExistingFile(resolvedModule.resolvedFileName) ? resolvedModule.resolvedFileName : null;
81
+ };
82
+ const resolveImportPath = (sourceFilePath, moduleSpecifier) => moduleSpecifier.startsWith(".") ? resolveRelativeImportPath(sourceFilePath, moduleSpecifier) : resolveConfigImportPath(sourceFilePath, moduleSpecifier);
83
+ const getImportedSourceFile = (filePath) => {
84
+ const cached = importedSourceFileCache.get(filePath);
85
+ if (cached) return cached;
86
+ if (!node_fs.default.existsSync(filePath)) return null;
87
+ const sourceFile = importedSourceProject.createSourceFile(filePath, node_fs.default.readFileSync(filePath, "utf-8"), { overwrite: true });
88
+ importedSourceFileCache.set(filePath, sourceFile);
89
+ return sourceFile;
90
+ };
91
+ const extractImportedIdentifierValues = (node, visited) => {
92
+ if (!ts_morph.Node.isIdentifier(node)) return [];
93
+ const sourceFile = node.getSourceFile();
94
+ const sourceFilePath = sourceFile.getFilePath();
95
+ const importMatch = sourceFile.getImportDeclarations().find((importDecl) => importDecl.getNamedImports().some((namedImport) => (namedImport.getAliasNode()?.getText() ?? namedImport.getName()) === node.getText()));
96
+ if (!importMatch) return [];
97
+ const namedImport = importMatch.getNamedImports().find((candidate) => (candidate.getAliasNode()?.getText() ?? candidate.getName()) === node.getText());
98
+ if (!namedImport) return [];
99
+ const resolvedPath = resolveImportPath(sourceFilePath, importMatch.getModuleSpecifierValue());
100
+ if (!resolvedPath) return [];
101
+ const importedSourceFile = getImportedSourceFile(resolvedPath);
102
+ if (!importedSourceFile) return [];
103
+ const initializer = importedSourceFile.getVariableDeclaration(namedImport.getName())?.getInitializer();
104
+ return initializer ? extractStringLiterals(initializer, visited) : [];
105
+ };
7
106
  /**
8
107
  * Extracts string literal values from an expression.
9
108
  *
@@ -109,7 +208,10 @@ const extractIdentifierValues = (node, visited) => {
109
208
  }
110
209
  return [];
111
210
  });
112
- return values.length > 0 ? values : extractLiteralValuesFromType(node);
211
+ if (values.length > 0) return values;
212
+ const importedValues = extractImportedIdentifierValues(node, visited);
213
+ if (importedValues.length > 0) return importedValues;
214
+ return extractLiteralValuesFromType(node);
113
215
  };
114
216
  /**
115
217
  * Extract string literals from arrow functions or function expressions
@@ -1,8 +1,105 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
- import { Node, SyntaxKind } from "ts-morph";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import { Node, Project, SyntaxKind, ts } from "ts-morph";
3
5
 
4
6
  //#region ../tailwind/dist/purger/optimized/ast/expressions.js
5
7
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
8
+ const importedSourceProject = new Project({ useInMemoryFileSystem: true });
9
+ const importedSourceFileCache = /* @__PURE__ */ new Map();
10
+ const tsConfigPathCache = /* @__PURE__ */ new Map();
11
+ const compilerOptionsCache = /* @__PURE__ */ new Map();
12
+ const hasImportQuery = (moduleSpecifier) => moduleSpecifier.includes("?");
13
+ const isExistingFile = (candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isFile();
14
+ const resolveRelativeImportPath = (sourceFilePath, moduleSpecifier) => {
15
+ if (!path.isAbsolute(sourceFilePath) || !moduleSpecifier.startsWith(".") || hasImportQuery(moduleSpecifier)) return null;
16
+ const basePath = path.resolve(path.dirname(sourceFilePath), moduleSpecifier);
17
+ return [
18
+ basePath,
19
+ `${basePath}.ts`,
20
+ `${basePath}.tsx`,
21
+ `${basePath}.js`,
22
+ `${basePath}.jsx`,
23
+ path.join(basePath, "index.ts"),
24
+ path.join(basePath, "index.tsx"),
25
+ path.join(basePath, "index.js"),
26
+ path.join(basePath, "index.jsx")
27
+ ].find((candidate) => isExistingFile(candidate)) ?? null;
28
+ };
29
+ const findNearestTypeScriptConfig = (sourceFilePath) => {
30
+ const sourceDir = path.dirname(sourceFilePath);
31
+ const cached = tsConfigPathCache.get(sourceDir);
32
+ if (cached !== void 0) return cached;
33
+ let currentDir = sourceDir;
34
+ while (true) {
35
+ const tsConfigPath = path.join(currentDir, "tsconfig.json");
36
+ if (isExistingFile(tsConfigPath)) {
37
+ tsConfigPathCache.set(sourceDir, tsConfigPath);
38
+ return tsConfigPath;
39
+ }
40
+ const jsConfigPath = path.join(currentDir, "jsconfig.json");
41
+ if (isExistingFile(jsConfigPath)) {
42
+ tsConfigPathCache.set(sourceDir, jsConfigPath);
43
+ return jsConfigPath;
44
+ }
45
+ const parentDir = path.dirname(currentDir);
46
+ if (parentDir === currentDir) {
47
+ tsConfigPathCache.set(sourceDir, null);
48
+ return null;
49
+ }
50
+ currentDir = parentDir;
51
+ }
52
+ };
53
+ const getCompilerOptionsForSourceFile = (sourceFilePath) => {
54
+ const configPath = findNearestTypeScriptConfig(sourceFilePath);
55
+ if (!configPath) return null;
56
+ const cached = compilerOptionsCache.get(configPath);
57
+ if (cached !== void 0) return cached;
58
+ const readResult = ts.readConfigFile(configPath, ts.sys.readFile);
59
+ if (readResult.error) {
60
+ compilerOptionsCache.set(configPath, null);
61
+ return null;
62
+ }
63
+ const parsed = ts.parseJsonConfigFileContent(readResult.config, ts.sys, path.dirname(configPath));
64
+ const compilerOptions = parsed.options.paths && !parsed.options.baseUrl ? {
65
+ ...parsed.options,
66
+ baseUrl: path.dirname(configPath)
67
+ } : parsed.options;
68
+ compilerOptionsCache.set(configPath, compilerOptions);
69
+ return compilerOptions;
70
+ };
71
+ const resolveConfigImportPath = (sourceFilePath, moduleSpecifier) => {
72
+ if (hasImportQuery(moduleSpecifier)) return null;
73
+ const compilerOptions = getCompilerOptionsForSourceFile(sourceFilePath);
74
+ if (!compilerOptions) return null;
75
+ const resolvedModule = ts.resolveModuleName(moduleSpecifier, sourceFilePath, compilerOptions, ts.sys).resolvedModule;
76
+ if (!resolvedModule) return null;
77
+ return isExistingFile(resolvedModule.resolvedFileName) ? resolvedModule.resolvedFileName : null;
78
+ };
79
+ const resolveImportPath = (sourceFilePath, moduleSpecifier) => moduleSpecifier.startsWith(".") ? resolveRelativeImportPath(sourceFilePath, moduleSpecifier) : resolveConfigImportPath(sourceFilePath, moduleSpecifier);
80
+ const getImportedSourceFile = (filePath) => {
81
+ const cached = importedSourceFileCache.get(filePath);
82
+ if (cached) return cached;
83
+ if (!fs.existsSync(filePath)) return null;
84
+ const sourceFile = importedSourceProject.createSourceFile(filePath, fs.readFileSync(filePath, "utf-8"), { overwrite: true });
85
+ importedSourceFileCache.set(filePath, sourceFile);
86
+ return sourceFile;
87
+ };
88
+ const extractImportedIdentifierValues = (node, visited) => {
89
+ if (!Node.isIdentifier(node)) return [];
90
+ const sourceFile = node.getSourceFile();
91
+ const sourceFilePath = sourceFile.getFilePath();
92
+ const importMatch = sourceFile.getImportDeclarations().find((importDecl) => importDecl.getNamedImports().some((namedImport) => (namedImport.getAliasNode()?.getText() ?? namedImport.getName()) === node.getText()));
93
+ if (!importMatch) return [];
94
+ const namedImport = importMatch.getNamedImports().find((candidate) => (candidate.getAliasNode()?.getText() ?? candidate.getName()) === node.getText());
95
+ if (!namedImport) return [];
96
+ const resolvedPath = resolveImportPath(sourceFilePath, importMatch.getModuleSpecifierValue());
97
+ if (!resolvedPath) return [];
98
+ const importedSourceFile = getImportedSourceFile(resolvedPath);
99
+ if (!importedSourceFile) return [];
100
+ const initializer = importedSourceFile.getVariableDeclaration(namedImport.getName())?.getInitializer();
101
+ return initializer ? extractStringLiterals(initializer, visited) : [];
102
+ };
6
103
  /**
7
104
  * Extracts string literal values from an expression.
8
105
  *
@@ -108,7 +205,10 @@ const extractIdentifierValues = (node, visited) => {
108
205
  }
109
206
  return [];
110
207
  });
111
- return values.length > 0 ? values : extractLiteralValuesFromType(node);
208
+ if (values.length > 0) return values;
209
+ const importedValues = extractImportedIdentifierValues(node, visited);
210
+ if (importedValues.length > 0) return importedValues;
211
+ return extractLiteralValuesFromType(node);
112
212
  };
113
213
  /**
114
214
  * Extract string literals from arrow functions or function expressions
@@ -7,7 +7,13 @@ let ts_morph = require("ts-morph");
7
7
  /**
8
8
  * Find all JSX usages of a component from its identifier
9
9
  */
10
- const findJsxReferences = (identifier) => identifier.findReferencesAsNodes().map((reference) => reference.getFirstAncestor((n) => ts_morph.Node.isJsxOpeningElement(n) || ts_morph.Node.isJsxSelfClosingElement(n))).filter((node) => Boolean(node) && (ts_morph.Node.isJsxOpeningElement(node) || ts_morph.Node.isJsxSelfClosingElement(node)));
10
+ const findJsxReferences = (identifier) => {
11
+ try {
12
+ return identifier.findReferencesAsNodes().map((reference) => reference.getFirstAncestor((n) => ts_morph.Node.isJsxOpeningElement(n) || ts_morph.Node.isJsxSelfClosingElement(n))).filter((node) => Boolean(node) && (ts_morph.Node.isJsxOpeningElement(node) || ts_morph.Node.isJsxSelfClosingElement(node)));
13
+ } catch {
14
+ return [];
15
+ }
16
+ };
11
17
 
12
18
  //#endregion
13
19
  exports.findJsxReferences = findJsxReferences;
@@ -6,7 +6,13 @@ import { Node, SyntaxKind } from "ts-morph";
6
6
  /**
7
7
  * Find all JSX usages of a component from its identifier
8
8
  */
9
- const findJsxReferences = (identifier) => identifier.findReferencesAsNodes().map((reference) => reference.getFirstAncestor((n) => Node.isJsxOpeningElement(n) || Node.isJsxSelfClosingElement(n))).filter((node) => Boolean(node) && (Node.isJsxOpeningElement(node) || Node.isJsxSelfClosingElement(node)));
9
+ const findJsxReferences = (identifier) => {
10
+ try {
11
+ return identifier.findReferencesAsNodes().map((reference) => reference.getFirstAncestor((n) => Node.isJsxOpeningElement(n) || Node.isJsxSelfClosingElement(n))).filter((node) => Boolean(node) && (Node.isJsxOpeningElement(node) || Node.isJsxSelfClosingElement(node)));
12
+ } catch {
13
+ return [];
14
+ }
15
+ };
10
16
 
11
17
  //#endregion
12
18
  export { findJsxReferences };
@@ -54,6 +54,10 @@ const resolveComponentInfo = (name) => {
54
54
  const getModuleSpecifierValue = (importDecl) => {
55
55
  return importDecl.getModuleSpecifierValue() ?? importDecl.getModuleSpecifier().getText().replace(/^['"]|['"]$/g, "");
56
56
  };
57
+ const isTypeOnlyNamedImport = (importDecl, importName) => {
58
+ if (importDecl.isTypeOnly()) return true;
59
+ return importDecl.getNamedImports().find((namedImport) => namedImport.getName() === importName)?.isTypeOnly() ?? false;
60
+ };
57
61
  const isUdsComponentModule = (moduleSpecifier) => {
58
62
  const cleaned = moduleSpecifier.replace(/^['"]|['"]$/g, "");
59
63
  return cleaned === "@yahoo/uds" || cleaned.startsWith("@yahoo/uds/");
@@ -122,7 +126,7 @@ const purgeFromCodeOptimized = async (code, options) => {
122
126
  componentNameLookup = buildComponentNameLookup(componentData);
123
127
  }
124
128
  const startTime = performance.now();
125
- const sourceFile = new ts_morph.Project({ useInMemoryFileSystem: true }).createSourceFile("input.tsx", code);
129
+ const sourceFile = new ts_morph.Project({ useInMemoryFileSystem: true }).createSourceFile(options.filePath ?? "input.tsx", code, { overwrite: true });
126
130
  const stats = {
127
131
  filesScanned: 1,
128
132
  timeMs: 0,
@@ -132,7 +136,9 @@ const purgeFromCodeOptimized = async (code, options) => {
132
136
  };
133
137
  const imports = [];
134
138
  sourceFile.getImportDeclarations().forEach((importDecl) => {
135
- if (isUdsComponentModule(getModuleSpecifierValue(importDecl))) importDecl.getNamedImports().forEach((namedImport) => imports.push(namedImport.getName()));
139
+ if (isUdsComponentModule(getModuleSpecifierValue(importDecl))) importDecl.getNamedImports().forEach((namedImport) => {
140
+ if (!namedImport.isTypeOnly() && !importDecl.isTypeOnly()) imports.push(namedImport.getName());
141
+ });
136
142
  });
137
143
  const componentProps = /* @__PURE__ */ new Map();
138
144
  const referencedComponents = /* @__PURE__ */ new Set();
@@ -282,17 +288,16 @@ const findComponentReferences = (sourceFile, componentName) => {
282
288
  sourceFile.getImportDeclarations().forEach((importDecl) => {
283
289
  if (!isUdsComponentModule(getModuleSpecifierValue(importDecl))) return;
284
290
  importDecl.getNamedImports().forEach((namedImport) => {
285
- if (namedImport.getName() === componentName) {
286
- const localName = namedImport.getAliasNode()?.getText() ?? componentName;
287
- require_jsx.findJsxReferences(namedImport.getFirstDescendantByKindOrThrow(ts_morph.ts.SyntaxKind.Identifier)).forEach((reference) => {
288
- const key = `${reference.getTagNameNode().getText()}:${reference.getStart()}`;
289
- if (!seenTags.has(key)) {
290
- seenTags.add(key);
291
- references.push(reference);
292
- }
293
- });
294
- collectMatchingTags(localName);
295
- }
291
+ if (namedImport.getName() !== componentName || isTypeOnlyNamedImport(importDecl, componentName)) return;
292
+ const localName = namedImport.getAliasNode()?.getText() ?? componentName;
293
+ require_jsx.findJsxReferences(namedImport.getFirstDescendantByKindOrThrow(ts_morph.ts.SyntaxKind.Identifier)).forEach((reference) => {
294
+ const key = `${reference.getTagNameNode().getText()}:${reference.getStart()}`;
295
+ if (!seenTags.has(key)) {
296
+ seenTags.add(key);
297
+ references.push(reference);
298
+ }
299
+ });
300
+ collectMatchingTags(localName);
296
301
  });
297
302
  });
298
303
  return references;
@@ -53,6 +53,10 @@ const resolveComponentInfo = (name) => {
53
53
  const getModuleSpecifierValue = (importDecl) => {
54
54
  return importDecl.getModuleSpecifierValue() ?? importDecl.getModuleSpecifier().getText().replace(/^['"]|['"]$/g, "");
55
55
  };
56
+ const isTypeOnlyNamedImport = (importDecl, importName) => {
57
+ if (importDecl.isTypeOnly()) return true;
58
+ return importDecl.getNamedImports().find((namedImport) => namedImport.getName() === importName)?.isTypeOnly() ?? false;
59
+ };
56
60
  const isUdsComponentModule = (moduleSpecifier) => {
57
61
  const cleaned = moduleSpecifier.replace(/^['"]|['"]$/g, "");
58
62
  return cleaned === "@yahoo/uds" || cleaned.startsWith("@yahoo/uds/");
@@ -121,7 +125,7 @@ const purgeFromCodeOptimized = async (code, options) => {
121
125
  componentNameLookup = buildComponentNameLookup(componentData);
122
126
  }
123
127
  const startTime = performance.now();
124
- const sourceFile = new Project({ useInMemoryFileSystem: true }).createSourceFile("input.tsx", code);
128
+ const sourceFile = new Project({ useInMemoryFileSystem: true }).createSourceFile(options.filePath ?? "input.tsx", code, { overwrite: true });
125
129
  const stats = {
126
130
  filesScanned: 1,
127
131
  timeMs: 0,
@@ -131,7 +135,9 @@ const purgeFromCodeOptimized = async (code, options) => {
131
135
  };
132
136
  const imports = [];
133
137
  sourceFile.getImportDeclarations().forEach((importDecl) => {
134
- if (isUdsComponentModule(getModuleSpecifierValue(importDecl))) importDecl.getNamedImports().forEach((namedImport) => imports.push(namedImport.getName()));
138
+ if (isUdsComponentModule(getModuleSpecifierValue(importDecl))) importDecl.getNamedImports().forEach((namedImport) => {
139
+ if (!namedImport.isTypeOnly() && !importDecl.isTypeOnly()) imports.push(namedImport.getName());
140
+ });
135
141
  });
136
142
  const componentProps = /* @__PURE__ */ new Map();
137
143
  const referencedComponents = /* @__PURE__ */ new Set();
@@ -281,17 +287,16 @@ const findComponentReferences = (sourceFile, componentName) => {
281
287
  sourceFile.getImportDeclarations().forEach((importDecl) => {
282
288
  if (!isUdsComponentModule(getModuleSpecifierValue(importDecl))) return;
283
289
  importDecl.getNamedImports().forEach((namedImport) => {
284
- if (namedImport.getName() === componentName) {
285
- const localName = namedImport.getAliasNode()?.getText() ?? componentName;
286
- findJsxReferences(namedImport.getFirstDescendantByKindOrThrow(ts.SyntaxKind.Identifier)).forEach((reference) => {
287
- const key = `${reference.getTagNameNode().getText()}:${reference.getStart()}`;
288
- if (!seenTags.has(key)) {
289
- seenTags.add(key);
290
- references.push(reference);
291
- }
292
- });
293
- collectMatchingTags(localName);
294
- }
290
+ if (namedImport.getName() !== componentName || isTypeOnlyNamedImport(importDecl, componentName)) return;
291
+ const localName = namedImport.getAliasNode()?.getText() ?? componentName;
292
+ findJsxReferences(namedImport.getFirstDescendantByKindOrThrow(ts.SyntaxKind.Identifier)).forEach((reference) => {
293
+ const key = `${reference.getTagNameNode().getText()}:${reference.getStart()}`;
294
+ if (!seenTags.has(key)) {
295
+ seenTags.add(key);
296
+ references.push(reference);
297
+ }
298
+ });
299
+ collectMatchingTags(localName);
295
300
  });
296
301
  });
297
302
  return references;
@@ -20,6 +20,7 @@ let knownComponents = null;
20
20
  */
21
21
  let componentPaths = null;
22
22
  let scannedComponentsDir = null;
23
+ const hasImportQuery = (moduleSpecifier) => moduleSpecifier.includes("?");
23
24
  const scanComponentFilePaths = async (componentsDir) => (0, fast_glob.default)(require_entryPoints.getAllowedEntryFileGlobPatterns(), {
24
25
  cwd: componentsDir,
25
26
  absolute: true
@@ -474,7 +475,7 @@ const resolveImportedIdentifier = (identifier) => {
474
475
  if (resolvedImport) return resolvedImport;
475
476
  if (!importDecl.getNamedImports().find((n) => n.getName() === name)) return;
476
477
  const moduleSpec = importDecl.getModuleSpecifierValue();
477
- if (!moduleSpec.startsWith(".")) return;
478
+ if (!moduleSpec.startsWith(".") || hasImportQuery(moduleSpec)) return;
478
479
  const resolvedBase = node_path.default.resolve(baseDir, moduleSpec);
479
480
  return [
480
481
  resolvedBase,
@@ -17,6 +17,7 @@ let knownComponents = null;
17
17
  */
18
18
  let componentPaths = null;
19
19
  let scannedComponentsDir = null;
20
+ const hasImportQuery = (moduleSpecifier) => moduleSpecifier.includes("?");
20
21
  const scanComponentFilePaths = async (componentsDir) => fg(getAllowedEntryFileGlobPatterns(), {
21
22
  cwd: componentsDir,
22
23
  absolute: true
@@ -471,7 +472,7 @@ const resolveImportedIdentifier = (identifier) => {
471
472
  if (resolvedImport) return resolvedImport;
472
473
  if (!importDecl.getNamedImports().find((n) => n.getName() === name)) return;
473
474
  const moduleSpec = importDecl.getModuleSpecifierValue();
474
- if (!moduleSpec.startsWith(".")) return;
475
+ if (!moduleSpec.startsWith(".") || hasImportQuery(moduleSpec)) return;
475
476
  const resolvedBase = path.resolve(baseDir, moduleSpec);
476
477
  return [
477
478
  resolvedBase,