@yahoo/uds 3.122.2 → 3.123.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/components/experimental/client/SegmentedControl.d.cts +2 -1
  2. package/dist/styles/styler.d.cts +12 -12
  3. package/dist/styles/styler.d.ts +12 -12
  4. package/dist/tailwind/dist/commands/css.cjs +17 -3
  5. package/dist/tailwind/dist/commands/css.d.cts.map +1 -1
  6. package/dist/tailwind/dist/commands/css.d.ts.map +1 -1
  7. package/dist/tailwind/dist/commands/css.helpers.cjs +2 -1
  8. package/dist/tailwind/dist/commands/css.helpers.js +2 -1
  9. package/dist/tailwind/dist/commands/css.helpers.js.map +1 -1
  10. package/dist/tailwind/dist/commands/css.js +17 -3
  11. package/dist/tailwind/dist/commands/css.js.map +1 -1
  12. package/dist/tailwind/dist/css/generate.cjs +3 -0
  13. package/dist/tailwind/dist/css/generate.helpers.cjs +14 -6
  14. package/dist/tailwind/dist/css/generate.helpers.js +15 -7
  15. package/dist/tailwind/dist/css/generate.helpers.js.map +1 -1
  16. package/dist/tailwind/dist/css/generate.js +3 -0
  17. package/dist/tailwind/dist/css/generate.js.map +1 -1
  18. package/dist/tailwind/dist/css/nodeUtils.cjs +91 -20
  19. package/dist/tailwind/dist/css/nodeUtils.js +90 -21
  20. package/dist/tailwind/dist/css/nodeUtils.js.map +1 -1
  21. package/dist/tailwind/dist/css/postcss.cjs +22 -1
  22. package/dist/tailwind/dist/css/postcss.helpers.cjs +12 -1
  23. package/dist/tailwind/dist/css/postcss.helpers.js +11 -1
  24. package/dist/tailwind/dist/css/postcss.helpers.js.map +1 -1
  25. package/dist/tailwind/dist/css/postcss.js +22 -2
  26. package/dist/tailwind/dist/css/postcss.js.map +1 -1
  27. package/dist/tailwind/dist/css/runner.cjs +171 -20
  28. package/dist/tailwind/dist/css/runner.helpers.cjs +58 -6
  29. package/dist/tailwind/dist/css/runner.helpers.js +54 -7
  30. package/dist/tailwind/dist/css/runner.helpers.js.map +1 -1
  31. package/dist/tailwind/dist/css/runner.js +172 -20
  32. package/dist/tailwind/dist/css/runner.js.map +1 -1
  33. package/dist/tailwind/dist/css/theme.d.cts +11 -0
  34. package/dist/tailwind/dist/css/theme.d.cts.map +1 -1
  35. package/dist/tailwind/dist/css/theme.d.ts +11 -0
  36. package/dist/tailwind/dist/css/theme.d.ts.map +1 -1
  37. package/dist/tailwind/dist/css/theme.js.map +1 -1
  38. package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +26 -3
  39. package/dist/tailwind/dist/purger/optimized/ast/expressions.js +26 -3
  40. package/dist/tailwind/dist/purger/optimized/ast/expressions.js.map +1 -1
  41. package/dist/uds/dist/automated-config/dist/generated/universalTokensConfigAuto.d.cts +2 -0
  42. package/dist/uds/dist/automated-config/dist/properties.d.cts +5 -0
  43. package/dist/uds/dist/automated-config/dist/types/ComponentConfig.d.cts +3 -0
  44. package/dist/uds/dist/automated-config/dist/types/ComponentStyles.d.cts +2 -0
  45. package/dist/uds/dist/automated-config/dist/types/ConfigSchema.d.cts +2 -0
  46. package/dist/uds/dist/automated-config/dist/utils/buildConfigSchema.d.cts +7 -0
  47. package/dist/uds/dist/automated-config/dist/utils/coalesceConfigVariant.d.cts +2 -0
  48. package/dist/uds/dist/automated-config/dist/utils/defaults.d.cts +2 -0
  49. package/dist/uds/dist/automated-config/dist/utils/getConfigVariantComponentStatesMatrix.d.cts +2 -0
  50. package/dist/uds/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +3 -0
  51. package/dist/uds/dist/automated-config/dist/utils/getConfigVariantPseudoStates.d.cts +3 -0
  52. package/dist/uds/dist/automated-config/dist/utils/getConfigVariants.d.cts +2 -0
  53. package/dist/uds/dist/automated-config/dist/utils/index.d.cts +12 -0
  54. package/dist/uds/dist/automated-config/dist/utils/subcomponents.d.cts +2 -0
  55. package/dist/uds/dist/components/Box.d.cts +4 -0
  56. package/dist/uds/dist/components/Divider/Divider.d.cts +3 -0
  57. package/dist/uds/dist/components/Divider/DividerCore.d.cts +5 -0
  58. package/dist/uds/dist/components/Divider/DividerInternal.d.cts +5 -0
  59. package/dist/uds/dist/components/Divider/index.d.cts +2 -0
  60. package/dist/uds/dist/components/FormLabel.d.cts +4 -0
  61. package/dist/uds/dist/components/HStack.d.cts +5 -0
  62. package/dist/uds/dist/components/Icon.d.cts +4 -0
  63. package/dist/uds/dist/components/Image.d.cts +3 -0
  64. package/dist/uds/dist/components/Link.d.cts +4 -0
  65. package/dist/uds/dist/components/Scrim.d.cts +3 -0
  66. package/dist/uds/dist/components/Text.d.cts +4 -0
  67. package/dist/uds/dist/components/VStack.d.cts +5 -0
  68. package/dist/uds/dist/components/client/Avatar/Avatar.d.cts +2 -0
  69. package/dist/uds/dist/components/client/Avatar/AvatarIcon.d.cts +4 -0
  70. package/dist/uds/dist/components/client/Avatar/AvatarImage.d.cts +6 -0
  71. package/dist/uds/dist/components/client/Avatar/AvatarText.d.cts +4 -0
  72. package/dist/uds/dist/components/client/Avatar/index.d.cts +5 -0
  73. package/dist/uds/dist/components/client/Badge.d.cts +4 -0
  74. package/dist/uds/dist/components/client/BottomSheet/BottomSheet.d.cts +5 -0
  75. package/dist/uds/dist/components/client/BottomSheet/BottomSheetContent.d.cts +2 -0
  76. package/dist/uds/dist/components/client/BottomSheet/BottomSheetHeader.d.cts +2 -0
  77. package/dist/uds/dist/components/client/BottomSheet/BottomSheetProvider.d.cts +3 -0
  78. package/dist/uds/dist/components/client/BottomSheet/UDSBottomSheetConfigProvider.d.cts +3 -0
  79. package/dist/uds/dist/components/client/BottomSheet/index.d.cts +7 -0
  80. package/dist/uds/dist/components/client/BottomSheet/useBottomSheetStore.d.cts +2 -0
  81. package/dist/uds/dist/components/client/Button.d.cts +5 -0
  82. package/dist/uds/dist/components/client/Checkbox.d.cts +4 -0
  83. package/dist/uds/dist/components/client/Chip/Chip.d.cts +5 -0
  84. package/dist/uds/dist/components/client/Chip/ChipBase.d.cts +6 -0
  85. package/dist/uds/dist/components/client/Chip/ChipButton.d.cts +5 -0
  86. package/dist/uds/dist/components/client/Chip/ChipDismissible.d.cts +5 -0
  87. package/dist/uds/dist/components/client/Chip/ChipLink.d.cts +5 -0
  88. package/dist/uds/dist/components/client/Chip/ChipToggle.d.cts +5 -0
  89. package/dist/uds/dist/components/client/Chip/index.d.cts +6 -0
  90. package/dist/uds/dist/components/client/IconButton.d.cts +5 -0
  91. package/dist/uds/dist/components/client/Input/Input.d.cts +7 -0
  92. package/dist/uds/dist/components/client/Input/InputHelpText.d.cts +2 -0
  93. package/dist/uds/dist/components/client/Input/InputHelpTextInternal.d.cts +6 -0
  94. package/dist/uds/dist/components/client/Input/index.d.cts +3 -0
  95. package/dist/uds/dist/components/client/Menu/Menu.Content.d.cts +6 -0
  96. package/dist/uds/dist/components/client/Menu/Menu.Divider.d.cts +3 -0
  97. package/dist/uds/dist/components/client/Menu/Menu.Item.d.cts +6 -0
  98. package/dist/uds/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +6 -0
  99. package/dist/uds/dist/components/client/Menu/Menu.Provider.d.cts +3 -0
  100. package/dist/uds/dist/components/client/Menu/Menu.Trigger.d.cts +5 -0
  101. package/dist/uds/dist/components/client/Menu/Menu.d.cts +2 -0
  102. package/dist/uds/dist/components/client/Menu/Menu.index.d.cts +9 -0
  103. package/dist/uds/dist/components/client/Menu/index.d.cts +9 -0
  104. package/dist/uds/dist/components/client/Popover/Popover.d.cts +2 -0
  105. package/dist/uds/dist/components/client/Popover/PopoverContent.d.cts +5 -0
  106. package/dist/uds/dist/components/client/Popover/PopoverTrigger.d.cts +2 -0
  107. package/dist/uds/dist/components/client/Popover/UDSPopoverConfigProvider.d.cts +4 -0
  108. package/dist/uds/dist/components/client/Popover/index.d.cts +6 -0
  109. package/dist/uds/dist/components/client/Pressable.d.cts +4 -0
  110. package/dist/uds/dist/components/client/Radio/Radio.d.cts +4 -0
  111. package/dist/uds/dist/components/client/Radio/RadioGroupProvider.d.cts +4 -0
  112. package/dist/uds/dist/components/client/Radio/index.d.cts +3 -0
  113. package/dist/uds/dist/components/client/SpringMotionConfig.d.cts +5 -0
  114. package/dist/uds/dist/components/client/Switch.d.cts +4 -0
  115. package/dist/uds/dist/components/client/Toast/Toast.d.cts +8 -0
  116. package/dist/uds/dist/components/client/Toast/ToastContainer.d.cts +6 -0
  117. package/dist/uds/dist/components/client/Toast/ToastPortal.d.cts +3 -0
  118. package/dist/uds/dist/components/client/Toast/UDSToastConfigProvider.d.cts +5 -0
  119. package/dist/uds/dist/components/client/Toast/createToast.d.cts +6 -0
  120. package/dist/uds/dist/components/client/Toast/index.d.cts +6 -0
  121. package/dist/uds/dist/components/client/Tooltip/Tooltip.d.cts +2 -0
  122. package/dist/uds/dist/components/client/Tooltip/TooltipContent.d.cts +3 -0
  123. package/dist/uds/dist/components/client/Tooltip/TooltipTrigger.d.cts +2 -0
  124. package/dist/uds/dist/components/client/Tooltip/UDSTooltipConfigProvider.d.cts +5 -0
  125. package/dist/uds/dist/components/client/Tooltip/index.d.cts +6 -0
  126. package/dist/uds/dist/components/client/index.d.cts +59 -0
  127. package/dist/uds/dist/components/client/providers/UDSBreakpointsConfigProvider.d.cts +4 -0
  128. package/dist/uds/dist/components/client/providers/UDSConfigProvider.d.cts +3 -0
  129. package/dist/uds/dist/components/index.d.cts +61 -0
  130. package/dist/uds/dist/config/dist/index.d.cts +4 -0
  131. package/dist/uds/dist/css-tokens/dist/index.d.cts +2 -0
  132. package/dist/uds/dist/fixtures/dist/index.d.cts +2 -0
  133. package/dist/uds/dist/fonts/dist/index.d.cts +2 -0
  134. package/dist/uds/dist/index.d.cts +93 -0
  135. package/dist/uds/dist/modes/dist/index.d.cts +2 -0
  136. package/dist/uds/dist/runtime/bottomSheetConfig.d.cts +3 -0
  137. package/dist/uds/dist/runtime/breakpointsConfig.d.cts +4 -0
  138. package/dist/uds/dist/runtime/index.d.cts +7 -0
  139. package/dist/uds/dist/runtime/popoverConfig.d.cts +5 -0
  140. package/dist/uds/dist/runtime/toastConfig.d.cts +4 -0
  141. package/dist/uds/dist/runtime/tooltipConfig.d.cts +5 -0
  142. package/dist/uds/dist/runtime/udsConfig.d.cts +8 -0
  143. package/dist/uds/dist/styles/styler.d.cts +2 -0
  144. package/dist/uds/dist/styles/stylerTypes.d.cts +3 -0
  145. package/dist/uds/dist/tailwind/dist/config/dist/index.d.cts +2 -0
  146. package/dist/uds/dist/tailwind/dist/index.d.cts +3 -0
  147. package/dist/uds/dist/tailwind/dist/tailwind/components/getResponsiveTextStyles.d.cts +2 -0
  148. package/dist/uds/dist/tailwind/dist/utils/parseTokens.d.cts +2 -0
  149. package/dist/uds/dist/tokens/automation/index.d.cts +10 -0
  150. package/dist/uds/dist/tokens/configs/shadow.d.cts +3 -0
  151. package/dist/uds/dist/tokens/consts/cssTokens.d.cts +2 -0
  152. package/dist/uds/dist/tokens/consts/defaultModes.d.cts +2 -0
  153. package/dist/uds/dist/tokens/consts/fontDeclarationsMap.d.cts +2 -0
  154. package/dist/uds/dist/tokens/index.d.cts +28 -0
  155. package/dist/uds/dist/tokens/parseButtonVariants.d.cts +3 -0
  156. package/dist/uds/dist/tokens/types.d.cts +9 -0
  157. package/dist/uds/dist/tokens/utils/getFontUrls.d.cts +4 -0
  158. package/dist/uds/dist/tokens/utils/spectrum.d.cts +3 -0
  159. package/dist/uds/dist/types/dist/index.d.cts +11 -0
  160. package/dist/uds/dist/types.d.cts +2 -0
  161. package/dist/uds/generated/componentData.cjs +131 -131
  162. package/dist/uds/generated/componentData.js +131 -131
  163. package/generated/componentData.json +183 -183
  164. package/package.json +1 -1
