@yahoo/uds 3.123.0 → 3.124.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
- package/dist/components/client/Toast/UDSToastConfigProvider.d.cts +5 -5
- package/dist/components/client/Toast/UDSToastConfigProvider.d.ts +5 -5
- package/dist/styles/styler.d.cts +34 -34
- package/dist/styles/styler.d.ts +34 -34
- package/dist/tailwind/dist/commands/css.cjs +17 -3
- package/dist/tailwind/dist/commands/css.d.cts.map +1 -1
- package/dist/tailwind/dist/commands/css.d.ts.map +1 -1
- package/dist/tailwind/dist/commands/css.helpers.cjs +2 -1
- package/dist/tailwind/dist/commands/css.helpers.js +2 -1
- package/dist/tailwind/dist/commands/css.helpers.js.map +1 -1
- package/dist/tailwind/dist/commands/css.js +17 -3
- package/dist/tailwind/dist/commands/css.js.map +1 -1
- package/dist/tailwind/dist/css/generate.cjs +3 -0
- package/dist/tailwind/dist/css/generate.helpers.cjs +14 -6
- package/dist/tailwind/dist/css/generate.helpers.js +15 -7
- package/dist/tailwind/dist/css/generate.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/generate.js +3 -0
- package/dist/tailwind/dist/css/generate.js.map +1 -1
- package/dist/tailwind/dist/css/nodeUtils.cjs +91 -20
- package/dist/tailwind/dist/css/nodeUtils.js +90 -21
- package/dist/tailwind/dist/css/nodeUtils.js.map +1 -1
- package/dist/tailwind/dist/css/postcss.cjs +22 -1
- package/dist/tailwind/dist/css/postcss.helpers.cjs +12 -1
- package/dist/tailwind/dist/css/postcss.helpers.js +11 -1
- package/dist/tailwind/dist/css/postcss.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/postcss.js +22 -2
- package/dist/tailwind/dist/css/postcss.js.map +1 -1
- package/dist/tailwind/dist/css/runner.cjs +171 -20
- package/dist/tailwind/dist/css/runner.helpers.cjs +58 -6
- package/dist/tailwind/dist/css/runner.helpers.js +54 -7
- package/dist/tailwind/dist/css/runner.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/runner.js +172 -20
- package/dist/tailwind/dist/css/runner.js.map +1 -1
- package/dist/tailwind/dist/css/theme.d.cts +11 -0
- package/dist/tailwind/dist/css/theme.d.cts.map +1 -1
- package/dist/tailwind/dist/css/theme.d.ts +11 -0
- package/dist/tailwind/dist/css/theme.d.ts.map +1 -1
- package/dist/tailwind/dist/css/theme.js.map +1 -1
- package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +26 -3
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js +26 -3
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js.map +1 -1
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.cts +1 -1
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.ts +1 -1
- package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.cts +4 -4
- package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.ts +4 -4
- package/dist/uds/generated/componentData.cjs +1152 -1152
- package/dist/uds/generated/componentData.js +1152 -1152
- package/generated/componentData.json +1738 -1738
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ const require_plugin = require('../plugin.cjs');
|
|
|
8
8
|
const require_optimizeCSS = require('../utils/optimizeCSS.cjs');
|
|
9
9
|
const require_postcssPreserveVars = require('../utils/postcssPreserveVars.cjs');
|
|
10
10
|
const require_postcss = require('./postcss.cjs');
|
|
11
|
+
const require_runner_helpers = require('./runner.helpers.cjs');
|
|
11
12
|
const require_utils = require('./utils.cjs');
|
|
12
13
|
let node_path = require("node:path");
|
|
13
14
|
node_path = require_runtime.__toESM(node_path);
|
|
@@ -40,7 +41,7 @@ const getCssFeatureFlags = (cssOptions) => {
|
|
|
40
41
|
};
|
|
41
42
|
};
|
|
42
43
|
const getContentGlobs = (contentDir) => {
|
|
43
|
-
return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => require_entryPoints.hasAllowedEntryFileExtension(dir) ? dir : node_path.default.join(dir, "**/*.{js,jsx,ts,tsx}"));
|
|
44
|
+
return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => require_entryPoints.hasAllowedEntryFileExtension(dir) ? dir : node_path.default.join(dir, "**/*.{js,jsx,mjs,cjs,ts,tsx}"));
|
|
44
45
|
};
|
|
45
46
|
const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
|
|
46
47
|
raw: rawContent,
|
|
@@ -90,7 +91,7 @@ const buildPostcssPlugins = (options) => {
|
|
|
90
91
|
};
|
|
91
92
|
const applyScopedColorModeFix = async (css, scopeClass) => {
|
|
92
93
|
if (!scopeClass) return css;
|
|
93
|
-
return (await (0, postcss.default)([require_postcss.fixScopedColorModeSelectorsPlugin(scopeClass)]).process(css, { from: void 0 })).css;
|
|
94
|
+
return (await (0, postcss.default)([require_postcss.fixScopedSelfOrParentSelectorsPlugin(scopeClass), require_postcss.fixScopedColorModeSelectorsPlugin(scopeClass)]).process(css, { from: void 0 })).css;
|
|
94
95
|
};
|
|
95
96
|
const optimizeGeneratedCss = async (options) => {
|
|
96
97
|
if (!options.shouldOptimize) return { css: options.css };
|
|
@@ -115,22 +116,29 @@ const optimizeGeneratedCss = async (options) => {
|
|
|
115
116
|
};
|
|
116
117
|
const printSimpleModeStats = (options) => {
|
|
117
118
|
const { print, magenta, cyan, yellow } = options;
|
|
119
|
+
const getDisplayPath = (targetPath) => {
|
|
120
|
+
const relativePath = node_path.default.relative(options.cwd, targetPath);
|
|
121
|
+
return relativePath.length === 0 ? "." : relativePath;
|
|
122
|
+
};
|
|
118
123
|
print("");
|
|
119
|
-
print(`${magenta("Output:")} ${cyan(options.outputPath)}`);
|
|
124
|
+
print(`${magenta("Output:")} ${cyan(getDisplayPath(options.outputPath))}`);
|
|
120
125
|
print(`${magenta("Stats:")}`);
|
|
121
126
|
print(` Files scanned: ${options.totalFilesScanned}`);
|
|
127
|
+
if (options.verbose && options.scannedFilePaths && options.scannedFilePaths.length > 0) [...new Set(options.scannedFilePaths)].sort((left, right) => left.localeCompare(right)).forEach((filePath) => print(` • ${cyan(getDisplayPath(filePath))}`));
|
|
122
128
|
print(` Classes: ${options.classCount}`);
|
|
123
129
|
print(` Size: ${require_utils.formatBytes(options.sizeBytes)} (${require_utils.formatBytes(options.sizeGzipBytes)} gzipped)`);
|
|
124
130
|
const optimizationStats = options.optimizationStats;
|
|
125
131
|
if (optimizationStats) {
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
if (optimizationStats.originalSizeGzip - options.sizeGzipBytes > 0) {
|
|
133
|
+
if (optimizationStats.fontFacesRemoved > 0) print(` • removed ${optimizationStats.fontFacesRemoved} unused @font-face`);
|
|
134
|
+
if (optimizationStats.emptyRulesRemoved > 0) print(` • removed ${optimizationStats.emptyRulesRemoved} empty rules`);
|
|
135
|
+
}
|
|
128
136
|
if (optimizationStats.validationErrors.length > 0) {
|
|
129
137
|
print(` ${yellow("Validation warnings:")}`);
|
|
130
138
|
optimizationStats.validationErrors.forEach((error) => print(` ${yellow("•")} ${error}`));
|
|
131
139
|
}
|
|
132
140
|
}
|
|
133
|
-
print(` Time: ${options.duration}
|
|
141
|
+
print(` Time: ${require_runner_helpers.formatCssDuration(options.duration)}`);
|
|
134
142
|
if (options.scope) print(` Scope: ${cyan(options.scope)}`);
|
|
135
143
|
};
|
|
136
144
|
|
|
@@ -6,7 +6,8 @@ import { getIconStyles } from "../tailwind/components/getIconStyles.js";
|
|
|
6
6
|
import { tailwindPlugin } from "../plugin.js";
|
|
7
7
|
import { optimizeCSS } from "../utils/optimizeCSS.js";
|
|
8
8
|
import { preserveVars, preserveVarsCleanup } from "../utils/postcssPreserveVars.js";
|
|
9
|
-
import { fixScopedColorModeSelectorsPlugin } from "./postcss.js";
|
|
9
|
+
import { fixScopedColorModeSelectorsPlugin, fixScopedSelfOrParentSelectorsPlugin } from "./postcss.js";
|
|
10
|
+
import { formatCssDuration } from "./runner.helpers.js";
|
|
10
11
|
import { formatBytes } from "./utils.js";
|
|
11
12
|
import path from "node:path";
|
|
12
13
|
import postcss from "postcss";
|
|
@@ -33,7 +34,7 @@ const getCssFeatureFlags = (cssOptions) => {
|
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
36
|
const getContentGlobs = (contentDir) => {
|
|
36
|
-
return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => hasAllowedEntryFileExtension(dir) ? dir : path.join(dir, "**/*.{js,jsx,ts,tsx}"));
|
|
37
|
+
return (Array.isArray(contentDir) ? contentDir : [contentDir]).map((dir) => hasAllowedEntryFileExtension(dir) ? dir : path.join(dir, "**/*.{js,jsx,mjs,cjs,ts,tsx}"));
|
|
37
38
|
};
|
|
38
39
|
const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
|
|
39
40
|
raw: rawContent,
|
|
@@ -83,7 +84,7 @@ const buildPostcssPlugins = (options) => {
|
|
|
83
84
|
};
|
|
84
85
|
const applyScopedColorModeFix = async (css, scopeClass) => {
|
|
85
86
|
if (!scopeClass) return css;
|
|
86
|
-
return (await postcss([fixScopedColorModeSelectorsPlugin(scopeClass)]).process(css, { from: void 0 })).css;
|
|
87
|
+
return (await postcss([fixScopedSelfOrParentSelectorsPlugin(scopeClass), fixScopedColorModeSelectorsPlugin(scopeClass)]).process(css, { from: void 0 })).css;
|
|
87
88
|
};
|
|
88
89
|
const optimizeGeneratedCss = async (options) => {
|
|
89
90
|
if (!options.shouldOptimize) return { css: options.css };
|
|
@@ -108,22 +109,29 @@ const optimizeGeneratedCss = async (options) => {
|
|
|
108
109
|
};
|
|
109
110
|
const printSimpleModeStats = (options) => {
|
|
110
111
|
const { print, magenta, cyan, yellow } = options;
|
|
112
|
+
const getDisplayPath = (targetPath) => {
|
|
113
|
+
const relativePath = path.relative(options.cwd, targetPath);
|
|
114
|
+
return relativePath.length === 0 ? "." : relativePath;
|
|
115
|
+
};
|
|
111
116
|
print("");
|
|
112
|
-
print(`${magenta("Output:")} ${cyan(options.outputPath)}`);
|
|
117
|
+
print(`${magenta("Output:")} ${cyan(getDisplayPath(options.outputPath))}`);
|
|
113
118
|
print(`${magenta("Stats:")}`);
|
|
114
119
|
print(` Files scanned: ${options.totalFilesScanned}`);
|
|
120
|
+
if (options.verbose && options.scannedFilePaths && options.scannedFilePaths.length > 0) [...new Set(options.scannedFilePaths)].sort((left, right) => left.localeCompare(right)).forEach((filePath) => print(` • ${cyan(getDisplayPath(filePath))}`));
|
|
115
121
|
print(` Classes: ${options.classCount}`);
|
|
116
122
|
print(` Size: ${formatBytes(options.sizeBytes)} (${formatBytes(options.sizeGzipBytes)} gzipped)`);
|
|
117
123
|
const optimizationStats = options.optimizationStats;
|
|
118
124
|
if (optimizationStats) {
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
if (optimizationStats.originalSizeGzip - options.sizeGzipBytes > 0) {
|
|
126
|
+
if (optimizationStats.fontFacesRemoved > 0) print(` • removed ${optimizationStats.fontFacesRemoved} unused @font-face`);
|
|
127
|
+
if (optimizationStats.emptyRulesRemoved > 0) print(` • removed ${optimizationStats.emptyRulesRemoved} empty rules`);
|
|
128
|
+
}
|
|
121
129
|
if (optimizationStats.validationErrors.length > 0) {
|
|
122
130
|
print(` ${yellow("Validation warnings:")}`);
|
|
123
131
|
optimizationStats.validationErrors.forEach((error) => print(` ${yellow("•")} ${error}`));
|
|
124
132
|
}
|
|
125
133
|
}
|
|
126
|
-
print(` Time: ${options.duration}
|
|
134
|
+
print(` Time: ${formatCssDuration(options.duration)}`);
|
|
127
135
|
if (options.scope) print(` Scope: ${cyan(options.scope)}`);
|
|
128
136
|
};
|
|
129
137
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.helpers.js","names":[],"sources":["../../src/css/generate.helpers.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport autoprefixer from 'autoprefixer';\nimport postcss from 'postcss';\n// @ts-expect-error - no types\nimport pruneVar from 'postcss-prune-var';\nimport postcssScope from 'postcss-scope';\nimport tailwindcss from 'tailwindcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\n// eslint-disable-next-line import/no-relative-packages\nimport { iconPruneVarsSafelist } from '../../../icons/src/safelist';\nimport { getInternalSafelistClasses } from '../purger/optimized/utils/safelist';\nimport { getIconStyles } from '../tailwind/components/getIconStyles';\nimport { tailwindPlugin } from '../tailwind/tailwindPlugin';\nimport { hasAllowedEntryFileExtension } from '../utils/entryPoints';\nimport type { OptimizeCSSOptions } from '../utils/optimizeCSS';\nimport { optimizeCSS } from '../utils/optimizeCSS';\nimport { preserveVars, preserveVarsCleanup } from '../utils/postcssPreserveVars';\nimport { fixScopedColorModeSelectorsPlugin } from './postcss';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport { formatBytes } from './utils';\n\ntype CssOptimizationOptions = UDSCSSOptimizationOptions;\n\ntype CssOptionsLike = {\n preflight?: boolean;\n fontFaceDeclarations?: boolean;\n optimization?: CssOptimizationOptions;\n};\n\ntype CssFeatureFlags = {\n enablePreflight: boolean;\n enableFontFaceDeclarations: boolean;\n shouldOptimize: boolean;\n shouldPruneVars: boolean;\n};\n\nconst getPruneVarSafelist = (cssOptions?: CssOptionsLike): UDSCSSVarSafelistPattern[] => {\n const pruneVars = cssOptions?.optimization?.pruneVars;\n const configuredSafelist =\n pruneVars && typeof pruneVars === 'object' ? (pruneVars.safelist ?? []) : [];\n\n return [...iconPruneVarsSafelist, ...configuredSafelist];\n};\n\nconst getCssFeatureFlags = (cssOptions?: CssOptionsLike): CssFeatureFlags => {\n const optimizationConfig = cssOptions?.optimization;\n const shouldOptimize = optimizationConfig?.enabled !== false;\n const pruneVars = optimizationConfig?.pruneVars;\n\n return {\n enablePreflight: cssOptions?.preflight !== false,\n enableFontFaceDeclarations: cssOptions?.fontFaceDeclarations !== false,\n shouldOptimize,\n shouldPruneVars: shouldOptimize && pruneVars !== false,\n };\n};\n\nconst getContentGlobs = (contentDir: string | string[]): string[] => {\n const contentDirs = Array.isArray(contentDir) ? contentDir : [contentDir];\n\n return contentDirs.map((dir) =>\n hasAllowedEntryFileExtension(dir) ? dir : path.join(dir, '**/*.{js,jsx,ts,tsx}'),\n );\n};\n\nconst getRawContentEntries = (rawContents: string[]): Array<{ raw: string; extension: 'html' }> =>\n rawContents.map((rawContent) => ({ raw: rawContent, extension: 'html' }));\n\nconst getInternalSafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const internalClasses = new Set(getInternalSafelistClasses());\n const matchedInternalClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && internalClasses.has(entry),\n );\n\n if (matchedInternalClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${matchedInternalClasses.join(' ')}\"></div>`];\n};\n\nconst getInternalIconModeCss = (scopeClass?: string): string => {\n const iconStyles = getIconStyles();\n\n return Object.entries(iconStyles)\n .map(([selector, declarations]) => {\n const scopedSelector = scopeClass ? `${scopeClass} ${selector}` : selector;\n const declarationString = Object.entries(declarations)\n .map(([property, value]) => `${property}: ${value};`)\n .join(' ');\n\n return `${scopedSelector} { ${declarationString} }`;\n })\n .join(' ');\n};\n\nconst createTailwindPlugin = (options: {\n contentDir: string | string[];\n rawContents?: string[];\n safelist: SafelistConfig[];\n config: UniversalTokensConfig;\n enablePreflight: boolean;\n enableFontFaceDeclarations: boolean;\n}): postcss.AcceptedPlugin => {\n const plugin = tailwindcss({\n content: [\n ...getContentGlobs(options.contentDir),\n ...getRawContentEntries(getInternalSafelistRawContent(options.safelist)),\n ...getRawContentEntries(options.rawContents ?? []),\n ],\n safelist: options.safelist,\n corePlugins: { preflight: options.enablePreflight },\n plugins: [\n tailwindPlugin({\n config: options.config,\n disableFontFaceDeclarations: !options.enableFontFaceDeclarations,\n ignorePluginSafelists: true,\n }),\n ],\n });\n\n return plugin as postcss.AcceptedPlugin;\n};\n\nconst getPruneVarPlugins = (\n safeVarPrefixes: UDSCSSVarSafelistPattern[],\n): postcss.AcceptedPlugin[] => {\n if (safeVarPrefixes.length === 0) {\n return [pruneVar() as postcss.AcceptedPlugin];\n }\n\n return [\n preserveVars({ preserve: safeVarPrefixes }) as postcss.AcceptedPlugin,\n pruneVar() as postcss.AcceptedPlugin,\n preserveVarsCleanup() as postcss.AcceptedPlugin,\n ];\n};\n\nconst buildPostcssPlugins = (options: {\n tailwindPlugin: postcss.AcceptedPlugin;\n shouldPruneVars: boolean;\n safeVarPrefixes: UDSCSSVarSafelistPattern[];\n scopeClass?: string;\n}): postcss.AcceptedPlugin[] => {\n const plugins: postcss.AcceptedPlugin[] = [options.tailwindPlugin, autoprefixer()];\n\n if (options.shouldPruneVars) {\n plugins.push(...getPruneVarPlugins(options.safeVarPrefixes));\n }\n\n if (options.scopeClass) {\n plugins.push(postcssScope(options.scopeClass) as postcss.AcceptedPlugin);\n }\n\n return plugins;\n};\n\nconst applyScopedColorModeFix = async (css: string, scopeClass?: string): Promise<string> => {\n if (!scopeClass) {\n return css;\n }\n\n const fixResult = await postcss([fixScopedColorModeSelectorsPlugin(scopeClass)]).process(css, {\n from: undefined,\n });\n\n return fixResult.css;\n};\n\nconst optimizeGeneratedCss = async (options: {\n css: string;\n shouldOptimize: boolean;\n optimizationConfig?: CssOptimizationOptions;\n referenceCss?: string;\n scopeClass?: string;\n}): Promise<{\n css: string;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}> => {\n if (!options.shouldOptimize) {\n return { css: options.css };\n }\n\n const optimizationOptions: OptimizeCSSOptions = {\n removeUnusedFonts: options.optimizationConfig?.removeUnusedFonts,\n removeEmptyRules: options.optimizationConfig?.removeEmptyRules,\n aggregateDuplicateSelectors: options.optimizationConfig?.aggregateDuplicateSelectors,\n referenceCss: options.referenceCss,\n scopeClass: options.scopeClass,\n };\n\n const optimized = await optimizeCSS(options.css, optimizationOptions);\n return {\n css: optimized.css,\n optimizationStats: {\n originalSize: optimized.stats.originalSize,\n originalSizeGzip: optimized.stats.originalSizeGzip,\n fontFacesRemoved: optimized.stats.fontFacesRemoved,\n emptyRulesRemoved: optimized.stats.emptyRulesRemoved,\n validationErrors: optimized.validation.errors,\n },\n };\n};\n\nconst printSimpleModeStats = (options: {\n outputPath: string;\n totalFilesScanned: number;\n classCount: number;\n sizeBytes: number;\n sizeGzipBytes: number;\n duration: number;\n scope?: string;\n optimizationStats?: {\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n print: (value: string) => void;\n magenta: (value: string) => string;\n cyan: (value: string) => string;\n yellow: (value: string) => string;\n}): void => {\n const { print, magenta, cyan, yellow } = options;\n\n print('');\n print(`${magenta('Output:')} ${cyan(options.outputPath)}`);\n print(`${magenta('Stats:')}`);\n print(` Files scanned: ${options.totalFilesScanned}`);\n print(` Classes: ${options.classCount}`);\n print(\n ` Size: ${formatBytes(options.sizeBytes)} (${formatBytes(options.sizeGzipBytes)} gzipped)`,\n );\n\n const optimizationStats = options.optimizationStats;\n if (optimizationStats) {\n const savedBytesGzip = optimizationStats.originalSizeGzip - options.sizeGzipBytes;\n if (savedBytesGzip > 0) {\n print(\n ` Optimized: saved ${formatBytes(savedBytesGzip)} gzip (${optimizationStats.fontFacesRemoved} unused @font-face, ${optimizationStats.emptyRulesRemoved} empty rules removed)`,\n );\n }\n\n if (optimizationStats.validationErrors.length > 0) {\n print(` ${yellow('Validation warnings:')}`);\n optimizationStats.validationErrors.forEach((error) => print(` ${yellow('•')} ${error}`));\n }\n }\n\n print(` Time: ${options.duration}ms`);\n if (options.scope) {\n print(` Scope: ${cyan(options.scope)}`);\n }\n};\n\nexport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getContentGlobs,\n getCssFeatureFlags,\n getInternalIconModeCss,\n getInternalSafelistRawContent,\n getPruneVarSafelist,\n optimizeGeneratedCss,\n printSimpleModeStats,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate.helpers.js","names":[],"sources":["../../src/css/generate.helpers.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport autoprefixer from 'autoprefixer';\nimport postcss from 'postcss';\n// @ts-expect-error - no types\nimport pruneVar from 'postcss-prune-var';\nimport postcssScope from 'postcss-scope';\nimport tailwindcss from 'tailwindcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\n// eslint-disable-next-line import/no-relative-packages\nimport { iconPruneVarsSafelist } from '../../../icons/src/safelist';\nimport { getInternalSafelistClasses } from '../purger/optimized/utils/safelist';\nimport { getIconStyles } from '../tailwind/components/getIconStyles';\nimport { tailwindPlugin } from '../tailwind/tailwindPlugin';\nimport { hasAllowedEntryFileExtension } from '../utils/entryPoints';\nimport type { OptimizeCSSOptions } from '../utils/optimizeCSS';\nimport { optimizeCSS } from '../utils/optimizeCSS';\nimport { preserveVars, preserveVarsCleanup } from '../utils/postcssPreserveVars';\nimport { fixScopedColorModeSelectorsPlugin, fixScopedSelfOrParentSelectorsPlugin } from './postcss';\nimport { formatCssDuration } from './runner.helpers';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport { formatBytes } from './utils';\n\ntype CssOptimizationOptions = UDSCSSOptimizationOptions;\n\ntype CssOptionsLike = {\n preflight?: boolean;\n fontFaceDeclarations?: boolean;\n optimization?: CssOptimizationOptions;\n};\n\ntype CssFeatureFlags = {\n enablePreflight: boolean;\n enableFontFaceDeclarations: boolean;\n shouldOptimize: boolean;\n shouldPruneVars: boolean;\n};\n\nconst getPruneVarSafelist = (cssOptions?: CssOptionsLike): UDSCSSVarSafelistPattern[] => {\n const pruneVars = cssOptions?.optimization?.pruneVars;\n const configuredSafelist =\n pruneVars && typeof pruneVars === 'object' ? (pruneVars.safelist ?? []) : [];\n\n return [...iconPruneVarsSafelist, ...configuredSafelist];\n};\n\nconst getCssFeatureFlags = (cssOptions?: CssOptionsLike): CssFeatureFlags => {\n const optimizationConfig = cssOptions?.optimization;\n const shouldOptimize = optimizationConfig?.enabled !== false;\n const pruneVars = optimizationConfig?.pruneVars;\n\n return {\n enablePreflight: cssOptions?.preflight !== false,\n enableFontFaceDeclarations: cssOptions?.fontFaceDeclarations !== false,\n shouldOptimize,\n shouldPruneVars: shouldOptimize && pruneVars !== false,\n };\n};\n\nconst getContentGlobs = (contentDir: string | string[]): string[] => {\n const contentDirs = Array.isArray(contentDir) ? contentDir : [contentDir];\n\n return contentDirs.map((dir) =>\n hasAllowedEntryFileExtension(dir) ? dir : path.join(dir, '**/*.{js,jsx,mjs,cjs,ts,tsx}'),\n );\n};\n\nconst getRawContentEntries = (rawContents: string[]): Array<{ raw: string; extension: 'html' }> =>\n rawContents.map((rawContent) => ({ raw: rawContent, extension: 'html' }));\n\nconst getInternalSafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const internalClasses = new Set(getInternalSafelistClasses());\n const matchedInternalClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && internalClasses.has(entry),\n );\n\n if (matchedInternalClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${matchedInternalClasses.join(' ')}\"></div>`];\n};\n\nconst getInternalIconModeCss = (scopeClass?: string): string => {\n const iconStyles = getIconStyles();\n\n return Object.entries(iconStyles)\n .map(([selector, declarations]) => {\n const scopedSelector = scopeClass ? `${scopeClass} ${selector}` : selector;\n const declarationString = Object.entries(declarations)\n .map(([property, value]) => `${property}: ${value};`)\n .join(' ');\n\n return `${scopedSelector} { ${declarationString} }`;\n })\n .join(' ');\n};\n\nconst createTailwindPlugin = (options: {\n contentDir: string | string[];\n rawContents?: string[];\n safelist: SafelistConfig[];\n config: UniversalTokensConfig;\n enablePreflight: boolean;\n enableFontFaceDeclarations: boolean;\n}): postcss.AcceptedPlugin => {\n const plugin = tailwindcss({\n content: [\n ...getContentGlobs(options.contentDir),\n ...getRawContentEntries(getInternalSafelistRawContent(options.safelist)),\n ...getRawContentEntries(options.rawContents ?? []),\n ],\n safelist: options.safelist,\n corePlugins: { preflight: options.enablePreflight },\n plugins: [\n tailwindPlugin({\n config: options.config,\n disableFontFaceDeclarations: !options.enableFontFaceDeclarations,\n ignorePluginSafelists: true,\n }),\n ],\n });\n\n return plugin as postcss.AcceptedPlugin;\n};\n\nconst getPruneVarPlugins = (\n safeVarPrefixes: UDSCSSVarSafelistPattern[],\n): postcss.AcceptedPlugin[] => {\n if (safeVarPrefixes.length === 0) {\n return [pruneVar() as postcss.AcceptedPlugin];\n }\n\n return [\n preserveVars({ preserve: safeVarPrefixes }) as postcss.AcceptedPlugin,\n pruneVar() as postcss.AcceptedPlugin,\n preserveVarsCleanup() as postcss.AcceptedPlugin,\n ];\n};\n\nconst buildPostcssPlugins = (options: {\n tailwindPlugin: postcss.AcceptedPlugin;\n shouldPruneVars: boolean;\n safeVarPrefixes: UDSCSSVarSafelistPattern[];\n scopeClass?: string;\n}): postcss.AcceptedPlugin[] => {\n const plugins: postcss.AcceptedPlugin[] = [options.tailwindPlugin, autoprefixer()];\n\n if (options.shouldPruneVars) {\n plugins.push(...getPruneVarPlugins(options.safeVarPrefixes));\n }\n\n if (options.scopeClass) {\n plugins.push(postcssScope(options.scopeClass) as postcss.AcceptedPlugin);\n }\n\n return plugins;\n};\n\nconst applyScopedColorModeFix = async (css: string, scopeClass?: string): Promise<string> => {\n if (!scopeClass) {\n return css;\n }\n\n const fixResult = await postcss([\n fixScopedSelfOrParentSelectorsPlugin(scopeClass),\n fixScopedColorModeSelectorsPlugin(scopeClass),\n ]).process(css, {\n from: undefined,\n });\n\n return fixResult.css;\n};\n\nconst optimizeGeneratedCss = async (options: {\n css: string;\n shouldOptimize: boolean;\n optimizationConfig?: CssOptimizationOptions;\n referenceCss?: string;\n scopeClass?: string;\n}): Promise<{\n css: string;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}> => {\n if (!options.shouldOptimize) {\n return { css: options.css };\n }\n\n const optimizationOptions: OptimizeCSSOptions = {\n removeUnusedFonts: options.optimizationConfig?.removeUnusedFonts,\n removeEmptyRules: options.optimizationConfig?.removeEmptyRules,\n aggregateDuplicateSelectors: options.optimizationConfig?.aggregateDuplicateSelectors,\n referenceCss: options.referenceCss,\n scopeClass: options.scopeClass,\n };\n\n const optimized = await optimizeCSS(options.css, optimizationOptions);\n return {\n css: optimized.css,\n optimizationStats: {\n originalSize: optimized.stats.originalSize,\n originalSizeGzip: optimized.stats.originalSizeGzip,\n fontFacesRemoved: optimized.stats.fontFacesRemoved,\n emptyRulesRemoved: optimized.stats.emptyRulesRemoved,\n validationErrors: optimized.validation.errors,\n },\n };\n};\n\nconst printSimpleModeStats = (options: {\n cwd: string;\n outputPath: string;\n totalFilesScanned: number;\n scannedFilePaths?: string[];\n classCount: number;\n sizeBytes: number;\n sizeGzipBytes: number;\n duration: number;\n scope?: string;\n verbose?: boolean;\n optimizationStats?: {\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n print: (value: string) => void;\n magenta: (value: string) => string;\n cyan: (value: string) => string;\n yellow: (value: string) => string;\n}): void => {\n const { print, magenta, cyan, yellow } = options;\n const getDisplayPath = (targetPath: string): string => {\n const relativePath = path.relative(options.cwd, targetPath);\n return relativePath.length === 0 ? '.' : relativePath;\n };\n\n print('');\n print(`${magenta('Output:')} ${cyan(getDisplayPath(options.outputPath))}`);\n print(`${magenta('Stats:')}`);\n print(` Files scanned: ${options.totalFilesScanned}`);\n if (options.verbose && options.scannedFilePaths && options.scannedFilePaths.length > 0) {\n [...new Set(options.scannedFilePaths)]\n .sort((left, right) => left.localeCompare(right))\n .forEach((filePath) => print(` • ${cyan(getDisplayPath(filePath))}`));\n }\n print(` Classes: ${options.classCount}`);\n print(\n ` Size: ${formatBytes(options.sizeBytes)} (${formatBytes(options.sizeGzipBytes)} gzipped)`,\n );\n\n const optimizationStats = options.optimizationStats;\n if (optimizationStats) {\n const savedBytesGzip = optimizationStats.originalSizeGzip - options.sizeGzipBytes;\n if (savedBytesGzip > 0) {\n if (optimizationStats.fontFacesRemoved > 0) {\n print(` • removed ${optimizationStats.fontFacesRemoved} unused @font-face`);\n }\n if (optimizationStats.emptyRulesRemoved > 0) {\n print(` • removed ${optimizationStats.emptyRulesRemoved} empty rules`);\n }\n }\n\n if (optimizationStats.validationErrors.length > 0) {\n print(` ${yellow('Validation warnings:')}`);\n optimizationStats.validationErrors.forEach((error) => print(` ${yellow('•')} ${error}`));\n }\n }\n\n print(` Time: ${formatCssDuration(options.duration)}`);\n if (options.scope) {\n print(` Scope: ${cyan(options.scope)}`);\n }\n};\n\nexport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getContentGlobs,\n getCssFeatureFlags,\n getInternalIconModeCss,\n getInternalSafelistRawContent,\n getPruneVarSafelist,\n optimizeGeneratedCss,\n printSimpleModeStats,\n};\n"],"mappings":"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"}
|
|
@@ -105,13 +105,16 @@ const generateSimpleModeCSS = async (options) => {
|
|
|
105
105
|
fs.writeFileSync(outputPath, cssResult.css);
|
|
106
106
|
const duration = Math.round(performance.now() - startTime);
|
|
107
107
|
if (shouldLogStats) printSimpleModeStats({
|
|
108
|
+
cwd: options.workspaceDir,
|
|
108
109
|
outputPath,
|
|
109
110
|
totalFilesScanned,
|
|
111
|
+
scannedFilePaths: scanResult.filePaths,
|
|
110
112
|
classCount: cssResult.classCount,
|
|
111
113
|
sizeBytes: cssResult.sizeBytes,
|
|
112
114
|
sizeGzipBytes: cssResult.sizeGzipBytes,
|
|
113
115
|
duration,
|
|
114
116
|
scope: options.scope,
|
|
117
|
+
verbose: options.verbose,
|
|
115
118
|
optimizationStats: cssResult.optimizationStats,
|
|
116
119
|
print,
|
|
117
120
|
magenta,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","names":[],"sources":["../../src/css/generate.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { gzipSync } from 'node:zlib';\n\nimport { cyan, magenta, print, spinStop, yellow } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\nimport postcss from 'postcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n} from '../purger/optimized';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { resolveEntryPaths } from '../utils/entryPoints';\nimport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getCssFeatureFlags,\n getInternalIconModeCss,\n optimizeGeneratedCss,\n printSimpleModeStats,\n} from './generate.helpers';\nimport { loadConfigFile, scanDirectoriesForSafelist } from './nodeUtils';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\n/**\n * Result from generating CSS\n */\ninterface CSSResult {\n css: string;\n sizeBytes: number;\n sizeGzipBytes: number;\n classCount: number;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}\n\n/**\n * CSS generation options for uds.theme.ts\n */\ninterface UDSCSSOptions {\n /** CSS scope wrapper class (optional) */\n scope?: string;\n /** Safelist of CSS classes to always include */\n safelist?: SafelistConfig[];\n /** CSS optimization settings */\n optimization?: UDSCSSOptimizationOptions;\n /** Include Tailwind preflight/reset styles (default: true) */\n preflight?: boolean;\n /** Include @font-face declarations (default: true) */\n fontFaceDeclarations?: boolean;\n /** Debounce delay (ms) for watch mode regenerations */\n watchDebounce?: number;\n}\n\n/**\n * Options for generateCSS function\n */\ninterface GenerateCSSOptions {\n /** CSS scope wrapper class */\n scope?: string;\n /** Directory to scan for arbitrary Tailwind classes (className props) */\n contentDir?: string | string[];\n /** CSS generation options from theme config */\n cssOptions?: UDSCSSOptions;\n /** Reference CSS to deduplicate font-faces against (for scoped CSS) */\n referenceCss?: string;\n /** CSS variable prefixes or patterns to preserve during pruning */\n safeVarPrefixes?: UDSCSSVarSafelistPattern[];\n}\n\nconst normalizeScope = (scope?: string): string | undefined => {\n const trimmedScope = scope?.trim();\n return trimmedScope ? trimmedScope : undefined;\n};\n\nconst getArbitrarySafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const arbitraryClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && entry.includes('['),\n );\n\n if (arbitraryClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${arbitraryClasses.join(' ')}\"></div>`];\n};\n\n/**\n * Generate CSS from a safelist using Tailwind + PostCSS\n * @param safelist - UDS component classes to include\n * @param config - Token configuration\n * @param options - Additional options\n */\nconst generateCSS = async (\n safelist: SafelistConfig[],\n config: UniversalTokensConfig,\n options?: GenerateCSSOptions,\n): Promise<CSSResult> => {\n // Do we need base?\n const sourceCSS = '@tailwind base; @tailwind components; @tailwind utilities';\n\n const contentDir = options?.contentDir ?? path.join(process.cwd(), 'src');\n const cssFlags = getCssFeatureFlags(options?.cssOptions);\n const optimizationConfig = options?.cssOptions?.optimization;\n const scopeClass = normalizeScope(options?.scope) ?? normalizeScope(options?.cssOptions?.scope);\n const twPlugin = createTailwindPlugin({\n contentDir,\n rawContents: getArbitrarySafelistRawContent(safelist),\n safelist,\n config,\n enablePreflight: cssFlags.enablePreflight,\n enableFontFaceDeclarations: cssFlags.enableFontFaceDeclarations,\n });\n const plugins = buildPostcssPlugins({\n tailwindPlugin: twPlugin,\n shouldPruneVars: cssFlags.shouldPruneVars,\n safeVarPrefixes: options?.safeVarPrefixes ?? [],\n scopeClass,\n });\n\n const result = await postcss(plugins).process(sourceCSS, { from: undefined });\n let css = await applyScopedColorModeFix(result.css, scopeClass);\n if (!css.includes('uds-light-mode-icon') || !css.includes('uds-dark-mode-icon')) {\n css = `${css} ${getInternalIconModeCss(scopeClass)}`.trim();\n }\n const optimizedCss = await optimizeGeneratedCss({\n css,\n shouldOptimize: cssFlags.shouldOptimize,\n optimizationConfig,\n referenceCss: options?.referenceCss,\n scopeClass,\n });\n css = optimizedCss.css;\n\n const sizeBytes = Buffer.byteLength(css, 'utf8');\n const sizeGzipBytes = gzipSync(css).length;\n\n return {\n css,\n sizeBytes,\n sizeGzipBytes,\n classCount: safelist.length,\n optimizationStats: optimizedCss.optimizationStats,\n };\n};\n\n/**\n * Generate CSS in simple mode (no uds.theme.ts)\n */\nconst generateSimpleModeCSS = async (options: {\n workspaceDir: string;\n entry: EntryValue;\n outFile: string;\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n scope?: string;\n configPath?: string;\n isWatch?: boolean;\n silent?: boolean;\n}): Promise<{ success: boolean; outputPath: string; packageDirs?: string[] }> => {\n const isWatch = options.isWatch === true;\n const isSilent = options.silent === true;\n const shouldLogStats = !isSilent && !isWatch;\n const startTime = performance.now();\n const colorModes: ('dark' | 'light')[] = ['dark']; // Light mode is already in :root\n\n // Load config if provided, otherwise use default\n let tokensConfig: UniversalTokensConfig = defaultTokensConfig;\n if (options.configPath) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(options.configPath);\n if (loadedConfig) {\n tokensConfig = loadedConfig;\n } else if (shouldLogStats) {\n spinStop('⚠️', `Config file not found: ${options.configPath}, using defaults`);\n }\n }\n\n // Extract variant defaults from config for auto-variant class generation\n const variantDefaults = extractVariantDefaults(tokensConfig);\n const runtimeConfigValues = extractRuntimeConfigValues(tokensConfig);\n\n const resolvedEntries = resolveEntryPaths(options.entry, options.workspaceDir);\n const entryDirs = resolvedEntries.map((entry) => entry.absolutePath);\n const scanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n options.variants,\n options.autoVariants,\n options.componentData,\n variantDefaults,\n runtimeConfigValues,\n );\n\n const totalFilesScanned = scanResult.filesScanned;\n const allClasses: string[] = [...scanResult.safelist];\n const allComponents = new Set<string>(scanResult.components);\n const packageDirs: string[] = [\n ...new Set(\n resolvedEntries.map((entry) =>\n entry.kind === 'directory' ? entry.absolutePath : entry.watchDirectory,\n ),\n ),\n ];\n\n // Add color mode classes\n const fullSafelist = [\n ...allClasses,\n ...getThemeAndScaleClasses(colorModes),\n ...getInternalSafelistClasses(),\n ];\n const finalSafelist = deduplicateSafelist(fullSafelist);\n\n // Generate CSS (Tailwind will scan entry dir for arbitrary classes on className props)\n const cssResult = await generateCSS(finalSafelist, tokensConfig, {\n scope: options.scope,\n contentDir: entryDirs,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(options.componentData, [...allComponents]),\n ...getConfigurableCssVariables(),\n ],\n });\n\n // Write output\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(options.workspaceDir, options.outFile);\n const outputDir = path.dirname(outputPath);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, cssResult.css);\n\n const duration = Math.round(performance.now() - startTime);\n\n if (shouldLogStats) {\n printSimpleModeStats({\n outputPath,\n totalFilesScanned,\n classCount: cssResult.classCount,\n sizeBytes: cssResult.sizeBytes,\n sizeGzipBytes: cssResult.sizeGzipBytes,\n duration,\n scope: options.scope,\n optimizationStats: cssResult.optimizationStats,\n print,\n magenta,\n cyan,\n yellow,\n });\n }\n\n return { success: true, outputPath, packageDirs };\n};\n\nexport { generateCSS, generateSimpleModeCSS };\nexport type { UDSCSSOptions };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate.js","names":[],"sources":["../../src/css/generate.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { gzipSync } from 'node:zlib';\n\nimport { cyan, magenta, print, spinStop, yellow } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\nimport postcss from 'postcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n} from '../purger/optimized';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { resolveEntryPaths } from '../utils/entryPoints';\nimport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getCssFeatureFlags,\n getInternalIconModeCss,\n optimizeGeneratedCss,\n printSimpleModeStats,\n} from './generate.helpers';\nimport { loadConfigFile, scanDirectoriesForSafelist } from './nodeUtils';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\n/**\n * Result from generating CSS\n */\ninterface CSSResult {\n css: string;\n sizeBytes: number;\n sizeGzipBytes: number;\n classCount: number;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}\n\n/**\n * CSS generation options for uds.theme.ts\n */\ninterface UDSCSSOptions {\n /** CSS scope wrapper class (optional) */\n scope?: string;\n /** Safelist of CSS classes to always include */\n safelist?: SafelistConfig[];\n /** CSS optimization settings */\n optimization?: UDSCSSOptimizationOptions;\n /** Include Tailwind preflight/reset styles (default: true) */\n preflight?: boolean;\n /** Include @font-face declarations (default: true) */\n fontFaceDeclarations?: boolean;\n /** Debounce delay (ms) for watch mode regenerations */\n watchDebounce?: number;\n}\n\n/**\n * Options for generateCSS function\n */\ninterface GenerateCSSOptions {\n /** CSS scope wrapper class */\n scope?: string;\n /** Directory to scan for arbitrary Tailwind classes (className props) */\n contentDir?: string | string[];\n /** CSS generation options from theme config */\n cssOptions?: UDSCSSOptions;\n /** Reference CSS to deduplicate font-faces against (for scoped CSS) */\n referenceCss?: string;\n /** CSS variable prefixes or patterns to preserve during pruning */\n safeVarPrefixes?: UDSCSSVarSafelistPattern[];\n}\n\nconst normalizeScope = (scope?: string): string | undefined => {\n const trimmedScope = scope?.trim();\n return trimmedScope ? trimmedScope : undefined;\n};\n\nconst getArbitrarySafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const arbitraryClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && entry.includes('['),\n );\n\n if (arbitraryClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${arbitraryClasses.join(' ')}\"></div>`];\n};\n\n/**\n * Generate CSS from a safelist using Tailwind + PostCSS\n * @param safelist - UDS component classes to include\n * @param config - Token configuration\n * @param options - Additional options\n */\nconst generateCSS = async (\n safelist: SafelistConfig[],\n config: UniversalTokensConfig,\n options?: GenerateCSSOptions,\n): Promise<CSSResult> => {\n // Do we need base?\n const sourceCSS = '@tailwind base; @tailwind components; @tailwind utilities';\n\n const contentDir = options?.contentDir ?? path.join(process.cwd(), 'src');\n const cssFlags = getCssFeatureFlags(options?.cssOptions);\n const optimizationConfig = options?.cssOptions?.optimization;\n const scopeClass = normalizeScope(options?.scope) ?? normalizeScope(options?.cssOptions?.scope);\n const twPlugin = createTailwindPlugin({\n contentDir,\n rawContents: getArbitrarySafelistRawContent(safelist),\n safelist,\n config,\n enablePreflight: cssFlags.enablePreflight,\n enableFontFaceDeclarations: cssFlags.enableFontFaceDeclarations,\n });\n const plugins = buildPostcssPlugins({\n tailwindPlugin: twPlugin,\n shouldPruneVars: cssFlags.shouldPruneVars,\n safeVarPrefixes: options?.safeVarPrefixes ?? [],\n scopeClass,\n });\n\n const result = await postcss(plugins).process(sourceCSS, { from: undefined });\n let css = await applyScopedColorModeFix(result.css, scopeClass);\n if (!css.includes('uds-light-mode-icon') || !css.includes('uds-dark-mode-icon')) {\n css = `${css} ${getInternalIconModeCss(scopeClass)}`.trim();\n }\n const optimizedCss = await optimizeGeneratedCss({\n css,\n shouldOptimize: cssFlags.shouldOptimize,\n optimizationConfig,\n referenceCss: options?.referenceCss,\n scopeClass,\n });\n css = optimizedCss.css;\n\n const sizeBytes = Buffer.byteLength(css, 'utf8');\n const sizeGzipBytes = gzipSync(css).length;\n\n return {\n css,\n sizeBytes,\n sizeGzipBytes,\n classCount: safelist.length,\n optimizationStats: optimizedCss.optimizationStats,\n };\n};\n\n/**\n * Generate CSS in simple mode (no uds.theme.ts)\n */\nconst generateSimpleModeCSS = async (options: {\n workspaceDir: string;\n entry: EntryValue;\n outFile: string;\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n scope?: string;\n configPath?: string;\n isWatch?: boolean;\n silent?: boolean;\n verbose?: boolean;\n}): Promise<{ success: boolean; outputPath: string; packageDirs?: string[] }> => {\n const isWatch = options.isWatch === true;\n const isSilent = options.silent === true;\n const shouldLogStats = !isSilent && !isWatch;\n const startTime = performance.now();\n const colorModes: ('dark' | 'light')[] = ['dark']; // Light mode is already in :root\n\n // Load config if provided, otherwise use default\n let tokensConfig: UniversalTokensConfig = defaultTokensConfig;\n if (options.configPath) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(options.configPath);\n if (loadedConfig) {\n tokensConfig = loadedConfig;\n } else if (shouldLogStats) {\n spinStop('⚠️', `Config file not found: ${options.configPath}, using defaults`);\n }\n }\n\n // Extract variant defaults from config for auto-variant class generation\n const variantDefaults = extractVariantDefaults(tokensConfig);\n const runtimeConfigValues = extractRuntimeConfigValues(tokensConfig);\n\n const resolvedEntries = resolveEntryPaths(options.entry, options.workspaceDir);\n const entryDirs = resolvedEntries.map((entry) => entry.absolutePath);\n const scanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n options.variants,\n options.autoVariants,\n options.componentData,\n variantDefaults,\n runtimeConfigValues,\n );\n\n const totalFilesScanned = scanResult.filesScanned;\n const allClasses: string[] = [...scanResult.safelist];\n const allComponents = new Set<string>(scanResult.components);\n const packageDirs: string[] = [\n ...new Set(\n resolvedEntries.map((entry) =>\n entry.kind === 'directory' ? entry.absolutePath : entry.watchDirectory,\n ),\n ),\n ];\n\n // Add color mode classes\n const fullSafelist = [\n ...allClasses,\n ...getThemeAndScaleClasses(colorModes),\n ...getInternalSafelistClasses(),\n ];\n const finalSafelist = deduplicateSafelist(fullSafelist);\n\n // Generate CSS (Tailwind will scan entry dir for arbitrary classes on className props)\n const cssResult = await generateCSS(finalSafelist, tokensConfig, {\n scope: options.scope,\n contentDir: entryDirs,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(options.componentData, [...allComponents]),\n ...getConfigurableCssVariables(),\n ],\n });\n\n // Write output\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(options.workspaceDir, options.outFile);\n const outputDir = path.dirname(outputPath);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, cssResult.css);\n\n const duration = Math.round(performance.now() - startTime);\n\n if (shouldLogStats) {\n printSimpleModeStats({\n cwd: options.workspaceDir,\n outputPath,\n totalFilesScanned,\n scannedFilePaths: scanResult.filePaths,\n classCount: cssResult.classCount,\n sizeBytes: cssResult.sizeBytes,\n sizeGzipBytes: cssResult.sizeGzipBytes,\n duration,\n scope: options.scope,\n verbose: options.verbose,\n optimizationStats: cssResult.optimizationStats,\n print,\n magenta,\n cyan,\n yellow,\n });\n }\n\n return { success: true, outputPath, packageDirs };\n};\n\nexport { generateCSS, generateSimpleModeCSS };\nexport type { UDSCSSOptions };\n"],"mappings":"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"}
|
|
@@ -24,11 +24,11 @@ const loadConfigFile = async (configPath) => {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
27
|
-
const files = await (0, fast_glob.default)("**/*.{js,jsx,ts,tsx}", {
|
|
27
|
+
const files = (await (0, fast_glob.default)("**/*.{js,jsx,mjs,cjs,ts,tsx}", {
|
|
28
28
|
cwd: dir,
|
|
29
29
|
absolute: true,
|
|
30
30
|
ignore: ["**/node_modules/**"]
|
|
31
|
-
});
|
|
31
|
+
})).sort((left, right) => left.localeCompare(right));
|
|
32
32
|
const results = await Promise.all(files.map(async (filePath) => {
|
|
33
33
|
return require_purgeFromCode.purgeFromCodeOptimized(node_fs.default.readFileSync(filePath, "utf-8"), {
|
|
34
34
|
colorModes,
|
|
@@ -41,10 +41,15 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
|
|
|
41
41
|
filePath
|
|
42
42
|
});
|
|
43
43
|
}));
|
|
44
|
+
const allClasses = results.flatMap((result) => result.safelist);
|
|
45
|
+
const allComponents = new Set(results.flatMap((result) => result.components));
|
|
46
|
+
const filesWithComponents = results.filter((result) => result.components.length > 0).length;
|
|
44
47
|
return {
|
|
45
|
-
safelist:
|
|
46
|
-
components: [...
|
|
47
|
-
filesScanned: files.length
|
|
48
|
+
safelist: allClasses,
|
|
49
|
+
components: [...allComponents],
|
|
50
|
+
filesScanned: files.length,
|
|
51
|
+
filesWithComponents,
|
|
52
|
+
filePaths: files
|
|
48
53
|
};
|
|
49
54
|
};
|
|
50
55
|
const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
@@ -60,7 +65,9 @@ const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants,
|
|
|
60
65
|
return {
|
|
61
66
|
safelist: result.safelist,
|
|
62
67
|
components: result.components,
|
|
63
|
-
filesScanned: 1
|
|
68
|
+
filesScanned: 1,
|
|
69
|
+
filesWithComponents: result.components.length > 0 ? 1 : 0,
|
|
70
|
+
filePaths: [filePath]
|
|
64
71
|
};
|
|
65
72
|
};
|
|
66
73
|
const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
@@ -71,7 +78,9 @@ const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVarian
|
|
|
71
78
|
return {
|
|
72
79
|
safelist: results.flatMap((result) => result.safelist),
|
|
73
80
|
components: [...new Set(results.flatMap((result) => result.components))],
|
|
74
|
-
filesScanned: results.reduce((total, result) => total + result.filesScanned, 0)
|
|
81
|
+
filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),
|
|
82
|
+
filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),
|
|
83
|
+
filePaths: results.flatMap((result) => result.filePaths).sort((left, right) => left.localeCompare(right))
|
|
75
84
|
};
|
|
76
85
|
};
|
|
77
86
|
const findMonorepoRoot = (startDir) => {
|
|
@@ -82,13 +91,45 @@ const findMonorepoRoot = (startDir) => {
|
|
|
82
91
|
};
|
|
83
92
|
return findUp(startDir);
|
|
84
93
|
};
|
|
94
|
+
const readPackageName = (packageJsonPath) => {
|
|
95
|
+
try {
|
|
96
|
+
const pkgJson = JSON.parse(node_fs.default.readFileSync(packageJsonPath, "utf8"));
|
|
97
|
+
return typeof pkgJson.name === "string" ? pkgJson.name : null;
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const findPackageRootFromResolvedEntry = (resolvedEntryPath, packageName) => {
|
|
103
|
+
let currentPath = node_fs.default.statSync(resolvedEntryPath).isDirectory() ? resolvedEntryPath : node_path.default.dirname(resolvedEntryPath);
|
|
104
|
+
while (true) {
|
|
105
|
+
const packageJsonPath = node_path.default.join(currentPath, "package.json");
|
|
106
|
+
if (node_fs.default.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) return currentPath;
|
|
107
|
+
const parentPath = node_path.default.dirname(currentPath);
|
|
108
|
+
if (parentPath === currentPath) return null;
|
|
109
|
+
currentPath = parentPath;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const findPackageRootInNodeModules = (startDir, packageName) => {
|
|
113
|
+
let currentDir = startDir;
|
|
114
|
+
while (true) {
|
|
115
|
+
const packageJsonPath = node_path.default.join(currentDir, "node_modules", packageName, "package.json");
|
|
116
|
+
if (node_fs.default.existsSync(packageJsonPath)) return node_path.default.dirname(packageJsonPath);
|
|
117
|
+
const parentDir = node_path.default.dirname(currentDir);
|
|
118
|
+
if (parentDir === currentDir) return null;
|
|
119
|
+
currentDir = parentDir;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
85
122
|
const resolvePackageRoot = (workspaceDir, packageName) => {
|
|
86
|
-
const
|
|
123
|
+
const requireFromWorkspace = (0, node_module.createRequire)(node_path.default.join(workspaceDir, "package.json"));
|
|
87
124
|
try {
|
|
88
|
-
const resolvedPackageJson =
|
|
125
|
+
const resolvedPackageJson = requireFromWorkspace.resolve(node_path.default.join(packageName, "package.json"));
|
|
89
126
|
return node_path.default.dirname(resolvedPackageJson);
|
|
90
127
|
} catch {
|
|
91
|
-
|
|
128
|
+
try {
|
|
129
|
+
const packageRoot = findPackageRootFromResolvedEntry(requireFromWorkspace.resolve(packageName), packageName);
|
|
130
|
+
if (packageRoot) return packageRoot;
|
|
131
|
+
} catch {}
|
|
132
|
+
return findPackageRootInNodeModules(workspaceDir, packageName);
|
|
92
133
|
}
|
|
93
134
|
};
|
|
94
135
|
const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
@@ -97,14 +138,17 @@ const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
|
97
138
|
absolute: true,
|
|
98
139
|
ignore: ["**/node_modules/**", "**/dist/**"]
|
|
99
140
|
}).find((pkgJsonPath) => {
|
|
100
|
-
|
|
101
|
-
return JSON.parse(node_fs.default.readFileSync(pkgJsonPath, "utf8")).name === packageName;
|
|
102
|
-
} catch {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
141
|
+
return readPackageName(pkgJsonPath) === packageName;
|
|
105
142
|
});
|
|
106
143
|
return matchingPath ? node_path.default.dirname(matchingPath) : null;
|
|
107
144
|
};
|
|
145
|
+
const findPackageRoot = (packageName) => {
|
|
146
|
+
const workspaceDir = process.cwd();
|
|
147
|
+
const monorepoRoot = findMonorepoRoot(workspaceDir);
|
|
148
|
+
let packageRoot = resolvePackageRoot(workspaceDir, packageName);
|
|
149
|
+
if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
|
|
150
|
+
return packageRoot;
|
|
151
|
+
};
|
|
108
152
|
const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
|
|
109
153
|
return [
|
|
110
154
|
packageRoot ? node_path.default.join(packageRoot, "src") : null,
|
|
@@ -119,11 +163,19 @@ const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) =>
|
|
|
119
163
|
};
|
|
120
164
|
const getFirstExistingPath = (candidates) => candidates.find((candidate) => node_fs.default.existsSync(candidate)) ?? null;
|
|
121
165
|
const findPackageSourceDir = (packageName) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
166
|
+
return getFirstExistingPath(buildPackageSourceCandidates(process.cwd(), packageName, findPackageRoot(packageName)));
|
|
167
|
+
};
|
|
168
|
+
const getPackageUdsScope = (packageName) => {
|
|
169
|
+
const packageRoot = findPackageRoot(packageName);
|
|
170
|
+
if (!packageRoot) return null;
|
|
171
|
+
const packageJsonPath = node_path.default.join(packageRoot, "package.json");
|
|
172
|
+
if (!node_fs.default.existsSync(packageJsonPath)) return null;
|
|
173
|
+
try {
|
|
174
|
+
const scope = JSON.parse(node_fs.default.readFileSync(packageJsonPath, "utf8")).uds?.scope;
|
|
175
|
+
return typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : null;
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
127
179
|
};
|
|
128
180
|
const scaffoldThemeConfig = async (options) => {
|
|
129
181
|
const workspaceDir = process.cwd();
|
|
@@ -155,6 +207,23 @@ export default defineTheme({
|
|
|
155
207
|
// Packages that inherit your app's theme (merged into main uds.css)
|
|
156
208
|
// inherit: ['@your-org/shared-ui'],
|
|
157
209
|
|
|
210
|
+
// Packages that generate separate scoped CSS outputs.
|
|
211
|
+
// Scope class is discovered from each package.json uds.scope.
|
|
212
|
+
// When entry is omitted, the package is scanned the same way as inherit.
|
|
213
|
+
// scoped: {
|
|
214
|
+
// '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'
|
|
215
|
+
// }
|
|
216
|
+
//
|
|
217
|
+
// Or use the expanded form for custom output paths:
|
|
218
|
+
// scoped: {
|
|
219
|
+
// '@your-org/shared-ui': {
|
|
220
|
+
// config: './packages/shared-ui/uds.config.ts',
|
|
221
|
+
// entry: './src',
|
|
222
|
+
// // outFile defaults to dist/shared-ui.css
|
|
223
|
+
// outFile: 'dist/shared-ui.css'
|
|
224
|
+
// },
|
|
225
|
+
// },
|
|
226
|
+
|
|
158
227
|
// CSS generation options (all optional)
|
|
159
228
|
// css: {
|
|
160
229
|
// safelist: [],
|
|
@@ -179,7 +248,9 @@ export default defineTheme({
|
|
|
179
248
|
};
|
|
180
249
|
|
|
181
250
|
//#endregion
|
|
251
|
+
exports.findPackageRoot = findPackageRoot;
|
|
182
252
|
exports.findPackageSourceDir = findPackageSourceDir;
|
|
253
|
+
exports.getPackageUdsScope = getPackageUdsScope;
|
|
183
254
|
exports.loadConfigFile = loadConfigFile;
|
|
184
255
|
exports.scaffoldThemeConfig = scaffoldThemeConfig;
|
|
185
256
|
exports.scanDirectoriesForSafelist = scanDirectoriesForSafelist;
|
|
@@ -20,11 +20,11 @@ const loadConfigFile = async (configPath) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
23
|
-
const files = await fg("**/*.{js,jsx,ts,tsx}", {
|
|
23
|
+
const files = (await fg("**/*.{js,jsx,mjs,cjs,ts,tsx}", {
|
|
24
24
|
cwd: dir,
|
|
25
25
|
absolute: true,
|
|
26
26
|
ignore: ["**/node_modules/**"]
|
|
27
|
-
});
|
|
27
|
+
})).sort((left, right) => left.localeCompare(right));
|
|
28
28
|
const results = await Promise.all(files.map(async (filePath) => {
|
|
29
29
|
return purgeFromCodeOptimized(fs.readFileSync(filePath, "utf-8"), {
|
|
30
30
|
colorModes,
|
|
@@ -37,10 +37,15 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
|
|
|
37
37
|
filePath
|
|
38
38
|
});
|
|
39
39
|
}));
|
|
40
|
+
const allClasses = results.flatMap((result) => result.safelist);
|
|
41
|
+
const allComponents = new Set(results.flatMap((result) => result.components));
|
|
42
|
+
const filesWithComponents = results.filter((result) => result.components.length > 0).length;
|
|
40
43
|
return {
|
|
41
|
-
safelist:
|
|
42
|
-
components: [...
|
|
43
|
-
filesScanned: files.length
|
|
44
|
+
safelist: allClasses,
|
|
45
|
+
components: [...allComponents],
|
|
46
|
+
filesScanned: files.length,
|
|
47
|
+
filesWithComponents,
|
|
48
|
+
filePaths: files
|
|
44
49
|
};
|
|
45
50
|
};
|
|
46
51
|
const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
@@ -56,7 +61,9 @@ const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants,
|
|
|
56
61
|
return {
|
|
57
62
|
safelist: result.safelist,
|
|
58
63
|
components: result.components,
|
|
59
|
-
filesScanned: 1
|
|
64
|
+
filesScanned: 1,
|
|
65
|
+
filesWithComponents: result.components.length > 0 ? 1 : 0,
|
|
66
|
+
filePaths: [filePath]
|
|
60
67
|
};
|
|
61
68
|
};
|
|
62
69
|
const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
|
|
@@ -67,7 +74,9 @@ const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVarian
|
|
|
67
74
|
return {
|
|
68
75
|
safelist: results.flatMap((result) => result.safelist),
|
|
69
76
|
components: [...new Set(results.flatMap((result) => result.components))],
|
|
70
|
-
filesScanned: results.reduce((total, result) => total + result.filesScanned, 0)
|
|
77
|
+
filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),
|
|
78
|
+
filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),
|
|
79
|
+
filePaths: results.flatMap((result) => result.filePaths).sort((left, right) => left.localeCompare(right))
|
|
71
80
|
};
|
|
72
81
|
};
|
|
73
82
|
const findMonorepoRoot = (startDir) => {
|
|
@@ -78,13 +87,45 @@ const findMonorepoRoot = (startDir) => {
|
|
|
78
87
|
};
|
|
79
88
|
return findUp(startDir);
|
|
80
89
|
};
|
|
90
|
+
const readPackageName = (packageJsonPath) => {
|
|
91
|
+
try {
|
|
92
|
+
const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
93
|
+
return typeof pkgJson.name === "string" ? pkgJson.name : null;
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const findPackageRootFromResolvedEntry = (resolvedEntryPath, packageName) => {
|
|
99
|
+
let currentPath = fs.statSync(resolvedEntryPath).isDirectory() ? resolvedEntryPath : path.dirname(resolvedEntryPath);
|
|
100
|
+
while (true) {
|
|
101
|
+
const packageJsonPath = path.join(currentPath, "package.json");
|
|
102
|
+
if (fs.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) return currentPath;
|
|
103
|
+
const parentPath = path.dirname(currentPath);
|
|
104
|
+
if (parentPath === currentPath) return null;
|
|
105
|
+
currentPath = parentPath;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const findPackageRootInNodeModules = (startDir, packageName) => {
|
|
109
|
+
let currentDir = startDir;
|
|
110
|
+
while (true) {
|
|
111
|
+
const packageJsonPath = path.join(currentDir, "node_modules", packageName, "package.json");
|
|
112
|
+
if (fs.existsSync(packageJsonPath)) return path.dirname(packageJsonPath);
|
|
113
|
+
const parentDir = path.dirname(currentDir);
|
|
114
|
+
if (parentDir === currentDir) return null;
|
|
115
|
+
currentDir = parentDir;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
81
118
|
const resolvePackageRoot = (workspaceDir, packageName) => {
|
|
82
|
-
const
|
|
119
|
+
const requireFromWorkspace = createRequire(path.join(workspaceDir, "package.json"));
|
|
83
120
|
try {
|
|
84
|
-
const resolvedPackageJson =
|
|
121
|
+
const resolvedPackageJson = requireFromWorkspace.resolve(path.join(packageName, "package.json"));
|
|
85
122
|
return path.dirname(resolvedPackageJson);
|
|
86
123
|
} catch {
|
|
87
|
-
|
|
124
|
+
try {
|
|
125
|
+
const packageRoot = findPackageRootFromResolvedEntry(requireFromWorkspace.resolve(packageName), packageName);
|
|
126
|
+
if (packageRoot) return packageRoot;
|
|
127
|
+
} catch {}
|
|
128
|
+
return findPackageRootInNodeModules(workspaceDir, packageName);
|
|
88
129
|
}
|
|
89
130
|
};
|
|
90
131
|
const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
@@ -93,14 +134,17 @@ const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
|
|
|
93
134
|
absolute: true,
|
|
94
135
|
ignore: ["**/node_modules/**", "**/dist/**"]
|
|
95
136
|
}).find((pkgJsonPath) => {
|
|
96
|
-
|
|
97
|
-
return JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")).name === packageName;
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
137
|
+
return readPackageName(pkgJsonPath) === packageName;
|
|
101
138
|
});
|
|
102
139
|
return matchingPath ? path.dirname(matchingPath) : null;
|
|
103
140
|
};
|
|
141
|
+
const findPackageRoot = (packageName) => {
|
|
142
|
+
const workspaceDir = process.cwd();
|
|
143
|
+
const monorepoRoot = findMonorepoRoot(workspaceDir);
|
|
144
|
+
let packageRoot = resolvePackageRoot(workspaceDir, packageName);
|
|
145
|
+
if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
|
|
146
|
+
return packageRoot;
|
|
147
|
+
};
|
|
104
148
|
const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
|
|
105
149
|
return [
|
|
106
150
|
packageRoot ? path.join(packageRoot, "src") : null,
|
|
@@ -115,11 +159,19 @@ const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) =>
|
|
|
115
159
|
};
|
|
116
160
|
const getFirstExistingPath = (candidates) => candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
|
|
117
161
|
const findPackageSourceDir = (packageName) => {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
162
|
+
return getFirstExistingPath(buildPackageSourceCandidates(process.cwd(), packageName, findPackageRoot(packageName)));
|
|
163
|
+
};
|
|
164
|
+
const getPackageUdsScope = (packageName) => {
|
|
165
|
+
const packageRoot = findPackageRoot(packageName);
|
|
166
|
+
if (!packageRoot) return null;
|
|
167
|
+
const packageJsonPath = path.join(packageRoot, "package.json");
|
|
168
|
+
if (!fs.existsSync(packageJsonPath)) return null;
|
|
169
|
+
try {
|
|
170
|
+
const scope = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).uds?.scope;
|
|
171
|
+
return typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : null;
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
123
175
|
};
|
|
124
176
|
const scaffoldThemeConfig = async (options) => {
|
|
125
177
|
const workspaceDir = process.cwd();
|
|
@@ -151,6 +203,23 @@ export default defineTheme({
|
|
|
151
203
|
// Packages that inherit your app's theme (merged into main uds.css)
|
|
152
204
|
// inherit: ['@your-org/shared-ui'],
|
|
153
205
|
|
|
206
|
+
// Packages that generate separate scoped CSS outputs.
|
|
207
|
+
// Scope class is discovered from each package.json uds.scope.
|
|
208
|
+
// When entry is omitted, the package is scanned the same way as inherit.
|
|
209
|
+
// scoped: {
|
|
210
|
+
// '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'
|
|
211
|
+
// }
|
|
212
|
+
//
|
|
213
|
+
// Or use the expanded form for custom output paths:
|
|
214
|
+
// scoped: {
|
|
215
|
+
// '@your-org/shared-ui': {
|
|
216
|
+
// config: './packages/shared-ui/uds.config.ts',
|
|
217
|
+
// entry: './src',
|
|
218
|
+
// // outFile defaults to dist/shared-ui.css
|
|
219
|
+
// outFile: 'dist/shared-ui.css'
|
|
220
|
+
// },
|
|
221
|
+
// },
|
|
222
|
+
|
|
154
223
|
// CSS generation options (all optional)
|
|
155
224
|
// css: {
|
|
156
225
|
// safelist: [],
|
|
@@ -175,5 +244,5 @@ export default defineTheme({
|
|
|
175
244
|
};
|
|
176
245
|
|
|
177
246
|
//#endregion
|
|
178
|
-
export { findPackageSourceDir, loadConfigFile, scaffoldThemeConfig, scanDirectoriesForSafelist, scanDirectoryForSafelist };
|
|
247
|
+
export { findPackageRoot, findPackageSourceDir, getPackageUdsScope, loadConfigFile, scaffoldThemeConfig, scanDirectoriesForSafelist, scanDirectoryForSafelist };
|
|
179
248
|
//# sourceMappingURL=nodeUtils.js.map
|