tailwindcss-patch 9.0.0-alpha.1 → 9.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +20 -0
  2. package/dist/{chunk-Z6OMJZTU.js → chunk-TOAZIPHJ.js} +29 -11
  3. package/dist/{chunk-SWLOK2S6.mjs → chunk-VDWTCQ74.mjs} +29 -11
  4. package/dist/cli.js +4 -4
  5. package/dist/cli.mjs +1 -1
  6. package/dist/index.d.mts +43 -35
  7. package/dist/index.d.ts +43 -35
  8. package/dist/index.js +2 -2
  9. package/dist/index.mjs +1 -1
  10. package/package.json +8 -3
  11. package/src/api/tailwindcss-patcher.ts +424 -0
  12. package/src/babel/index.ts +12 -0
  13. package/src/cache/context.ts +212 -0
  14. package/src/cache/store.ts +1440 -0
  15. package/src/cache/types.ts +71 -0
  16. package/src/cli.ts +20 -0
  17. package/src/commands/basic-handlers.ts +145 -0
  18. package/src/commands/cli.ts +56 -0
  19. package/src/commands/command-context.ts +77 -0
  20. package/src/commands/command-definitions.ts +102 -0
  21. package/src/commands/command-metadata.ts +68 -0
  22. package/src/commands/command-registrar.ts +39 -0
  23. package/src/commands/command-runtime.ts +33 -0
  24. package/src/commands/default-handler-map.ts +25 -0
  25. package/src/commands/migrate-config.ts +104 -0
  26. package/src/commands/migrate-handler.ts +67 -0
  27. package/src/commands/migration-aggregation.ts +100 -0
  28. package/src/commands/migration-args.ts +85 -0
  29. package/src/commands/migration-file-executor.ts +189 -0
  30. package/src/commands/migration-output.ts +115 -0
  31. package/src/commands/migration-report-loader.ts +26 -0
  32. package/src/commands/migration-report.ts +21 -0
  33. package/src/commands/migration-source.ts +318 -0
  34. package/src/commands/migration-target-files.ts +161 -0
  35. package/src/commands/migration-target-resolver.ts +34 -0
  36. package/src/commands/migration-types.ts +65 -0
  37. package/src/commands/restore-handler.ts +24 -0
  38. package/src/commands/status-handler.ts +17 -0
  39. package/src/commands/status-output.ts +60 -0
  40. package/src/commands/token-output.ts +30 -0
  41. package/src/commands/types.ts +137 -0
  42. package/src/commands/validate-handler.ts +42 -0
  43. package/src/commands/validate.ts +83 -0
  44. package/src/config/index.ts +25 -0
  45. package/src/config/workspace.ts +87 -0
  46. package/src/constants.ts +4 -0
  47. package/src/extraction/candidate-extractor.ts +354 -0
  48. package/src/index.ts +57 -0
  49. package/src/install/class-collector.ts +1 -0
  50. package/src/install/context-registry.ts +1 -0
  51. package/src/install/index.ts +5 -0
  52. package/src/install/patch-runner.ts +1 -0
  53. package/src/install/process-tailwindcss.ts +1 -0
  54. package/src/install/status.ts +1 -0
  55. package/src/logger.ts +5 -0
  56. package/src/options/legacy.ts +93 -0
  57. package/src/options/normalize.ts +262 -0
  58. package/src/options/types.ts +217 -0
  59. package/src/patching/operations/export-context/index.ts +110 -0
  60. package/src/patching/operations/export-context/postcss-v2.ts +235 -0
  61. package/src/patching/operations/export-context/postcss-v3.ts +249 -0
  62. package/src/patching/operations/extend-length-units.ts +197 -0
  63. package/src/patching/patch-runner.ts +46 -0
  64. package/src/patching/status.ts +262 -0
  65. package/src/runtime/class-collector.ts +105 -0
  66. package/src/runtime/collector.ts +148 -0
  67. package/src/runtime/context-registry.ts +65 -0
  68. package/src/runtime/process-tailwindcss.ts +115 -0
  69. package/src/types.ts +159 -0
  70. package/src/utils.ts +52 -0