@@ -105,13 +105,16 @@ const generateSimpleModeCSS = async (options) => {
105
105
  fs.writeFileSync(outputPath, cssResult.css);
106
106
  const duration = Math.round(performance.now() - startTime);
107
107
  if (shouldLogStats) printSimpleModeStats({
108
+ cwd: options.workspaceDir,
108
109
  outputPath,
109
110
  totalFilesScanned,
111
+ scannedFilePaths: scanResult.filePaths,
110
112
  classCount: cssResult.classCount,
111
113
  sizeBytes: cssResult.sizeBytes,
112
114
  sizeGzipBytes: cssResult.sizeGzipBytes,
113
115
  duration,
114
116
  scope: options.scope,
117
+ verbose: options.verbose,
115
118
  optimizationStats: cssResult.optimizationStats,
116
119
  print,
117
120
  magenta,
@@ -1 +1 @@
1
- {"version":3,"file":"generate.js","names":[],"sources":["../../src/css/generate.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { gzipSync } from 'node:zlib';\n\nimport { cyan, magenta, print, spinStop, yellow } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\nimport postcss from 'postcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n} from '../purger/optimized';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { resolveEntryPaths } from '../utils/entryPoints';\nimport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getCssFeatureFlags,\n getInternalIconModeCss,\n optimizeGeneratedCss,\n printSimpleModeStats,\n} from './generate.helpers';\nimport { loadConfigFile, scanDirectoriesForSafelist } from './nodeUtils';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\n/**\n * Result from generating CSS\n */\ninterface CSSResult {\n css: string;\n sizeBytes: number;\n sizeGzipBytes: number;\n classCount: number;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}\n\n/**\n * CSS generation options for uds.theme.ts\n */\ninterface UDSCSSOptions {\n /** CSS scope wrapper class (optional) */\n scope?: string;\n /** Safelist of CSS classes to always include */\n safelist?: SafelistConfig[];\n /** CSS optimization settings */\n optimization?: UDSCSSOptimizationOptions;\n /** Include Tailwind preflight/reset styles (default: true) */\n preflight?: boolean;\n /** Include @font-face declarations (default: true) */\n fontFaceDeclarations?: boolean;\n /** Debounce delay (ms) for watch mode regenerations */\n watchDebounce?: number;\n}\n\n/**\n * Options for generateCSS function\n */\ninterface GenerateCSSOptions {\n /** CSS scope wrapper class */\n scope?: string;\n /** Directory to scan for arbitrary Tailwind classes (className props) */\n contentDir?: string | string[];\n /** CSS generation options from theme config */\n cssOptions?: UDSCSSOptions;\n /** Reference CSS to deduplicate font-faces against (for scoped CSS) */\n referenceCss?: string;\n /** CSS variable prefixes or patterns to preserve during pruning */\n safeVarPrefixes?: UDSCSSVarSafelistPattern[];\n}\n\nconst normalizeScope = (scope?: string): string | undefined => {\n const trimmedScope = scope?.trim();\n return trimmedScope ? trimmedScope : undefined;\n};\n\nconst getArbitrarySafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const arbitraryClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && entry.includes('['),\n );\n\n if (arbitraryClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${arbitraryClasses.join(' ')}\"></div>`];\n};\n\n/**\n * Generate CSS from a safelist using Tailwind + PostCSS\n * @param safelist - UDS component classes to include\n * @param config - Token configuration\n * @param options - Additional options\n */\nconst generateCSS = async (\n safelist: SafelistConfig[],\n config: UniversalTokensConfig,\n options?: GenerateCSSOptions,\n): Promise<CSSResult> => {\n // Do we need base?\n const sourceCSS = '@tailwind base; @tailwind components; @tailwind utilities';\n\n const contentDir = options?.contentDir ?? path.join(process.cwd(), 'src');\n const cssFlags = getCssFeatureFlags(options?.cssOptions);\n const optimizationConfig = options?.cssOptions?.optimization;\n const scopeClass = normalizeScope(options?.scope) ?? normalizeScope(options?.cssOptions?.scope);\n const twPlugin = createTailwindPlugin({\n contentDir,\n rawContents: getArbitrarySafelistRawContent(safelist),\n safelist,\n config,\n enablePreflight: cssFlags.enablePreflight,\n enableFontFaceDeclarations: cssFlags.enableFontFaceDeclarations,\n });\n const plugins = buildPostcssPlugins({\n tailwindPlugin: twPlugin,\n shouldPruneVars: cssFlags.shouldPruneVars,\n safeVarPrefixes: options?.safeVarPrefixes ?? [],\n scopeClass,\n });\n\n const result = await postcss(plugins).process(sourceCSS, { from: undefined });\n let css = await applyScopedColorModeFix(result.css, scopeClass);\n if (!css.includes('uds-light-mode-icon') || !css.includes('uds-dark-mode-icon')) {\n css = `${css} ${getInternalIconModeCss(scopeClass)}`.trim();\n }\n const optimizedCss = await optimizeGeneratedCss({\n css,\n shouldOptimize: cssFlags.shouldOptimize,\n optimizationConfig,\n referenceCss: options?.referenceCss,\n scopeClass,\n });\n css = optimizedCss.css;\n\n const sizeBytes = Buffer.byteLength(css, 'utf8');\n const sizeGzipBytes = gzipSync(css).length;\n\n return {\n css,\n sizeBytes,\n sizeGzipBytes,\n classCount: safelist.length,\n optimizationStats: optimizedCss.optimizationStats,\n };\n};\n\n/**\n * Generate CSS in simple mode (no uds.theme.ts)\n */\nconst generateSimpleModeCSS = async (options: {\n workspaceDir: string;\n entry: EntryValue;\n outFile: string;\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n scope?: string;\n configPath?: string;\n isWatch?: boolean;\n silent?: boolean;\n}): Promise<{ success: boolean; outputPath: string; packageDirs?: string[] }> => {\n const isWatch = options.isWatch === true;\n const isSilent = options.silent === true;\n const shouldLogStats = !isSilent && !isWatch;\n const startTime = performance.now();\n const colorModes: ('dark' | 'light')[] = ['dark']; // Light mode is already in :root\n\n // Load config if provided, otherwise use default\n let tokensConfig: UniversalTokensConfig = defaultTokensConfig;\n if (options.configPath) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(options.configPath);\n if (loadedConfig) {\n tokensConfig = loadedConfig;\n } else if (shouldLogStats) {\n spinStop('⚠️', `Config file not found: ${options.configPath}, using defaults`);\n }\n }\n\n // Extract variant defaults from config for auto-variant class generation\n const variantDefaults = extractVariantDefaults(tokensConfig);\n const runtimeConfigValues = extractRuntimeConfigValues(tokensConfig);\n\n const resolvedEntries = resolveEntryPaths(options.entry, options.workspaceDir);\n const entryDirs = resolvedEntries.map((entry) => entry.absolutePath);\n const scanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n options.variants,\n options.autoVariants,\n options.componentData,\n variantDefaults,\n runtimeConfigValues,\n );\n\n const totalFilesScanned = scanResult.filesScanned;\n const allClasses: string[] = [...scanResult.safelist];\n const allComponents = new Set<string>(scanResult.components);\n const packageDirs: string[] = [\n ...new Set(\n resolvedEntries.map((entry) =>\n entry.kind === 'directory' ? entry.absolutePath : entry.watchDirectory,\n ),\n ),\n ];\n\n // Add color mode classes\n const fullSafelist = [\n ...allClasses,\n ...getThemeAndScaleClasses(colorModes),\n ...getInternalSafelistClasses(),\n ];\n const finalSafelist = deduplicateSafelist(fullSafelist);\n\n // Generate CSS (Tailwind will scan entry dir for arbitrary classes on className props)\n const cssResult = await generateCSS(finalSafelist, tokensConfig, {\n scope: options.scope,\n contentDir: entryDirs,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(options.componentData, [...allComponents]),\n ...getConfigurableCssVariables(),\n ],\n });\n\n // Write output\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(options.workspaceDir, options.outFile);\n const outputDir = path.dirname(outputPath);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, cssResult.css);\n\n const duration = Math.round(performance.now() - startTime);\n\n if (shouldLogStats) {\n printSimpleModeStats({\n outputPath,\n totalFilesScanned,\n classCount: cssResult.classCount,\n sizeBytes: cssResult.sizeBytes,\n sizeGzipBytes: cssResult.sizeGzipBytes,\n duration,\n scope: options.scope,\n optimizationStats: cssResult.optimizationStats,\n print,\n magenta,\n cyan,\n yellow,\n });\n }\n\n return { success: true, outputPath, packageDirs };\n};\n\nexport { generateCSS, generateSimpleModeCSS };\nexport type { UDSCSSOptions };\n"],"mappings":"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"}
1
+ {"version":3,"file":"generate.js","names":[],"sources":["../../src/css/generate.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { gzipSync } from 'node:zlib';\n\nimport { cyan, magenta, print, spinStop, yellow } from '@yahoo/uds-cli/lib';\nimport type { UniversalTokensConfig } from '@yahoo/uds-config';\nimport { defaultTokensConfig } from '@yahoo/uds-config';\nimport postcss from 'postcss';\nimport type { SafelistConfig } from 'tailwindcss/types/config';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport {\n deduplicateSafelist,\n getInternalSafelistClasses,\n getThemeAndScaleClasses,\n} from '../purger/optimized';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { resolveEntryPaths } from '../utils/entryPoints';\nimport {\n applyScopedColorModeFix,\n buildPostcssPlugins,\n createTailwindPlugin,\n getCssFeatureFlags,\n getInternalIconModeCss,\n optimizeGeneratedCss,\n printSimpleModeStats,\n} from './generate.helpers';\nimport { loadConfigFile, scanDirectoriesForSafelist } from './nodeUtils';\nimport type { UDSCSSOptimizationOptions, UDSCSSVarSafelistPattern } from './theme';\nimport {\n extractRuntimeConfigValues,\n extractVariantDefaults,\n getConfigurableCssVariables,\n getMotionVarPrefixes,\n} from './utils';\n\n/**\n * Result from generating CSS\n */\ninterface CSSResult {\n css: string;\n sizeBytes: number;\n sizeGzipBytes: number;\n classCount: number;\n optimizationStats?: {\n originalSize: number;\n originalSizeGzip: number;\n fontFacesRemoved: number;\n emptyRulesRemoved: number;\n validationErrors: string[];\n };\n}\n\n/**\n * CSS generation options for uds.theme.ts\n */\ninterface UDSCSSOptions {\n /** CSS scope wrapper class (optional) */\n scope?: string;\n /** Safelist of CSS classes to always include */\n safelist?: SafelistConfig[];\n /** CSS optimization settings */\n optimization?: UDSCSSOptimizationOptions;\n /** Include Tailwind preflight/reset styles (default: true) */\n preflight?: boolean;\n /** Include @font-face declarations (default: true) */\n fontFaceDeclarations?: boolean;\n /** Debounce delay (ms) for watch mode regenerations */\n watchDebounce?: number;\n}\n\n/**\n * Options for generateCSS function\n */\ninterface GenerateCSSOptions {\n /** CSS scope wrapper class */\n scope?: string;\n /** Directory to scan for arbitrary Tailwind classes (className props) */\n contentDir?: string | string[];\n /** CSS generation options from theme config */\n cssOptions?: UDSCSSOptions;\n /** Reference CSS to deduplicate font-faces against (for scoped CSS) */\n referenceCss?: string;\n /** CSS variable prefixes or patterns to preserve during pruning */\n safeVarPrefixes?: UDSCSSVarSafelistPattern[];\n}\n\nconst normalizeScope = (scope?: string): string | undefined => {\n const trimmedScope = scope?.trim();\n return trimmedScope ? trimmedScope : undefined;\n};\n\nconst getArbitrarySafelistRawContent = (safelist: SafelistConfig[]): string[] => {\n const arbitraryClasses = safelist.filter(\n (entry): entry is string => typeof entry === 'string' && entry.includes('['),\n );\n\n if (arbitraryClasses.length === 0) {\n return [];\n }\n\n return [`<div class=\"${arbitraryClasses.join(' ')}\"></div>`];\n};\n\n/**\n * Generate CSS from a safelist using Tailwind + PostCSS\n * @param safelist - UDS component classes to include\n * @param config - Token configuration\n * @param options - Additional options\n */\nconst generateCSS = async (\n safelist: SafelistConfig[],\n config: UniversalTokensConfig,\n options?: GenerateCSSOptions,\n): Promise<CSSResult> => {\n // Do we need base?\n const sourceCSS = '@tailwind base; @tailwind components; @tailwind utilities';\n\n const contentDir = options?.contentDir ?? path.join(process.cwd(), 'src');\n const cssFlags = getCssFeatureFlags(options?.cssOptions);\n const optimizationConfig = options?.cssOptions?.optimization;\n const scopeClass = normalizeScope(options?.scope) ?? normalizeScope(options?.cssOptions?.scope);\n const twPlugin = createTailwindPlugin({\n contentDir,\n rawContents: getArbitrarySafelistRawContent(safelist),\n safelist,\n config,\n enablePreflight: cssFlags.enablePreflight,\n enableFontFaceDeclarations: cssFlags.enableFontFaceDeclarations,\n });\n const plugins = buildPostcssPlugins({\n tailwindPlugin: twPlugin,\n shouldPruneVars: cssFlags.shouldPruneVars,\n safeVarPrefixes: options?.safeVarPrefixes ?? [],\n scopeClass,\n });\n\n const result = await postcss(plugins).process(sourceCSS, { from: undefined });\n let css = await applyScopedColorModeFix(result.css, scopeClass);\n if (!css.includes('uds-light-mode-icon') || !css.includes('uds-dark-mode-icon')) {\n css = `${css} ${getInternalIconModeCss(scopeClass)}`.trim();\n }\n const optimizedCss = await optimizeGeneratedCss({\n css,\n shouldOptimize: cssFlags.shouldOptimize,\n optimizationConfig,\n referenceCss: options?.referenceCss,\n scopeClass,\n });\n css = optimizedCss.css;\n\n const sizeBytes = Buffer.byteLength(css, 'utf8');\n const sizeGzipBytes = gzipSync(css).length;\n\n return {\n css,\n sizeBytes,\n sizeGzipBytes,\n classCount: safelist.length,\n optimizationStats: optimizedCss.optimizationStats,\n };\n};\n\n/**\n * Generate CSS in simple mode (no uds.theme.ts)\n */\nconst generateSimpleModeCSS = async (options: {\n workspaceDir: string;\n entry: EntryValue;\n outFile: string;\n variants: Record<string, Record<string, string>>;\n autoVariants: Record<string, Record<string, string>>;\n componentData: Record<string, SerializedComponentInfo>;\n scope?: string;\n configPath?: string;\n isWatch?: boolean;\n silent?: boolean;\n verbose?: boolean;\n}): Promise<{ success: boolean; outputPath: string; packageDirs?: string[] }> => {\n const isWatch = options.isWatch === true;\n const isSilent = options.silent === true;\n const shouldLogStats = !isSilent && !isWatch;\n const startTime = performance.now();\n const colorModes: ('dark' | 'light')[] = ['dark']; // Light mode is already in :root\n\n // Load config if provided, otherwise use default\n let tokensConfig: UniversalTokensConfig = defaultTokensConfig;\n if (options.configPath) {\n const loadedConfig = await loadConfigFile<UniversalTokensConfig>(options.configPath);\n if (loadedConfig) {\n tokensConfig = loadedConfig;\n } else if (shouldLogStats) {\n spinStop('⚠️', `Config file not found: ${options.configPath}, using defaults`);\n }\n }\n\n // Extract variant defaults from config for auto-variant class generation\n const variantDefaults = extractVariantDefaults(tokensConfig);\n const runtimeConfigValues = extractRuntimeConfigValues(tokensConfig);\n\n const resolvedEntries = resolveEntryPaths(options.entry, options.workspaceDir);\n const entryDirs = resolvedEntries.map((entry) => entry.absolutePath);\n const scanResult = await scanDirectoriesForSafelist(\n entryDirs,\n colorModes,\n options.variants,\n options.autoVariants,\n options.componentData,\n variantDefaults,\n runtimeConfigValues,\n );\n\n const totalFilesScanned = scanResult.filesScanned;\n const allClasses: string[] = [...scanResult.safelist];\n const allComponents = new Set<string>(scanResult.components);\n const packageDirs: string[] = [\n ...new Set(\n resolvedEntries.map((entry) =>\n entry.kind === 'directory' ? entry.absolutePath : entry.watchDirectory,\n ),\n ),\n ];\n\n // Add color mode classes\n const fullSafelist = [\n ...allClasses,\n ...getThemeAndScaleClasses(colorModes),\n ...getInternalSafelistClasses(),\n ];\n const finalSafelist = deduplicateSafelist(fullSafelist);\n\n // Generate CSS (Tailwind will scan entry dir for arbitrary classes on className props)\n const cssResult = await generateCSS(finalSafelist, tokensConfig, {\n scope: options.scope,\n contentDir: entryDirs,\n safeVarPrefixes: [\n ...getMotionVarPrefixes(options.componentData, [...allComponents]),\n ...getConfigurableCssVariables(),\n ],\n });\n\n // Write output\n const outputPath = path.isAbsolute(options.outFile)\n ? options.outFile\n : path.join(options.workspaceDir, options.outFile);\n const outputDir = path.dirname(outputPath);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, cssResult.css);\n\n const duration = Math.round(performance.now() - startTime);\n\n if (shouldLogStats) {\n printSimpleModeStats({\n cwd: options.workspaceDir,\n outputPath,\n totalFilesScanned,\n scannedFilePaths: scanResult.filePaths,\n classCount: cssResult.classCount,\n sizeBytes: cssResult.sizeBytes,\n sizeGzipBytes: cssResult.sizeGzipBytes,\n duration,\n scope: options.scope,\n verbose: options.verbose,\n optimizationStats: cssResult.optimizationStats,\n print,\n magenta,\n cyan,\n yellow,\n });\n }\n\n return { success: true, outputPath, packageDirs };\n};\n\nexport { generateCSS, generateSimpleModeCSS };\nexport type { UDSCSSOptions };\n"],"mappings":"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"}
@@ -24,11 +24,11 @@ const loadConfigFile = async (configPath) => {
24
24
  }
25
25
  };
26
26
  const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
27
- const files = await (0, fast_glob.default)("**/*.{js,jsx,ts,tsx}", {
27
+ const files = (await (0, fast_glob.default)("**/*.{js,jsx,mjs,cjs,ts,tsx}", {
28
28
  cwd: dir,
29
29
  absolute: true,
30
30
  ignore: ["**/node_modules/**"]
31
- });
31
+ })).sort((left, right) => left.localeCompare(right));
32
32
  const results = await Promise.all(files.map(async (filePath) => {
33
33
  return require_purgeFromCode.purgeFromCodeOptimized(node_fs.default.readFileSync(filePath, "utf-8"), {
34
34
  colorModes,
@@ -41,10 +41,15 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
41
41
  filePath
42
42
  });
43
43
  }));
44
+ const allClasses = results.flatMap((result) => result.safelist);
45
+ const allComponents = new Set(results.flatMap((result) => result.components));
46
+ const filesWithComponents = results.filter((result) => result.components.length > 0).length;
44
47
  return {
45
- safelist: results.flatMap((result) => result.safelist),
46
- components: [...new Set(results.flatMap((result) => result.components))],
47
- filesScanned: files.length
48
+ safelist: allClasses,
49
+ components: [...allComponents],
50
+ filesScanned: files.length,
51
+ filesWithComponents,
52
+ filePaths: files
48
53
  };
49
54
  };
50
55
  const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
@@ -60,7 +65,9 @@ const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants,
60
65
  return {
61
66
  safelist: result.safelist,
62
67
  components: result.components,
63
- filesScanned: 1
68
+ filesScanned: 1,
69
+ filesWithComponents: result.components.length > 0 ? 1 : 0,
70
+ filePaths: [filePath]
64
71
  };
65
72
  };
