@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.
Files changed (51) hide show
  1. package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
  2. package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
  3. package/dist/components/client/Toast/UDSToastConfigProvider.d.cts +5 -5
  4. package/dist/components/client/Toast/UDSToastConfigProvider.d.ts +5 -5
  5. package/dist/styles/styler.d.cts +34 -34
  6. package/dist/styles/styler.d.ts +34 -34
  7. package/dist/tailwind/dist/commands/css.cjs +17 -3
  8. package/dist/tailwind/dist/commands/css.d.cts.map +1 -1
  9. package/dist/tailwind/dist/commands/css.d.ts.map +1 -1
  10. package/dist/tailwind/dist/commands/css.helpers.cjs +2 -1
  11. package/dist/tailwind/dist/commands/css.helpers.js +2 -1
  12. package/dist/tailwind/dist/commands/css.helpers.js.map +1 -1
  13. package/dist/tailwind/dist/commands/css.js +17 -3
  14. package/dist/tailwind/dist/commands/css.js.map +1 -1
  15. package/dist/tailwind/dist/css/generate.cjs +3 -0
  16. package/dist/tailwind/dist/css/generate.helpers.cjs +14 -6
  17. package/dist/tailwind/dist/css/generate.helpers.js +15 -7
  18. package/dist/tailwind/dist/css/generate.helpers.js.map +1 -1
  19. package/dist/tailwind/dist/css/generate.js +3 -0
  20. package/dist/tailwind/dist/css/generate.js.map +1 -1
  21. package/dist/tailwind/dist/css/nodeUtils.cjs +91 -20
  22. package/dist/tailwind/dist/css/nodeUtils.js +90 -21
  23. package/dist/tailwind/dist/css/nodeUtils.js.map +1 -1
  24. package/dist/tailwind/dist/css/postcss.cjs +22 -1
  25. package/dist/tailwind/dist/css/postcss.helpers.cjs +12 -1
  26. package/dist/tailwind/dist/css/postcss.helpers.js +11 -1
  27. package/dist/tailwind/dist/css/postcss.helpers.js.map +1 -1
  28. package/dist/tailwind/dist/css/postcss.js +22 -2
  29. package/dist/tailwind/dist/css/postcss.js.map +1 -1
  30. package/dist/tailwind/dist/css/runner.cjs +171 -20
  31. package/dist/tailwind/dist/css/runner.helpers.cjs +58 -6
  32. package/dist/tailwind/dist/css/runner.helpers.js +54 -7
  33. package/dist/tailwind/dist/css/runner.helpers.js.map +1 -1
  34. package/dist/tailwind/dist/css/runner.js +172 -20
  35. package/dist/tailwind/dist/css/runner.js.map +1 -1
  36. package/dist/tailwind/dist/css/theme.d.cts +11 -0
  37. package/dist/tailwind/dist/css/theme.d.cts.map +1 -1
  38. package/dist/tailwind/dist/css/theme.d.ts +11 -0
  39. package/dist/tailwind/dist/css/theme.d.ts.map +1 -1
  40. package/dist/tailwind/dist/css/theme.js.map +1 -1
  41. package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +26 -3
  42. package/dist/tailwind/dist/purger/optimized/ast/expressions.js +26 -3
  43. package/dist/tailwind/dist/purger/optimized/ast/expressions.js.map +1 -1
  44. package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.cts +1 -1
  45. package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.ts +1 -1
  46. package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.cts +4 -4
  47. package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.ts +4 -4
  48. package/dist/uds/generated/componentData.cjs +1152 -1152
  49. package/dist/uds/generated/componentData.js +1152 -1152
  50. package/generated/componentData.json +1738 -1738
  51. 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
