@yahoo/uds 3.122.0 → 3.122.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +2 -2
  2. package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +2 -2
  3. package/dist/components/SvgFloatingOverlay.cjs +2 -2
  4. package/dist/components/SvgFloatingOverlay.d.cts +2 -0
  5. package/dist/components/SvgFloatingOverlay.d.ts +2 -0
  6. package/dist/components/SvgFloatingOverlay.js +2 -2
  7. package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
  8. package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
  9. package/dist/components/client/Popover/PopoverContent.cjs +2 -0
  10. package/dist/components/client/Popover/PopoverContent.js +2 -0
  11. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.cts +1 -1
  12. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.ts +1 -1
  13. package/dist/components/client/Tooltip/TooltipContent.cjs +3 -0
  14. package/dist/components/client/Tooltip/TooltipContent.js +3 -0
  15. package/dist/components/experimental/client/index.cjs +1 -14
  16. package/dist/components/experimental/client/index.d.cts +1 -2
  17. package/dist/components/experimental/client/index.d.ts +1 -2
  18. package/dist/components/experimental/client/index.js +1 -2
  19. package/dist/components/experimental/index.cjs +2 -24
  20. package/dist/components/experimental/index.d.cts +1 -2
  21. package/dist/components/experimental/index.d.ts +1 -2
  22. package/dist/components/experimental/index.js +2 -13
  23. package/dist/styles/styler.d.cts +2 -2
  24. package/dist/styles/styler.d.ts +2 -2
  25. package/dist/tailwind/dist/css/generate.cjs +6 -1
  26. package/dist/tailwind/dist/css/generate.d.cts.map +1 -1
  27. package/dist/tailwind/dist/css/generate.d.ts.map +1 -1
  28. package/dist/tailwind/dist/css/generate.helpers.cjs +22 -3
  29. package/dist/tailwind/dist/css/generate.helpers.js +20 -2
  30. package/dist/tailwind/dist/css/generate.helpers.js.map +1 -1
  31. package/dist/tailwind/dist/css/generate.js +8 -3
  32. package/dist/tailwind/dist/css/generate.js.map +1 -1
  33. package/dist/tailwind/dist/css/runner.cjs +5 -1
  34. package/dist/tailwind/dist/css/runner.js +6 -2
  35. package/dist/tailwind/dist/css/runner.js.map +1 -1
  36. package/dist/tailwind/dist/purger/optimized/purge.cjs +1 -0
  37. package/dist/tailwind/dist/purger/optimized/purge.js +2 -1
  38. package/dist/tailwind/dist/purger/optimized/purge.js.map +1 -1
  39. package/dist/tailwind/dist/purger/optimized/utils/safelist.cjs +7 -0
  40. package/dist/tailwind/dist/purger/optimized/utils/safelist.js +7 -1
  41. package/dist/tailwind/dist/purger/optimized/utils/safelist.js.map +1 -1
  42. package/dist/uds/generated/componentData.cjs +1142 -1165
  43. package/dist/uds/generated/componentData.js +1138 -1155
  44. package/dist/uds/generated/tailwindPurge.cjs +6 -140
  45. package/dist/uds/generated/tailwindPurge.js +6 -140
  46. package/dist/utils/getUnscaledAnchorRect.cjs +34 -0
  47. package/dist/utils/getUnscaledAnchorRect.d.cts +17 -0
  48. package/dist/utils/getUnscaledAnchorRect.d.ts +17 -0
  49. package/dist/utils/getUnscaledAnchorRect.js +32 -0
  50. package/generated/componentData.json +1381 -1398
  51. package/generated/tailwindPurge.ts +3 -3
  52. package/package.json +1 -1
  53. package/dist/components/experimental/client/ExperimentalPopover.cjs +0 -54
  54. package/dist/components/experimental/client/ExperimentalPopover.d.cts +0 -40
  55. package/dist/components/experimental/client/ExperimentalPopover.d.ts +0 -40
  56. package/dist/components/experimental/client/ExperimentalPopover.js +0 -42
@@ -1,7 +1,9 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
2
2
  const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
3
3
  const require_entryPoints = require('../utils/entryPoints.cjs');
4
- const require_safelist = require('../icons/src/safelist.cjs');
4
+ const require_safelist = require('../purger/optimized/utils/safelist.cjs');
5
+ const require_safelist$1 = require('../icons/src/safelist.cjs');
6
+ const require_getIconStyles = require('../tailwind/components/getIconStyles.cjs');
5
7
  const require_plugin = require('../plugin.cjs');
6
8
  const require_optimizeCSS = require('../utils/optimizeCSS.cjs');
7
9
  const require_postcssPreserveVars = require('../utils/postcssPreserveVars.cjs');
@@ -24,7 +26,7 @@ tailwindcss = require_runtime.__toESM(tailwindcss);
24
26
  const getPruneVarSafelist = (cssOptions) => {
25
27
  const pruneVars = cssOptions?.optimization?.pruneVars;
26
28
  const configuredSafelist = pruneVars && typeof pruneVars === "object" ? pruneVars.safelist ?? [] : [];
27
- return [...require_safelist.iconPruneVarsSafelist, ...configuredSafelist];
29
+ return [...require_safelist$1.iconPruneVarsSafelist, ...configuredSafelist];
28
30
  };
29
31
  const getCssFeatureFlags = (cssOptions) => {
30
32
  const optimizationConfig = cssOptions?.optimization;
@@ -44,9 +46,25 @@ const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
44
46
  raw: rawContent,
45
47
  extension: "html"
46
48
  }));