66
73
  const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
@@ -71,7 +78,9 @@ const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVarian
71
78
  return {
72
79
  safelist: results.flatMap((result) => result.safelist),
73
80
  components: [...new Set(results.flatMap((result) => result.components))],
74
- filesScanned: results.reduce((total, result) => total + result.filesScanned, 0)
81
+ filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),
82
+ filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),
83
+ filePaths: results.flatMap((result) => result.filePaths).sort((left, right) => left.localeCompare(right))
75
84
  };
76
85
  };
77
86
  const findMonorepoRoot = (startDir) => {
@@ -82,13 +91,45 @@ const findMonorepoRoot = (startDir) => {
82
91
  };
83
92
  return findUp(startDir);
84
93
  };
94
+ const readPackageName = (packageJsonPath) => {
95
+ try {
96
+ const pkgJson = JSON.parse(node_fs.default.readFileSync(packageJsonPath, "utf8"));
97
+ return typeof pkgJson.name === "string" ? pkgJson.name : null;
98
+ } catch {
99
+ return null;
100
+ }
101
+ };
102
+ const findPackageRootFromResolvedEntry = (resolvedEntryPath, packageName) => {
103
+ let currentPath = node_fs.default.statSync(resolvedEntryPath).isDirectory() ? resolvedEntryPath : node_path.default.dirname(resolvedEntryPath);
104
+ while (true) {
105
+ const packageJsonPath = node_path.default.join(currentPath, "package.json");
106
+ if (node_fs.default.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) return currentPath;
107
+ const parentPath = node_path.default.dirname(currentPath);
108
+ if (parentPath === currentPath) return null;
109
+ currentPath = parentPath;
110
+ }
111
+ };
112
+ const findPackageRootInNodeModules = (startDir, packageName) => {
113
+ let currentDir = startDir;
114
+ while (true) {
115
+ const packageJsonPath = node_path.default.join(currentDir, "node_modules", packageName, "package.json");
116
+ if (node_fs.default.existsSync(packageJsonPath)) return node_path.default.dirname(packageJsonPath);
117
+ const parentDir = node_path.default.dirname(currentDir);
118
+ if (parentDir === currentDir) return null;
119
+ currentDir = parentDir;
120
+ }
121
+ };
85
122
  const resolvePackageRoot = (workspaceDir, packageName) => {
86
- const require = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
123
+ const requireFromWorkspace = (0, node_module.createRequire)(node_path.default.join(workspaceDir, "package.json"));
87
124
  try {
88
- const resolvedPackageJson = require.resolve(node_path.default.join(packageName, "package.json"), { paths: [workspaceDir] });
125
+ const resolvedPackageJson = requireFromWorkspace.resolve(node_path.default.join(packageName, "package.json"));
89
126
  return node_path.default.dirname(resolvedPackageJson);
90
127
  } catch {
91
- return null;
128
+ try {
129
+ const packageRoot = findPackageRootFromResolvedEntry(requireFromWorkspace.resolve(packageName), packageName);
130
+ if (packageRoot) return packageRoot;
131
+ } catch {}
132
+ return findPackageRootInNodeModules(workspaceDir, packageName);
92
133
  }
93
134
  };
