@yahoo/uds 3.123.0 → 3.124.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.cts +1 -1
- package/dist/components/client/Menu/Menu.ItemCheckbox.d.ts +1 -1
- package/dist/components/client/Toast/UDSToastConfigProvider.d.cts +5 -5
- package/dist/components/client/Toast/UDSToastConfigProvider.d.ts +5 -5
- package/dist/styles/styler.d.cts +34 -34
- package/dist/styles/styler.d.ts +34 -34
- package/dist/tailwind/dist/commands/css.cjs +17 -3
- package/dist/tailwind/dist/commands/css.d.cts.map +1 -1
- package/dist/tailwind/dist/commands/css.d.ts.map +1 -1
- package/dist/tailwind/dist/commands/css.helpers.cjs +2 -1
- package/dist/tailwind/dist/commands/css.helpers.js +2 -1
- package/dist/tailwind/dist/commands/css.helpers.js.map +1 -1
- package/dist/tailwind/dist/commands/css.js +17 -3
- package/dist/tailwind/dist/commands/css.js.map +1 -1
- package/dist/tailwind/dist/css/generate.cjs +3 -0
- package/dist/tailwind/dist/css/generate.helpers.cjs +14 -6
- package/dist/tailwind/dist/css/generate.helpers.js +15 -7
- package/dist/tailwind/dist/css/generate.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/generate.js +3 -0
- package/dist/tailwind/dist/css/generate.js.map +1 -1
- package/dist/tailwind/dist/css/nodeUtils.cjs +91 -20
- package/dist/tailwind/dist/css/nodeUtils.js +90 -21
- package/dist/tailwind/dist/css/nodeUtils.js.map +1 -1
- package/dist/tailwind/dist/css/postcss.cjs +22 -1
- package/dist/tailwind/dist/css/postcss.helpers.cjs +12 -1
- package/dist/tailwind/dist/css/postcss.helpers.js +11 -1
- package/dist/tailwind/dist/css/postcss.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/postcss.js +22 -2
- package/dist/tailwind/dist/css/postcss.js.map +1 -1
- package/dist/tailwind/dist/css/runner.cjs +171 -20
- package/dist/tailwind/dist/css/runner.helpers.cjs +58 -6
- package/dist/tailwind/dist/css/runner.helpers.js +54 -7
- package/dist/tailwind/dist/css/runner.helpers.js.map +1 -1
- package/dist/tailwind/dist/css/runner.js +172 -20
- package/dist/tailwind/dist/css/runner.js.map +1 -1
- package/dist/tailwind/dist/css/theme.d.cts +11 -0
- package/dist/tailwind/dist/css/theme.d.cts.map +1 -1
- package/dist/tailwind/dist/css/theme.d.ts +11 -0
- package/dist/tailwind/dist/css/theme.d.ts.map +1 -1
- package/dist/tailwind/dist/css/theme.js.map +1 -1
- package/dist/tailwind/dist/purger/optimized/ast/expressions.cjs +26 -3
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js +26 -3
- package/dist/tailwind/dist/purger/optimized/ast/expressions.js.map +1 -1
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.cts +1 -1
- package/dist/tailwind/dist/tailwind/utils/getFontStyles.d.ts +1 -1
- package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.cts +4 -4
- package/dist/tailwind/dist/tailwind/utils/getShadowStyles.d.ts +4 -4
- package/dist/uds/generated/componentData.cjs +1152 -1152
- package/dist/uds/generated/componentData.js +1152 -1152
- package/generated/componentData.json +1738 -1738
- package/package.json +1 -1
|
@@ -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\
|
|
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"}
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Tailwind and Purger v0.0.0-development */
|
|
2
|
-
import { buildScopedColorModeSelectorList } from "./postcss.helpers.js";
|
|
2
|
+
import { buildScopedColorModeSelectorList, getScopedSelfOrParentAlternativeSelector } from "./postcss.helpers.js";
|
|
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 = 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,5 +51,5 @@ const fixScopedColorModeSelectorsPlugin = (scopeClass) => {
|
|
|
31
51
|
};
|
|
32
52
|
|
|
33
53
|
//#endregion
|
|
34
|
-
export { fixScopedColorModeSelectorsPlugin };
|
|
54
|
+
export { fixScopedColorModeSelectorsPlugin, fixScopedSelfOrParentSelectorsPlugin };
|
|
35
55
|
//# sourceMappingURL=postcss.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postcss.js","names":[],"sources":["../../src/css/postcss.ts"],"sourcesContent":["import type postcss from 'postcss';\n\nimport {
|
|
1
|
+
{"version":3,"file":"postcss.js","names":[],"sources":["../../src/css/postcss.ts"],"sourcesContent":["import type postcss from 'postcss';\n\nimport {\n buildScopedColorModeSelectorList,\n getScopedSelfOrParentAlternativeSelector,\n} from './postcss.helpers';\n\nconst fixScopedSelfOrParentSelectorsPlugin = (scopeClass: string): postcss.Plugin => {\n return {\n postcssPlugin: 'fix-scoped-self-or-parent-selectors',\n Once(root) {\n root.walkRules((rule) => {\n if (!rule.selector.includes(scopeClass)) {\n return;\n }\n\n const nextSelectors = rule.selectors.reduce<string[]>((acc, selector) => {\n const sameElementSelector = getScopedSelfOrParentAlternativeSelector(\n selector,\n scopeClass,\n );\n\n if (sameElementSelector && !rule.selectors.includes(sameElementSelector)) {\n return [...acc, selector, sameElementSelector];\n }\n\n return [...acc, selector];\n }, []);\n\n if (nextSelectors.length !== rule.selectors.length) {\n rule.selectors = nextSelectors;\n }\n });\n },\n };\n};\n\n/**\n * PostCSS plugin to fix color mode selectors for scoped CSS.\n *\n * postcss-scope converts selectors like:\n * `.uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo`\n *\n * But the color mode class is typically on <html> or <body>, which is an\n * ANCESTOR of the scope, not a descendant. This plugin adds alternative\n * selectors so color modes work correctly:\n *\n * `.scope .uds-color-mode-dark .foo` → `.scope .uds-color-mode-dark .foo, .uds-color-mode-dark .scope .foo, .uds-color-mode-dark.scope .foo`\n *\n * This ensures styles apply whether the color mode class is inside or outside the scope.\n */\nconst fixScopedColorModeSelectorsPlugin = (scopeClass: string): postcss.Plugin => {\n const colorModePattern = /\\.(uds-color-mode-(?:dark|light))/;\n\n return {\n postcssPlugin: 'fix-scoped-color-mode-selectors',\n // Use Once to process all rules after parsing is complete\n Once(root) {\n root.walkRules((rule) => {\n // Skip if selector doesn't contain both scope and color mode\n if (!rule.selector.includes(scopeClass) || !colorModePattern.test(rule.selector)) {\n return;\n }\n\n const nextSelector = buildScopedColorModeSelectorList(rule.selector, scopeClass);\n if (nextSelector !== rule.selector) {\n rule.selector = nextSelector;\n }\n });\n },\n };\n};\nexport { fixScopedColorModeSelectorsPlugin, fixScopedSelfOrParentSelectorsPlugin };\n"],"mappings":";;;;AAOA,MAAM,wCAAwC,eAAuC;AACnF,QAAO;EACL,eAAe;EACf,KAAK,MAAM;AACT,QAAK,WAAW,SAAS;AACvB,QAAI,CAAC,KAAK,SAAS,SAAS,WAAW,CACrC;IAGF,MAAM,gBAAgB,KAAK,UAAU,QAAkB,KAAK,aAAa;KACvE,MAAM,sBAAsB,yCAC1B,UACA,WACD;AAED,SAAI,uBAAuB,CAAC,KAAK,UAAU,SAAS,oBAAoB,CACtE,QAAO;MAAC,GAAG;MAAK;MAAU;MAAoB;AAGhD,YAAO,CAAC,GAAG,KAAK,SAAS;OACxB,EAAE,CAAC;AAEN,QAAI,cAAc,WAAW,KAAK,UAAU,OAC1C,MAAK,YAAY;KAEnB;;EAEL;;;;;;;;;;;;;;;;AAiBH,MAAM,qCAAqC,eAAuC;CAChF,MAAM,mBAAmB;AAEzB,QAAO;EACL,eAAe;EAEf,KAAK,MAAM;AACT,QAAK,WAAW,SAAS;AAEvB,QAAI,CAAC,KAAK,SAAS,SAAS,WAAW,IAAI,CAAC,iBAAiB,KAAK,KAAK,SAAS,CAC9E;IAGF,MAAM,eAAe,iCAAiC,KAAK,UAAU,WAAW;AAChF,QAAI,iBAAiB,KAAK,SACxB,MAAK,WAAW;KAElB;;EAEL"}
|
|
@@ -8,19 +8,60 @@ const require_entryPoints = require('../utils/entryPoints.cjs');
|
|
|
8
8
|
const require_nodeUtils = require('./nodeUtils.cjs');
|
|
9
9
|
const require_index = require('../config/dist/index.cjs');
|
|
10
10
|
const require_safelist = require('../purger/optimized/utils/safelist.cjs');
|
|
11
|
+
const require_runner_helpers = require('./runner.helpers.cjs');
|
|
11
12
|
const require_utils = require('./utils.cjs');
|
|
12
13
|
const require_generate_helpers = require('./generate.helpers.cjs');
|
|
13
14
|
const require_generate = require('./generate.cjs');
|
|
14
|
-
const require_runner_helpers = require('./runner.helpers.cjs');
|
|
15
15
|
let node_fs = require("node:fs");
|
|
16
16
|
node_fs = require_runtime.__toESM(node_fs);
|
|
17
|
-
let node_path = require("node:path");
|
|
18
|
-
node_path = require_runtime.__toESM(node_path);
|
|
19
17
|
|
|
20
18
|
//#region src/css/runner.ts
|
|
19
|
+
const getScopedPackageOutputPath = (packageName, outFile) => {
|
|
20
|
+
if (typeof outFile === "string" && outFile.trim().length > 0) return outFile;
|
|
21
|
+
return `dist/${packageName.split("/").pop() ?? packageName}.css`;
|
|
22
|
+
};
|
|
23
|
+
const normalizeScopedPackageConfig = (scopedPackageValue) => {
|
|
24
|
+
if (typeof scopedPackageValue === "string") return { config: scopedPackageValue };
|
|
25
|
+
return scopedPackageValue;
|
|
26
|
+
};
|
|
27
|
+
const resolveScopedEntryDirs = (packageRoot, packageDir, entry) => {
|
|
28
|
+
if (entry === void 0) return [packageDir];
|
|
29
|
+
return require_entryPoints.resolveEntryPaths(entry, packageRoot).map((resolvedEntry) => resolvedEntry.absolutePath);
|
|
30
|
+
};
|
|
31
|
+
const PATH_SEPARATOR = "/";
|
|
32
|
+
const normalizePath = (value) => value.replace(/\\/g, PATH_SEPARATOR);
|
|
33
|
+
const isAbsolutePath = (value) => {
|
|
34
|
+
const normalizedValue = normalizePath(value);
|
|
35
|
+
return normalizedValue.startsWith(PATH_SEPARATOR) || /^[A-Za-z]:\//.test(normalizedValue);
|
|
36
|
+
};
|
|
37
|
+
const joinPath = (...parts) => {
|
|
38
|
+
const filteredParts = parts.filter((part) => part.length > 0);
|
|
39
|
+
if (filteredParts.length === 0) return "";
|
|
40
|
+
return filteredParts.map((part, index) => {
|
|
41
|
+
const normalizedPart = normalizePath(part);
|
|
42
|
+
if (index === 0) return normalizedPart.replace(/\/+$/g, "");
|
|
43
|
+
return normalizedPart.replace(/^\/+|\/+$/g, "");
|
|
44
|
+
}).join(PATH_SEPARATOR).replace(/\/+/g, PATH_SEPARATOR).replace(/\/\.\//g, PATH_SEPARATOR);
|
|
45
|
+
};
|
|
46
|
+
const dirnamePath = (value) => {
|
|
47
|
+
const normalizedValue = normalizePath(value).replace(/\/+$/g, "");
|
|
48
|
+
const lastSeparatorIndex = normalizedValue.lastIndexOf(PATH_SEPARATOR);
|
|
49
|
+
if (lastSeparatorIndex <= 0) return lastSeparatorIndex === 0 ? PATH_SEPARATOR : ".";
|
|
50
|
+
return normalizedValue.slice(0, lastSeparatorIndex);
|
|
51
|
+
};
|
|
52
|
+
const basenamePath = (value) => {
|
|
53
|
+
const normalizedValue = normalizePath(value).replace(/\/+$/g, "");
|
|
54
|
+
const lastSeparatorIndex = normalizedValue.lastIndexOf(PATH_SEPARATOR);
|
|
55
|
+
return lastSeparatorIndex >= 0 ? normalizedValue.slice(lastSeparatorIndex + 1) : normalizedValue;
|
|
56
|
+
};
|
|
57
|
+
const resolveOutputPath = (workspaceDir, outFile) => isAbsolutePath(outFile) ? outFile : joinPath(workspaceDir, outFile);
|
|
58
|
+
const ensureOutputDirectory = (outputPath) => {
|
|
59
|
+
const outputDir = dirnamePath(outputPath);
|
|
60
|
+
if (!node_fs.default.existsSync(outputDir)) node_fs.default.mkdirSync(outputDir, { recursive: true });
|
|
61
|
+
};
|
|
21
62
|
const SOURCE_FILE_PATTERN = /\.(jsx?|tsx?)$/i;
|
|
22
|
-
const getWatchDirs = (dirs) => [...new Set(dirs.filter((dir) => !dir.split(
|
|
23
|
-
const isCoveredByRecursiveWatch = (watchPath, targetPath) => targetPath === watchPath || targetPath.startsWith(`${watchPath}${
|
|
63
|
+
const getWatchDirs = (dirs) => [...new Set(dirs.filter((dir) => !normalizePath(dir).split(PATH_SEPARATOR).includes("node_modules")))];
|
|
64
|
+
const isCoveredByRecursiveWatch = (watchPath, targetPath) => targetPath === watchPath || targetPath.startsWith(`${watchPath}${PATH_SEPARATOR}`);
|
|
24
65
|
const getEntryWatchTargets = (entries) => {
|
|
25
66
|
const directoryTargets = getWatchDirs(entries.filter((entry) => entry.kind === "directory").map((entry) => entry.absolutePath)).map((watchPath) => ({
|
|
26
67
|
watchPath,
|
|
@@ -44,7 +85,7 @@ const watchSourceFiles = (targets, onFileChange) => {
|
|
|
44
85
|
targets.forEach((target) => {
|
|
45
86
|
node_fs.default.watch(target.watchPath, { recursive: target.recursive }, (_eventType, filename) => {
|
|
46
87
|
if (!filename || !SOURCE_FILE_PATTERN.test(filename)) return;
|
|
47
|
-
if (target.fileNames && !target.fileNames.includes(
|
|
88
|
+
if (target.fileNames && !target.fileNames.includes(basenamePath(String(filename)))) return;
|
|
48
89
|
onFileChange();
|
|
49
90
|
});
|
|
50
91
|
});
|
|
@@ -82,8 +123,13 @@ const createQueuedRegenerator = (options) => {
|
|
|
82
123
|
};
|
|
83
124
|
return regenerate;
|
|
84
125
|
};
|
|
126
|
+
const printVerboseScanFiles = (log, workspaceDir, filePaths) => {
|
|
127
|
+
require_runner_helpers.getVerboseScanFileList(workspaceDir, filePaths).forEach((filePath) => {
|
|
128
|
+
log.listItem(filePath);
|
|
129
|
+
});
|
|
130
|
+
};
|
|
85
131
|
const runCssCommand = async (options, context) => {
|
|
86
|
-
if (!node_fs.default.existsSync(
|
|
132
|
+
if (!node_fs.default.existsSync(joinPath(options.workspaceDir, String(options.themeConfigPath)))) {
|
|
87
133
|
await runSimpleMode(options, context);
|
|
88
134
|
return;
|
|
89
135
|
}
|
|
@@ -104,7 +150,8 @@ const runSimpleMode = async (options, context) => {
|
|
|
104
150
|
scope: options.scope,
|
|
105
151
|
configPath,
|
|
106
152
|
isWatch: options.watch,
|
|
107
|
-
silent: options.silent
|
|
153
|
+
silent: options.silent,
|
|
154
|
+
verbose: options.verbose
|
|
108
155
|
});
|
|
109
156
|
if (options.watch) await runSimpleModeWatch(options, context, entry, configPath, result.packageDirs ?? []);
|
|
110
157
|
} catch (error) {
|
|
@@ -184,7 +231,7 @@ const loadThemeModeSetup = async (options) => {
|
|
|
184
231
|
};
|
|
185
232
|
const runThemeMode = async (options, context) => {
|
|
186
233
|
const workspaceDir = options.workspaceDir;
|
|
187
|
-
const outputPath =
|
|
234
|
+
const outputPath = resolveOutputPath(workspaceDir, String(options.outFile));
|
|
188
235
|
let effectiveSilent = options.silent;
|
|
189
236
|
let log = require_logger.createLogger({ silent: effectiveSilent });
|
|
190
237
|
log.spinStart("Loading theme configuration...");
|
|
@@ -205,12 +252,21 @@ const runThemeMode = async (options, context) => {
|
|
|
205
252
|
const generateThemeModeCSS = async (opts) => {
|
|
206
253
|
const genStartTime = performance.now();
|
|
207
254
|
const genLog = opts?.isWatch ? require_logger.createLogger({ silent: true }) : log;
|
|
255
|
+
const scopedCssOutputs = [];
|
|
208
256
|
genLog.spinStart("Scanning app code...");
|
|
209
257
|
const appScanResult = await require_nodeUtils.scanDirectoriesForSafelist(entryDirs, colorModes, context.variants, context.autoVariants, context.componentData, appVariantDefaults, runtimeConfigValues);
|
|
210
|
-
genLog.spinStop("✅",
|
|
258
|
+
genLog.spinStop("✅", require_runner_helpers.getScanSummaryMessage({
|
|
259
|
+
label: "app",
|
|
260
|
+
filesScanned: appScanResult.filesScanned,
|
|
261
|
+
filesWithComponents: appScanResult.filesWithComponents,
|
|
262
|
+
componentCount: appScanResult.components.length,
|
|
263
|
+
mode: "app"
|
|
264
|
+
}));
|
|
265
|
+
if (options.verbose) printVerboseScanFiles(genLog, workspaceDir, appScanResult.filePaths);
|
|
211
266
|
genLog.spinStart("Generating main CSS...");
|
|
212
267
|
const inheritedClasses = [...appScanResult.safelist];
|
|
213
268
|
const inheritedComponents = new Set(appScanResult.components);
|
|
269
|
+
const scopedPackageTargets = [];
|
|
214
270
|
const processInheritedPackage = async (packageName) => {
|
|
215
271
|
genLog.spinStart(`Processing package: ${packageName}...`);
|
|
216
272
|
const packageDir = require_nodeUtils.findPackageSourceDir(packageName);
|
|
@@ -222,12 +278,50 @@ const runThemeMode = async (options, context) => {
|
|
|
222
278
|
const packageScanResult = await require_nodeUtils.scanDirectoryForSafelist(packageDir, colorModes, context.variants, context.autoVariants, context.componentData, appVariantDefaults, runtimeConfigValues, true);
|
|
223
279
|
inheritedClasses.push(...packageScanResult.safelist);
|
|
224
280
|
packageScanResult.components.forEach((comp) => inheritedComponents.add(comp));
|
|
225
|
-
genLog.spinStop("✅",
|
|
281
|
+
genLog.spinStop("✅", require_runner_helpers.getScanSummaryMessage({
|
|
282
|
+
label: packageName,
|
|
283
|
+
filesScanned: packageScanResult.filesScanned,
|
|
284
|
+
filesWithComponents: packageScanResult.filesWithComponents,
|
|
285
|
+
componentCount: packageScanResult.components.length,
|
|
286
|
+
mode: "inherit"
|
|
287
|
+
}));
|
|
288
|
+
if (options.verbose) printVerboseScanFiles(genLog, workspaceDir, packageScanResult.filePaths);
|
|
289
|
+
};
|
|
290
|
+
const processScopedPackage = async (packageName, scopedPackageValue) => {
|
|
291
|
+
genLog.spinStart(`Processing scoped package: ${packageName}...`);
|
|
292
|
+
const scopedPackageConfig = normalizeScopedPackageConfig(scopedPackageValue);
|
|
293
|
+
const packageRoot = require_nodeUtils.findPackageRoot(packageName);
|
|
294
|
+
const packageDir = require_nodeUtils.findPackageSourceDir(packageName);
|
|
295
|
+
if (!packageRoot || !packageDir) {
|
|
296
|
+
genLog.spinStop("⚠️", `Scoped package not found: ${packageName}`);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const scopeClass = require_nodeUtils.getPackageUdsScope(packageName);
|
|
300
|
+
if (!scopeClass) {
|
|
301
|
+
genLog.spinStop("⚠️", `Scoped package missing package.json uds.scope: ${packageName}`);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const entryDirs = resolveScopedEntryDirs(packageRoot, packageDir, scopedPackageConfig.entry);
|
|
305
|
+
entryDirs.forEach((entryDir) => {
|
|
306
|
+
if (!packageDirs.includes(entryDir)) packageDirs.push(entryDir);
|
|
307
|
+
});
|
|
308
|
+
scopedPackageTargets.push({
|
|
309
|
+
packageName,
|
|
310
|
+
packageRoot,
|
|
311
|
+
packageDir,
|
|
312
|
+
entryDirs,
|
|
313
|
+
scopeClass,
|
|
314
|
+
config: scopedPackageConfig
|
|
315
|
+
});
|
|
226
316
|
};
|
|
227
317
|
await (themeConfig.inherit ?? []).reduce(async (promise, packageName) => {
|
|
228
318
|
await promise;
|
|
229
319
|
await processInheritedPackage(packageName);
|
|
230
320
|
}, Promise.resolve());
|
|
321
|
+
await Object.entries(themeConfig.scoped ?? {}).reduce(async (promise, [packageName, scopedPackageConfig]) => {
|
|
322
|
+
await promise;
|
|
323
|
+
await processScopedPackage(packageName, scopedPackageConfig);
|
|
324
|
+
}, Promise.resolve());
|
|
231
325
|
const mainSafelist = require_safelist.deduplicateSafelist([
|
|
232
326
|
...inheritedClasses,
|
|
233
327
|
...require_safelist.getThemeAndScaleClasses(colorModes),
|
|
@@ -244,24 +338,80 @@ const runThemeMode = async (options, context) => {
|
|
|
244
338
|
...require_generate_helpers.getPruneVarSafelist(themeConfig.css)
|
|
245
339
|
]
|
|
246
340
|
});
|
|
247
|
-
|
|
248
|
-
if (!node_fs.default.existsSync(outputDir)) node_fs.default.mkdirSync(outputDir, { recursive: true });
|
|
341
|
+
ensureOutputDirectory(outputPath);
|
|
249
342
|
node_fs.default.writeFileSync(outputPath, mainCssResult.css);
|
|
250
|
-
|
|
343
|
+
for (const scopedPackageTarget of scopedPackageTargets) {
|
|
344
|
+
const packageConfig = await require_nodeUtils.loadConfigFile(isAbsolutePath(scopedPackageTarget.config.config) ? scopedPackageTarget.config.config : joinPath(scopedPackageTarget.packageRoot, scopedPackageTarget.config.config)) ?? require_index.defaultTokensConfig;
|
|
345
|
+
const packageVariantDefaults = require_utils.extractVariantDefaults(packageConfig);
|
|
346
|
+
const packageRuntimeConfigValues = require_utils.extractRuntimeConfigValues(packageConfig);
|
|
347
|
+
const packageScanResult = await require_nodeUtils.scanDirectoriesForSafelist(scopedPackageTarget.entryDirs, colorModes, context.variants, context.autoVariants, context.componentData, packageVariantDefaults, packageRuntimeConfigValues, true);
|
|
348
|
+
genLog.spinStop("✅", require_runner_helpers.getScanSummaryMessage({
|
|
349
|
+
label: scopedPackageTarget.packageName,
|
|
350
|
+
filesScanned: packageScanResult.filesScanned,
|
|
351
|
+
filesWithComponents: packageScanResult.filesWithComponents,
|
|
352
|
+
componentCount: packageScanResult.components.length,
|
|
353
|
+
mode: "scoped"
|
|
354
|
+
}));
|
|
355
|
+
if (options.verbose) printVerboseScanFiles(genLog, workspaceDir, packageScanResult.filePaths);
|
|
356
|
+
const packageSafelist = require_safelist.deduplicateSafelist([
|
|
357
|
+
...packageScanResult.safelist,
|
|
358
|
+
...require_safelist.getThemeAndScaleClasses(colorModes),
|
|
359
|
+
...require_safelist.getInternalSafelistClasses()
|
|
360
|
+
]);
|
|
361
|
+
const scopedCssResult = await require_generate.generateCSS([...themeConfig.css?.safelist ?? [], ...packageSafelist], packageConfig, {
|
|
362
|
+
scope: scopedPackageTarget.scopeClass,
|
|
363
|
+
contentDir: scopedPackageTarget.entryDirs,
|
|
364
|
+
cssOptions: themeConfig.css,
|
|
365
|
+
referenceCss: themeConfig.css?.optimization?.deduplicateScopedCss === false ? void 0 : mainCssResult.css,
|
|
366
|
+
safeVarPrefixes: [
|
|
367
|
+
...require_utils.getMotionVarPrefixes(context.componentData, [...packageScanResult.components]),
|
|
368
|
+
...require_utils.getConfigurableCssVariables(),
|
|
369
|
+
...require_generate_helpers.getPruneVarSafelist(themeConfig.css)
|
|
370
|
+
]
|
|
371
|
+
});
|
|
372
|
+
const scopedOutputPath = resolveOutputPath(workspaceDir, getScopedPackageOutputPath(scopedPackageTarget.packageName, scopedPackageTarget.config.outFile));
|
|
373
|
+
ensureOutputDirectory(scopedOutputPath);
|
|
374
|
+
node_fs.default.writeFileSync(scopedOutputPath, scopedCssResult.css);
|
|
375
|
+
scopedCssOutputs.push({
|
|
376
|
+
label: scopedPackageTarget.packageName,
|
|
377
|
+
outputPath: scopedOutputPath,
|
|
378
|
+
sizeGzipBytes: scopedCssResult.sizeGzipBytes,
|
|
379
|
+
optimizationStats: scopedCssResult.optimizationStats
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
const mainCssSummary = require_runner_helpers.getMainCssSummaryMessage({
|
|
251
383
|
sizeGzipBytes: mainCssResult.sizeGzipBytes,
|
|
252
384
|
optimizationStats: mainCssResult.optimizationStats,
|
|
253
385
|
formatBytes: require_utils.formatBytes
|
|
254
|
-
})
|
|
386
|
+
});
|
|
387
|
+
genLog.spinStop("✅", mainCssSummary.summaryLine);
|
|
388
|
+
mainCssSummary.detailLines.forEach((detailLine) => {
|
|
389
|
+
genLog.print(detailLine);
|
|
390
|
+
});
|
|
391
|
+
scopedCssOutputs.forEach((scopedCssOutput) => {
|
|
392
|
+
const scopedCssSummary = require_runner_helpers.getScopedCssSummaryMessage(scopedCssOutput.label, {
|
|
393
|
+
sizeGzipBytes: scopedCssOutput.sizeGzipBytes,
|
|
394
|
+
optimizationStats: scopedCssOutput.optimizationStats,
|
|
395
|
+
formatBytes: require_utils.formatBytes
|
|
396
|
+
});
|
|
397
|
+
genLog.spinStop("✅", scopedCssSummary.summaryLine);
|
|
398
|
+
scopedCssSummary.detailLines.forEach((detailLine) => {
|
|
399
|
+
genLog.print(detailLine);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
255
402
|
const duration = Math.round(performance.now() - genStartTime);
|
|
403
|
+
const outputFileSection = require_runner_helpers.getOutputFileSection(workspaceDir, [outputPath, ...scopedCssOutputs.map((scopedCssOutput) => scopedCssOutput.outputPath)]);
|
|
256
404
|
genLog.newline();
|
|
257
|
-
genLog.print(
|
|
258
|
-
|
|
259
|
-
|
|
405
|
+
genLog.print(outputFileSection.label);
|
|
406
|
+
outputFileSection.paths.forEach((filePath) => {
|
|
407
|
+
genLog.listItem(filePath);
|
|
408
|
+
});
|
|
260
409
|
genLog.newline();
|
|
261
|
-
genLog.print(`${require_colors.magenta("Total time:")} ${duration}
|
|
410
|
+
genLog.print(`${require_colors.magenta("Total time:")} ${require_runner_helpers.formatCssDuration(duration)}`);
|
|
262
411
|
return {
|
|
263
412
|
duration,
|
|
264
413
|
outputPath,
|
|
414
|
+
outputPaths: outputFileSection.paths,
|
|
265
415
|
packageDirs
|
|
266
416
|
};
|
|
267
417
|
};
|
|
@@ -292,7 +442,8 @@ const runThemeMode = async (options, context) => {
|
|
|
292
442
|
onSuccess: (result) => {
|
|
293
443
|
if (!effectiveSilent) {
|
|
294
444
|
const updatedAt = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
295
|
-
|
|
445
|
+
const updatedMessage = result?.duration == null ? "CSS updated" : `CSS updated (${require_runner_helpers.formatCssDuration(result.duration)})`;
|
|
446
|
+
log.print(`${require_colors.gray(`[${updatedAt}]`)} ${require_colors.green(updatedMessage)}`);
|
|
296
447
|
log.newline();
|
|
297
448
|
}
|
|
298
449
|
},
|
|
@@ -4,13 +4,60 @@ let node_path = require("node:path");
|
|
|
4
4
|
node_path = require_runtime.__toESM(node_path);
|
|
5
5
|
|
|
6
6
|
//#region src/css/runner.helpers.ts
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
7
|
+
const getDisplayPath = (cwd, targetPath) => {
|
|
8
|
+
const relativePath = node_path.default.relative(cwd, targetPath);
|
|
9
|
+
return relativePath.length === 0 ? "." : relativePath;
|
|
10
|
+
};
|
|
11
|
+
const getVerboseScanFileList = (cwd, filePaths) => [...new Set(filePaths.map((filePath) => getDisplayPath(cwd, filePath)))].sort((left, right) => left.localeCompare(right));
|
|
12
|
+
const getOptimizationDetailLines = (optimizationStats) => {
|
|
13
|
+
const detailLines = [];
|
|
14
|
+
if (optimizationStats.fontFacesRemoved > 0) detailLines.push(` • removed ${optimizationStats.fontFacesRemoved} unused @font-face`);
|
|
15
|
+
if (optimizationStats.emptyRulesRemoved > 0) detailLines.push(` • removed ${optimizationStats.emptyRulesRemoved} empty rules`);
|
|
16
|
+
return detailLines;
|
|
17
|
+
};
|
|
18
|
+
const formatCssDuration = (durationMs) => {
|
|
19
|
+
return `${(Math.floor(durationMs / 100) / 10).toFixed(1)}s`;
|
|
20
|
+
};
|
|
21
|
+
const getCssSummaryMessage = (options) => {
|
|
22
|
+
const { label, optimizationStats, sizeGzipBytes, formatBytes } = options;
|
|
23
|
+
const summaryLine = `${label}: ${formatBytes(sizeGzipBytes)} gzip`;
|
|
24
|
+
if (!optimizationStats) return {
|
|
25
|
+
summaryLine,
|
|
26
|
+
detailLines: []
|
|
27
|
+
};
|
|
10
28
|
const { originalSizeGzip, fontFacesRemoved, emptyRulesRemoved } = optimizationStats;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
if (originalSizeGzip - sizeGzipBytes <= 0) return {
|
|
30
|
+
summaryLine,
|
|
31
|
+
detailLines: []
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
summaryLine,
|
|
35
|
+
detailLines: getOptimizationDetailLines({
|
|
36
|
+
originalSizeGzip,
|
|
37
|
+
fontFacesRemoved,
|
|
38
|
+
emptyRulesRemoved
|
|
39
|
+
})
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const getMainCssSummaryMessage = (options) => {
|
|
43
|
+
return getCssSummaryMessage({
|
|
44
|
+
label: "Main CSS",
|
|
45
|
+
...options
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const getScopedCssSummaryMessage = (packageName, options) => getCssSummaryMessage({
|
|
49
|
+
label: `${packageName} CSS`,
|
|
50
|
+
...options
|
|
51
|
+
});
|
|
52
|
+
const getOutputFileSection = (cwd, outputPaths) => ({
|
|
53
|
+
label: "Output files:",
|
|
54
|
+
paths: outputPaths.map((outputPath) => getDisplayPath(cwd, outputPath))
|
|
55
|
+
});
|
|
56
|
+
const getScanSummaryMessage = (options) => {
|
|
57
|
+
const nonComponentFileCount = Math.max(options.filesScanned - options.filesWithComponents, 0);
|
|
58
|
+
const fileLabel = nonComponentFileCount === 1 ? "file" : "files";
|
|
59
|
+
const componentLabel = options.componentCount === 1 ? "component" : "components";
|
|
60
|
+
return `${options.label}: ${nonComponentFileCount} ${fileLabel}, ${options.componentCount} ${componentLabel} (${options.mode})`;
|
|
14
61
|
};
|
|
15
62
|
const getWatchDirectoryGroups = (entryDirs, dirs) => {
|
|
16
63
|
const watchDirs = [...new Set(dirs.filter((dir) => !dir.split(node_path.default.sep).includes("node_modules")))];
|
|
@@ -21,5 +68,10 @@ const getWatchDirectoryGroups = (entryDirs, dirs) => {
|
|
|
21
68
|
};
|
|
22
69
|
|
|
23
70
|
//#endregion
|
|
71
|
+
exports.formatCssDuration = formatCssDuration;
|
|
24
72
|
exports.getMainCssSummaryMessage = getMainCssSummaryMessage;
|
|
73
|
+
exports.getOutputFileSection = getOutputFileSection;
|
|
74
|
+
exports.getScanSummaryMessage = getScanSummaryMessage;
|
|
75
|
+
exports.getScopedCssSummaryMessage = getScopedCssSummaryMessage;
|
|
76
|
+
exports.getVerboseScanFileList = getVerboseScanFileList;
|
|
25
77
|
exports.getWatchDirectoryGroups = getWatchDirectoryGroups;
|