@@ -0,0 +1,30 @@
1
+ import type { TailwindTokenByFileMap, TailwindTokenLocation } from '../types'
2
+
3
+ export type TokenOutputFormat = 'json' | 'lines' | 'grouped-json'
4
+ export type TokenGroupKey = 'relative' | 'absolute'
5
+
6
+ export const TOKEN_FORMATS: TokenOutputFormat[] = ['json', 'lines', 'grouped-json']
7
+ export const DEFAULT_TOKEN_REPORT = '.tw-patch/tw-token-report.json'
8
+
9
+ export function formatTokenLine(entry: TailwindTokenLocation) {
10
+ return `${entry.relativeFile}:${entry.line}:${entry.column} ${entry.rawCandidate} (${entry.start}-${entry.end})`
11
+ }
12
+
13
+ export function formatGroupedPreview(map: TailwindTokenByFileMap, limit: number = 3) {
14
+ const files = Object.keys(map)
15
+ if (!files.length) {
16
+ return { preview: '', moreFiles: 0 }
17
+ }
18
+
19
+ const lines = files.slice(0, limit).map((file) => {
20
+ const tokens = map[file] ?? []
21
+ const sample = tokens.slice(0, 3).map(token => token.rawCandidate).join(', ')
22
+ const suffix = tokens.length > 3 ? ', …' : ''
23
+ return `${file}: ${tokens.length} tokens (${sample}${suffix})`
24
+ })
25
+
26
+ return {
27
+ preview: lines.join('\n'),
28
+ moreFiles: Math.max(0, files.length - limit),
29
+ }
30
+ }
@@ -0,0 +1,137 @@
1
+ import type { CAC, Command } from 'cac'
2
+ import type { TailwindcssConfigResult } from '../config/workspace'
3
+ import type logger from '../logger'
4
+ import type {
5
+ ExtractResult,
6
+ PatchStatusReport,
7
+ TailwindCssPatchOptions,
8
+ TailwindTokenReport,
9
+ } from '../types'
10
+ import type { ConfigFileMigrationReport, RestoreConfigFilesResult } from './migration-types'
11
+ import type { TokenGroupKey, TokenOutputFormat } from './token-output'
12
+
13
+ export type TailwindcssPatchCommand = 'install' | 'extract' | 'tokens' | 'init' | 'migrate' | 'restore' | 'validate' | 'status'
14
+
15
+ export const tailwindcssPatchCommands: TailwindcssPatchCommand[] = ['install', 'extract', 'tokens', 'init', 'migrate', 'restore', 'validate', 'status']
16
+
17
+ type CacOptionConfig = Parameters<Command['option']>[2]
18
+
19
+ export interface TailwindcssPatchCommandOptionDefinition {
20
+ flags: string
21
+ description?: string
22
+ config?: CacOptionConfig
23
+ }
24
+
25
+ export interface TailwindcssPatchCommandOptions {
26
+ name?: string
27
+ aliases?: string[]
28
+ description?: string
29
+ optionDefs?: TailwindcssPatchCommandOptionDefinition[]
30
+ appendDefaultOptions?: boolean
31
+ }
32
+
33
+ interface BaseCommandArgs {
34
+ cwd: string
35
+ }
36
+
37
+ interface InstallCommandArgs extends BaseCommandArgs {}
38
+ interface ExtractCommandArgs extends BaseCommandArgs {
39
+ output?: string
40
+ format?: 'json' | 'lines'
41
+ css?: string
42
+ write?: boolean
43
+ }
44
+ interface TokensCommandArgs extends BaseCommandArgs {
45
+ output?: string
46
+ format?: TokenOutputFormat
47
+ groupKey?: TokenGroupKey
48
+ write?: boolean
49
+ }
50
+ interface InitCommandArgs extends BaseCommandArgs {}
51
+ interface MigrateCommandArgs extends BaseCommandArgs {
52
+ config?: string
53
+ dryRun?: boolean
54
+ workspace?: boolean
55
+ maxDepth?: string | number
56
+ include?: string | string[]
57
+ exclude?: string | string[]
58
+ reportFile?: string
59
+ backupDir?: string
60
+ check?: boolean
61
+ json?: boolean
62
+ }
63
+ interface RestoreCommandArgs extends BaseCommandArgs {
64
+ reportFile?: string
65
+ dryRun?: boolean
66
+ strict?: boolean
67
+ json?: boolean
68
+ }
69
+ interface ValidateCommandArgs extends BaseCommandArgs {
70
+ reportFile?: string
71
+ strict?: boolean
72
+ json?: boolean
73
+ }
74
+ interface StatusCommandArgs extends BaseCommandArgs {
75
+ json?: boolean
76
+ }
77
+
78
+ export interface TailwindcssPatchCommandArgMap {
79
+ install: InstallCommandArgs
80
+ extract: ExtractCommandArgs
81
+ tokens: TokensCommandArgs
82
+ init: InitCommandArgs
83
+ migrate: MigrateCommandArgs
84
+ restore: RestoreCommandArgs
85
+ validate: ValidateCommandArgs
86
+ status: StatusCommandArgs
87
+ }
88
+
89
+ export interface TailwindcssPatchCommandResultMap {
90
+ install: void
91
+ extract: ExtractResult
92
+ tokens: TailwindTokenReport
93
+ init: void
94
+ migrate: ConfigFileMigrationReport
95
+ restore: RestoreConfigFilesResult
96
+ validate: RestoreConfigFilesResult
97
+ status: PatchStatusReport
98
+ }
99
+
100
+ export interface TailwindcssPatchCommandContext<TCommand extends TailwindcssPatchCommand> {
101
+ cli: CAC
102
+ command: Command
103
+ commandName: TCommand
104
+ args: TailwindcssPatchCommandArgMap[TCommand]
105
+ cwd: string
106
+ logger: typeof logger
107
+ loadConfig: () => Promise<TailwindcssConfigResult>
108
+ loadPatchOptions: (overrides?: TailwindCssPatchOptions) => Promise<TailwindCssPatchOptions>
109
+ createPatcher: (overrides?: TailwindCssPatchOptions) => Promise<import('../api/tailwindcss-patcher').TailwindcssPatcher>
110
+ }
111
+
112
+ export type TailwindcssPatchCommandDefaultHandlerMap = {
113
+ [K in TailwindcssPatchCommand]: (
114
+ context: TailwindcssPatchCommandContext<K>,
115
+ ) => Promise<TailwindcssPatchCommandResultMap[K]>
116
+ }
117
+
118
+ export type TailwindcssPatchCommandHandler<TCommand extends TailwindcssPatchCommand> = (
119
+ context: TailwindcssPatchCommandContext<TCommand>,
120
+ next: () => Promise<TailwindcssPatchCommandResultMap[TCommand]>,
121
+ ) => Promise<TailwindcssPatchCommandResultMap[TCommand]> | TailwindcssPatchCommandResultMap[TCommand]
122
+
123
+ export type TailwindcssPatchCommandHandlerMap = Partial<{
124
+ [K in TailwindcssPatchCommand]: TailwindcssPatchCommandHandler<K>
125
+ }>
126
+
127
+ export interface TailwindcssPatchCliMountOptions {
128
+ commandPrefix?: string
129
+ commands?: TailwindcssPatchCommand[]
130
+ commandOptions?: Partial<Record<TailwindcssPatchCommand, TailwindcssPatchCommandOptions>>
131
+ commandHandlers?: TailwindcssPatchCommandHandlerMap
132
+ }
133
+
134
+ export interface TailwindcssPatchCliOptions {
135
+ name?: string
136
+ mountOptions?: TailwindcssPatchCliMountOptions
137
+ }
@@ -0,0 +1,42 @@
1
+ import type { TailwindcssPatchCommandContext } from './types'
2
+
3
+ import { restoreConfigFiles } from './migrate-config'
4
+ import { resolveValidateCommandArgs } from './migration-args'
5
+ import {
6
+ logValidateFailureAsJson,
7
+ logValidateFailureSummary,
8
+ logValidateSuccessAsJson,
9
+ logValidateSuccessSummary,
10
+ } from './migration-output'
11
+ import { classifyValidateError, ValidateCommandError } from './validate'
12
+
13
+ export async function validateCommandDefaultHandler(ctx: TailwindcssPatchCommandContext<'validate'>) {
14
+ const { args } = ctx
15
+ const validateArgs = resolveValidateCommandArgs(args)
16
+ try {
17
+ const result = await restoreConfigFiles({
18
+ cwd: ctx.cwd,
19
+ reportFile: validateArgs.reportFile,
20
+ dryRun: true,
21
+ strict: validateArgs.strict,
22
+ })
23
+
24
+ if (args.json) {
25
+ logValidateSuccessAsJson(result)
26
+ return result
27
+ }
28
+
29
+ logValidateSuccessSummary(result)
30
+ return result
31
+ }
32
+ catch (error) {
33
+ const summary = classifyValidateError(error)
34
+ if (args.json) {
35
+ logValidateFailureAsJson(summary)
36
+ }
37
+ else {
38
+ logValidateFailureSummary(summary)
39
+ }
40
+ throw new ValidateCommandError(summary, { cause: error })
41
+ }
42
+ }
@@ -0,0 +1,83 @@
1
+ import type { RestoreConfigFilesResult } from './migration-types'
2
+
3
+ export const VALIDATE_EXIT_CODES = {
4
+ OK: 0,
5
+ REPORT_INCOMPATIBLE: 21,
6
+ MISSING_BACKUPS: 22,
7
+ IO_ERROR: 23,
8
+ UNKNOWN_ERROR: 24,
9
+ } as const
10
+
11
+ export const VALIDATE_FAILURE_REASONS = [
12
+ 'report-incompatible',
13
+ 'missing-backups',
14
+ 'io-error',
15
+ 'unknown-error',
16
+ ] as const
17
+
18
+ export type ValidateFailureReason = (typeof VALIDATE_FAILURE_REASONS)[number]
19
+
20
+ export interface ValidateFailureSummary {
21
+ reason: ValidateFailureReason
22
+ exitCode: number
23
+ message: string
24
+ }
25
+
26
+ export interface ValidateJsonSuccessPayload extends RestoreConfigFilesResult {
27
+ ok: true
28
+ }
29
+
30
+ export interface ValidateJsonFailurePayload {
31
+ ok: false
32
+ reason: ValidateFailureReason
33
+ exitCode: number
34
+ message: string
35
+ }
36
+
37
+ const IO_ERROR_CODES = new Set(['ENOENT', 'EACCES', 'EPERM', 'EISDIR', 'ENOTDIR', 'EMFILE', 'ENFILE'])
38
+
39
+ function isNodeError(error: unknown): error is NodeJS.ErrnoException {
40
+ return !!error && typeof error === 'object' && ('code' in error || 'message' in error)
41
+ }
42
+
43
+ export function classifyValidateError(error: unknown): ValidateFailureSummary {
44
+ const message = error instanceof Error ? error.message : String(error)
45
+ if (message.startsWith('Unsupported report kind') || message.startsWith('Unsupported report schema version')) {
46
+ return {
47
+ reason: 'report-incompatible',
48
+ exitCode: VALIDATE_EXIT_CODES.REPORT_INCOMPATIBLE,
49
+ message,
50
+ }
51
+ }
52
+ if (message.startsWith('Restore failed:')) {
53
+ return {
54
+ reason: 'missing-backups',
55
+ exitCode: VALIDATE_EXIT_CODES.MISSING_BACKUPS,
56
+ message,
57
+ }
58
+ }
59
+ if (isNodeError(error) && typeof error.code === 'string' && IO_ERROR_CODES.has(error.code)) {
60
+ return {
61
+ reason: 'io-error',
62
+ exitCode: VALIDATE_EXIT_CODES.IO_ERROR,
63
+ message,
64
+ }
65
+ }
66
+ return {
67
+ reason: 'unknown-error',
68
+ exitCode: VALIDATE_EXIT_CODES.UNKNOWN_ERROR,
69
+ message,
70
+ }
71
+ }
72
+
73
+ export class ValidateCommandError extends Error {
74
+ reason: ValidateFailureReason
75
+ exitCode: number
76
+
77
+ constructor(summary: ValidateFailureSummary, options?: ErrorOptions) {
78
+ super(summary.message, options)
79
+ this.name = 'ValidateCommandError'
80
+ this.reason = summary.reason
81
+ this.exitCode = summary.exitCode
82
+ }
83
+ }
@@ -0,0 +1,25 @@
1
+ export { fromUnifiedConfig } from '../options/legacy'
2
+ export { normalizeOptions } from '../options/normalize'
3
+ export type {
4
+ ApplyOptions,
5
+ CacheOptions,
6
+ CacheStrategy,
7
+ ExposeContextOptions,
8
+ ExtendLengthUnitsOptions,
9
+ ExtractOptions,
10
+ NormalizedTailwindCssPatchOptions,
11
+ NormalizedCacheOptions,
12
+ NormalizedExtendLengthUnitsOptions,
13
+ TailwindCssOptions,
14
+ TailwindCssPatchOptions,
15
+ TailwindV2Options,
16
+ TailwindV3Options,
17
+ TailwindV4Options,
18
+ } from '../options/types'
19
+ export {
20
+ loadPatchOptionsForWorkspace,
21
+ loadWorkspaceConfigModule,
22
+ loadWorkspaceDefu,
23
+ type TailwindcssConfigModule,
24
+ type TailwindcssConfigResult,
25
+ } from './workspace'
@@ -0,0 +1,87 @@
1
+ import type { TailwindCssPatchOptions } from '../types'
2
+ import { pathToFileURL } from 'node:url'
3
+ import path from 'pathe'
4
+ import { fromUnifiedConfig } from '../options/legacy'
5
+
6
+ export interface TailwindcssConfigModule {
7
+ CONFIG_NAME: string
8
+ getConfig: (cwd?: string) => Promise<{ config?: { registry?: unknown, patch?: unknown } }>
9
+ initConfig: (cwd: string) => Promise<unknown>
10
+ }
11
+
12
+ export type TailwindcssConfigResult = Awaited<ReturnType<TailwindcssConfigModule['getConfig']>>
13
+ type DefuFn = (...objects: unknown[]) => unknown
14
+
15
+ let configModulePromise: Promise<TailwindcssConfigModule> | undefined
16
+ let defuPromise: Promise<DefuFn> | undefined
17
+
18
+ function isNodeError(error: unknown): error is NodeJS.ErrnoException {
19
+ return !!error && typeof error === 'object' && ('code' in error || 'message' in error)
20
+ }
21
+
22
+ export function isMissingModuleError(error: unknown, pkgName: string) {
23
+ if (!isNodeError(error)) {
24
+ return false
25
+ }
26
+
27
+ const code = error.code
28
+ if (code !== 'MODULE_NOT_FOUND' && code !== 'ERR_MODULE_NOT_FOUND') {
29
+ return false
30
+ }
31
+
32
+ const message = error.message ?? ''
33
+ return message.includes(pkgName) || message.includes(`${pkgName}/dist/`)
34
+ }
35
+
36
+ function isMissingConfigModuleError(error: unknown) {
37
+ return isMissingModuleError(error, '@tailwindcss-mangle/config')
38
+ }
39
+
40
+ function isMissingSharedModuleError(error: unknown) {
41
+ return isMissingModuleError(error, '@tailwindcss-mangle/shared')
42
+ }
43
+
44
+ export async function loadWorkspaceConfigModule() {
45
+ if (!configModulePromise) {
46
+ configModulePromise = (import('@tailwindcss-mangle/config') as Promise<TailwindcssConfigModule>)
47
+ .catch(async (error) => {
48
+ if (!isMissingConfigModuleError(error)) {
49
+ throw error
50
+ }
51
+ const fallback = path.resolve(__dirname, '../../../config/src/index.ts')
52
+ return import(pathToFileURL(fallback).href) as Promise<TailwindcssConfigModule>
53
+ })
54
+ }
55
+ return configModulePromise
56
+ }
57
+
58
+ export async function loadWorkspaceDefu() {
59
+ if (!defuPromise) {
60
+ defuPromise = (import('@tailwindcss-mangle/shared') as Promise<{ defu: DefuFn }>)
61
+ .then(mod => mod.defu)
62
+ .catch(async (error) => {
63
+ if (!isMissingSharedModuleError(error)) {
64
+ throw error
65
+ }
66
+ const fallback = path.resolve(__dirname, '../../../shared/src/utils.ts')
67
+ const mod = await import(pathToFileURL(fallback).href) as { defu: DefuFn }
68
+ return mod.defu
69
+ })
70
+ }
71
+ return defuPromise
72
+ }
73
+
74
+ export async function loadPatchOptionsForWorkspace(cwd: string, overrides?: TailwindCssPatchOptions) {
75
+ const merge = await loadWorkspaceDefu()
76
+ const configModule = await loadWorkspaceConfigModule()
77
+ const { config } = await configModule.getConfig(cwd)
78
+ if (config && typeof config === 'object' && 'patch' in config && config.patch !== undefined) {
79
+ throw new Error('Legacy workspace config field "patch" is no longer supported. Move patcher options under "registry".')
80
+ }
81
+
82
+ const base = config?.registry
83
+ ? fromUnifiedConfig(config.registry)
84
+ : {}
85
+ const merged = merge(overrides ?? {}, base) as TailwindCssPatchOptions
86
+ return merged
87
+ }
@@ -0,0 +1,4 @@
1
+ import packageJson from '../package.json'
2
+
3
+ export const pkgName = 'tailwindcss-patch'
4
+ export const pkgVersion = packageJson.version