94
135
  const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
@@ -97,14 +138,17 @@ const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
97
138
  absolute: true,
98
139
  ignore: ["**/node_modules/**", "**/dist/**"]
99
140
  }).find((pkgJsonPath) => {
100
- try {
101
- return JSON.parse(node_fs.default.readFileSync(pkgJsonPath, "utf8")).name === packageName;
102
- } catch {
103
- return false;
104
- }
141
+ return readPackageName(pkgJsonPath) === packageName;
105
142
  });
106
143
  return matchingPath ? node_path.default.dirname(matchingPath) : null;
107
144
  };
145
+ const findPackageRoot = (packageName) => {
146
+ const workspaceDir = process.cwd();
147
+ const monorepoRoot = findMonorepoRoot(workspaceDir);
148
+ let packageRoot = resolvePackageRoot(workspaceDir, packageName);
149
+ if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
150
+ return packageRoot;
151
+ };
108
152
  const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
109
153
  return [
110
154
  packageRoot ? node_path.default.join(packageRoot, "src") : null,
@@ -119,11 +163,19 @@ const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) =>
119
163
  };
120
164
  const getFirstExistingPath = (candidates) => candidates.find((candidate) => node_fs.default.existsSync(candidate)) ?? null;
121
165
  const findPackageSourceDir = (packageName) => {
122
- const workspaceDir = process.cwd();
123
- const monorepoRoot = findMonorepoRoot(workspaceDir);
124
- let packageRoot = resolvePackageRoot(workspaceDir, packageName);
125
- if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
126
- return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
166
+ return getFirstExistingPath(buildPackageSourceCandidates(process.cwd(), packageName, findPackageRoot(packageName)));
167
+ };
168
+ const getPackageUdsScope = (packageName) => {
169
+ const packageRoot = findPackageRoot(packageName);
170
+ if (!packageRoot) return null;
171
+ const packageJsonPath = node_path.default.join(packageRoot, "package.json");
172
+ if (!node_fs.default.existsSync(packageJsonPath)) return null;
173
+ try {
174
+ const scope = JSON.parse(node_fs.default.readFileSync(packageJsonPath, "utf8")).uds?.scope;
175
+ return typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : null;
176
+ } catch {
177
+ return null;
178
+ }
127
179
  };