- const savedBytesGzip = optimizationStats.originalSizeGzip - options.sizeGzipBytes;
127
- if (savedBytesGzip > 0) print(` Optimized: saved ${require_utils.formatBytes(savedBytesGzip)} gzip (${optimizationStats.fontFacesRemoved} unused @font-face, ${optimizationStats.emptyRulesRemoved} empty rules removed)`);
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}ms`);
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
- const savedBytesGzip = optimizationStats.originalSizeGzip - options.sizeGzipBytes;
120
- if (savedBytesGzip > 0) print(` Optimized: saved ${formatBytes(savedBytesGzip)} gzip (${optimizationStats.fontFacesRemoved} unused @font-face, ${optimizationStats.emptyRulesRemoved} empty rules removed)`);
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}ms`);
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":";;;;;;;;;;;;;;;;;;;AAwCA,MAAM,uBAAuB,eAA4D;CACvF,MAAM,YAAY,YAAY,cAAc;CAC5C,MAAM,qBACJ,aAAa,OAAO,cAAc,WAAY,UAAU,YAAY,EAAE,GAAI,EAAE;AAE9E,QAAO,CAAC,GAAG,uBAAuB,GAAG,mBAAmB;;AAG1D,MAAM,sBAAsB,eAAiD;CAC3E,MAAM,qBAAqB,YAAY;CACvC,MAAM,iBAAiB,oBAAoB,YAAY;CACvD,MAAM,YAAY,oBAAoB;AAEtC,QAAO;EACL,iBAAiB,YAAY,cAAc;EAC3C,4BAA4B,YAAY,yBAAyB;EACjE;EACA,iBAAiB,kBAAkB,cAAc;EAClD;;AAGH,MAAM,mBAAmB,eAA4C;AAGnE,SAFoB,MAAM,QAAQ,WAAW,GAAG,aAAa,CAAC,WAAW,EAEtD,KAAK,QACtB,6BAA6B,IAAI,GAAG,MAAM,KAAK,KAAK,KAAK,+BAA+B,CACzF;;AAGH,MAAM,wBAAwB,gBAC5B,YAAY,KAAK,gBAAgB;CAAE,KAAK;CAAY,WAAW;CAAQ,EAAE;AAE3E,MAAM,iCAAiC,aAAyC;CAC9E,MAAM,kBAAkB,IAAI,IAAI,4BAA4B,CAAC;CAC7D,MAAM,yBAAyB,SAAS,QACrC,UAA2B,OAAO,UAAU,YAAY,gBAAgB,IAAI,MAAM,CACpF;AAED,KAAI,uBAAuB,WAAW,EACpC,QAAO,EAAE;AAGX,QAAO,CAAC,eAAe,uBAAuB,KAAK,IAAI,CAAC,UAAU;;AAGpE,MAAM,0BAA0B,eAAgC;CAC9D,MAAM,aAAa,eAAe;AAElC,QAAO,OAAO,QAAQ,WAAW,CAC9B,KAAK,CAAC,UAAU,kBAAkB;AAMjC,SAAO,GALgB,aAAa,GAAG,WAAW,GAAG,aAAa,SAKzC,KAJC,OAAO,QAAQ,aAAa,CACnD,KAAK,CAAC,UAAU,WAAW,GAAG,SAAS,IAAI,MAAM,GAAG,CACpD,KAAK,IAAI,CAEoC;GAChD,CACD,KAAK,IAAI;;AAGd,MAAM,wBAAwB,YAOA;AAkB5B,QAjBe,YAAY;EACzB,SAAS;GACP,GAAG,gBAAgB,QAAQ,WAAW;GACtC,GAAG,qBAAqB,8BAA8B,QAAQ,SAAS,CAAC;GACxE,GAAG,qBAAqB,QAAQ,eAAe,EAAE,CAAC;GACnD;EACD,UAAU,QAAQ;EAClB,aAAa,EAAE,WAAW,QAAQ,iBAAiB;EACnD,SAAS,CACP,eAAe;GACb,QAAQ,QAAQ;GAChB,6BAA6B,CAAC,QAAQ;GACtC,uBAAuB;GACxB,CAAC,CACH;EACF,CAAC;;AAKJ,MAAM,sBACJ,oBAC6B;AAC7B,KAAI,gBAAgB,WAAW,EAC7B,QAAO,CAAC,UAAU,CAA2B;AAG/C,QAAO;EACL,aAAa,EAAE,UAAU,iBAAiB,CAAC;EAC3C,UAAU;EACV,qBAAqB;EACtB;;AAGH,MAAM,uBAAuB,YAKG;CAC9B,MAAM,UAAoC,CAAC,QAAQ,gBAAgB,cAAc,CAAC;AAElF,KAAI,QAAQ,gBACV,SAAQ,KAAK,GAAG,mBAAmB,QAAQ,gBAAgB,CAAC;AAG9D,KAAI,QAAQ,WACV,SAAQ,KAAK,aAAa,QAAQ,WAAW,CAA2B;AAG1E,QAAO;;AAGT,MAAM,0BAA0B,OAAO,KAAa,eAAyC;AAC3F,KAAI,CAAC,WACH,QAAO;AAUT,SAPkB,MAAM,QAAQ,CAC9B,qCAAqC,WAAW,EAChD,kCAAkC,WAAW,CAC9C,CAAC,CAAC,QAAQ,KAAK,EACd,MAAM,QACP,CAAC,EAEe;;AAGnB,MAAM,uBAAuB,OAAO,YAe9B;AACJ,KAAI,CAAC,QAAQ,eACX,QAAO,EAAE,KAAK,QAAQ,KAAK;CAG7B,MAAM,sBAA0C;EAC9C,mBAAmB,QAAQ,oBAAoB;EAC/C,kBAAkB,QAAQ,oBAAoB;EAC9C,6BAA6B,QAAQ,oBAAoB;EACzD,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACrB;CAED,MAAM,YAAY,MAAM,YAAY,QAAQ,KAAK,oBAAoB;AACrE,QAAO;EACL,KAAK,UAAU;EACf,mBAAmB;GACjB,cAAc,UAAU,MAAM;GAC9B,kBAAkB,UAAU,MAAM;GAClC,kBAAkB,UAAU,MAAM;GAClC,mBAAmB,UAAU,MAAM;GACnC,kBAAkB,UAAU,WAAW;GACxC;EACF;;AAGH,MAAM,wBAAwB,YAqBlB;CACV,MAAM,EAAE,OAAO,SAAS,MAAM,WAAW;CACzC,MAAM,kBAAkB,eAA+B;EACrD,MAAM,eAAe,KAAK,SAAS,QAAQ,KAAK,WAAW;AAC3D,SAAO,aAAa,WAAW,IAAI,MAAM;;AAG3C,OAAM,GAAG;AACT,OAAM,GAAG,QAAQ,UAAU,CAAC,GAAG,KAAK,eAAe,QAAQ,WAAW,CAAC,GAAG;AAC1E,OAAM,GAAG,QAAQ,SAAS,GAAG;AAC7B,OAAM,qBAAqB,QAAQ,oBAAoB;AACvD,KAAI,QAAQ,WAAW,QAAQ,oBAAoB,QAAQ,iBAAiB,SAAS,EACnF,EAAC,GAAG,IAAI,IAAI,QAAQ,iBAAiB,CAAC,CACnC,MAAM,MAAM,UAAU,KAAK,cAAc,MAAM,CAAC,CAChD,SAAS,aAAa,MAAM,WAAW,KAAK,eAAe,SAAS,CAAC,GAAG,CAAC;AAE9E,OAAM,eAAe,QAAQ,aAAa;AAC1C,OACE,YAAY,YAAY,QAAQ,UAAU,CAAC,IAAI,YAAY,QAAQ,cAAc,CAAC,WACnF;CAED,MAAM,oBAAoB,QAAQ;AAClC,KAAI,mBAAmB;AAErB,MADuB,kBAAkB,mBAAmB,QAAQ,gBAC/C,GAAG;AACtB,OAAI,kBAAkB,mBAAmB,EACvC,OAAM,mBAAmB,kBAAkB,iBAAiB,oBAAoB;AAElF,OAAI,kBAAkB,oBAAoB,EACxC,OAAM,mBAAmB,kBAAkB,kBAAkB,cAAc;;AAI/E,MAAI,kBAAkB,iBAAiB,SAAS,GAAG;AACjD,SAAM,MAAM,OAAO,uBAAuB,GAAG;AAC7C,qBAAkB,iBAAiB,SAAS,UAAU,MAAM,SAAS,OAAO,IAAI,CAAC,GAAG,QAAQ,CAAC;;;AAIjG,OAAM,YAAY,kBAAkB,QAAQ,SAAS,GAAG;AACxD,KAAI,QAAQ,MACV,OAAM,aAAa,KAAK,QAAQ,MAAM,GAAG"}
@@ -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: results.flatMap((result) => result.safelist),
46
- components: [...new Set(results.flatMap((result) => result.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 require = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
123
+ const requireFromWorkspace = (0, node_module.createRequire)(node_path.default.join(workspaceDir, "package.json"));
87
124
  try {
88
- const resolvedPackageJson = require.resolve(node_path.default.join(packageName, "package.json"), { paths: [workspaceDir] });
125
+ const resolvedPackageJson = requireFromWorkspace.resolve(node_path.default.join(packageName, "package.json"));
89
126
  return node_path.default.dirname(resolvedPackageJson);
90
127
  } catch {
91
- return null;
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
- try {
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
- const workspaceDir = process.cwd();
123
- const monorepoRoot = findMonorepoRoot(workspaceDir);
124
- let packageRoot = resolvePackageRoot(workspaceDir, packageName);
125
- if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
126
- return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
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: results.flatMap((result) => result.safelist),
42
- components: [...new Set(results.flatMap((result) => result.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 require = createRequire(import.meta.url);
119
+ const requireFromWorkspace = createRequire(path.join(workspaceDir, "package.json"));
83
120
  try {
84
- const resolvedPackageJson = require.resolve(path.join(packageName, "package.json"), { paths: [workspaceDir] });
121
+ const resolvedPackageJson = requireFromWorkspace.resolve(path.join(packageName, "package.json"));
85
122
  return path.dirname(resolvedPackageJson);
86
123
  } catch {
87
- return null;
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
- try {
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
- const workspaceDir = process.cwd();
119
- const monorepoRoot = findMonorepoRoot(workspaceDir);
120
- let packageRoot = resolvePackageRoot(workspaceDir, packageName);
121
- if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
122
- return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
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