tailwindcss-patch 9.0.0-alpha.1 → 9.0.0-alpha.3
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/README.md +20 -0
- package/dist/{chunk-Z6OMJZTU.js → chunk-77GHKSKG.js} +59 -732
- package/dist/{chunk-SWLOK2S6.mjs → chunk-D6ICWMM4.mjs} +63 -736
- package/dist/chunk-PMN7HS4Y.js +25 -0
- package/dist/chunk-YYBY7EM5.mjs +21 -0
- package/dist/cli.js +7 -5
- package/dist/cli.mjs +5 -3
- package/dist/commands/cli-runtime.d.mts +13 -0
- package/dist/commands/cli-runtime.d.ts +13 -0
- package/dist/commands/cli-runtime.js +1331 -0
- package/dist/commands/cli-runtime.mjs +1331 -0
- package/dist/index.d.mts +17 -677
- package/dist/index.d.ts +17 -677
- package/dist/index.js +5 -7
- package/dist/index.mjs +6 -8
- package/dist/validate-nbmOI2w8.d.mts +677 -0
- package/dist/validate-nbmOI2w8.d.ts +677 -0
- package/package.json +11 -3
- package/src/api/tailwindcss-patcher.ts +424 -0
- package/src/babel/index.ts +12 -0
- package/src/cache/context.ts +212 -0
- package/src/cache/store.ts +1440 -0
- package/src/cache/types.ts +71 -0
- package/src/cli.bundle.ts +20 -0
- package/src/cli.ts +20 -0
- package/src/commands/basic-handlers.ts +145 -0
- package/src/commands/cli.ts +56 -0
- package/src/commands/command-context.ts +77 -0
- package/src/commands/command-definitions.ts +102 -0
- package/src/commands/command-metadata.ts +68 -0
- package/src/commands/command-registrar.ts +39 -0
- package/src/commands/command-runtime.ts +33 -0
- package/src/commands/default-handler-map.ts +25 -0
- package/src/commands/migrate-config.ts +104 -0
- package/src/commands/migrate-handler.ts +67 -0
- package/src/commands/migration-aggregation.ts +100 -0
- package/src/commands/migration-args.ts +85 -0
- package/src/commands/migration-file-executor.ts +189 -0
- package/src/commands/migration-output.ts +115 -0
- package/src/commands/migration-report-loader.ts +26 -0
- package/src/commands/migration-report.ts +21 -0
- package/src/commands/migration-source.ts +318 -0
- package/src/commands/migration-target-files.ts +161 -0
- package/src/commands/migration-target-resolver.ts +34 -0
- package/src/commands/migration-types.ts +65 -0
- package/src/commands/restore-handler.ts +24 -0
- package/src/commands/status-handler.ts +17 -0
- package/src/commands/status-output.ts +60 -0
- package/src/commands/token-output.ts +30 -0
- package/src/commands/types.ts +137 -0
- package/src/commands/validate-handler.ts +42 -0
- package/src/commands/validate.ts +83 -0
- package/src/config/index.ts +25 -0
- package/src/config/workspace.ts +87 -0
- package/src/constants.ts +4 -0
- package/src/extraction/candidate-extractor.ts +354 -0
- package/src/index.bundle.ts +105 -0
- package/src/index.ts +57 -0
- package/src/install/class-collector.ts +1 -0
- package/src/install/context-registry.ts +1 -0
- package/src/install/index.ts +5 -0
- package/src/install/patch-runner.ts +1 -0
- package/src/install/process-tailwindcss.ts +1 -0
- package/src/install/status.ts +1 -0
- package/src/logger.ts +5 -0
- package/src/options/legacy.ts +93 -0
- package/src/options/normalize.ts +262 -0
- package/src/options/types.ts +217 -0
- package/src/patching/operations/export-context/index.ts +110 -0
- package/src/patching/operations/export-context/postcss-v2.ts +235 -0
- package/src/patching/operations/export-context/postcss-v3.ts +249 -0
- package/src/patching/operations/extend-length-units.ts +197 -0
- package/src/patching/patch-runner.ts +46 -0
- package/src/patching/status.ts +262 -0
- package/src/runtime/class-collector.ts +105 -0
- package/src/runtime/collector.ts +148 -0
- package/src/runtime/context-registry.ts +65 -0
- package/src/runtime/process-tailwindcss.ts +115 -0
- package/src/types.ts +159 -0
- package/src/utils.ts +52 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export const CACHE_SCHEMA_VERSION = 2
|
|
2
|
+
export const CACHE_FINGERPRINT_VERSION = 1
|
|
3
|
+
|
|
4
|
+
export type CacheSchemaVersion = typeof CACHE_SCHEMA_VERSION
|
|
5
|
+
export type CacheFingerprintVersion = typeof CACHE_FINGERPRINT_VERSION
|
|
6
|
+
export type CacheClearScope = 'current' | 'all'
|
|
7
|
+
|
|
8
|
+
export interface CacheContextMetadata {
|
|
9
|
+
fingerprintVersion: CacheFingerprintVersion
|
|
10
|
+
projectRootRealpath: string
|
|
11
|
+
processCwdRealpath: string
|
|
12
|
+
cacheCwdRealpath: string
|
|
13
|
+
tailwindConfigPath?: string
|
|
14
|
+
tailwindConfigMtimeMs?: number
|
|
15
|
+
tailwindPackageRootRealpath: string
|
|
16
|
+
tailwindPackageVersion: string
|
|
17
|
+
patcherVersion: string
|
|
18
|
+
majorVersion: 2 | 3 | 4
|
|
19
|
+
optionsHash: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CacheContextDescriptor {
|
|
23
|
+
fingerprint: string
|
|
24
|
+
metadata: CacheContextMetadata
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CacheIndexEntry {
|
|
28
|
+
context: CacheContextMetadata
|
|
29
|
+
values: string[]
|
|
30
|
+
updatedAt: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface CacheIndexFileV2 {
|
|
34
|
+
schemaVersion: CacheSchemaVersion
|
|
35
|
+
updatedAt: string
|
|
36
|
+
contexts: Record<string, CacheIndexEntry>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type CacheReadReason
|
|
40
|
+
= 'hit'
|
|
41
|
+
| 'cache-disabled'
|
|
42
|
+
| 'noop-driver'
|
|
43
|
+
| 'file-missing'
|
|
44
|
+
| 'context-not-found'
|
|
45
|
+
| 'context-mismatch'
|
|
46
|
+
| 'legacy-schema'
|
|
47
|
+
| 'invalid-schema'
|
|
48
|
+
|
|
49
|
+
export interface CacheReadMeta {
|
|
50
|
+
hit: boolean
|
|
51
|
+
reason: CacheReadReason
|
|
52
|
+
fingerprint?: string
|
|
53
|
+
schemaVersion?: number
|
|
54
|
+
details: string[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface CacheReadResult {
|
|
58
|
+
data: Set<string>
|
|
59
|
+
meta: CacheReadMeta
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface CacheClearOptions {
|
|
63
|
+
scope?: CacheClearScope
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CacheClearResult {
|
|
67
|
+
scope: CacheClearScope
|
|
68
|
+
filesRemoved: number
|
|
69
|
+
entriesRemoved: number
|
|
70
|
+
contextsRemoved: number
|
|
71
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import { createTailwindcssPatchCli, ValidateCommandError } from './index.bundle'
|
|
3
|
+
import logger from './logger'
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const cli = createTailwindcssPatchCli()
|
|
7
|
+
cli.help()
|
|
8
|
+
cli.parse(process.argv, { run: false })
|
|
9
|
+
await cli.runMatchedCommand()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
main().catch((error) => {
|
|
13
|
+
if (error instanceof ValidateCommandError) {
|
|
14
|
+
process.exitCode = error.exitCode
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
18
|
+
logger.error(message)
|
|
19
|
+
process.exitCode = 1
|
|
20
|
+
})
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import { createTailwindcssPatchCli, ValidateCommandError } from './commands/cli'
|
|
3
|
+
import logger from './logger'
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const cli = createTailwindcssPatchCli()
|
|
7
|
+
cli.help()
|
|
8
|
+
cli.parse(process.argv, { run: false })
|
|
9
|
+
await cli.runMatchedCommand()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
main().catch((error) => {
|
|
13
|
+
if (error instanceof ValidateCommandError) {
|
|
14
|
+
process.exitCode = error.exitCode
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
18
|
+
logger.error(message)
|
|
19
|
+
process.exitCode = 1
|
|
20
|
+
})
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { TailwindCssPatchOptions } from '../types'
|
|
2
|
+
import type { TokenGroupKey, TokenOutputFormat } from './token-output'
|
|
3
|
+
import type { TailwindcssPatchCommandContext } from './types'
|
|
4
|
+
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
import fs from 'fs-extra'
|
|
7
|
+
import path from 'pathe'
|
|
8
|
+
import { TailwindcssPatcher } from '../api/tailwindcss-patcher'
|
|
9
|
+
import { loadWorkspaceConfigModule } from '../config/workspace'
|
|
10
|
+
import { groupTokensByFile } from '../extraction/candidate-extractor'
|
|
11
|
+
import logger from '../logger'
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_TOKEN_REPORT,
|
|
14
|
+
formatGroupedPreview,
|
|
15
|
+
formatTokenLine,
|
|
16
|
+
TOKEN_FORMATS,
|
|
17
|
+
} from './token-output'
|
|
18
|
+
|
|
19
|
+
const DEFAULT_CONFIG_NAME = 'tailwindcss-mangle'
|
|
20
|
+
|
|
21
|
+
export async function installCommandDefaultHandler(_ctx: TailwindcssPatchCommandContext<'install'>) {
|
|
22
|
+
const patcher = await _ctx.createPatcher()
|
|
23
|
+
await patcher.patch()
|
|
24
|
+
logger.success('Tailwind CSS runtime patched successfully.')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function extractCommandDefaultHandler(ctx: TailwindcssPatchCommandContext<'extract'>) {
|
|
28
|
+
const { args } = ctx
|
|
29
|
+
const overrides: TailwindCssPatchOptions = {}
|
|
30
|
+
let hasOverrides = false
|
|
31
|
+
|
|
32
|
+
if (args.output || args.format) {
|
|
33
|
+
overrides.extract = {
|
|
34
|
+
...(args.output === undefined ? {} : { file: args.output }),
|
|
35
|
+
...(args.format === undefined ? {} : { format: args.format }),
|
|
36
|
+
}
|
|
37
|
+
hasOverrides = true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (args.css) {
|
|
41
|
+
overrides.tailwindcss = {
|
|
42
|
+
v4: {
|
|
43
|
+
cssEntries: [args.css],
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
hasOverrides = true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const patcher = await ctx.createPatcher(hasOverrides ? overrides : undefined)
|
|
50
|
+
const extractOptions = args.write === undefined ? {} : { write: args.write }
|
|
51
|
+
const result = await patcher.extract(extractOptions)
|
|
52
|
+
|
|
53
|
+
if (result.filename) {
|
|
54
|
+
logger.success(`Collected ${result.classList.length} classes → ${result.filename}`)
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
logger.success(`Collected ${result.classList.length} classes.`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function tokensCommandDefaultHandler(ctx: TailwindcssPatchCommandContext<'tokens'>) {
|
|
64
|
+
const { args } = ctx
|
|
65
|
+
const patcher = await ctx.createPatcher()
|
|
66
|
+
const report = await patcher.collectContentTokens()
|
|
67
|
+
|
|
68
|
+
const shouldWrite = args.write ?? true
|
|
69
|
+
let format: TokenOutputFormat = args.format ?? 'json'
|
|
70
|
+
if (!TOKEN_FORMATS.includes(format)) {
|
|
71
|
+
format = 'json'
|
|
72
|
+
}
|
|
73
|
+
const targetFile = args.output ?? DEFAULT_TOKEN_REPORT
|
|
74
|
+
const groupKey: TokenGroupKey = args.groupKey === 'absolute' ? 'absolute' : 'relative'
|
|
75
|
+
const buildGrouped = () =>
|
|
76
|
+
groupTokensByFile(report, {
|
|
77
|
+
key: groupKey,
|
|
78
|
+
stripAbsolutePaths: groupKey !== 'absolute',
|
|
79
|
+
})
|
|
80
|
+
const grouped = format === 'grouped-json' ? buildGrouped() : null
|
|
81
|
+
const resolveGrouped = () => grouped ?? buildGrouped()
|
|
82
|
+
|
|
83
|
+
if (shouldWrite) {
|
|
84
|
+
const target = path.resolve(targetFile)
|
|
85
|
+
await fs.ensureDir(path.dirname(target))
|
|
86
|
+
if (format === 'json') {
|
|
87
|
+
await fs.writeJSON(target, report, { spaces: 2 })
|
|
88
|
+
}
|
|
89
|
+
else if (format === 'grouped-json') {
|
|
90
|
+
await fs.writeJSON(target, resolveGrouped(), { spaces: 2 })
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const lines = report.entries.map(formatTokenLine)
|
|
94
|
+
await fs.writeFile(target, `${lines.join('\n')}\n`, 'utf8')
|
|
95
|
+
}
|
|
96
|
+
logger.success(`Collected ${report.entries.length} tokens (${format}) → ${target.replace(process.cwd(), '.')}`)
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
logger.success(`Collected ${report.entries.length} tokens from ${report.filesScanned} files.`)
|
|
100
|
+
if (format === 'lines') {
|
|
101
|
+
const preview = report.entries.slice(0, 5).map(formatTokenLine).join('\n')
|
|
102
|
+
if (preview) {
|
|
103
|
+
logger.log('')
|
|
104
|
+
logger.info(preview)
|
|
105
|
+
if (report.entries.length > 5) {
|
|
106
|
+
logger.info(`…and ${report.entries.length - 5} more.`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (format === 'grouped-json') {
|
|
111
|
+
const map = resolveGrouped()
|
|
112
|
+
const { preview, moreFiles } = formatGroupedPreview(map)
|
|
113
|
+
if (preview) {
|
|
114
|
+
logger.log('')
|
|
115
|
+
logger.info(preview)
|
|
116
|
+
if (moreFiles > 0) {
|
|
117
|
+
logger.info(`…and ${moreFiles} more files.`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const previewEntries = report.entries.slice(0, 3)
|
|
123
|
+
if (previewEntries.length) {
|
|
124
|
+
logger.log('')
|
|
125
|
+
logger.info(JSON.stringify(previewEntries, null, 2))
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (report.skippedFiles.length) {
|
|
131
|
+
logger.warn('Skipped files:')
|
|
132
|
+
for (const skipped of report.skippedFiles) {
|
|
133
|
+
logger.warn(` • ${skipped.file} (${skipped.reason})`)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return report
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function initCommandDefaultHandler(ctx: TailwindcssPatchCommandContext<'init'>) {
|
|
141
|
+
const configModule = await loadWorkspaceConfigModule()
|
|
142
|
+
await configModule.initConfig(ctx.cwd)
|
|
143
|
+
const configName = configModule.CONFIG_NAME || DEFAULT_CONFIG_NAME
|
|
144
|
+
logger.success(`✨ ${configName}.config.ts initialized!`)
|
|
145
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { CAC } from 'cac'
|
|
2
|
+
import type {
|
|
3
|
+
TailwindcssPatchCliMountOptions,
|
|
4
|
+
TailwindcssPatchCliOptions,
|
|
5
|
+
} from './types'
|
|
6
|
+
|
|
7
|
+
import cac from 'cac'
|
|
8
|
+
import { buildDefaultCommandDefinitions } from './command-definitions'
|
|
9
|
+
import { registerTailwindcssPatchCommand } from './command-registrar'
|
|
10
|
+
import { tailwindcssPatchCommands } from './types'
|
|
11
|
+
import {
|
|
12
|
+
VALIDATE_EXIT_CODES,
|
|
13
|
+
VALIDATE_FAILURE_REASONS,
|
|
14
|
+
ValidateCommandError,
|
|
15
|
+
} from './validate'
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
tailwindcssPatchCommands,
|
|
19
|
+
VALIDATE_EXIT_CODES,
|
|
20
|
+
VALIDATE_FAILURE_REASONS,
|
|
21
|
+
ValidateCommandError,
|
|
22
|
+
}
|
|
23
|
+
export type {
|
|
24
|
+
TailwindcssPatchCliMountOptions,
|
|
25
|
+
TailwindcssPatchCliOptions,
|
|
26
|
+
TailwindcssPatchCommand,
|
|
27
|
+
TailwindcssPatchCommandContext,
|
|
28
|
+
TailwindcssPatchCommandHandler,
|
|
29
|
+
TailwindcssPatchCommandHandlerMap,
|
|
30
|
+
TailwindcssPatchCommandOptionDefinition,
|
|
31
|
+
TailwindcssPatchCommandOptions,
|
|
32
|
+
} from './types'
|
|
33
|
+
export type {
|
|
34
|
+
ValidateFailureReason,
|
|
35
|
+
ValidateFailureSummary,
|
|
36
|
+
ValidateJsonFailurePayload,
|
|
37
|
+
ValidateJsonSuccessPayload,
|
|
38
|
+
} from './validate'
|
|
39
|
+
|
|
40
|
+
export function mountTailwindcssPatchCommands(cli: CAC, options: TailwindcssPatchCliMountOptions = {}) {
|
|
41
|
+
const prefix = options.commandPrefix ?? ''
|
|
42
|
+
const selectedCommands = options.commands ?? tailwindcssPatchCommands
|
|
43
|
+
const defaultDefinitions = buildDefaultCommandDefinitions()
|
|
44
|
+
|
|
45
|
+
for (const name of selectedCommands) {
|
|
46
|
+
registerTailwindcssPatchCommand(cli, name, options, prefix, defaultDefinitions)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return cli
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createTailwindcssPatchCli(options: TailwindcssPatchCliOptions = {}) {
|
|
53
|
+
const cli = cac(options.name ?? 'tw-patch')
|
|
54
|
+
mountTailwindcssPatchCommands(cli, options.mountOptions)
|
|
55
|
+
return cli
|
|
56
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { CAC, Command } from 'cac'
|
|
2
|
+
import type { TailwindcssConfigResult } from '../config/workspace'
|
|
3
|
+
import type { TailwindCssPatchOptions } from '../types'
|
|
4
|
+
import type {
|
|
5
|
+
TailwindcssPatchCommand,
|
|
6
|
+
TailwindcssPatchCommandArgMap,
|
|
7
|
+
TailwindcssPatchCommandContext,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
import process from 'node:process'
|
|
11
|
+
import path from 'pathe'
|
|
12
|
+
import { TailwindcssPatcher } from '../api/tailwindcss-patcher'
|
|
13
|
+
import { loadPatchOptionsForWorkspace, loadWorkspaceConfigModule } from '../config/workspace'
|
|
14
|
+
import logger from '../logger'
|
|
15
|
+
|
|
16
|
+
export function resolveCommandCwd(rawCwd?: string) {
|
|
17
|
+
if (!rawCwd) {
|
|
18
|
+
return process.cwd()
|
|
19
|
+
}
|
|
20
|
+
return path.resolve(rawCwd)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createMemoizedPromiseRunner<TResult>(factory: () => Promise<TResult>) {
|
|
24
|
+
let promise: Promise<TResult> | undefined
|
|
25
|
+
return () => {
|
|
26
|
+
if (!promise) {
|
|
27
|
+
promise = factory()
|
|
28
|
+
}
|
|
29
|
+
return promise
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createTailwindcssPatchCommandContext<TCommand extends TailwindcssPatchCommand>(
|
|
34
|
+
cli: CAC,
|
|
35
|
+
command: Command,
|
|
36
|
+
commandName: TCommand,
|
|
37
|
+
args: TailwindcssPatchCommandArgMap[TCommand],
|
|
38
|
+
cwd: string,
|
|
39
|
+
): TailwindcssPatchCommandContext<TCommand> {
|
|
40
|
+
const loadCachedConfig = createMemoizedPromiseRunner<TailwindcssConfigResult>(() =>
|
|
41
|
+
loadWorkspaceConfigModule().then(mod => mod.getConfig(cwd)),
|
|
42
|
+
)
|
|
43
|
+
const loadCachedPatchOptions = createMemoizedPromiseRunner<TailwindCssPatchOptions>(() =>
|
|
44
|
+
loadPatchOptionsForWorkspace(cwd),
|
|
45
|
+
)
|
|
46
|
+
const createCachedPatcher = createMemoizedPromiseRunner<TailwindcssPatcher>(async () => {
|
|
47
|
+
const patchOptions = await loadCachedPatchOptions()
|
|
48
|
+
return new TailwindcssPatcher(patchOptions)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const loadPatchOptionsForContext = (overrides?: TailwindCssPatchOptions) => {
|
|
52
|
+
if (overrides) {
|
|
53
|
+
return loadPatchOptionsForWorkspace(cwd, overrides)
|
|
54
|
+
}
|
|
55
|
+
return loadCachedPatchOptions()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const createPatcherForContext = async (overrides?: TailwindCssPatchOptions) => {
|
|
59
|
+
if (overrides) {
|
|
60
|
+
const patchOptions = await loadPatchOptionsForWorkspace(cwd, overrides)
|
|
61
|
+
return new TailwindcssPatcher(patchOptions)
|
|
62
|
+
}
|
|
63
|
+
return createCachedPatcher()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
cli,
|
|
68
|
+
command,
|
|
69
|
+
commandName,
|
|
70
|
+
args,
|
|
71
|
+
cwd,
|
|
72
|
+
logger,
|
|
73
|
+
loadConfig: loadCachedConfig,
|
|
74
|
+
loadPatchOptions: loadPatchOptionsForContext,
|
|
75
|
+
createPatcher: createPatcherForContext,
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { TailwindcssPatchCommand, TailwindcssPatchCommandOptionDefinition } from './types'
|
|
2
|
+
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { DEFAULT_TOKEN_REPORT } from './token-output'
|
|
5
|
+
|
|
6
|
+
export interface TailwindcssPatchCommandDefinition {
|
|
7
|
+
description: string
|
|
8
|
+
optionDefs: TailwindcssPatchCommandOptionDefinition[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type TailwindcssPatchCommandDefinitions = Record<TailwindcssPatchCommand, TailwindcssPatchCommandDefinition>
|
|
12
|
+
|
|
13
|
+
function createCwdOptionDefinition(description: string = 'Working directory'): TailwindcssPatchCommandOptionDefinition {
|
|
14
|
+
return {
|
|
15
|
+
flags: '--cwd <dir>',
|
|
16
|
+
description,
|
|
17
|
+
config: { default: process.cwd() },
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildDefaultCommandDefinitions(): TailwindcssPatchCommandDefinitions {
|
|
22
|
+
return {
|
|
23
|
+
install: {
|
|
24
|
+
description: 'Apply Tailwind CSS runtime patches',
|
|
25
|
+
optionDefs: [createCwdOptionDefinition()],
|
|
26
|
+
},
|
|
27
|
+
extract: {
|
|
28
|
+
description: 'Collect generated class names into a cache file',
|
|
29
|
+
optionDefs: [
|
|
30
|
+
createCwdOptionDefinition(),
|
|
31
|
+
{ flags: '--output <file>', description: 'Override output file path' },
|
|
32
|
+
{ flags: '--format <format>', description: 'Output format (json|lines)' },
|
|
33
|
+
{ flags: '--css <file>', description: 'Tailwind CSS entry CSS when using v4' },
|
|
34
|
+
{ flags: '--no-write', description: 'Skip writing to disk' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
tokens: {
|
|
38
|
+
description: 'Extract Tailwind tokens with file/position metadata',
|
|
39
|
+
optionDefs: [
|
|
40
|
+
createCwdOptionDefinition(),
|
|
41
|
+
{ flags: '--output <file>', description: 'Override output file path', config: { default: DEFAULT_TOKEN_REPORT } },
|
|
42
|
+
{
|
|
43
|
+
flags: '--format <format>',
|
|
44
|
+
description: 'Output format (json|lines|grouped-json)',
|
|
45
|
+
config: { default: 'json' },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
flags: '--group-key <key>',
|
|
49
|
+
description: 'Grouping key for grouped-json output (relative|absolute)',
|
|
50
|
+
config: { default: 'relative' },
|
|
51
|
+
},
|
|
52
|
+
{ flags: '--no-write', description: 'Skip writing to disk' },
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
init: {
|
|
56
|
+
description: 'Generate a tailwindcss-patch config file',
|
|
57
|
+
optionDefs: [createCwdOptionDefinition()],
|
|
58
|
+
},
|
|
59
|
+
migrate: {
|
|
60
|
+
description: 'Migrate deprecated config fields to modern options',
|
|
61
|
+
optionDefs: [
|
|
62
|
+
createCwdOptionDefinition(),
|
|
63
|
+
{ flags: '--config <file>', description: 'Migrate a specific config file path' },
|
|
64
|
+
{ flags: '--workspace', description: 'Scan workspace recursively for config files' },
|
|
65
|
+
{ flags: '--max-depth <n>', description: 'Maximum recursion depth for --workspace', config: { default: 6 } },
|
|
66
|
+
{ flags: '--include <glob>', description: 'Only migrate files that match this glob (repeatable)' },
|
|
67
|
+
{ flags: '--exclude <glob>', description: 'Skip files that match this glob (repeatable)' },
|
|
68
|
+
{ flags: '--report-file <file>', description: 'Write migration report JSON to a file' },
|
|
69
|
+
{ flags: '--backup-dir <dir>', description: 'Write pre-migration backups into this directory' },
|
|
70
|
+
{ flags: '--check', description: 'Exit with an error when migration changes are required' },
|
|
71
|
+
{ flags: '--json', description: 'Print the migration report as JSON' },
|
|
72
|
+
{ flags: '--dry-run', description: 'Preview changes without writing files' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
restore: {
|
|
76
|
+
description: 'Restore config files from a previous migration report backup snapshot',
|
|
77
|
+
optionDefs: [
|
|
78
|
+
createCwdOptionDefinition(),
|
|
79
|
+
{ flags: '--report-file <file>', description: 'Migration report file generated by migrate' },
|
|
80
|
+
{ flags: '--dry-run', description: 'Preview restore targets without writing files' },
|
|
81
|
+
{ flags: '--strict', description: 'Fail when any backup file is missing' },
|
|
82
|
+
{ flags: '--json', description: 'Print the restore result as JSON' },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
validate: {
|
|
86
|
+
description: 'Validate migration report compatibility without modifying files',
|
|
87
|
+
optionDefs: [
|
|
88
|
+
createCwdOptionDefinition(),
|
|
89
|
+
{ flags: '--report-file <file>', description: 'Migration report file to validate' },
|
|
90
|
+
{ flags: '--strict', description: 'Fail when any backup file is missing' },
|
|
91
|
+
{ flags: '--json', description: 'Print validation result as JSON' },
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
status: {
|
|
95
|
+
description: 'Check which Tailwind patches are applied',
|
|
96
|
+
optionDefs: [
|
|
97
|
+
createCwdOptionDefinition(),
|
|
98
|
+
{ flags: '--json', description: 'Print a JSON report of patch status' },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Command } from 'cac'
|
|
2
|
+
import type { TailwindcssPatchCommandDefinitions } from './command-definitions'
|
|
3
|
+
import type {
|
|
4
|
+
TailwindcssPatchCliMountOptions,
|
|
5
|
+
TailwindcssPatchCommand,
|
|
6
|
+
TailwindcssPatchCommandOptionDefinition,
|
|
7
|
+
TailwindcssPatchCommandOptions,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
function addPrefixIfMissing(value: string, prefix: string) {
|
|
11
|
+
if (!prefix || value.startsWith(prefix)) {
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
return `${prefix}${value}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveCommandNames(
|
|
18
|
+
command: TailwindcssPatchCommand,
|
|
19
|
+
mountOptions: TailwindcssPatchCliMountOptions,
|
|
20
|
+
prefix: string,
|
|
21
|
+
) {
|
|
22
|
+
const override = mountOptions.commandOptions?.[command]
|
|
23
|
+
const baseName = override?.name ?? command
|
|
24
|
+
const name = addPrefixIfMissing(baseName, prefix)
|
|
25
|
+
const aliases = (override?.aliases ?? []).map(alias => addPrefixIfMissing(alias, prefix))
|
|
26
|
+
return { name, aliases }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveOptionDefinitions(
|
|
30
|
+
defaults: TailwindcssPatchCommandOptionDefinition[],
|
|
31
|
+
override?: TailwindcssPatchCommandOptions,
|
|
32
|
+
) {
|
|
33
|
+
if (!override) {
|
|
34
|
+
return defaults
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const appendDefaults = override.appendDefaultOptions ?? true
|
|
38
|
+
const customDefs = override.optionDefs ?? []
|
|
39
|
+
if (!appendDefaults) {
|
|
40
|
+
return customDefs
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (customDefs.length === 0) {
|
|
44
|
+
return defaults
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [...defaults, ...customDefs]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function resolveCommandMetadata(
|
|
51
|
+
command: TailwindcssPatchCommand,
|
|
52
|
+
mountOptions: TailwindcssPatchCliMountOptions,
|
|
53
|
+
prefix: string,
|
|
54
|
+
defaults: TailwindcssPatchCommandDefinitions,
|
|
55
|
+
) {
|
|
56
|
+
const names = resolveCommandNames(command, mountOptions, prefix)
|
|
57
|
+
const definition = defaults[command]
|
|
58
|
+
const override = mountOptions.commandOptions?.[command]
|
|
59
|
+
const description = override?.description ?? definition.description
|
|
60
|
+
const optionDefs = resolveOptionDefinitions(definition.optionDefs, override)
|
|
61
|
+
return { ...names, description, optionDefs }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function applyCommandOptions(command: Command, optionDefs: TailwindcssPatchCommandOptionDefinition[]) {
|
|
65
|
+
for (const option of optionDefs) {
|
|
66
|
+
command.option(option.flags, option.description ?? '', option.config)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CAC } from 'cac'
|
|
2
|
+
import type { TailwindcssPatchCommandDefinitions } from './command-definitions'
|
|
3
|
+
import type {
|
|
4
|
+
TailwindcssPatchCliMountOptions,
|
|
5
|
+
TailwindcssPatchCommand,
|
|
6
|
+
TailwindcssPatchCommandArgMap,
|
|
7
|
+
TailwindcssPatchCommandDefaultHandlerMap,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
applyCommandOptions,
|
|
12
|
+
resolveCommandMetadata,
|
|
13
|
+
} from './command-metadata'
|
|
14
|
+
import { runWithCommandHandler } from './command-runtime'
|
|
15
|
+
import { defaultCommandHandlers } from './default-handler-map'
|
|
16
|
+
|
|
17
|
+
export function registerTailwindcssPatchCommand<TCommand extends TailwindcssPatchCommand>(
|
|
18
|
+
cli: CAC,
|
|
19
|
+
commandName: TCommand,
|
|
20
|
+
options: TailwindcssPatchCliMountOptions,
|
|
21
|
+
prefix: string,
|
|
22
|
+
defaultDefinitions: TailwindcssPatchCommandDefinitions,
|
|
23
|
+
) {
|
|
24
|
+
const metadata = resolveCommandMetadata(commandName, options, prefix, defaultDefinitions)
|
|
25
|
+
const command = cli.command(metadata.name, metadata.description)
|
|
26
|
+
applyCommandOptions(command, metadata.optionDefs)
|
|
27
|
+
command.action(async (args: TailwindcssPatchCommandArgMap[TCommand]) => {
|
|
28
|
+
const defaultHandler = defaultCommandHandlers[commandName] as TailwindcssPatchCommandDefaultHandlerMap[TCommand]
|
|
29
|
+
return runWithCommandHandler(
|
|
30
|
+
cli,
|
|
31
|
+
command,
|
|
32
|
+
commandName,
|
|
33
|
+
args,
|
|
34
|
+
options.commandHandlers?.[commandName],
|
|
35
|
+
defaultHandler,
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
metadata.aliases.forEach(alias => command.alias(alias))
|
|
39
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CAC, Command } from 'cac'
|
|
2
|
+
import type {
|
|
3
|
+
TailwindcssPatchCommand,
|
|
4
|
+
TailwindcssPatchCommandArgMap,
|
|
5
|
+
TailwindcssPatchCommandContext,
|
|
6
|
+
TailwindcssPatchCommandHandler,
|
|
7
|
+
TailwindcssPatchCommandResultMap,
|
|
8
|
+
} from './types'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
createMemoizedPromiseRunner,
|
|
12
|
+
createTailwindcssPatchCommandContext,
|
|
13
|
+
resolveCommandCwd,
|
|
14
|
+
} from './command-context'
|
|
15
|
+
|
|
16
|
+
export function runWithCommandHandler<TCommand extends TailwindcssPatchCommand>(
|
|
17
|
+
cli: CAC,
|
|
18
|
+
command: Command,
|
|
19
|
+
commandName: TCommand,
|
|
20
|
+
args: TailwindcssPatchCommandArgMap[TCommand],
|
|
21
|
+
handler: TailwindcssPatchCommandHandler<TCommand> | undefined,
|
|
22
|
+
defaultHandler: (
|
|
23
|
+
context: TailwindcssPatchCommandContext<TCommand>,
|
|
24
|
+
) => Promise<TailwindcssPatchCommandResultMap[TCommand]>,
|
|
25
|
+
) {
|
|
26
|
+
const cwd = resolveCommandCwd(args.cwd)
|
|
27
|
+
const context = createTailwindcssPatchCommandContext(cli, command, commandName, args, cwd)
|
|
28
|
+
const runDefault = createMemoizedPromiseRunner(() => defaultHandler(context))
|
|
29
|
+
if (!handler) {
|
|
30
|
+
return runDefault()
|
|
31
|
+
}
|
|
32
|
+
return handler(context, runDefault)
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TailwindcssPatchCommandDefaultHandlerMap } from './types'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
extractCommandDefaultHandler,
|
|
5
|
+
initCommandDefaultHandler,
|
|
6
|
+
installCommandDefaultHandler,
|
|
7
|
+
tokensCommandDefaultHandler,
|
|
8
|
+
} from './basic-handlers'
|
|
9
|
+
import {
|
|
10
|
+
migrateCommandDefaultHandler,
|
|
11
|
+
} from './migrate-handler'
|
|
12
|
+
import { restoreCommandDefaultHandler } from './restore-handler'
|
|
13
|
+
import { statusCommandDefaultHandler } from './status-handler'
|
|
14
|
+
import { validateCommandDefaultHandler } from './validate-handler'
|
|
15
|
+
|
|
16
|
+
export const defaultCommandHandlers = {
|
|
17
|
+
install: installCommandDefaultHandler,
|
|
18
|
+
extract: extractCommandDefaultHandler,
|
|
19
|
+
tokens: tokensCommandDefaultHandler,
|
|
20
|
+
init: initCommandDefaultHandler,
|
|
21
|
+
migrate: migrateCommandDefaultHandler,
|
|
22
|
+
restore: restoreCommandDefaultHandler,
|
|
23
|
+
validate: validateCommandDefaultHandler,
|
|
24
|
+
status: statusCommandDefaultHandler,
|
|
25
|
+
} satisfies TailwindcssPatchCommandDefaultHandlerMap
|