128
180
  const scaffoldThemeConfig = async (options) => {
129
181
  const workspaceDir = process.cwd();
@@ -155,6 +207,23 @@ export default defineTheme({
155
207
  // Packages that inherit your app's theme (merged into main uds.css)
156
208
  // inherit: ['@your-org/shared-ui'],
157
209
 
210
+ // Packages that generate separate scoped CSS outputs.
211
+ // Scope class is discovered from each package.json uds.scope.
212
+ // When entry is omitted, the package is scanned the same way as inherit.
213
+ // scoped: {
214
+ // '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'
215
+ // }
216
+ //
217
+ // Or use the expanded form for custom output paths:
218
+ // scoped: {
219
+ // '@your-org/shared-ui': {
220
+ // config: './packages/shared-ui/uds.config.ts',
221
+ // entry: './src',
222
+ // // outFile defaults to dist/shared-ui.css
223
+ // outFile: 'dist/shared-ui.css'
224
+ // },
225
+ // },
226
+
158
227
  // CSS generation options (all optional)
159
228
  // css: {
160
229
  // safelist: [],
@@ -179,7 +248,9 @@ export default defineTheme({
179
248
  };
180
249
 
181
250
  //#endregion
251
+ exports.findPackageRoot = findPackageRoot;
182
252
  exports.findPackageSourceDir = findPackageSourceDir;
253
+ exports.getPackageUdsScope = getPackageUdsScope;
183
254
  exports.loadConfigFile = loadConfigFile;
184
255
  exports.scaffoldThemeConfig = scaffoldThemeConfig;
185
256
  exports.scanDirectoriesForSafelist = scanDirectoriesForSafelist;
@@ -20,11 +20,11 @@ const loadConfigFile = async (configPath) => {
20
20
  }
21
21
  };
22
22
  const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
23
- const files = await fg("**/*.{js,jsx,ts,tsx}", {
23
+ const files = (await fg("**/*.{js,jsx,mjs,cjs,ts,tsx}", {
24
24
  cwd: dir,
25
25
  absolute: true,
26
26
  ignore: ["**/node_modules/**"]
27
- });
27
+ })).sort((left, right) => left.localeCompare(right));
28
28
  const results = await Promise.all(files.map(async (filePath) => {
29
29
  return purgeFromCodeOptimized(fs.readFileSync(filePath, "utf-8"), {
30
30
  colorModes,
@@ -37,10 +37,15 @@ const scanDirectoryForSafelist = async (dir, colorModes, variants, autoVariants,
37
37
  filePath
38
38
  });
39
39
  }));
40
+ const allClasses = results.flatMap((result) => result.safelist);
41
+ const allComponents = new Set(results.flatMap((result) => result.components));
42
+ const filesWithComponents = results.filter((result) => result.components.length > 0).length;
40
43
  return {
41
- safelist: results.flatMap((result) => result.safelist),
42
- components: [...new Set(results.flatMap((result) => result.components))],
43
- filesScanned: files.length
44
+ safelist: allClasses,
45
+ components: [...allComponents],
46
+ filesScanned: files.length,
47
+ filesWithComponents,
48
+ filePaths: files
44
49
  };
45
50
  };
46
51
  const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
@@ -56,7 +61,9 @@ const scanFileForSafelist = async (filePath, colorModes, variants, autoVariants,
56
61
  return {
57
62
  safelist: result.safelist,
58
63
  components: result.components,
59
- filesScanned: 1
64
+ filesScanned: 1,
65
+ filesWithComponents: result.components.length > 0 ? 1 : 0,
66
+ filePaths: [filePath]
60
67
  };
61
68
  };
62
69
  const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVariants, componentData, variantDefaults, runtimeConfigValues, includeAllClassNamePrimitives = false) => {
@@ -67,7 +74,9 @@ const scanDirectoriesForSafelist = async (dirs, colorModes, variants, autoVarian
67
74
  return {
68
75
  safelist: results.flatMap((result) => result.safelist),
69
76
  components: [...new Set(results.flatMap((result) => result.components))],
70
- filesScanned: results.reduce((total, result) => total + result.filesScanned, 0)
77
+ filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),
78
+ filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),
79
+ filePaths: results.flatMap((result) => result.filePaths).sort((left, right) => left.localeCompare(right))
71
80
  };
72
81
  };
73
82
  const findMonorepoRoot = (startDir) => {
@@ -78,13 +87,45 @@ const findMonorepoRoot = (startDir) => {
78
87
  };
79
88
  return findUp(startDir);
80
89
  };
90
+ const readPackageName = (packageJsonPath) => {
91
+ try {
92
+ const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
93
+ return typeof pkgJson.name === "string" ? pkgJson.name : null;
94
+ } catch {
95
+ return null;
96
+ }
97
+ };
98
+ const findPackageRootFromResolvedEntry = (resolvedEntryPath, packageName) => {
99
+ let currentPath = fs.statSync(resolvedEntryPath).isDirectory() ? resolvedEntryPath : path.dirname(resolvedEntryPath);
100
+ while (true) {
101
+ const packageJsonPath = path.join(currentPath, "package.json");
102
+ if (fs.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) return currentPath;
103
+ const parentPath = path.dirname(currentPath);
104
+ if (parentPath === currentPath) return null;
105
+ currentPath = parentPath;
106
+ }
107
+ };
108
+ const findPackageRootInNodeModules = (startDir, packageName) => {
109
+ let currentDir = startDir;
110
+ while (true) {
111
+ const packageJsonPath = path.join(currentDir, "node_modules", packageName, "package.json");
112
+ if (fs.existsSync(packageJsonPath)) return path.dirname(packageJsonPath);
113
+ const parentDir = path.dirname(currentDir);
114
+ if (parentDir === currentDir) return null;
115
+ currentDir = parentDir;
116
+ }
117
+ };
81
118
  const resolvePackageRoot = (workspaceDir, packageName) => {
82
- const require = createRequire(import.meta.url);
119
+ const requireFromWorkspace = createRequire(path.join(workspaceDir, "package.json"));
83
120
  try {
84
- const resolvedPackageJson = require.resolve(path.join(packageName, "package.json"), { paths: [workspaceDir] });
121
+ const resolvedPackageJson = requireFromWorkspace.resolve(path.join(packageName, "package.json"));
85
122
  return path.dirname(resolvedPackageJson);
86
123
  } catch {
87
- return null;
124
+ try {
125
+ const packageRoot = findPackageRootFromResolvedEntry(requireFromWorkspace.resolve(packageName), packageName);
126
+ if (packageRoot) return packageRoot;
127
+ } catch {}
128
+ return findPackageRootInNodeModules(workspaceDir, packageName);
88
129
  }
89
130
  };
90
131
  const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
@@ -93,14 +134,17 @@ const findPackageRootInMonorepo = (monorepoRoot, packageName) => {
93
134
  absolute: true,
94
135
  ignore: ["**/node_modules/**", "**/dist/**"]
95
136
  }).find((pkgJsonPath) => {
96
- try {
97
- return JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")).name === packageName;
98
- } catch {
99
- return false;
100
- }
137
+ return readPackageName(pkgJsonPath) === packageName;
101
138
  });
102
139
  return matchingPath ? path.dirname(matchingPath) : null;
103
140
  };
141
+ const findPackageRoot = (packageName) => {
142
+ const workspaceDir = process.cwd();
143
+ const monorepoRoot = findMonorepoRoot(workspaceDir);
144
+ let packageRoot = resolvePackageRoot(workspaceDir, packageName);
145
+ if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
146
+ return packageRoot;
147
+ };
104
148
  const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) => {
105
149
  return [
106
150
  packageRoot ? path.join(packageRoot, "src") : null,
@@ -115,11 +159,19 @@ const buildPackageSourceCandidates = (workspaceDir, packageName, packageRoot) =>
115
159
  };
116
160
  const getFirstExistingPath = (candidates) => candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
117
161
  const findPackageSourceDir = (packageName) => {
118
- const workspaceDir = process.cwd();
119
- const monorepoRoot = findMonorepoRoot(workspaceDir);
120
- let packageRoot = resolvePackageRoot(workspaceDir, packageName);
121
- if (!packageRoot && monorepoRoot) packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);
122
- return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));
162
+ return getFirstExistingPath(buildPackageSourceCandidates(process.cwd(), packageName, findPackageRoot(packageName)));
163
+ };
164
+ const getPackageUdsScope = (packageName) => {
165
+ const packageRoot = findPackageRoot(packageName);
166
+ if (!packageRoot) return null;
167
+ const packageJsonPath = path.join(packageRoot, "package.json");
168
+ if (!fs.existsSync(packageJsonPath)) return null;
169
+ try {
170
+ const scope = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")).uds?.scope;
171
+ return typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : null;
172
+ } catch {
173
+ return null;
174
+ }
123
175
  };
