@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.
- package/dist/components/client/BottomSheet/BottomSheet.cjs +37 -8
- package/dist/components/client/BottomSheet/BottomSheet.js +38 -9
- package/dist/components/client/BottomSheet/BottomSheetContent.cjs +4 -2
- package/dist/components/client/BottomSheet/BottomSheetContent.js +4 -2
- package/dist/components/client/BottomSheet/BottomSheetInternalContext.cjs +15 -0
- package/dist/components/client/BottomSheet/BottomSheetInternalContext.d.cts +12 -0
- package/dist/components/client/BottomSheet/BottomSheetInternalContext.d.ts +12 -0
- package/dist/components/client/BottomSheet/BottomSheetInternalContext.js +12 -0
- package/dist/styles/styler.d.cts +19 -19
- package/dist/styles/styler.d.ts +19 -19
- package/dist/tailwind/dist/css/generate.cjs +6 -0
- package/dist/tailwind/dist/css/generate.helpers.cjs +5 -1
- package/dist/tailwind/dist/css/generate.helpers.js +5 -1
- package/dist/tailwind/dist/css/generate.js +6 -0
- package/dist/tailwind/dist/css/nodeUtils.cjs +2 -1
- package/dist/tailwind/dist/css/nodeUtils.js +2 -1
- package/dist/tailwind/dist/css/postcss.cjs +1 -1
- package/dist/tailwind/dist/css/postcss.helpers.cjs +8 -6
- package/dist/tailwind/dist/css/postcss.helpers.js +8 -6
- package/dist/tailwind/dist/css/postcss.js +1 -1
- package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +103 -1
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js +102 -2
- package/dist/tailwind/dist/purger/optimized/ast/jsx.cjs +7 -1
- package/dist/tailwind/dist/purger/optimized/ast/jsx.js +7 -1
- package/dist/tailwind/dist/purger/optimized/purgeFromCode.cjs +18 -13
- package/dist/tailwind/dist/purger/optimized/purgeFromCode.js +18 -13
- package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.cjs +2 -1
- package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.js +2 -1
- package/dist/uds/generated/componentData.cjs +825 -806
- package/dist/uds/generated/componentData.js +799 -786
- package/dist/uds/generated/tailwindPurge.cjs +7 -7
- package/dist/uds/generated/tailwindPurge.js +7 -7
- package/dist/uds/package.cjs +1 -1
- package/dist/uds/package.js +1 -1
- package/generated/componentData.json +1122 -1107
- package/generated/tailwindPurge.ts +2 -2
- 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,
|
|
@@ -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
|
-
|
|
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
|
|
18
|
-
return
|
|
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
|
-
|
|
22
|
-
]
|
|
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
|
-
|
|
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
|
|
17
|
-
return
|
|
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
|
-
|
|
21
|
-
]
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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()
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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) =>
|
|
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()
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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,
|