49
+ const getInternalSafelistRawContent = (safelist) => {
50
+ const internalClasses = new Set(require_safelist.getInternalSafelistClasses());
51
+ const matchedInternalClasses = safelist.filter((entry) => typeof entry === "string" && internalClasses.has(entry));
52
+ if (matchedInternalClasses.length === 0) return [];
53
+ return [`<div class="${matchedInternalClasses.join(" ")}"></div>`];
54
+ };
55
+ const getInternalIconModeCss = (scopeClass) => {
56
+ const iconStyles = require_getIconStyles.getIconStyles();
57
+ return Object.entries(iconStyles).map(([selector, declarations]) => {
58
+ return `${scopeClass ? `${scopeClass} ${selector}` : selector} { ${Object.entries(declarations).map(([property, value]) => `${property}: ${value};`).join(" ")} }`;
59
+ }).join(" ");
60
+ };
47
61
  const createTailwindPlugin = (options) => {
48
62
  return (0, tailwindcss.default)({
49
- content: [...getContentGlobs(options.contentDir), ...getRawContentEntries(options.rawContents ?? [])],
63
+ content: [
64
+ ...getContentGlobs(options.contentDir),
65
+ ...getRawContentEntries(getInternalSafelistRawContent(options.safelist)),
66
+ ...getRawContentEntries(options.rawContents ?? [])
67
+ ],
50
68
  safelist: options.safelist,
51
69
  corePlugins: { preflight: options.enablePreflight },
52
70
  plugins: [require_plugin.tailwindPlugin({
@@ -121,6 +139,7 @@ exports.applyScopedColorModeFix = applyScopedColorModeFix;
121
139
  exports.buildPostcssPlugins = buildPostcssPlugins;
122
140
  exports.createTailwindPlugin = createTailwindPlugin;
123
141
  exports.getCssFeatureFlags = getCssFeatureFlags;
142
+ exports.getInternalIconModeCss = getInternalIconModeCss;
124
143
  exports.getPruneVarSafelist = getPruneVarSafelist;
125
144
  exports.optimizeGeneratedCss = optimizeGeneratedCss;
126
145
  exports.printSimpleModeStats = printSimpleModeStats;
@@ -1,6 +1,8 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
2
2
  import { hasAllowedEntryFileExtension } from "../utils/entryPoints.js";
3
+ import { getInternalSafelistClasses } from "../purger/optimized/utils/safelist.js";
3
4
  import { iconPruneVarsSafelist } from "../icons/src/safelist.js";
5
+ import { getIconStyles } from "../tailwind/components/getIconStyles.js";
4
6
  import { tailwindPlugin } from "../plugin.js";
5
7
  import { optimizeCSS } from "../utils/optimizeCSS.js";
6
8
  import { preserveVars, preserveVarsCleanup } from "../utils/postcssPreserveVars.js";
@@ -37,9 +39,25 @@ const getRawContentEntries = (rawContents) => rawContents.map((rawContent) => ({
37
39
  raw: rawContent,
38
40
  extension: "html"
39
41
  }));
42
+ const getInternalSafelistRawContent = (safelist) => {
43
+ const internalClasses = new Set(getInternalSafelistClasses());
44
+ const matchedInternalClasses = safelist.filter((entry) => typeof entry === "string" && internalClasses.has(entry));
45
+ if (matchedInternalClasses.length === 0) return [];
46
+ return [`<div class="${matchedInternalClasses.join(" ")}"></div>`];
47
+ };
48
+ const getInternalIconModeCss = (scopeClass) => {
49
+ const iconStyles = getIconStyles();
50
+ return Object.entries(iconStyles).map(([selector, declarations]) => {
51
+ return `${scopeClass ? `${scopeClass} ${selector}` : selector} { ${Object.entries(declarations).map(([property, value]) => `${property}: ${value};`).join(" ")} }`;
52
+ }).join(" ");
53
+ };
40
54
  const createTailwindPlugin = (options) => {
41
55
  return tailwindcss({
42
- content: [...getContentGlobs(options.contentDir), ...getRawContentEntries(options.rawContents ?? [])],
56
+ content: [
57
+ ...getContentGlobs(options.contentDir),
58
+ ...getRawContentEntries(getInternalSafelistRawContent(options.safelist)),
59
+ ...getRawContentEntries(options.rawContents ?? [])
60
+ ],
43
61
  safelist: options.safelist,
44
62
  corePlugins: { preflight: options.enablePreflight },
45
63
  plugins: [tailwindPlugin({
@@ -110,5 +128,5 @@ const printSimpleModeStats = (options) => {
110
128
  };
111
129
 
112
130
  //#endregion
113
- export { applyScopedColorModeFix, buildPostcssPlugins, createTailwindPlugin, getCssFeatureFlags, getPruneVarSafelist, optimizeGeneratedCss, printSimpleModeStats };
131
+ export { applyScopedColorModeFix, buildPostcssPlugins, createTailwindPlugin, getCssFeatureFlags, getInternalIconModeCss, getPruneVarSafelist, optimizeGeneratedCss, printSimpleModeStats };
114
132
  //# sourceMappingURL=generate.helpers.js.map
@@ -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 { 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 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(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 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 } 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":";;;;;;;;;;;;;;;;;;AAuCA,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,uBAAuB,CACjF;;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;AAOT,SAJkB,MAAM,QAAQ,CAAC,kCAAkC,WAAW,CAAC,CAAC,CAAC,QAAQ,KAAK,EAC5F,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,YAkBlB;CACV,MAAM,EAAE,OAAO,SAAS,MAAM,WAAW;AAEzC,OAAM,GAAG;AACT,OAAM,GAAG,QAAQ,UAAU,CAAC,GAAG,KAAK,QAAQ,WAAW,GAAG;AAC1D,OAAM,GAAG,QAAQ,SAAS,GAAG;AAC7B,OAAM,qBAAqB,QAAQ,oBAAoB;AACvD,OAAM,eAAe,QAAQ,aAAa;AAC1C,OACE,YAAY,YAAY,QAAQ,UAAU,CAAC,IAAI,YAAY,QAAQ,cAAc,CAAC,WACnF;CAED,MAAM,oBAAoB,QAAQ;AAClC,KAAI,mBAAmB;EACrB,MAAM,iBAAiB,kBAAkB,mBAAmB,QAAQ;AACpE,MAAI,iBAAiB,EACnB,OACE,uBAAuB,YAAY,eAAe,CAAC,SAAS,kBAAkB,iBAAiB,sBAAsB,kBAAkB,kBAAkB,uBAC1J;AAGH,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,QAAQ,SAAS,IAAI;AACvC,KAAI,QAAQ,MACV,OAAM,aAAa,KAAK,QAAQ,MAAM,GAAG"}
@@ -5,9 +5,9 @@ import { spinStop } from "../cli/dist/lib/spinner.js";
5
5
  import { resolveEntryPaths } from "../utils/entryPoints.js";
6
6
  import { loadConfigFile, scanDirectoriesForSafelist } from "./nodeUtils.js";
7
7
  import { defaultTokensConfig } from "../config/dist/index.js";
8
- import { deduplicateSafelist, getThemeAndScaleClasses } from "../purger/optimized/utils/safelist.js";
8
+ import { deduplicateSafelist, getInternalSafelistClasses, getThemeAndScaleClasses } from "../purger/optimized/utils/safelist.js";
9
9
  import { extractRuntimeConfigValues, extractVariantDefaults, getConfigurableCssVariables, getMotionVarPrefixes } from "./utils.js";
10
- import { applyScopedColorModeFix, buildPostcssPlugins, createTailwindPlugin, getCssFeatureFlags, optimizeGeneratedCss, printSimpleModeStats } from "./generate.helpers.js";
10
+ import { applyScopedColorModeFix, buildPostcssPlugins, createTailwindPlugin, getCssFeatureFlags, getInternalIconModeCss, optimizeGeneratedCss, printSimpleModeStats } from "./generate.helpers.js";
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
13
  import { gzipSync } from "node:zlib";
@@ -48,6 +48,7 @@ const generateCSS = async (safelist, config, options) => {
48
48
  safeVarPrefixes: options?.safeVarPrefixes ?? [],
49
49
  scopeClass
50
50
  })).process(sourceCSS, { from: void 0 })).css, scopeClass);
51
+ if (!css.includes("uds-light-mode-icon") || !css.includes("uds-dark-mode-icon")) css = `${css} ${getInternalIconModeCss(scopeClass)}`.trim();
51
52
  const optimizedCss = await optimizeGeneratedCss({
52
53
  css,
53
54
  shouldOptimize: cssFlags.shouldOptimize,
@@ -89,7 +90,11 @@ const generateSimpleModeCSS = async (options) => {
89
90
  const allClasses = [...scanResult.safelist];
90
91
  const allComponents = new Set(scanResult.components);
91
92
  const packageDirs = [...new Set(resolvedEntries.map((entry) => entry.kind === "directory" ? entry.absolutePath : entry.watchDirectory))];
92
- const cssResult = await generateCSS(deduplicateSafelist([...allClasses, ...getThemeAndScaleClasses(colorModes)]), tokensConfig, {
93
+ const cssResult = await generateCSS(deduplicateSafelist([
94
+ ...allClasses,
95
+ ...getThemeAndScaleClasses(colorModes),
96
+ ...getInternalSafelistClasses()
97
+ ]), tokensConfig, {
93
98
  scope: options.scope,
94
99
  contentDir: entryDirs,
95
100
  safeVarPrefixes: [...getMotionVarPrefixes(options.componentData, [...allComponents]), ...getConfigurableCssVariables()]
@@ -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 { deduplicateSafelist, getThemeAndScaleClasses } from '../purger/optimized';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { resolveEntryPaths } from '../utils/entryPoints';\nimport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getCssFeatureFlags,\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 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 = [...allClasses, ...getThemeAndScaleClasses(colorModes)];\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}): 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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"}
@@ -228,7 +228,11 @@ const runThemeMode = async (options, context) => {
228
228
  await promise;
229
229
  await processInheritedPackage(packageName);
230
230
  }, Promise.resolve());
231
- const mainSafelist = require_safelist.deduplicateSafelist([...inheritedClasses, ...require_safelist.getThemeAndScaleClasses(colorModes)]);
231
+ const mainSafelist = require_safelist.deduplicateSafelist([
232
+ ...inheritedClasses,
233
+ ...require_safelist.getThemeAndScaleClasses(colorModes),
234
+ ...require_safelist.getInternalSafelistClasses()
235
+ ]);
232
236
  const allMotionComponents = [...inheritedComponents];
233
237
  const mainCssResult = await require_generate.generateCSS([...themeConfig.css?.safelist ?? [], ...mainSafelist], appConfig, {
234
238
  scope: options.scope,
@@ -6,7 +6,7 @@ import { createLogger } from "../cli/dist/lib/logger.js";
6
6
  import { DEFAULT_ENTRY, resolveEntryPaths } from "../utils/entryPoints.js";
7
7
  import { findPackageSourceDir, loadConfigFile, scanDirectoriesForSafelist, scanDirectoryForSafelist } from "./nodeUtils.js";
8
8
  import { defaultTokensConfig } from "../config/dist/index.js";
9
- import { deduplicateSafelist, getThemeAndScaleClasses } from "../purger/optimized/utils/safelist.js";
9
+ import { deduplicateSafelist, getInternalSafelistClasses, getThemeAndScaleClasses } from "../purger/optimized/utils/safelist.js";
10
10
  import { extractRuntimeConfigValues, extractVariantDefaults, formatBytes, getConfigurableCssVariables, getMotionVarPrefixes } from "./utils.js";
11
11
  import { getPruneVarSafelist } from "./generate.helpers.js";
12
12
  import { generateCSS, generateSimpleModeCSS } from "./generate.js";
@@ -225,7 +225,11 @@ const runThemeMode = async (options, context) => {
225
225
  await promise;
226
226
  await processInheritedPackage(packageName);
227
227
  }, Promise.resolve());
228
- const mainSafelist = deduplicateSafelist([...inheritedClasses, ...getThemeAndScaleClasses(colorModes)]);
228
+ const mainSafelist = deduplicateSafelist([
229
+ ...inheritedClasses,
230
+ ...getThemeAndScaleClasses(colorModes),
231
+ ...getInternalSafelistClasses()
232
+ ]);
229
233
  const allMotionComponents = [...inheritedComponents];
230
234
  const mainCssResult = await generateCSS([...themeConfig.css?.safelist ?? [], ...mainSafelist], appConfig, {
231
235
  scope: options.scope,
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","names":[],"sources":["../../src/css/runner.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { createLogger, gray, green, magenta, print, spinStart, spinStop } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport { deduplicateSafelist, getThemeAndScaleClasses } from '../purger/optimized/utils/safelist';\nimport type { EntryValue, ResolvedEntryPath } from '../utils/entryPoints';\nimport { DEFAULT_ENTRY, resolveEntryPaths } from '../utils/entryPoints';\nimport { generateCSS, generateSimpleModeCSS } from './generate';\nimport { getPruneVarSafelist } from './generate.helpers';\nimport {\n findPackageSourceDir,\n loadConfigFile,\n scanDirectoriesForSafelist,\n scanDirectoryForSafelist,\n} from './nodeUtils';\nimport { getMainCssSummaryMessage, getWatchDirectoryGroups } from './runner.helpers';\nimport type { UDSThemeConfig, UDSThemeConfigInput, UDSThemeContext } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n formatBytes,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\ntype CssCommandContext = {\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n};\n\ntype CssCommandOptions = {\n workspaceDir: string;\n outFile: string;\n themeConfigPath: string;\n scope?: string;\n entryOption?: EntryValue;\n configOption?: string;\n watch: boolean;\n silent: boolean;\n};\n\ntype ThemeModeSetup = {\n themeConfig: UDSThemeConfig;\n colorModes: ('dark' | 'light')[];\n entries: ResolvedEntryPath[];\n appConfig: UniversalTokensConfig;\n appVariantDefaults: ReturnType<typeof extractVariantDefaults>;\n runtimeConfigValues: ReturnType<typeof extractRuntimeConfigValues>;\n effectiveSilent: boolean;\n};\n\nconst SOURCE_FILE_PATTERN = /\\.(jsx?|tsx?)$/i;\n\ntype WatchTarget = {\n watchPath: string;\n recursive: boolean;\n fileNames?: string[];\n};\n\nconst getWatchDirs = (dirs: string[]): string[] => [\n ...new Set(dirs.filter((dir) => !dir.split(path.sep).includes('node_modules'))),\n];\n\nconst isCoveredByRecursiveWatch = (watchPath: string, targetPath: string): boolean =>\n targetPath === watchPath || targetPath.startsWith(`${watchPath}${path.sep}`);\n\nconst getEntryWatchTargets = (entries: ResolvedEntryPath[]): WatchTarget[] => {\n const directoryTargets = getWatchDirs(\n entries.filter((entry) => entry.kind === 'directory').map((entry) => entry.absolutePath),\n ).map((watchPath) => ({ watchPath, recursive: true }));\n\n const fileNamesByDirectory = new Map<string, Set<string>>();\n\n entries\n .filter(\n (entry): entry is ResolvedEntryPath & { kind: 'file'; fileName: string } =>\n entry.kind === 'file' && typeof entry.fileName === 'string',\n )\n .forEach((entry) => {\n if (\n directoryTargets.some((target) =>\n isCoveredByRecursiveWatch(target.watchPath, entry.absolutePath),\n )\n ) {\n return;\n }\n\n const fileNames = fileNamesByDirectory.get(entry.watchDirectory) ?? new Set<string>();\n fileNames.add(entry.fileName);\n fileNamesByDirectory.set(entry.watchDirectory, fileNames);\n });\n\n const fileTargets = [...fileNamesByDirectory.entries()].map(([watchPath, fileNames]) => ({\n watchPath,\n recursive: false,\n fileNames: [...fileNames],\n }));\n\n return [...directoryTargets, ...fileTargets];\n};\n\nconst watchSourceFiles = (targets: WatchTarget[], onFileChange: () => void): void => {\n targets.forEach((target) => {\n fs.watch(target.watchPath, { recursive: target.recursive }, (_eventType, filename) => {\n if (!filename || !SOURCE_FILE_PATTERN.test(filename)) {\n return;\n }\n\n if (target.fileNames && !target.fileNames.includes(path.basename(String(filename)))) {\n return;\n }\n\n onFileChange();\n });\n });\n};\n\nconst createDebouncedAction = (action: () => void, delayMs: number): (() => void) => {\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n return () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(action, delayMs);\n };\n};\n\nconst createQueuedRegenerator = <T>(options: {\n onStart?: () => void;\n onSuccess?: (result: T) => void;\n onError: (message: string) => void;\n regenerateOnce: () => Promise<T>;\n}): (() => Promise<void>) => {\n let isGenerating = false;\n let pendingRegenerate = false;\n\n const regenerate = async (): Promise<void> => {\n if (isGenerating) {\n pendingRegenerate = true;\n return;\n }\n\n isGenerating = true;\n try {\n options.onStart?.();\n const result = await options.regenerateOnce();\n options.onSuccess?.(result);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'CSS generation failed';\n options.onError(message);\n } finally {\n isGenerating = false;\n\n if (pendingRegenerate) {\n pendingRegenerate = false;\n await regenerate();\n }\n }\n };\n\n return regenerate;\n};\n\nconst runCssCommand = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const themeConfigExists = fs.existsSync(\n path.join(options.workspaceDir, String(options.themeConfigPath)),\n );\n\n if (!themeConfigExists) {\n await runSimpleMode(options, context);\n return;\n }\n\n await runThemeMode(options, context);\n};\n\nconst runSimpleMode = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const entry = options.entryOption ?? DEFAULT_ENTRY;\n const configPath = typeof options.configOption === 'string' ? options.configOption : undefined;\n\n if (!options.watch && !options.silent) {\n spinStart('Generating CSS...');\n }\n\n try {\n const result = await generateSimpleModeCSS({\n workspaceDir: options.workspaceDir,\n entry,\n outFile: String(options.outFile),\n variants: context.variants,\n autoVariants: context.autoVariants,\n componentData: context.componentData,\n scope: options.scope,\n configPath,\n isWatch: options.watch,\n silent: options.silent,\n });\n\n if (options.watch) {\n await runSimpleModeWatch(options, context, entry, configPath, result.packageDirs ?? []);\n }\n } catch (error) {\n spinStop('❌', error instanceof Error ? error.message : 'CSS generation failed');\n process.exitCode = 1;\n }\n};\n\nconst runSimpleModeWatch = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n entry: EntryValue,\n configPath: string | undefined,\n packageDirs: string[],\n): Promise<void> => {\n const resolvedEntries = resolveEntryPaths(entry, options.workspaceDir);\n const entryWatchTargets = getEntryWatchTargets(resolvedEntries);\n const fallbackTargets = getWatchDirs(packageDirs).map((watchPath) => ({\n watchPath,\n recursive: true,\n }));\n const watchTargets = packageDirs.length > 0 ? fallbackTargets : entryWatchTargets;\n\n if (!options.silent) {\n print('');\n print(`${magenta('Watching for changes...')}`);\n watchTargets.forEach((target) => print(` ${gray('•')} ${target.watchPath}`));\n print(`${gray('Press Ctrl+C to stop')}`);\n print('');\n }\n\n const regenerate = createQueuedRegenerator({\n onStart: () => {\n if (!options.silent) {\n const timestamp = new Date().toLocaleTimeString();\n print(`${gray(`[${timestamp}]`)} Change detected, regenerating...`);\n }\n },\n regenerateOnce: async () => {\n await generateSimpleModeCSS({\n workspaceDir: options.workspaceDir,\n entry,\n outFile: String(options.outFile),\n variants: context.variants,\n autoVariants: context.autoVariants,\n componentData: context.componentData,\n scope: options.scope,\n configPath,\n isWatch: true,\n silent: true,\n });\n },\n onSuccess: () => {\n if (!options.silent) {\n const updatedAt = new Date().toLocaleTimeString();\n print(`${gray(`[${updatedAt}]`)} ${green('CSS updated')}`);\n print('');\n }\n },\n onError: (message) => {\n print(`Error: ${message}`);\n },\n });\n\n watchSourceFiles(\n watchTargets,\n createDebouncedAction(() => {\n void regenerate();\n }, 100),\n );\n\n await new Promise(() => {});\n};\n\nconst loadThemeModeSetup = async (options: CssCommandOptions): Promise<ThemeModeSetup | null> => {\n const themeConfigInput = await loadConfigFile<UDSThemeConfigInput>(\n String(options.themeConfigPath),\n );\n if (!themeConfigInput) {\n return null;\n }\n\n const themeContext: UDSThemeContext = {\n cwd: options.workspaceDir,\n watch: options.watch,\n };\n const themeConfig: UDSThemeConfig =\n typeof themeConfigInput === 'function'\n ? await themeConfigInput(themeContext)\n : themeConfigInput;\n\n let appConfig: UniversalTokensConfig = defaultTokensConfig;\n if (themeConfig.config) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(themeConfig.config);\n if (loadedConfig) {\n appConfig = loadedConfig;\n }\n }\n\n return {\n themeConfig,\n colorModes: themeConfig.colorModes ?? ['dark'],\n entries: resolveEntryPaths(themeConfig.entry, options.workspaceDir),\n appConfig,\n appVariantDefaults: extractVariantDefaults(appConfig),\n runtimeConfigValues: extractRuntimeConfigValues(appConfig),\n effectiveSilent: options.silent || themeConfig.silent === true,\n };\n};\n\nconst runThemeMode = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const workspaceDir = options.workspaceDir;\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(workspaceDir, String(options.outFile));\n let effectiveSilent = options.silent;\n let log = createLogger({ silent: effectiveSilent });\n\n log.spinStart('Loading theme configuration...');\n\n try {\n const setup = await loadThemeModeSetup(options);\n if (!setup) {\n log.spinStop('❌', `Theme config not found: ${options.themeConfigPath}`);\n process.exitCode = 1;\n return;\n }\n\n const { themeConfig, colorModes, entries, appConfig, appVariantDefaults, runtimeConfigValues } =\n setup;\n effectiveSilent = setup.effectiveSilent;\n log = createLogger({ silent: effectiveSilent });\n const entryDirs = entries.map((entry) => entry.absolutePath);\n\n if (!effectiveSilent) {\n log.spinStop('✅', 'Theme configuration loaded');\n }\n\n if (themeConfig.config && appConfig === defaultTokensConfig) {\n log.warn(`App config not found: ${themeConfig.config}, using defaults`);\n }\n const packageDirs: string[] = [];\n\n const generateThemeModeCSS = async (opts?: { isWatch?: boolean }) => {\n const genStartTime = performance.now();\n const genLog = opts?.isWatch ? createLogger({ silent: true }) : log;\n\n genLog.spinStart('Scanning app code...');\n const appScanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n context.variants,\n context.autoVariants,\n context.componentData,\n appVariantDefaults,\n runtimeConfigValues,\n );\n genLog.spinStop('✅', `Scanned ${appScanResult.filesScanned} files`);\n\n genLog.spinStart('Generating main CSS...');\n\n const inheritedClasses: string[] = [...appScanResult.safelist];\n const inheritedComponents = new Set<string>(appScanResult.components);\n\n const processInheritedPackage = async (packageName: string) => {\n genLog.spinStart(`Processing package: ${packageName}...`);\n\n const packageDir = findPackageSourceDir(packageName);\n if (!packageDir) {\n genLog.spinStop('⚠️', `Package not found: ${packageName}`);\n return;\n }\n\n if (!packageDirs.includes(packageDir)) {\n packageDirs.push(packageDir);\n }\n\n const packageScanResult = await scanDirectoryForSafelist(\n packageDir,\n colorModes,\n context.variants,\n context.autoVariants,\n context.componentData,\n appVariantDefaults,\n runtimeConfigValues,\n true,\n );\n inheritedClasses.push(...packageScanResult.safelist);\n packageScanResult.components.forEach((comp) => inheritedComponents.add(comp));\n genLog.spinStop('✅', `${packageName}: ${packageScanResult.filesScanned} files (inherit)`);\n };\n\n await (themeConfig.inherit ?? []).reduce(async (promise, packageName) => {\n await promise;\n await processInheritedPackage(packageName);\n }, Promise.resolve());\n\n const mainSafelist = deduplicateSafelist([\n ...inheritedClasses,\n ...getThemeAndScaleClasses(colorModes),\n ]);\n\n const allMotionComponents: string[] = [...inheritedComponents];\n\n const mainCssResult = await generateCSS(\n [...(themeConfig.css?.safelist ?? []), ...mainSafelist],\n appConfig,\n {\n scope: options.scope,\n contentDir: entryDirs,\n cssOptions: themeConfig.css,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(context.componentData, allMotionComponents),\n ...getConfigurableCssVariables(),\n ...getPruneVarSafelist(themeConfig.css),\n ],\n },\n );\n\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, mainCssResult.css);\n\n genLog.spinStop(\n '✅',\n getMainCssSummaryMessage({\n sizeGzipBytes: mainCssResult.sizeGzipBytes,\n optimizationStats: mainCssResult.optimizationStats,\n formatBytes,\n }),\n );\n\n const duration = Math.round(performance.now() - genStartTime);\n\n genLog.newline();\n genLog.print(green('CSS generation complete!'));\n genLog.newline();\n genLog.label('Output file:', outputPath);\n genLog.newline();\n genLog.print(`${magenta('Total time:')} ${duration}ms`);\n\n return { duration, outputPath, packageDirs };\n };\n\n await generateThemeModeCSS();\n\n if (options.watch) {\n const entryWatchTargets = getEntryWatchTargets(entries);\n const entryWatchDirs = getWatchDirs(entryWatchTargets.map((target) => target.watchPath));\n const { filteredPackageDirs } = getWatchDirectoryGroups(entryWatchDirs, [\n ...entryDirs,\n ...packageDirs,\n ]);\n\n if (!effectiveSilent) {\n log.newline();\n log.print(`${magenta('Watching for changes...')}`);\n entryDirs.forEach((entryDir) => {\n log.listItem(`App: ${entryDir}`);\n });\n filteredPackageDirs.forEach((dir) => {\n log.listItem(`Package: ${dir}`);\n });\n log.print(`${gray('Press Ctrl+C to stop')}`);\n log.newline();\n }\n\n const regenerate = createQueuedRegenerator({\n onStart: () => {\n if (!effectiveSilent) {\n const timestamp = new Date().toLocaleTimeString();\n log.print(`${gray(`[${timestamp}]`)} Change detected, regenerating...`);\n }\n },\n regenerateOnce: async () => generateThemeModeCSS({ isWatch: true }),\n onSuccess: (result) => {\n if (!effectiveSilent) {\n const updatedAt = new Date().toLocaleTimeString();\n log.print(`${gray(`[${updatedAt}]`)} ${green(`CSS updated (${result?.duration}ms)`)}`);\n log.newline();\n }\n },\n onError: (message) => {\n log.print(message);\n },\n });\n\n const watchDebounce = themeConfig.css?.watchDebounce ?? 100;\n\n watchSourceFiles(\n [\n ...entryWatchTargets,\n ...filteredPackageDirs\n .filter(\n (packageDir) =>\n !entryWatchTargets.some((target) =>\n isCoveredByRecursiveWatch(target.watchPath, packageDir),\n ),\n )\n .map((watchPath) => ({ watchPath, recursive: true })),\n ],\n createDebouncedAction(() => {\n void regenerate();\n }, watchDebounce),\n );\n\n await new Promise(() => {});\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'CSS generation failed';\n if (effectiveSilent) {\n spinStop('❌', message);\n } else {\n log.spinStop('❌', message);\n }\n process.exitCode = 1;\n }\n};\n\nexport { runCssCommand };\nexport type { CssCommandContext, CssCommandOptions };\n"],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","names":[],"sources":["../../src/css/runner.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { createLogger, gray, green, magenta, print, spinStart, spinStop } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n} from '../purger/optimized/utils/safelist';\nimport type { EntryValue, ResolvedEntryPath } from '../utils/entryPoints';\nimport { DEFAULT_ENTRY, resolveEntryPaths } from '../utils/entryPoints';\nimport { generateCSS, generateSimpleModeCSS } from './generate';\nimport { getPruneVarSafelist } from './generate.helpers';\nimport {\n findPackageSourceDir,\n loadConfigFile,\n scanDirectoriesForSafelist,\n scanDirectoryForSafelist,\n} from './nodeUtils';\nimport { getMainCssSummaryMessage, getWatchDirectoryGroups } from './runner.helpers';\nimport type { UDSThemeConfig, UDSThemeConfigInput, UDSThemeContext } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n formatBytes,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\ntype CssCommandContext = {\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n};\n\ntype CssCommandOptions = {\n workspaceDir: string;\n outFile: string;\n themeConfigPath: string;\n scope?: string;\n entryOption?: EntryValue;\n configOption?: string;\n watch: boolean;\n silent: boolean;\n};\n\ntype ThemeModeSetup = {\n themeConfig: UDSThemeConfig;\n colorModes: ('dark' | 'light')[];\n entries: ResolvedEntryPath[];\n appConfig: UniversalTokensConfig;\n appVariantDefaults: ReturnType<typeof extractVariantDefaults>;\n runtimeConfigValues: ReturnType<typeof extractRuntimeConfigValues>;\n effectiveSilent: boolean;\n};\n\nconst SOURCE_FILE_PATTERN = /\\.(jsx?|tsx?)$/i;\n\ntype WatchTarget = {\n watchPath: string;\n recursive: boolean;\n fileNames?: string[];\n};\n\nconst getWatchDirs = (dirs: string[]): string[] => [\n ...new Set(dirs.filter((dir) => !dir.split(path.sep).includes('node_modules'))),\n];\n\nconst isCoveredByRecursiveWatch = (watchPath: string, targetPath: string): boolean =>\n targetPath === watchPath || targetPath.startsWith(`${watchPath}${path.sep}`);\n\nconst getEntryWatchTargets = (entries: ResolvedEntryPath[]): WatchTarget[] => {\n const directoryTargets = getWatchDirs(\n entries.filter((entry) => entry.kind === 'directory').map((entry) => entry.absolutePath),\n ).map((watchPath) => ({ watchPath, recursive: true }));\n\n const fileNamesByDirectory = new Map<string, Set<string>>();\n\n entries\n .filter(\n (entry): entry is ResolvedEntryPath & { kind: 'file'; fileName: string } =>\n entry.kind === 'file' && typeof entry.fileName === 'string',\n )\n .forEach((entry) => {\n if (\n directoryTargets.some((target) =>\n isCoveredByRecursiveWatch(target.watchPath, entry.absolutePath),\n )\n ) {\n return;\n }\n\n const fileNames = fileNamesByDirectory.get(entry.watchDirectory) ?? new Set<string>();\n fileNames.add(entry.fileName);\n fileNamesByDirectory.set(entry.watchDirectory, fileNames);\n });\n\n const fileTargets = [...fileNamesByDirectory.entries()].map(([watchPath, fileNames]) => ({\n watchPath,\n recursive: false,\n fileNames: [...fileNames],\n }));\n\n return [...directoryTargets, ...fileTargets];\n};\n\nconst watchSourceFiles = (targets: WatchTarget[], onFileChange: () => void): void => {\n targets.forEach((target) => {\n fs.watch(target.watchPath, { recursive: target.recursive }, (_eventType, filename) => {\n if (!filename || !SOURCE_FILE_PATTERN.test(filename)) {\n return;\n }\n\n if (target.fileNames && !target.fileNames.includes(path.basename(String(filename)))) {\n return;\n }\n\n onFileChange();\n });\n });\n};\n\nconst createDebouncedAction = (action: () => void, delayMs: number): (() => void) => {\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n return () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(action, delayMs);\n };\n};\n\nconst createQueuedRegenerator = <T>(options: {\n onStart?: () => void;\n onSuccess?: (result: T) => void;\n onError: (message: string) => void;\n regenerateOnce: () => Promise<T>;\n}): (() => Promise<void>) => {\n let isGenerating = false;\n let pendingRegenerate = false;\n\n const regenerate = async (): Promise<void> => {\n if (isGenerating) {\n pendingRegenerate = true;\n return;\n }\n\n isGenerating = true;\n try {\n options.onStart?.();\n const result = await options.regenerateOnce();\n options.onSuccess?.(result);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'CSS generation failed';\n options.onError(message);\n } finally {\n isGenerating = false;\n\n if (pendingRegenerate) {\n pendingRegenerate = false;\n await regenerate();\n }\n }\n };\n\n return regenerate;\n};\n\nconst runCssCommand = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const themeConfigExists = fs.existsSync(\n path.join(options.workspaceDir, String(options.themeConfigPath)),\n );\n\n if (!themeConfigExists) {\n await runSimpleMode(options, context);\n return;\n }\n\n await runThemeMode(options, context);\n};\n\nconst runSimpleMode = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const entry = options.entryOption ?? DEFAULT_ENTRY;\n const configPath = typeof options.configOption === 'string' ? options.configOption : undefined;\n\n if (!options.watch && !options.silent) {\n spinStart('Generating CSS...');\n }\n\n try {\n const result = await generateSimpleModeCSS({\n workspaceDir: options.workspaceDir,\n entry,\n outFile: String(options.outFile),\n variants: context.variants,\n autoVariants: context.autoVariants,\n componentData: context.componentData,\n scope: options.scope,\n configPath,\n isWatch: options.watch,\n silent: options.silent,\n });\n\n if (options.watch) {\n await runSimpleModeWatch(options, context, entry, configPath, result.packageDirs ?? []);\n }\n } catch (error) {\n spinStop('❌', error instanceof Error ? error.message : 'CSS generation failed');\n process.exitCode = 1;\n }\n};\n\nconst runSimpleModeWatch = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n entry: EntryValue,\n configPath: string | undefined,\n packageDirs: string[],\n): Promise<void> => {\n const resolvedEntries = resolveEntryPaths(entry, options.workspaceDir);\n const entryWatchTargets = getEntryWatchTargets(resolvedEntries);\n const fallbackTargets = getWatchDirs(packageDirs).map((watchPath) => ({\n watchPath,\n recursive: true,\n }));\n const watchTargets = packageDirs.length > 0 ? fallbackTargets : entryWatchTargets;\n\n if (!options.silent) {\n print('');\n print(`${magenta('Watching for changes...')}`);\n watchTargets.forEach((target) => print(` ${gray('•')} ${target.watchPath}`));\n print(`${gray('Press Ctrl+C to stop')}`);\n print('');\n }\n\n const regenerate = createQueuedRegenerator({\n onStart: () => {\n if (!options.silent) {\n const timestamp = new Date().toLocaleTimeString();\n print(`${gray(`[${timestamp}]`)} Change detected, regenerating...`);\n }\n },\n regenerateOnce: async () => {\n await generateSimpleModeCSS({\n workspaceDir: options.workspaceDir,\n entry,\n outFile: String(options.outFile),\n variants: context.variants,\n autoVariants: context.autoVariants,\n componentData: context.componentData,\n scope: options.scope,\n configPath,\n isWatch: true,\n silent: true,\n });\n },\n onSuccess: () => {\n if (!options.silent) {\n const updatedAt = new Date().toLocaleTimeString();\n print(`${gray(`[${updatedAt}]`)} ${green('CSS updated')}`);\n print('');\n }\n },\n onError: (message) => {\n print(`Error: ${message}`);\n },\n });\n\n watchSourceFiles(\n watchTargets,\n createDebouncedAction(() => {\n void regenerate();\n }, 100),\n );\n\n await new Promise(() => {});\n};\n\nconst loadThemeModeSetup = async (options: CssCommandOptions): Promise<ThemeModeSetup | null> => {\n const themeConfigInput = await loadConfigFile<UDSThemeConfigInput>(\n String(options.themeConfigPath),\n );\n if (!themeConfigInput) {\n return null;\n }\n\n const themeContext: UDSThemeContext = {\n cwd: options.workspaceDir,\n watch: options.watch,\n };\n const themeConfig: UDSThemeConfig =\n typeof themeConfigInput === 'function'\n ? await themeConfigInput(themeContext)\n : themeConfigInput;\n\n let appConfig: UniversalTokensConfig = defaultTokensConfig;\n if (themeConfig.config) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(themeConfig.config);\n if (loadedConfig) {\n appConfig = loadedConfig;\n }\n }\n\n return {\n themeConfig,\n colorModes: themeConfig.colorModes ?? ['dark'],\n entries: resolveEntryPaths(themeConfig.entry, options.workspaceDir),\n appConfig,\n appVariantDefaults: extractVariantDefaults(appConfig),\n runtimeConfigValues: extractRuntimeConfigValues(appConfig),\n effectiveSilent: options.silent || themeConfig.silent === true,\n };\n};\n\nconst runThemeMode = async (\n options: CssCommandOptions,\n context: CssCommandContext,\n): Promise<void> => {\n const workspaceDir = options.workspaceDir;\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(workspaceDir, String(options.outFile));\n let effectiveSilent = options.silent;\n let log = createLogger({ silent: effectiveSilent });\n\n log.spinStart('Loading theme configuration...');\n\n try {\n const setup = await loadThemeModeSetup(options);\n if (!setup) {\n log.spinStop('❌', `Theme config not found: ${options.themeConfigPath}`);\n process.exitCode = 1;\n return;\n }\n\n const { themeConfig, colorModes, entries, appConfig, appVariantDefaults, runtimeConfigValues } =\n setup;\n effectiveSilent = setup.effectiveSilent;\n log = createLogger({ silent: effectiveSilent });\n const entryDirs = entries.map((entry) => entry.absolutePath);\n\n if (!effectiveSilent) {\n log.spinStop('✅', 'Theme configuration loaded');\n }\n\n if (themeConfig.config && appConfig === defaultTokensConfig) {\n log.warn(`App config not found: ${themeConfig.config}, using defaults`);\n }\n const packageDirs: string[] = [];\n\n const generateThemeModeCSS = async (opts?: { isWatch?: boolean }) => {\n const genStartTime = performance.now();\n const genLog = opts?.isWatch ? createLogger({ silent: true }) : log;\n\n genLog.spinStart('Scanning app code...');\n const appScanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n context.variants,\n context.autoVariants,\n context.componentData,\n appVariantDefaults,\n runtimeConfigValues,\n );\n genLog.spinStop('✅', `Scanned ${appScanResult.filesScanned} files`);\n\n genLog.spinStart('Generating main CSS...');\n\n const inheritedClasses: string[] = [...appScanResult.safelist];\n const inheritedComponents = new Set<string>(appScanResult.components);\n\n const processInheritedPackage = async (packageName: string) => {\n genLog.spinStart(`Processing package: ${packageName}...`);\n\n const packageDir = findPackageSourceDir(packageName);\n if (!packageDir) {\n genLog.spinStop('⚠️', `Package not found: ${packageName}`);\n return;\n }\n\n if (!packageDirs.includes(packageDir)) {\n packageDirs.push(packageDir);\n }\n\n const packageScanResult = await scanDirectoryForSafelist(\n packageDir,\n colorModes,\n context.variants,\n context.autoVariants,\n context.componentData,\n appVariantDefaults,\n runtimeConfigValues,\n true,\n );\n inheritedClasses.push(...packageScanResult.safelist);\n packageScanResult.components.forEach((comp) => inheritedComponents.add(comp));\n genLog.spinStop('✅', `${packageName}: ${packageScanResult.filesScanned} files (inherit)`);\n };\n\n await (themeConfig.inherit ?? []).reduce(async (promise, packageName) => {\n await promise;\n await processInheritedPackage(packageName);\n }, Promise.resolve());\n\n const mainSafelist = deduplicateSafelist([\n ...inheritedClasses,\n ...getThemeAndScaleClasses(colorModes),\n ...getInternalSafelistClasses(),\n ]);\n\n const allMotionComponents: string[] = [...inheritedComponents];\n\n const mainCssResult = await generateCSS(\n [...(themeConfig.css?.safelist ?? []), ...mainSafelist],\n appConfig,\n {\n scope: options.scope,\n contentDir: entryDirs,\n cssOptions: themeConfig.css,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(context.componentData, allMotionComponents),\n ...getConfigurableCssVariables(),\n ...getPruneVarSafelist(themeConfig.css),\n ],\n },\n );\n\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, mainCssResult.css);\n\n genLog.spinStop(\n '✅',\n getMainCssSummaryMessage({\n sizeGzipBytes: mainCssResult.sizeGzipBytes,\n optimizationStats: mainCssResult.optimizationStats,\n formatBytes,\n }),\n );\n\n const duration = Math.round(performance.now() - genStartTime);\n\n genLog.newline();\n genLog.print(green('CSS generation complete!'));\n genLog.newline();\n genLog.label('Output file:', outputPath);\n genLog.newline();\n genLog.print(`${magenta('Total time:')} ${duration}ms`);\n\n return { duration, outputPath, packageDirs };\n };\n\n await generateThemeModeCSS();\n\n if (options.watch) {\n const entryWatchTargets = getEntryWatchTargets(entries);\n const entryWatchDirs = getWatchDirs(entryWatchTargets.map((target) => target.watchPath));\n const { filteredPackageDirs } = getWatchDirectoryGroups(entryWatchDirs, [\n ...entryDirs,\n ...packageDirs,\n ]);\n\n if (!effectiveSilent) {\n log.newline();\n log.print(`${magenta('Watching for changes...')}`);\n entryDirs.forEach((entryDir) => {\n log.listItem(`App: ${entryDir}`);\n });\n filteredPackageDirs.forEach((dir) => {\n log.listItem(`Package: ${dir}`);\n });\n log.print(`${gray('Press Ctrl+C to stop')}`);\n log.newline();\n }\n\n const regenerate = createQueuedRegenerator({\n onStart: () => {\n if (!effectiveSilent) {\n const timestamp = new Date().toLocaleTimeString();\n log.print(`${gray(`[${timestamp}]`)} Change detected, regenerating...`);\n }\n },\n regenerateOnce: async () => generateThemeModeCSS({ isWatch: true }),\n onSuccess: (result) => {\n if (!effectiveSilent) {\n const updatedAt = new Date().toLocaleTimeString();\n log.print(`${gray(`[${updatedAt}]`)} ${green(`CSS updated (${result?.duration}ms)`)}`);\n log.newline();\n }\n },\n onError: (message) => {\n log.print(message);\n },\n });\n\n const watchDebounce = themeConfig.css?.watchDebounce ?? 100;\n\n watchSourceFiles(\n [\n ...entryWatchTargets,\n ...filteredPackageDirs\n .filter(\n (packageDir) =>\n !entryWatchTargets.some((target) =>\n isCoveredByRecursiveWatch(target.watchPath, packageDir),\n ),\n )\n .map((watchPath) => ({ watchPath, recursive: true })),\n ],\n createDebouncedAction(() => {\n void regenerate();\n }, watchDebounce),\n );\n\n await new Promise(() => {});\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'CSS generation failed';\n if (effectiveSilent) {\n spinStop('❌', message);\n } else {\n log.spinStop('❌', message);\n }\n process.exitCode = 1;\n }\n};\n\nexport { runCssCommand };\nexport type { CssCommandContext, CssCommandOptions };\n"],"mappings":"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"}
@@ -54,6 +54,7 @@ const purgeOptimized = async (options) => {
54
54
  stats.expressionsResolved += result.stats.expressionsResolved;
55
55
  });
56
56
  allClasses.push(...require_safelist.getThemeAndScaleClasses(colorModes));
57
+ allClasses.push(...require_safelist.getInternalSafelistClasses());
57
58
  const finalSafelist = require_safelist.deduplicateSafelist(allClasses).sort();
58
59
  await require_safelist.saveSafelistToFile(finalSafelist, node_path.default.join(workspaceDir, output));
59
60
  stats.timeMs = Math.round(performance.now() - startTime);
@@ -1,7 +1,7 @@
1
1
  /*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
2
2
  import { purgeFromCodeOptimized } from "./purgeFromCode.js";
3
3
  import { DEFAULT_ENTRY } from "../../utils/entryPoints.js";
4
- import { deduplicateSafelist, getThemeAndScaleClasses, saveSafelistToFile } from "./utils/safelist.js";
4
+ import { deduplicateSafelist, getInternalSafelistClasses, getThemeAndScaleClasses, saveSafelistToFile } from "./utils/safelist.js";
5
5
  import { scanForFiles } from "./utils/files.js";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
@@ -51,6 +51,7 @@ const purgeOptimized = async (options) => {
51
51
  stats.expressionsResolved += result.stats.expressionsResolved;
52
52
  });
53
53
  allClasses.push(...getThemeAndScaleClasses(colorModes));
54
+ allClasses.push(...getInternalSafelistClasses());
54
55
  const finalSafelist = deduplicateSafelist(allClasses).sort();
55
56
  await saveSafelistToFile(finalSafelist, path.join(workspaceDir, output));
56
57
  stats.timeMs = Math.round(performance.now() - startTime);
@@ -1 +1 @@
1
- {"version":3,"file":"purge.js","names":[],"sources":["../../../src/purger/optimized/purge.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { DEFAULT_ENTRY } from '../../utils/entryPoints';\nimport { purgeFromCodeOptimized } from './purgeFromCode';\nimport type { PurgeOptions, PurgeResult, PurgeStats } from './types';\nimport { scanForFiles } from './utils/files';\nimport { deduplicateSafelist, getThemeAndScaleClasses, saveSafelistToFile } from './utils/safelist';\n\n// Track warned locations to avoid duplicates\nconst warnedLocations = new Set<string>();\n\n/**\n * Clear warned locations (call at start of new purge run)\n */\nexport const clearWarnings = (): void => {\n warnedLocations.clear();\n};\n\n/**\n * Main purge function - optimized version\n *\n * Uses purgeFromCodeOptimized internally to ensure consistent behavior\n * between CLI and playground.\n */\nexport const purgeOptimized = async (options: PurgeOptions): Promise<PurgeResult> => {\n const {\n entry = DEFAULT_ENTRY,\n output = 'dist/safelist.ts',\n colorModes = ['dark'], // Light mode is already in :root\n variants,\n autoVariants,\n componentData,\n } = options;\n\n const startTime = performance.now();\n clearWarnings();\n\n const workspaceDir = process.env.PWD ?? process.cwd();\n\n const files = await scanForFiles(entry);\n\n // Aggregate results from all files\n const allClasses: string[] = [];\n const allImports = new Set<string>();\n const allComponents = new Set<string>();\n\n const stats: PurgeStats = {\n filesScanned: files.length,\n timeMs: 0,\n classesGenerated: 0,\n spreadsTraced: 0,\n expressionsResolved: 0,\n };\n\n // Process each file using purgeFromCodeOptimized\n const results = await Promise.all(\n files.map(async (filePath) => {\n const code = fs.readFileSync(filePath, 'utf-8');\n return purgeFromCodeOptimized(code, {\n colorModes,\n variants,\n autoVariants,\n componentData,\n });\n }),\n );\n\n results.forEach((result) => {\n allClasses.push(...result.safelist);\n result.imports.forEach((imp) => allImports.add(imp));\n result.components.forEach((comp) => allComponents.add(comp));\n stats.spreadsTraced += result.stats.spreadsTraced;\n stats.expressionsResolved += result.stats.expressionsResolved;\n });\n\n // Add color mode classes\n allClasses.push(...getThemeAndScaleClasses(colorModes));\n\n const finalSafelist = deduplicateSafelist(allClasses).sort();\n\n await saveSafelistToFile(finalSafelist, path.join(workspaceDir, output));\n\n stats.timeMs = Math.round(performance.now() - startTime);\n stats.classesGenerated = finalSafelist.length;\n\n return {\n safelist: finalSafelist,\n imports: [...allImports],\n components: [...allComponents],\n stats,\n };\n};\n"],"mappings":";;;;;;;;;AAUA,MAAM,kCAAkB,IAAI,KAAa;;;;AAKzC,MAAa,sBAA4B;AACvC,iBAAgB,OAAO;;;;;;;;AASzB,MAAa,iBAAiB,OAAO,YAAgD;CACnF,MAAM,EACJ,QAAQ,eACR,SAAS,oBACT,aAAa,CAAC,OAAO,EACrB,UACA,cACA,kBACE;CAEJ,MAAM,YAAY,YAAY,KAAK;AACnC,gBAAe;CAEf,MAAM,eAAe,QAAQ,IAAI,OAAO,QAAQ,KAAK;CAErD,MAAM,QAAQ,MAAM,aAAa,MAAM;CAGvC,MAAM,aAAuB,EAAE;CAC/B,MAAM,6BAAa,IAAI,KAAa;CACpC,MAAM,gCAAgB,IAAI,KAAa;CAEvC,MAAM,QAAoB;EACxB,cAAc,MAAM;EACpB,QAAQ;EACR,kBAAkB;EAClB,eAAe;EACf,qBAAqB;EACtB;AAeD,EAZgB,MAAM,QAAQ,IAC5B,MAAM,IAAI,OAAO,aAAa;AAE5B,SAAO,uBADM,GAAG,aAAa,UAAU,QAAQ,EACX;GAClC;GACA;GACA;GACA;GACD,CAAC;GACF,CACH,EAEO,SAAS,WAAW;AAC1B,aAAW,KAAK,GAAG,OAAO,SAAS;AACnC,SAAO,QAAQ,SAAS,QAAQ,WAAW,IAAI,IAAI,CAAC;AACpD,SAAO,WAAW,SAAS,SAAS,cAAc,IAAI,KAAK,CAAC;AAC5D,QAAM,iBAAiB,OAAO,MAAM;AACpC,QAAM,uBAAuB,OAAO,MAAM;GAC1C;AAGF,YAAW,KAAK,GAAG,wBAAwB,WAAW,CAAC;CAEvD,MAAM,gBAAgB,oBAAoB,WAAW,CAAC,MAAM;AAE5D,OAAM,mBAAmB,eAAe,KAAK,KAAK,cAAc,OAAO,CAAC;AAExE,OAAM,SAAS,KAAK,MAAM,YAAY,KAAK,GAAG,UAAU;AACxD,OAAM,mBAAmB,cAAc;AAEvC,QAAO;EACL,UAAU;EACV,SAAS,CAAC,GAAG,WAAW;EACxB,YAAY,CAAC,GAAG,cAAc;EAC9B;EACD"}
1
+ {"version":3,"file":"purge.js","names":[],"sources":["../../../src/purger/optimized/purge.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { DEFAULT_ENTRY } from '../../utils/entryPoints';\nimport { purgeFromCodeOptimized } from './purgeFromCode';\nimport type { PurgeOptions, PurgeResult, PurgeStats } from './types';\nimport { scanForFiles } from './utils/files';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n saveSafelistToFile,\n} from './utils/safelist';\n\n// Track warned locations to avoid duplicates\nconst warnedLocations = new Set<string>();\n\n/**\n * Clear warned locations (call at start of new purge run)\n */\nexport const clearWarnings = (): void => {\n warnedLocations.clear();\n};\n\n/**\n * Main purge function - optimized version\n *\n * Uses purgeFromCodeOptimized internally to ensure consistent behavior\n * between CLI and playground.\n */\nexport const purgeOptimized = async (options: PurgeOptions): Promise<PurgeResult> => {\n const {\n entry = DEFAULT_ENTRY,\n output = 'dist/safelist.ts',\n colorModes = ['dark'], // Light mode is already in :root\n variants,\n autoVariants,\n componentData,\n } = options;\n\n const startTime = performance.now();\n clearWarnings();\n\n const workspaceDir = process.env.PWD ?? process.cwd();\n\n const files = await scanForFiles(entry);\n\n // Aggregate results from all files\n const allClasses: string[] = [];\n const allImports = new Set<string>();\n const allComponents = new Set<string>();\n\n const stats: PurgeStats = {\n filesScanned: files.length,\n timeMs: 0,\n classesGenerated: 0,\n spreadsTraced: 0,\n expressionsResolved: 0,\n };\n\n // Process each file using purgeFromCodeOptimized\n const results = await Promise.all(\n files.map(async (filePath) => {\n const code = fs.readFileSync(filePath, 'utf-8');\n return purgeFromCodeOptimized(code, {\n colorModes,\n variants,\n autoVariants,\n componentData,\n });\n }),\n );\n\n results.forEach((result) => {\n allClasses.push(...result.safelist);\n result.imports.forEach((imp) => allImports.add(imp));\n result.components.forEach((comp) => allComponents.add(comp));\n stats.spreadsTraced += result.stats.spreadsTraced;\n stats.expressionsResolved += result.stats.expressionsResolved;\n });\n\n // Add color mode classes\n allClasses.push(...getThemeAndScaleClasses(colorModes));\n allClasses.push(...getInternalSafelistClasses());\n\n const finalSafelist = deduplicateSafelist(allClasses).sort();\n\n await saveSafelistToFile(finalSafelist, path.join(workspaceDir, output));\n\n stats.timeMs = Math.round(performance.now() - startTime);\n stats.classesGenerated = finalSafelist.length;\n\n return {\n safelist: finalSafelist,\n imports: [...allImports],\n components: [...allComponents],\n stats,\n };\n};\n"],"mappings":";;;;;;;;;AAeA,MAAM,kCAAkB,IAAI,KAAa;;;;AAKzC,MAAa,sBAA4B;AACvC,iBAAgB,OAAO;;;;;;;;AASzB,MAAa,iBAAiB,OAAO,YAAgD;CACnF,MAAM,EACJ,QAAQ,eACR,SAAS,oBACT,aAAa,CAAC,OAAO,EACrB,UACA,cACA,kBACE;CAEJ,MAAM,YAAY,YAAY,KAAK;AACnC,gBAAe;CAEf,MAAM,eAAe,QAAQ,IAAI,OAAO,QAAQ,KAAK;CAErD,MAAM,QAAQ,MAAM,aAAa,MAAM;CAGvC,MAAM,aAAuB,EAAE;CAC/B,MAAM,6BAAa,IAAI,KAAa;CACpC,MAAM,gCAAgB,IAAI,KAAa;CAEvC,MAAM,QAAoB;EACxB,cAAc,MAAM;EACpB,QAAQ;EACR,kBAAkB;EAClB,eAAe;EACf,qBAAqB;EACtB;AAeD,EAZgB,MAAM,QAAQ,IAC5B,MAAM,IAAI,OAAO,aAAa;AAE5B,SAAO,uBADM,GAAG,aAAa,UAAU,QAAQ,EACX;GAClC;GACA;GACA;GACA;GACD,CAAC;GACF,CACH,EAEO,SAAS,WAAW;AAC1B,aAAW,KAAK,GAAG,OAAO,SAAS;AACnC,SAAO,QAAQ,SAAS,QAAQ,WAAW,IAAI,IAAI,CAAC;AACpD,SAAO,WAAW,SAAS,SAAS,cAAc,IAAI,KAAK,CAAC;AAC5D,QAAM,iBAAiB,OAAO,MAAM;AACpC,QAAM,uBAAuB,OAAO,MAAM;GAC1C;AAGF,YAAW,KAAK,GAAG,wBAAwB,WAAW,CAAC;AACvD,YAAW,KAAK,GAAG,4BAA4B,CAAC;CAEhD,MAAM,gBAAgB,oBAAoB,WAAW,CAAC,MAAM;AAE5D,OAAM,mBAAmB,eAAe,KAAK,KAAK,cAAc,OAAO,CAAC;AAExE,OAAM,SAAS,KAAK,MAAM,YAAY,KAAK,GAAG,UAAU;AACxD,OAAM,mBAAmB,cAAc;AAEvC,QAAO;EACL,UAAU;EACV,SAAS,CAAC,GAAG,WAAW;EACxB,YAAY,CAAC,GAAG,cAAc;EAC9B;EACD"}
@@ -10,6 +10,7 @@ const colorModeToClass = {
10
10
  dark: require_index.DARK_COLOR_MODE_CLASSNAME,
11
11
  light: require_index.LIGHT_COLOR_MODE_CLASSNAME
12
12
  };
13
+ const internalSafelistClasses = ["uds-light-mode-icon", "uds-dark-mode-icon"];
13
14
  /**
14
15
  * Deduplicate and clean a safelist
15
16
  */
@@ -36,6 +37,11 @@ const getThemeAndScaleClasses = (colorModes) => {
36
37
  return colorModes.map((mode) => colorModeToClass[mode]).filter((className) => Boolean(className));
37
38
  };
38
39
  /**
40
+ * Get internal framework classes that are required even when plugin safelists
41
+ * are intentionally ignored by the optimized CSS generation path.
42
+ */
43
+ const getInternalSafelistClasses = () => [...internalSafelistClasses];
44
+ /**
39
45
  * Save safelist to a file
40
46
  */
41
47
  const saveSafelistToFile = async (safelist, outputPath) => {
@@ -51,5 +57,6 @@ export const safelist = ${JSON.stringify(safelist)};
51
57
 
52
58
  //#endregion
53
59
  exports.deduplicateSafelist = deduplicateSafelist;
60
+ exports.getInternalSafelistClasses = getInternalSafelistClasses;
54
61
  exports.getThemeAndScaleClasses = getThemeAndScaleClasses;
55
62
  exports.saveSafelistToFile = saveSafelistToFile;
@@ -8,6 +8,7 @@ const colorModeToClass = {
8
8
  dark: DARK_COLOR_MODE_CLASSNAME,
9
9
  light: LIGHT_COLOR_MODE_CLASSNAME
10
10
  };
11
+ const internalSafelistClasses = ["uds-light-mode-icon", "uds-dark-mode-icon"];
11
12
  /**
12
13
  * Deduplicate and clean a safelist
13
14
  */
@@ -34,6 +35,11 @@ const getThemeAndScaleClasses = (colorModes) => {
34
35
  return colorModes.map((mode) => colorModeToClass[mode]).filter((className) => Boolean(className));
35
36
  };
36
37
  /**
38
+ * Get internal framework classes that are required even when plugin safelists
39
+ * are intentionally ignored by the optimized CSS generation path.
40
+ */
41
+ const getInternalSafelistClasses = () => [...internalSafelistClasses];
42
+ /**
37
43
  * Save safelist to a file
38
44
  */
39
45
  const saveSafelistToFile = async (safelist, outputPath) => {
@@ -48,5 +54,5 @@ export const safelist = ${JSON.stringify(safelist)};
48
54
  };
49
55
 
50
56
  //#endregion
51
- export { deduplicateSafelist, getThemeAndScaleClasses, saveSafelistToFile };
57
+ export { deduplicateSafelist, getInternalSafelistClasses, getThemeAndScaleClasses, saveSafelistToFile };
52
58
  //# sourceMappingURL=safelist.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safelist.js","names":[],"sources":["../../../../src/purger/optimized/utils/safelist.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\n\nimport { DARK_COLOR_MODE_CLASSNAME, LIGHT_COLOR_MODE_CLASSNAME } from '@yahoo/uds-css-tokens';\nimport type { ColorModeConfig } from '@yahoo/uds-types';\n\nconst colorModeToClass: Record<keyof ColorModeConfig, string> = {\n dark: DARK_COLOR_MODE_CLASSNAME,\n light: LIGHT_COLOR_MODE_CLASSNAME,\n};\n\n/**\n * Deduplicate and clean a safelist\n */\nconst deduplicateSafelist = (safelist: string[]): string[] => {\n const deduped = safelist\n .map((cls) => cls.replaceAll('\\\\', '').trim())\n .filter((cleaned) => cleaned && isValidClassName(cleaned));\n\n return Array.from(new Set(deduped));\n};\n\n/**\n * Check if a class name is valid (not malformed from CSS escape sequences)\n */\nconst isValidClassName = (cls: string): boolean => {\n // Filter out malformed classes from CSS escape sequences\n if (cls.match(/^[0-9]/)) {\n return false;\n }\n if (cls.match(/[0-9][a-z]$/)) {\n return false;\n }\n if (cls.includes('2c')) {\n return false;\n }\n return true;\n};\n\n/**\n * Filter out autoVariant classes (we add them dynamically based on usage)\n */\nexport const filterAutoVariantClasses = (classes: string[]): string[] =>\n classes.filter((cls) => !cls.match(/^uds-[a-z]+-(?:variant|size)-/));\n\n/**\n * Get classes for enabled color modes.\n * Note: Light mode is not included by default since :root already defines light mode styles.\n * Only dark mode class is needed to enable dark mode switching.\n */\nexport const getThemeAndScaleClasses = (colorModes?: ('dark' | 'light')[]): string[] => {\n if (!colorModes || colorModes.length === 0) {\n // Default: only dark mode (light mode is already in :root)\n return [colorModeToClass.dark];\n }\n\n return colorModes\n .map((mode) => colorModeToClass[mode])\n .filter((className): className is string => Boolean(className));\n};\n\n/**\n * Get autoVariant classes for specific prop values used by a component\n */\nexport const getAutoVariantClasses = (\n componentName: string,\n usedProps: Map<string, Set<string>>,\n autoVariants: Record<string, Record<string, string>>,\n): string[] => {\n const componentLower = componentName.toLowerCase();\n\n return [...usedProps.entries()].flatMap(([propName, values]) => {\n const propNameCapitalized = propName.charAt(0).toUpperCase() + propName.slice(1);\n\n // Look for matching autoVariant keys\n return Object.entries(autoVariants)\n .filter(\n ([autoVariantKey]) =>\n autoVariantKey.startsWith(componentLower + propNameCapitalized) ||\n autoVariantKey.startsWith(componentLower + propName),\n )\n .flatMap(([, variantGroup]) =>\n [...values]\n .map((value) => variantGroup[value as keyof typeof variantGroup])\n .filter((className): className is string => Boolean(className)),\n );\n });\n};\n\n/**\n * Save safelist to a file\n */\nexport const saveSafelistToFile = async (safelist: string[], outputPath: string): Promise<void> => {\n const content = `\n//! This file is generated by the optimized purger from @yahoo/uds\n//! Do not edit directly\n//! If there is issue with this file please report to #ask-uds\nexport const safelist = ${JSON.stringify(safelist)};\n`;\n\n mkdirSync(path.dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, content);\n};\n\nexport { deduplicateSafelist };\n"],"mappings":";;;;;;AAMA,MAAM,mBAA0D;CAC9D,MAAM;CACN,OAAO;CACR;;;;AAKD,MAAM,uBAAuB,aAAiC;CAC5D,MAAM,UAAU,SACb,KAAK,QAAQ,IAAI,WAAW,MAAM,GAAG,CAAC,MAAM,CAAC,CAC7C,QAAQ,YAAY,WAAW,iBAAiB,QAAQ,CAAC;AAE5D,QAAO,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC;;;;;AAMrC,MAAM,oBAAoB,QAAyB;AAEjD,KAAI,IAAI,MAAM,SAAS,CACrB,QAAO;AAET,KAAI,IAAI,MAAM,cAAc,CAC1B,QAAO;AAET,KAAI,IAAI,SAAS,KAAK,CACpB,QAAO;AAET,QAAO;;;;;;;AAcT,MAAa,2BAA2B,eAAgD;AACtF,KAAI,CAAC,cAAc,WAAW,WAAW,EAEvC,QAAO,CAAC,iBAAiB,KAAK;AAGhC,QAAO,WACJ,KAAK,SAAS,iBAAiB,MAAM,CACrC,QAAQ,cAAmC,QAAQ,UAAU,CAAC;;;;;AAkCnE,MAAa,qBAAqB,OAAO,UAAoB,eAAsC;CACjG,MAAM,UAAU;;;;0BAIQ,KAAK,UAAU,SAAS,CAAC;;AAGjD,WAAU,KAAK,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,eAAc,YAAY,QAAQ"}
1
+ {"version":3,"file":"safelist.js","names":[],"sources":["../../../../src/purger/optimized/utils/safelist.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\n\nimport { DARK_COLOR_MODE_CLASSNAME, LIGHT_COLOR_MODE_CLASSNAME } from '@yahoo/uds-css-tokens';\nimport type { ColorModeConfig } from '@yahoo/uds-types';\n\nconst colorModeToClass: Record<keyof ColorModeConfig, string> = {\n dark: DARK_COLOR_MODE_CLASSNAME,\n light: LIGHT_COLOR_MODE_CLASSNAME,\n};\n\nconst internalSafelistClasses = ['uds-light-mode-icon', 'uds-dark-mode-icon'] as const;\n\n/**\n * Deduplicate and clean a safelist\n */\nconst deduplicateSafelist = (safelist: string[]): string[] => {\n const deduped = safelist\n .map((cls) => cls.replaceAll('\\\\', '').trim())\n .filter((cleaned) => cleaned && isValidClassName(cleaned));\n\n return Array.from(new Set(deduped));\n};\n\n/**\n * Check if a class name is valid (not malformed from CSS escape sequences)\n */\nconst isValidClassName = (cls: string): boolean => {\n // Filter out malformed classes from CSS escape sequences\n if (cls.match(/^[0-9]/)) {\n return false;\n }\n if (cls.match(/[0-9][a-z]$/)) {\n return false;\n }\n if (cls.includes('2c')) {\n return false;\n }\n return true;\n};\n\n/**\n * Filter out autoVariant classes (we add them dynamically based on usage)\n */\nexport const filterAutoVariantClasses = (classes: string[]): string[] =>\n classes.filter((cls) => !cls.match(/^uds-[a-z]+-(?:variant|size)-/));\n\n/**\n * Get classes for enabled color modes.\n * Note: Light mode is not included by default since :root already defines light mode styles.\n * Only dark mode class is needed to enable dark mode switching.\n */\nexport const getThemeAndScaleClasses = (colorModes?: ('dark' | 'light')[]): string[] => {\n if (!colorModes || colorModes.length === 0) {\n // Default: only dark mode (light mode is already in :root)\n return [colorModeToClass.dark];\n }\n\n return colorModes\n .map((mode) => colorModeToClass[mode])\n .filter((className): className is string => Boolean(className));\n};\n\n/**\n * Get internal framework classes that are required even when plugin safelists\n * are intentionally ignored by the optimized CSS generation path.\n */\nexport const getInternalSafelistClasses = (): string[] => [...internalSafelistClasses];\n\n/**\n * Get autoVariant classes for specific prop values used by a component\n */\nexport const getAutoVariantClasses = (\n componentName: string,\n usedProps: Map<string, Set<string>>,\n autoVariants: Record<string, Record<string, string>>,\n): string[] => {\n const componentLower = componentName.toLowerCase();\n\n return [...usedProps.entries()].flatMap(([propName, values]) => {\n const propNameCapitalized = propName.charAt(0).toUpperCase() + propName.slice(1);\n\n // Look for matching autoVariant keys\n return Object.entries(autoVariants)\n .filter(\n ([autoVariantKey]) =>\n autoVariantKey.startsWith(componentLower + propNameCapitalized) ||\n autoVariantKey.startsWith(componentLower + propName),\n )\n .flatMap(([, variantGroup]) =>\n [...values]\n .map((value) => variantGroup[value as keyof typeof variantGroup])\n .filter((className): className is string => Boolean(className)),\n );\n });\n};\n\n/**\n * Save safelist to a file\n */\nexport const saveSafelistToFile = async (safelist: string[], outputPath: string): Promise<void> => {\n const content = `\n//! This file is generated by the optimized purger from @yahoo/uds\n//! Do not edit directly\n//! If there is issue with this file please report to #ask-uds\nexport const safelist = ${JSON.stringify(safelist)};\n`;\n\n mkdirSync(path.dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, content);\n};\n\nexport { deduplicateSafelist };\n"],"mappings":";;;;;;AAMA,MAAM,mBAA0D;CAC9D,MAAM;CACN,OAAO;CACR;AAED,MAAM,0BAA0B,CAAC,uBAAuB,qBAAqB;;;;AAK7E,MAAM,uBAAuB,aAAiC;CAC5D,MAAM,UAAU,SACb,KAAK,QAAQ,IAAI,WAAW,MAAM,GAAG,CAAC,MAAM,CAAC,CAC7C,QAAQ,YAAY,WAAW,iBAAiB,QAAQ,CAAC;AAE5D,QAAO,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC;;;;;AAMrC,MAAM,oBAAoB,QAAyB;AAEjD,KAAI,IAAI,MAAM,SAAS,CACrB,QAAO;AAET,KAAI,IAAI,MAAM,cAAc,CAC1B,QAAO;AAET,KAAI,IAAI,SAAS,KAAK,CACpB,QAAO;AAET,QAAO;;;;;;;AAcT,MAAa,2BAA2B,eAAgD;AACtF,KAAI,CAAC,cAAc,WAAW,WAAW,EAEvC,QAAO,CAAC,iBAAiB,KAAK;AAGhC,QAAO,WACJ,KAAK,SAAS,iBAAiB,MAAM,CACrC,QAAQ,cAAmC,QAAQ,UAAU,CAAC;;;;;;AAOnE,MAAa,mCAA6C,CAAC,GAAG,wBAAwB;;;;AAiCtF,MAAa,qBAAqB,OAAO,UAAoB,eAAsC;CACjG,MAAM,UAAU;;;;0BAIQ,KAAK,UAAU,SAAS,CAAC;;AAGjD,WAAU,KAAK,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,eAAc,YAAY,QAAQ"}