124
176
  const scaffoldThemeConfig = async (options) => {
125
177
  const workspaceDir = process.cwd();
@@ -151,6 +203,23 @@ export default defineTheme({
151
203
  // Packages that inherit your app's theme (merged into main uds.css)
152
204
  // inherit: ['@your-org/shared-ui'],
153
205
 
206
+ // Packages that generate separate scoped CSS outputs.
207
+ // Scope class is discovered from each package.json uds.scope.
208
+ // When entry is omitted, the package is scanned the same way as inherit.
209
+ // scoped: {
210
+ // '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'
211
+ // }
212
+ //
213
+ // Or use the expanded form for custom output paths:
214
+ // scoped: {
215
+ // '@your-org/shared-ui': {
216
+ // config: './packages/shared-ui/uds.config.ts',
217
+ // entry: './src',
218
+ // // outFile defaults to dist/shared-ui.css
219
+ // outFile: 'dist/shared-ui.css'
220
+ // },
221
+ // },
222
+
154
223
  // CSS generation options (all optional)
155
224
  // css: {
156
225
  // safelist: [],
@@ -175,5 +244,5 @@ export default defineTheme({
175
244
  };
176
245
 
177
246
  //#endregion
178
- export { findPackageSourceDir, loadConfigFile, scaffoldThemeConfig, scanDirectoriesForSafelist, scanDirectoryForSafelist };
247
+ export { findPackageRoot, findPackageSourceDir, getPackageUdsScope, loadConfigFile, scaffoldThemeConfig, scanDirectoriesForSafelist, scanDirectoryForSafelist };
179
248
  //# sourceMappingURL=nodeUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nodeUtils.js","names":[],"sources":["../../src/css/nodeUtils.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport { cyan, green, magenta, print, red } from '@yahoo/uds-cli/lib';\nimport fg from 'fast-glob';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport type { RuntimeConfigValues, VariantDefaults } from '../purger/optimized/purgeFromCode';\nimport { purgeFromCodeOptimized } from '../purger/optimized/purgeFromCode';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { formatEntryValue } from '../utils/entryPoints';\n\nconst loadConfigFile = async <T>(configPath: string): Promise<T | null> => {\n const absolutePath = path.isAbsolute(configPath)\n ? configPath\n : path.join(process.cwd(), configPath);\n\n if (!fs.existsSync(absolutePath)) {\n return null;\n }\n\n try {\n const module = await import(absolutePath);\n return module.default ?? module.config ?? module;\n } catch (error) {\n throw new Error(\n `Failed to load config file: ${absolutePath}\\n${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n};\n\nconst scanDirectoryForSafelist = async (\n dir: string,\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<{ safelist: string[]; components: string[]; filesScanned: number }> => {\n const files = await fg('**/*.{js,jsx,ts,tsx}', {\n cwd: dir,\n absolute: true,\n ignore: ['**/node_modules/**'],\n });\n\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 variantDefaults,\n runtimeConfigValues,\n variants,\n autoVariants,\n componentData,\n includeAllClassNamePrimitives,\n filePath,\n });\n }),\n );\n\n const allClasses = results.flatMap((result) => result.safelist);\n const allComponents = new Set(results.flatMap((result) => result.components));\n\n return {\n safelist: allClasses,\n components: [...allComponents],\n filesScanned: files.length,\n };\n};\n\nconst scanFileForSafelist = async (\n filePath: string,\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<{ safelist: string[]; components: string[]; filesScanned: number }> => {\n const code = fs.readFileSync(filePath, 'utf-8');\n const result = await purgeFromCodeOptimized(code, {\n colorModes,\n variantDefaults,\n runtimeConfigValues,\n variants,\n autoVariants,\n componentData,\n includeAllClassNamePrimitives,\n });\n\n return {\n safelist: result.safelist,\n components: result.components,\n filesScanned: 1,\n };\n};\n\nconst scanDirectoriesForSafelist = async (\n dirs: string[],\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<{ safelist: string[]; components: string[]; filesScanned: number }> => {\n const results = await Promise.all(\n dirs.map((dir) => {\n if (fs.existsSync(dir) && fs.statSync(dir).isFile()) {\n return scanFileForSafelist(\n dir,\n colorModes,\n variants,\n autoVariants,\n componentData,\n variantDefaults,\n runtimeConfigValues,\n includeAllClassNamePrimitives,\n );\n }\n\n return scanDirectoryForSafelist(\n dir,\n colorModes,\n variants,\n autoVariants,\n componentData,\n variantDefaults,\n runtimeConfigValues,\n includeAllClassNamePrimitives,\n );\n }),\n );\n\n return {\n safelist: results.flatMap((result) => result.safelist),\n components: [...new Set(results.flatMap((result) => result.components))],\n filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),\n };\n};\n\nconst findMonorepoRoot = (startDir: string): string | null => {\n const findUp = (currentDir: string): string | null => {\n if (fs.existsSync(path.join(currentDir, 'packages'))) {\n return currentDir;\n }\n\n const parentDir = path.dirname(currentDir);\n return parentDir === currentDir ? null : findUp(parentDir);\n };\n\n return findUp(startDir);\n};\n\nconst resolvePackageRoot = (workspaceDir: string, packageName: string): string | null => {\n const require = createRequire(import.meta.url);\n\n try {\n const resolvedPackageJson = require.resolve(path.join(packageName, 'package.json'), {\n paths: [workspaceDir],\n });\n return path.dirname(resolvedPackageJson);\n } catch {\n return null;\n }\n};\n\nconst findPackageRootInMonorepo = (monorepoRoot: string, packageName: string): string | null => {\n const packageJsonPaths = fg.sync('packages/**/package.json', {\n cwd: monorepoRoot,\n absolute: true,\n ignore: ['**/node_modules/**', '**/dist/**'],\n });\n\n const matchingPath = packageJsonPaths.find((pkgJsonPath) => {\n try {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')) as { name?: string };\n return pkgJson.name === packageName;\n } catch {\n return false;\n }\n });\n\n return matchingPath ? path.dirname(matchingPath) : null;\n};\n\nconst buildPackageSourceCandidates = (\n workspaceDir: string,\n packageName: string,\n packageRoot: string | null,\n): string[] => {\n return [\n packageRoot ? path.join(packageRoot, 'src') : null,\n packageRoot ? path.join(packageRoot, 'lib') : null,\n packageRoot ? path.join(packageRoot, 'dist') : null,\n packageRoot,\n path.join(workspaceDir, 'node_modules', packageName, 'src'),\n path.join(workspaceDir, 'node_modules', packageName, 'lib'),\n path.join(workspaceDir, 'node_modules', packageName, 'dist'),\n path.join(workspaceDir, 'node_modules', packageName),\n ].filter(Boolean) as string[];\n};\n\nconst getFirstExistingPath = (candidates: string[]): string | null =>\n candidates.find((candidate) => fs.existsSync(candidate)) ?? null;\n\nconst findPackageSourceDir = (packageName: string): string | null => {\n const workspaceDir = process.cwd();\n const monorepoRoot = findMonorepoRoot(workspaceDir);\n\n let packageRoot = resolvePackageRoot(workspaceDir, packageName);\n if (!packageRoot && monorepoRoot) {\n packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);\n }\n\n return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));\n};\n\nconst scaffoldThemeConfig = async (options: {\n outputPath?: string;\n configPath?: string;\n entry?: EntryValue;\n force?: boolean;\n}): Promise<void> => {\n const workspaceDir = process.cwd();\n const outputPath = options.outputPath ?? 'uds.theme.ts';\n const absoluteOutputPath = path.isAbsolute(outputPath)\n ? outputPath\n : path.join(workspaceDir, outputPath);\n\n if (fs.existsSync(absoluteOutputPath) && !options.force) {\n print(red(`Error: ${outputPath} already exists. Use --force to overwrite.`));\n process.exitCode = 1;\n return;\n }\n\n const configPath = options.configPath ?? './uds.config.ts';\n const entry = options.entry ?? './src';\n const serializedEntry = formatEntryValue(entry);\n\n const template = `import { defineTheme } from '@yahoo/uds';\n\n/**\n * UDS Theme Configuration\n * \n * This file configures CSS generation for your app and shared packages.\n * Run \\`uds css\\` to generate optimized CSS.\n */\nexport default defineTheme({\n // Path to your uds.config.ts file\n config: '${configPath}',\n\n // Entry directory or .tsx file path for scanning your app code\n entry: ${serializedEntry},\n\n // Color modes to include (light mode is always in :root)\n colorModes: ['dark'],\n\n // Packages that inherit your app's theme (merged into main uds.css)\n // inherit: ['@your-org/shared-ui'],\n\n // CSS generation options (all optional)\n // css: {\n // safelist: [],\n // preflight: true,\n // fontFaceDeclarations: true,\n // optimization: {\n // removeUnusedFonts: false,\n // removeEmptyRules: true,\n // deduplicateScopedCss: true\n // }\n // }\n});\n`;\n\n fs.writeFileSync(absoluteOutputPath, template);\n\n print('');\n print(green('✅ Created uds.theme.ts'));\n print('');\n print(`${magenta('Next steps:')}`);\n print(` 1. Review and customize ${cyan(outputPath)}`);\n print(` 2. Run ${cyan('uds css')} to generate CSS`);\n print('');\n};\n\nexport {\n findPackageSourceDir,\n loadConfigFile,\n scaffoldThemeConfig,\n scanDirectoriesForSafelist,\n scanDirectoryForSafelist,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"nodeUtils.js","names":[],"sources":["../../src/css/nodeUtils.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport { cyan, green, magenta, print, red } from '@yahoo/uds-cli/lib';\nimport fg from 'fast-glob';\n\nimport type { SerializedComponentInfo } from '../commands/generateComponentData';\nimport type { RuntimeConfigValues, VariantDefaults } from '../purger/optimized/purgeFromCode';\nimport { purgeFromCodeOptimized } from '../purger/optimized/purgeFromCode';\nimport type { EntryValue } from '../utils/entryPoints';\nimport { formatEntryValue } from '../utils/entryPoints';\n\ntype SafelistScanResult = {\n safelist: string[];\n components: string[];\n filesScanned: number;\n filesWithComponents: number;\n filePaths: string[];\n};\n\nconst loadConfigFile = async <T>(configPath: string): Promise<T | null> => {\n const absolutePath = path.isAbsolute(configPath)\n ? configPath\n : path.join(process.cwd(), configPath);\n\n if (!fs.existsSync(absolutePath)) {\n return null;\n }\n\n try {\n const module = await import(absolutePath);\n return module.default ?? module.config ?? module;\n } catch (error) {\n throw new Error(\n `Failed to load config file: ${absolutePath}\\n${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n};\n\nconst scanDirectoryForSafelist = async (\n dir: string,\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<SafelistScanResult> => {\n const files = (\n await fg('**/*.{js,jsx,mjs,cjs,ts,tsx}', {\n cwd: dir,\n absolute: true,\n ignore: ['**/node_modules/**'],\n })\n ).sort((left, right) => left.localeCompare(right));\n\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 variantDefaults,\n runtimeConfigValues,\n variants,\n autoVariants,\n componentData,\n includeAllClassNamePrimitives,\n filePath,\n });\n }),\n );\n\n const allClasses = results.flatMap((result) => result.safelist);\n const allComponents = new Set(results.flatMap((result) => result.components));\n const filesWithComponents = results.filter((result) => result.components.length > 0).length;\n\n return {\n safelist: allClasses,\n components: [...allComponents],\n filesScanned: files.length,\n filesWithComponents,\n filePaths: files,\n };\n};\n\nconst scanFileForSafelist = async (\n filePath: string,\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<SafelistScanResult> => {\n const code = fs.readFileSync(filePath, 'utf-8');\n const result = await purgeFromCodeOptimized(code, {\n colorModes,\n variantDefaults,\n runtimeConfigValues,\n variants,\n autoVariants,\n componentData,\n includeAllClassNamePrimitives,\n });\n\n return {\n safelist: result.safelist,\n components: result.components,\n filesScanned: 1,\n filesWithComponents: result.components.length > 0 ? 1 : 0,\n filePaths: [filePath],\n };\n};\n\nconst scanDirectoriesForSafelist = async (\n dirs: string[],\n colorModes: ('dark' | 'light')[],\n variants: Record<string, Record<string, string>>,\n autoVariants: Record<string, Record<string, string>>,\n componentData: Record<string, SerializedComponentInfo>,\n variantDefaults?: VariantDefaults,\n runtimeConfigValues?: RuntimeConfigValues,\n includeAllClassNamePrimitives = false,\n): Promise<SafelistScanResult> => {\n const results = await Promise.all(\n dirs.map((dir) => {\n if (fs.existsSync(dir) && fs.statSync(dir).isFile()) {\n return scanFileForSafelist(\n dir,\n colorModes,\n variants,\n autoVariants,\n componentData,\n variantDefaults,\n runtimeConfigValues,\n includeAllClassNamePrimitives,\n );\n }\n\n return scanDirectoryForSafelist(\n dir,\n colorModes,\n variants,\n autoVariants,\n componentData,\n variantDefaults,\n runtimeConfigValues,\n includeAllClassNamePrimitives,\n );\n }),\n );\n\n return {\n safelist: results.flatMap((result) => result.safelist),\n components: [...new Set(results.flatMap((result) => result.components))],\n filesScanned: results.reduce((total, result) => total + result.filesScanned, 0),\n filesWithComponents: results.reduce((total, result) => total + result.filesWithComponents, 0),\n filePaths: results\n .flatMap((result) => result.filePaths)\n .sort((left, right) => left.localeCompare(right)),\n };\n};\n\nconst findMonorepoRoot = (startDir: string): string | null => {\n const findUp = (currentDir: string): string | null => {\n if (fs.existsSync(path.join(currentDir, 'packages'))) {\n return currentDir;\n }\n\n const parentDir = path.dirname(currentDir);\n return parentDir === currentDir ? null : findUp(parentDir);\n };\n\n return findUp(startDir);\n};\n\nconst readPackageName = (packageJsonPath: string): string | null => {\n try {\n const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string };\n return typeof pkgJson.name === 'string' ? pkgJson.name : null;\n } catch {\n return null;\n }\n};\n\nconst findPackageRootFromResolvedEntry = (\n resolvedEntryPath: string,\n packageName: string,\n): string | null => {\n let currentPath = fs.statSync(resolvedEntryPath).isDirectory()\n ? resolvedEntryPath\n : path.dirname(resolvedEntryPath);\n\n while (true) {\n const packageJsonPath = path.join(currentPath, 'package.json');\n if (fs.existsSync(packageJsonPath) && readPackageName(packageJsonPath) === packageName) {\n return currentPath;\n }\n\n const parentPath = path.dirname(currentPath);\n if (parentPath === currentPath) {\n return null;\n }\n\n currentPath = parentPath;\n }\n};\n\nconst findPackageRootInNodeModules = (startDir: string, packageName: string): string | null => {\n let currentDir = startDir;\n\n while (true) {\n const packageJsonPath = path.join(currentDir, 'node_modules', packageName, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n return path.dirname(packageJsonPath);\n }\n\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n return null;\n }\n\n currentDir = parentDir;\n }\n};\n\nconst resolvePackageRoot = (workspaceDir: string, packageName: string): string | null => {\n const requireFromWorkspace = createRequire(path.join(workspaceDir, 'package.json'));\n\n try {\n const resolvedPackageJson = requireFromWorkspace.resolve(\n path.join(packageName, 'package.json'),\n );\n return path.dirname(resolvedPackageJson);\n } catch {\n try {\n const resolvedPackageEntry = requireFromWorkspace.resolve(packageName);\n const packageRoot = findPackageRootFromResolvedEntry(resolvedPackageEntry, packageName);\n if (packageRoot) {\n return packageRoot;\n }\n } catch {\n // Fall through to explicit node_modules lookup below.\n }\n\n return findPackageRootInNodeModules(workspaceDir, packageName);\n }\n};\n\ntype PackageJsonShape = {\n uds?: {\n scope?: string;\n };\n};\n\nconst findPackageRootInMonorepo = (monorepoRoot: string, packageName: string): string | null => {\n const packageJsonPaths = fg.sync('packages/**/package.json', {\n cwd: monorepoRoot,\n absolute: true,\n ignore: ['**/node_modules/**', '**/dist/**'],\n });\n\n const matchingPath = packageJsonPaths.find((pkgJsonPath) => {\n return readPackageName(pkgJsonPath) === packageName;\n });\n\n return matchingPath ? path.dirname(matchingPath) : null;\n};\n\nconst findPackageRoot = (packageName: string): string | null => {\n const workspaceDir = process.cwd();\n const monorepoRoot = findMonorepoRoot(workspaceDir);\n\n let packageRoot = resolvePackageRoot(workspaceDir, packageName);\n if (!packageRoot && monorepoRoot) {\n packageRoot = findPackageRootInMonorepo(monorepoRoot, packageName);\n }\n\n return packageRoot;\n};\n\nconst buildPackageSourceCandidates = (\n workspaceDir: string,\n packageName: string,\n packageRoot: string | null,\n): string[] => {\n return [\n packageRoot ? path.join(packageRoot, 'src') : null,\n packageRoot ? path.join(packageRoot, 'lib') : null,\n packageRoot ? path.join(packageRoot, 'dist') : null,\n packageRoot,\n path.join(workspaceDir, 'node_modules', packageName, 'src'),\n path.join(workspaceDir, 'node_modules', packageName, 'lib'),\n path.join(workspaceDir, 'node_modules', packageName, 'dist'),\n path.join(workspaceDir, 'node_modules', packageName),\n ].filter(Boolean) as string[];\n};\n\nconst getFirstExistingPath = (candidates: string[]): string | null =>\n candidates.find((candidate) => fs.existsSync(candidate)) ?? null;\n\nconst findPackageSourceDir = (packageName: string): string | null => {\n const workspaceDir = process.cwd();\n const packageRoot = findPackageRoot(packageName);\n\n return getFirstExistingPath(buildPackageSourceCandidates(workspaceDir, packageName, packageRoot));\n};\n\nconst getPackageUdsScope = (packageName: string): string | null => {\n const packageRoot = findPackageRoot(packageName);\n if (!packageRoot) {\n return null;\n }\n\n const packageJsonPath = path.join(packageRoot, 'package.json');\n if (!fs.existsSync(packageJsonPath)) {\n return null;\n }\n\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as PackageJsonShape;\n const scope = packageJson.uds?.scope;\n return typeof scope === 'string' && scope.trim().length > 0 ? scope.trim() : null;\n } catch {\n return null;\n }\n};\n\nconst scaffoldThemeConfig = async (options: {\n outputPath?: string;\n configPath?: string;\n entry?: EntryValue;\n force?: boolean;\n}): Promise<void> => {\n const workspaceDir = process.cwd();\n const outputPath = options.outputPath ?? 'uds.theme.ts';\n const absoluteOutputPath = path.isAbsolute(outputPath)\n ? outputPath\n : path.join(workspaceDir, outputPath);\n\n if (fs.existsSync(absoluteOutputPath) && !options.force) {\n print(red(`Error: ${outputPath} already exists. Use --force to overwrite.`));\n process.exitCode = 1;\n return;\n }\n\n const configPath = options.configPath ?? './uds.config.ts';\n const entry = options.entry ?? './src';\n const serializedEntry = formatEntryValue(entry);\n\n const template = `import { defineTheme } from '@yahoo/uds';\n\n/**\n * UDS Theme Configuration\n * \n * This file configures CSS generation for your app and shared packages.\n * Run \\`uds css\\` to generate optimized CSS.\n */\nexport default defineTheme({\n // Path to your uds.config.ts file\n config: '${configPath}',\n\n // Entry directory or .tsx file path for scanning your app code\n entry: ${serializedEntry},\n\n // Color modes to include (light mode is always in :root)\n colorModes: ['dark'],\n\n // Packages that inherit your app's theme (merged into main uds.css)\n // inherit: ['@your-org/shared-ui'],\n\n // Packages that generate separate scoped CSS outputs.\n // Scope class is discovered from each package.json uds.scope.\n // When entry is omitted, the package is scanned the same way as inherit.\n // scoped: {\n // '@your-org/shared-ui': './packages/shared-ui/uds.config.ts'\n // }\n //\n // Or use the expanded form for custom output paths:\n // scoped: {\n // '@your-org/shared-ui': {\n // config: './packages/shared-ui/uds.config.ts',\n // entry: './src',\n // // outFile defaults to dist/shared-ui.css\n // outFile: 'dist/shared-ui.css'\n // },\n // },\n\n // CSS generation options (all optional)\n // css: {\n // safelist: [],\n // preflight: true,\n // fontFaceDeclarations: true,\n // optimization: {\n // removeUnusedFonts: false,\n // removeEmptyRules: true,\n // deduplicateScopedCss: true\n // }\n // }\n});\n`;\n\n fs.writeFileSync(absoluteOutputPath, template);\n\n print('');\n print(green('✅ Created uds.theme.ts'));\n print('');\n print(`${magenta('Next steps:')}`);\n print(` 1. Review and customize ${cyan(outputPath)}`);\n print(` 2. Run ${cyan('uds css')} to generate CSS`);\n print('');\n};\n\nexport {\n findPackageRoot,\n findPackageSourceDir,\n getPackageUdsScope,\n loadConfigFile,\n scaffoldThemeConfig,\n scanDirectoriesForSafelist,\n scanDirectoryForSafelist,\n};\nexport type { SafelistScanResult };\n"],"mappings":"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"}
@@ -2,6 +2,26 @@
2
2
  const require_postcss_helpers = require('./postcss.helpers.cjs');
3
3
 
4
4
  //#region src/css/postcss.ts
5
+ const fixScopedSelfOrParentSelectorsPlugin = (scopeClass) => {
6
+ return {
7
+ postcssPlugin: "fix-scoped-self-or-parent-selectors",
8
+ Once(root) {
9
+ root.walkRules((rule) => {
10
+ if (!rule.selector.includes(scopeClass)) return;
11
+ const nextSelectors = rule.selectors.reduce((acc, selector) => {
12
+ const sameElementSelector = require_postcss_helpers.getScopedSelfOrParentAlternativeSelector(selector, scopeClass);
13
+ if (sameElementSelector && !rule.selectors.includes(sameElementSelector)) return [
14
+ ...acc,
15
+ selector,
16
+ sameElementSelector
17
+ ];
18
+ return [...acc, selector];
19
+ }, []);
20
+ if (nextSelectors.length !== rule.selectors.length) rule.selectors = nextSelectors;
21
+ });
22
+ }
23
+ };
24
+ };
5
25
  /**
6
26
  * PostCSS plugin to fix color mode selectors for scoped CSS.
7
27
  *
@@ -31,4 +51,5 @@ const fixScopedColorModeSelectorsPlugin = (scopeClass) => {
31
51
  };
32
52
 
33
53
  //#endregion
34
- exports.fixScopedColorModeSelectorsPlugin = fixScopedColorModeSelectorsPlugin;
54
+ exports.fixScopedColorModeSelectorsPlugin = fixScopedColorModeSelectorsPlugin;
55
+ exports.fixScopedSelfOrParentSelectorsPlugin = fixScopedSelfOrParentSelectorsPlugin;
@@ -3,6 +3,7 @@
3
3
  //#region src/css/postcss.helpers.ts
4
4
  const COLOR_MODE_RE = /^(\.(uds-color-mode-(?:dark|light)))(\s+.+)?$/;
5
5
  const escapeForRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6
+ const SCOPED_SELF_OR_PARENT_RE = /^(\.[^\s>+~]+)(.*)$/;
6
7
  const getScopedColorModeAlternativeSelector = (selector, scopeClass, variant = "descendant") => {
7
8
  const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
8
9
  if (!scopeMatch) return null;
@@ -23,6 +24,16 @@ const buildScopedColorModeSelectorList = (ruleSelector, scopeClass) => {
23
24
  ];
24
25
  }, []).join(", ");
25
26
  };
27
+ const getScopedSelfOrParentAlternativeSelector = (selector, scopeClass) => {
28
+ const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
29
+ if (!scopeMatch) return null;
30
+ const targetMatch = scopeMatch[2].match(SCOPED_SELF_OR_PARENT_RE);
31
+ if (!targetMatch) return null;
32
+ const scopedTarget = targetMatch[1];
33
+ if (/^\.uds-color-mode-(?:dark|light)(?:$|[.#[:])/.test(scopedTarget)) return null;
34
+ return `${scopeClass}${scopedTarget}${targetMatch[2]}`;
35
+ };
26
36
 
27
37
  //#endregion
28
- exports.buildScopedColorModeSelectorList = buildScopedColorModeSelectorList;
38
+ exports.buildScopedColorModeSelectorList = buildScopedColorModeSelectorList;
39
+ exports.getScopedSelfOrParentAlternativeSelector = getScopedSelfOrParentAlternativeSelector;
@@ -2,6 +2,7 @@
2
2
  //#region src/css/postcss.helpers.ts
3
3
  const COLOR_MODE_RE = /^(\.(uds-color-mode-(?:dark|light)))(\s+.+)?$/;
4
4
  const escapeForRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ const SCOPED_SELF_OR_PARENT_RE = /^(\.[^\s>+~]+)(.*)$/;
5
6
  const getScopedColorModeAlternativeSelector = (selector, scopeClass, variant = "descendant") => {
6
7
  const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
7
8
  if (!scopeMatch) return null;
@@ -22,7 +23,16 @@ const buildScopedColorModeSelectorList = (ruleSelector, scopeClass) => {
22
23
  ];
23
24
  }, []).join(", ");
24
25
  };
26
+ const getScopedSelfOrParentAlternativeSelector = (selector, scopeClass) => {
27
+ const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\s+(.+)$`));
28
+ if (!scopeMatch) return null;
29
+ const targetMatch = scopeMatch[2].match(SCOPED_SELF_OR_PARENT_RE);
30
+ if (!targetMatch) return null;
31
+ const scopedTarget = targetMatch[1];
32
+ if (/^\.uds-color-mode-(?:dark|light)(?:$|[.#[:])/.test(scopedTarget)) return null;
33
+ return `${scopeClass}${scopedTarget}${targetMatch[2]}`;
34
+ };
25
35
 
26
36
  //#endregion
27
- export { buildScopedColorModeSelectorList };
37
+ export { buildScopedColorModeSelectorList, getScopedSelfOrParentAlternativeSelector };
28
38
  //# sourceMappingURL=postcss.helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"postcss.helpers.js","names":[],"sources":["../../src/css/postcss.helpers.ts"],"sourcesContent":["const COLOR_MODE_RE = /^(\\.(uds-color-mode-(?:dark|light)))(\\s+.+)?$/;\n\nconst escapeForRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\ntype ScopedColorModeSelectorVariant = 'descendant' | 'same-element';\n\nconst getScopedColorModeAlternativeSelector = (\n selector: string,\n scopeClass: string,\n variant: ScopedColorModeSelectorVariant = 'descendant',\n): string | null => {\n const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\\\s+(.+)$`));\n\n if (!scopeMatch) {\n return null;\n }\n\n const afterScope = scopeMatch[2];\n const colorModeMatch = afterScope.match(COLOR_MODE_RE);\n if (!colorModeMatch) {\n return null;\n }\n\n const colorModeClass = colorModeMatch[1];\n const rest = colorModeMatch[3] ?? '';\n return variant === 'same-element'\n ? `${colorModeClass}${scopeClass}${rest}`\n : `${colorModeClass} ${scopeClass}${rest}`;\n};\n\nconst buildScopedColorModeSelectorList = (ruleSelector: string, scopeClass: string): string => {\n const selectors = ruleSelector.split(',').map((value) => value.trim());\n const nextSelectors = selectors.reduce<string[]>((acc, selector) => {\n const altSelectors = [\n getScopedColorModeAlternativeSelector(selector, scopeClass),\n getScopedColorModeAlternativeSelector(selector, scopeClass, 'same-element'),\n ].filter((value): value is string => Boolean(value));\n const nextAltSelectors = altSelectors.filter(\n (altSelector) => !selectors.includes(altSelector) && !acc.includes(altSelector),\n );\n\n return [...acc, selector, ...nextAltSelectors];\n }, []);\n\n return nextSelectors.join(', ');\n};\n\nexport { buildScopedColorModeSelectorList, getScopedColorModeAlternativeSelector };\n"],"mappings":";;AAAA,MAAM,gBAAgB;AAEtB,MAAM,mBAAmB,UAA0B,MAAM,QAAQ,uBAAuB,OAAO;AAI/F,MAAM,yCACJ,UACA,YACA,UAA0C,iBACxB;CAClB,MAAM,aAAa,SAAS,MAAM,IAAI,OAAO,KAAK,gBAAgB,WAAW,CAAC,YAAY,CAAC;AAE3F,KAAI,CAAC,WACH,QAAO;CAIT,MAAM,iBADa,WAAW,GACI,MAAM,cAAc;AACtD,KAAI,CAAC,eACH,QAAO;CAGT,MAAM,iBAAiB,eAAe;CACtC,MAAM,OAAO,eAAe,MAAM;AAClC,QAAO,YAAY,iBACf,GAAG,iBAAiB,aAAa,SACjC,GAAG,eAAe,GAAG,aAAa;;AAGxC,MAAM,oCAAoC,cAAsB,eAA+B;CAC7F,MAAM,YAAY,aAAa,MAAM,IAAI,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC;AAatE,QAZsB,UAAU,QAAkB,KAAK,aAAa;EAKlE,MAAM,mBAJe,CACnB,sCAAsC,UAAU,WAAW,EAC3D,sCAAsC,UAAU,YAAY,eAAe,CAC5E,CAAC,QAAQ,UAA2B,QAAQ,MAAM,CAAC,CACd,QACnC,gBAAgB,CAAC,UAAU,SAAS,YAAY,IAAI,CAAC,IAAI,SAAS,YAAY,CAChF;AAED,SAAO;GAAC,GAAG;GAAK;GAAU,GAAG;GAAiB;IAC7C,EAAE,CAAC,CAEe,KAAK,KAAK"}
1
+ {"version":3,"file":"postcss.helpers.js","names":[],"sources":["../../src/css/postcss.helpers.ts"],"sourcesContent":["const COLOR_MODE_RE = /^(\\.(uds-color-mode-(?:dark|light)))(\\s+.+)?$/;\n\nconst escapeForRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\ntype ScopedColorModeSelectorVariant = 'descendant' | 'same-element';\n\nconst SCOPED_SELF_OR_PARENT_RE = /^(\\.[^\\s>+~]+)(.*)$/;\n\nconst getScopedColorModeAlternativeSelector = (\n selector: string,\n scopeClass: string,\n variant: ScopedColorModeSelectorVariant = 'descendant',\n): string | null => {\n const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\\\s+(.+)$`));\n\n if (!scopeMatch) {\n return null;\n }\n\n const afterScope = scopeMatch[2];\n const colorModeMatch = afterScope.match(COLOR_MODE_RE);\n if (!colorModeMatch) {\n return null;\n }\n\n const colorModeClass = colorModeMatch[1];\n const rest = colorModeMatch[3] ?? '';\n return variant === 'same-element'\n ? `${colorModeClass}${scopeClass}${rest}`\n : `${colorModeClass} ${scopeClass}${rest}`;\n};\n\nconst buildScopedColorModeSelectorList = (ruleSelector: string, scopeClass: string): string => {\n const selectors = ruleSelector.split(',').map((value) => value.trim());\n const nextSelectors = selectors.reduce<string[]>((acc, selector) => {\n const altSelectors = [\n getScopedColorModeAlternativeSelector(selector, scopeClass),\n getScopedColorModeAlternativeSelector(selector, scopeClass, 'same-element'),\n ].filter((value): value is string => Boolean(value));\n const nextAltSelectors = altSelectors.filter(\n (altSelector) => !selectors.includes(altSelector) && !acc.includes(altSelector),\n );\n\n return [...acc, selector, ...nextAltSelectors];\n }, []);\n\n return nextSelectors.join(', ');\n};\n\nconst getScopedSelfOrParentAlternativeSelector = (\n selector: string,\n scopeClass: string,\n): string | null => {\n const scopeMatch = selector.match(new RegExp(`^(${escapeForRegExp(scopeClass)})\\\\s+(.+)$`));\n\n if (!scopeMatch) {\n return null;\n }\n\n const afterScope = scopeMatch[2];\n const targetMatch = afterScope.match(SCOPED_SELF_OR_PARENT_RE);\n if (!targetMatch) {\n return null;\n }\n\n const scopedTarget = targetMatch[1];\n if (/^\\.uds-color-mode-(?:dark|light)(?:$|[.#[:])/.test(scopedTarget)) {\n return null;\n }\n\n return `${scopeClass}${scopedTarget}${targetMatch[2]}`;\n};\n\nconst buildScopedSelfOrParentSelectorList = (ruleSelector: string, scopeClass: string): string => {\n const selectors = ruleSelector.split(',').map((value) => value.trim());\n const nextSelectors = selectors.reduce<string[]>((acc, selector) => {\n const sameElementSelector = getScopedSelfOrParentAlternativeSelector(selector, scopeClass);\n const nextAltSelectors: string[] = [];\n\n if (\n sameElementSelector &&\n !selectors.includes(sameElementSelector) &&\n !acc.includes(sameElementSelector)\n ) {\n nextAltSelectors.push(sameElementSelector);\n }\n\n return [...acc, selector, ...nextAltSelectors];\n }, []);\n\n return nextSelectors.join(', ');\n};\n\nexport {\n buildScopedColorModeSelectorList,\n buildScopedSelfOrParentSelectorList,\n getScopedColorModeAlternativeSelector,\n getScopedSelfOrParentAlternativeSelector,\n};\n"],"mappings":";;AAAA,MAAM,gBAAgB;AAEtB,MAAM,mBAAmB,UAA0B,MAAM,QAAQ,uBAAuB,OAAO;AAI/F,MAAM,2BAA2B;AAEjC,MAAM,yCACJ,UACA,YACA,UAA0C,iBACxB;CAClB,MAAM,aAAa,SAAS,MAAM,IAAI,OAAO,KAAK,gBAAgB,WAAW,CAAC,YAAY,CAAC;AAE3F,KAAI,CAAC,WACH,QAAO;CAIT,MAAM,iBADa,WAAW,GACI,MAAM,cAAc;AACtD,KAAI,CAAC,eACH,QAAO;CAGT,MAAM,iBAAiB,eAAe;CACtC,MAAM,OAAO,eAAe,MAAM;AAClC,QAAO,YAAY,iBACf,GAAG,iBAAiB,aAAa,SACjC,GAAG,eAAe,GAAG,aAAa;;AAGxC,MAAM,oCAAoC,cAAsB,eAA+B;CAC7F,MAAM,YAAY,aAAa,MAAM,IAAI,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC;AAatE,QAZsB,UAAU,QAAkB,KAAK,aAAa;EAKlE,MAAM,mBAJe,CACnB,sCAAsC,UAAU,WAAW,EAC3D,sCAAsC,UAAU,YAAY,eAAe,CAC5E,CAAC,QAAQ,UAA2B,QAAQ,MAAM,CAAC,CACd,QACnC,gBAAgB,CAAC,UAAU,SAAS,YAAY,IAAI,CAAC,IAAI,SAAS,YAAY,CAChF;AAED,SAAO;GAAC,GAAG;GAAK;GAAU,GAAG;GAAiB;IAC7C,EAAE,CAAC,CAEe,KAAK,KAAK;;AAGjC,MAAM,4CACJ,UACA,eACkB;CAClB,MAAM,aAAa,SAAS,MAAM,IAAI,OAAO,KAAK,gBAAgB,WAAW,CAAC,YAAY,CAAC;AAE3F,KAAI,CAAC,WACH,QAAO;CAIT,MAAM,cADa,WAAW,GACC,MAAM,yBAAyB;AAC9D,KAAI,CAAC,YACH,QAAO;CAGT,MAAM,eAAe,YAAY;AACjC,KAAI,+CAA+C,KAAK,aAAa,CACnE,QAAO;AAGT,QAAO,GAAG,aAAa,eAAe,YAAY"}