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.
- package/README.md +20 -0
- package/dist/{chunk-Z6OMJZTU.js → chunk-TOAZIPHJ.js} +29 -11
- package/dist/{chunk-SWLOK2S6.mjs → chunk-VDWTCQ74.mjs} +29 -11
- package/dist/cli.js +4 -4
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +43 -35
- package/dist/index.d.ts +43 -35
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/package.json +8 -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.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.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,46 @@
|
|
|
1
|
+
import type { PackageInfo } from 'local-pkg'
|
|
2
|
+
import type { NormalizedTailwindCssPatchOptions } from '../options/types'
|
|
3
|
+
import { applyExposeContextPatch } from './operations/export-context'
|
|
4
|
+
import { applyExtendLengthUnitsPatchV3, applyExtendLengthUnitsPatchV4 } from './operations/extend-length-units'
|
|
5
|
+
|
|
6
|
+
export interface PatchRunnerContext {
|
|
7
|
+
packageInfo: PackageInfo
|
|
8
|
+
options: NormalizedTailwindCssPatchOptions
|
|
9
|
+
majorVersion: 2 | 3 | 4
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PatchRunnerResult {
|
|
13
|
+
exposeContext?: ReturnType<typeof applyExposeContextPatch>
|
|
14
|
+
extendLengthUnits?: ReturnType<typeof applyExtendLengthUnitsPatchV3> | ReturnType<typeof applyExtendLengthUnitsPatchV4>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function applyTailwindPatches(context: PatchRunnerContext): PatchRunnerResult {
|
|
18
|
+
const { packageInfo, options, majorVersion } = context
|
|
19
|
+
const results: PatchRunnerResult = {}
|
|
20
|
+
|
|
21
|
+
if (options.features.exposeContext.enabled && (majorVersion === 2 || majorVersion === 3)) {
|
|
22
|
+
results.exposeContext = applyExposeContextPatch({
|
|
23
|
+
rootDir: packageInfo.rootPath,
|
|
24
|
+
refProperty: options.features.exposeContext.refProperty,
|
|
25
|
+
overwrite: options.overwrite,
|
|
26
|
+
majorVersion,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.features.extendLengthUnits?.enabled) {
|
|
31
|
+
if (majorVersion === 3) {
|
|
32
|
+
results.extendLengthUnits = applyExtendLengthUnitsPatchV3(
|
|
33
|
+
packageInfo.rootPath,
|
|
34
|
+
options.features.extendLengthUnits,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
else if (majorVersion === 4) {
|
|
38
|
+
results.extendLengthUnits = applyExtendLengthUnitsPatchV4(
|
|
39
|
+
packageInfo.rootPath,
|
|
40
|
+
options.features.extendLengthUnits,
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return results
|
|
46
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import type { PackageInfo } from 'local-pkg'
|
|
2
|
+
import type {
|
|
3
|
+
NormalizedExtendLengthUnitsOptions,
|
|
4
|
+
NormalizedTailwindCssPatchOptions,
|
|
5
|
+
} from '../options/types'
|
|
6
|
+
import type { PatchStatusEntry, PatchStatusReport } from '../types'
|
|
7
|
+
import * as t from '@babel/types'
|
|
8
|
+
import fs from 'fs-extra'
|
|
9
|
+
import path from 'pathe'
|
|
10
|
+
|
|
11
|
+
import { parse, traverse } from '../babel'
|
|
12
|
+
import { transformPostcssPluginV2, transformProcessTailwindFeaturesReturnContextV2 } from './operations/export-context/postcss-v2'
|
|
13
|
+
import { transformPostcssPlugin, transformProcessTailwindFeaturesReturnContext } from './operations/export-context/postcss-v3'
|
|
14
|
+
import { applyExtendLengthUnitsPatchV4 } from './operations/extend-length-units'
|
|
15
|
+
|
|
16
|
+
interface PatchStatusContext {
|
|
17
|
+
packageInfo: PackageInfo
|
|
18
|
+
options: NormalizedTailwindCssPatchOptions
|
|
19
|
+
majorVersion: 2 | 3 | 4
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function inspectLengthUnitsArray(
|
|
23
|
+
content: string,
|
|
24
|
+
variableName: string,
|
|
25
|
+
units: string[],
|
|
26
|
+
) {
|
|
27
|
+
const ast = parse(content)
|
|
28
|
+
let found = false
|
|
29
|
+
let missingUnits: string[] = []
|
|
30
|
+
|
|
31
|
+
traverse(ast, {
|
|
32
|
+
Identifier(path) {
|
|
33
|
+
if (
|
|
34
|
+
path.node.name === variableName
|
|
35
|
+
&& t.isVariableDeclarator(path.parent)
|
|
36
|
+
&& t.isArrayExpression(path.parent.init)
|
|
37
|
+
) {
|
|
38
|
+
found = true
|
|
39
|
+
const existing = new Set(
|
|
40
|
+
path.parent.init.elements
|
|
41
|
+
.map(element => (t.isStringLiteral(element) ? element.value : undefined))
|
|
42
|
+
.filter(Boolean) as string[],
|
|
43
|
+
)
|
|
44
|
+
missingUnits = units.filter(unit => !existing.has(unit))
|
|
45
|
+
path.stop()
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
found,
|
|
52
|
+
missingUnits,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function checkExposeContextPatch(context: PatchStatusContext): PatchStatusEntry {
|
|
57
|
+
const { packageInfo, options, majorVersion } = context
|
|
58
|
+
const refProperty = options.features.exposeContext.refProperty
|
|
59
|
+
|
|
60
|
+
if (!options.features.exposeContext.enabled) {
|
|
61
|
+
return {
|
|
62
|
+
name: 'exposeContext',
|
|
63
|
+
status: 'skipped',
|
|
64
|
+
reason: 'exposeContext feature disabled',
|
|
65
|
+
files: [],
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (majorVersion === 4) {
|
|
70
|
+
return {
|
|
71
|
+
name: 'exposeContext',
|
|
72
|
+
status: 'unsupported',
|
|
73
|
+
reason: 'Context export patch is only required for Tailwind v2/v3',
|
|
74
|
+
files: [],
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const checks: Array<{ relative: string, exists: boolean, patched: boolean }> = []
|
|
79
|
+
|
|
80
|
+
function inspectFile(
|
|
81
|
+
relative: string,
|
|
82
|
+
transform: (content: string) => { hasPatched: boolean },
|
|
83
|
+
) {
|
|
84
|
+
const filePath = path.resolve(packageInfo.rootPath, relative)
|
|
85
|
+
if (!fs.existsSync(filePath)) {
|
|
86
|
+
checks.push({ relative, exists: false, patched: false })
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
const content = fs.readFileSync(filePath, 'utf8')
|
|
90
|
+
const { hasPatched } = transform(content)
|
|
91
|
+
checks.push({
|
|
92
|
+
relative,
|
|
93
|
+
exists: true,
|
|
94
|
+
patched: hasPatched,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (majorVersion === 3) {
|
|
99
|
+
inspectFile('lib/processTailwindFeatures.js', transformProcessTailwindFeaturesReturnContext)
|
|
100
|
+
const pluginCandidates = ['lib/plugin.js', 'lib/index.js']
|
|
101
|
+
const pluginRelative = pluginCandidates.find(candidate => fs.existsSync(path.resolve(packageInfo.rootPath, candidate)))
|
|
102
|
+
if (pluginRelative) {
|
|
103
|
+
inspectFile(pluginRelative, content => transformPostcssPlugin(content, { refProperty }))
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
checks.push({ relative: 'lib/plugin.js', exists: false, patched: false })
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
inspectFile('lib/jit/processTailwindFeatures.js', transformProcessTailwindFeaturesReturnContextV2)
|
|
111
|
+
inspectFile('lib/jit/index.js', content => transformPostcssPluginV2(content, { refProperty }))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const files = checks.filter(check => check.exists).map(check => check.relative)
|
|
115
|
+
const missingFiles = checks.filter(check => !check.exists)
|
|
116
|
+
const unpatchedFiles = checks.filter(check => check.exists && !check.patched)
|
|
117
|
+
|
|
118
|
+
const reasons: string[] = []
|
|
119
|
+
if (missingFiles.length) {
|
|
120
|
+
reasons.push(`missing files: ${missingFiles.map(item => item.relative).join(', ')}`)
|
|
121
|
+
}
|
|
122
|
+
if (unpatchedFiles.length) {
|
|
123
|
+
reasons.push(`unpatched files: ${unpatchedFiles.map(item => item.relative).join(', ')}`)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
name: 'exposeContext',
|
|
128
|
+
status: reasons.length ? 'not-applied' : 'applied',
|
|
129
|
+
...(reasons.length ? { reason: reasons.join('; ') } : {}),
|
|
130
|
+
files,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function checkExtendLengthUnitsV3(rootDir: string, options: NormalizedExtendLengthUnitsOptions): PatchStatusEntry {
|
|
135
|
+
const lengthUnitsFilePath = options.lengthUnitsFilePath ?? 'lib/util/dataTypes.js'
|
|
136
|
+
const variableName = options.variableName ?? 'lengthUnits'
|
|
137
|
+
const target = path.resolve(rootDir, lengthUnitsFilePath)
|
|
138
|
+
const files = fs.existsSync(target) ? [path.relative(rootDir, target)] : []
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(target)) {
|
|
141
|
+
return {
|
|
142
|
+
name: 'extendLengthUnits',
|
|
143
|
+
status: 'not-applied',
|
|
144
|
+
reason: `missing ${lengthUnitsFilePath}`,
|
|
145
|
+
files,
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const content = fs.readFileSync(target, 'utf8')
|
|
150
|
+
const { found, missingUnits } = inspectLengthUnitsArray(content, variableName, options.units)
|
|
151
|
+
|
|
152
|
+
if (!found) {
|
|
153
|
+
return {
|
|
154
|
+
name: 'extendLengthUnits',
|
|
155
|
+
status: 'not-applied',
|
|
156
|
+
reason: `could not locate ${variableName} array in ${lengthUnitsFilePath}`,
|
|
157
|
+
files,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (missingUnits.length) {
|
|
162
|
+
return {
|
|
163
|
+
name: 'extendLengthUnits',
|
|
164
|
+
status: 'not-applied',
|
|
165
|
+
reason: `missing units: ${missingUnits.join(', ')}`,
|
|
166
|
+
files,
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
name: 'extendLengthUnits',
|
|
172
|
+
status: 'applied',
|
|
173
|
+
files,
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function checkExtendLengthUnitsV4(rootDir: string, options: NormalizedExtendLengthUnitsOptions): PatchStatusEntry {
|
|
178
|
+
const distDir = path.resolve(rootDir, 'dist')
|
|
179
|
+
if (!fs.existsSync(distDir)) {
|
|
180
|
+
return {
|
|
181
|
+
name: 'extendLengthUnits',
|
|
182
|
+
status: 'not-applied',
|
|
183
|
+
reason: 'dist directory not found for Tailwind v4 package',
|
|
184
|
+
files: [],
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result = applyExtendLengthUnitsPatchV4(rootDir, {
|
|
189
|
+
...options,
|
|
190
|
+
enabled: true,
|
|
191
|
+
overwrite: false,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
if (result.files.length === 0) {
|
|
195
|
+
return {
|
|
196
|
+
name: 'extendLengthUnits',
|
|
197
|
+
status: 'not-applied',
|
|
198
|
+
reason: 'no bundle chunks matched the length unit pattern',
|
|
199
|
+
files: [],
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const files = result.files.map(file => path.relative(rootDir, file.file))
|
|
204
|
+
const pending = result.files.filter(file => !file.hasPatched)
|
|
205
|
+
if (pending.length) {
|
|
206
|
+
return {
|
|
207
|
+
name: 'extendLengthUnits',
|
|
208
|
+
status: 'not-applied',
|
|
209
|
+
reason: `missing units in ${pending.length} bundle${pending.length > 1 ? 's' : ''}`,
|
|
210
|
+
files: pending.map(file => path.relative(rootDir, file.file)),
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
name: 'extendLengthUnits',
|
|
216
|
+
status: 'applied',
|
|
217
|
+
files,
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function checkExtendLengthUnitsPatch(context: PatchStatusContext): PatchStatusEntry {
|
|
222
|
+
const { packageInfo, options, majorVersion } = context
|
|
223
|
+
|
|
224
|
+
if (!options.features.extendLengthUnits) {
|
|
225
|
+
return {
|
|
226
|
+
name: 'extendLengthUnits',
|
|
227
|
+
status: 'skipped',
|
|
228
|
+
reason: 'extendLengthUnits feature disabled',
|
|
229
|
+
files: [],
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (majorVersion === 2) {
|
|
234
|
+
return {
|
|
235
|
+
name: 'extendLengthUnits',
|
|
236
|
+
status: 'unsupported',
|
|
237
|
+
reason: 'length unit extension is only applied for Tailwind v3/v4',
|
|
238
|
+
files: [],
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (majorVersion === 3) {
|
|
243
|
+
return checkExtendLengthUnitsV3(packageInfo.rootPath, options.features.extendLengthUnits)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return checkExtendLengthUnitsV4(packageInfo.rootPath, options.features.extendLengthUnits)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function getPatchStatusReport(context: PatchStatusContext): PatchStatusReport {
|
|
250
|
+
return {
|
|
251
|
+
package: {
|
|
252
|
+
name: context.packageInfo.name ?? context.packageInfo.packageJson?.name,
|
|
253
|
+
version: context.packageInfo.version,
|
|
254
|
+
root: context.packageInfo.rootPath,
|
|
255
|
+
},
|
|
256
|
+
majorVersion: context.majorVersion,
|
|
257
|
+
entries: [
|
|
258
|
+
checkExposeContextPatch(context),
|
|
259
|
+
checkExtendLengthUnitsPatch(context),
|
|
260
|
+
],
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { NormalizedTailwindCssPatchOptions } from '../options/types'
|
|
2
|
+
import type { TailwindcssRuntimeContext } from '../types'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import fs from 'fs-extra'
|
|
5
|
+
import path from 'pathe'
|
|
6
|
+
import { extractValidCandidates } from '../extraction/candidate-extractor'
|
|
7
|
+
import { isObject } from '../utils'
|
|
8
|
+
|
|
9
|
+
export function collectClassesFromContexts(
|
|
10
|
+
contexts: TailwindcssRuntimeContext[],
|
|
11
|
+
filter: (className: string) => boolean,
|
|
12
|
+
) {
|
|
13
|
+
const set = new Set<string>()
|
|
14
|
+
for (const context of contexts) {
|
|
15
|
+
if (!isObject(context) || !context.classCache) {
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const key of context.classCache.keys()) {
|
|
20
|
+
const className = key.toString()
|
|
21
|
+
if (filter(className)) {
|
|
22
|
+
set.add(className)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return set
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function collectClassesFromTailwindV4(
|
|
30
|
+
options: NormalizedTailwindCssPatchOptions,
|
|
31
|
+
) {
|
|
32
|
+
const set = new Set<string>()
|
|
33
|
+
const v4Options = options.tailwind.v4
|
|
34
|
+
if (!v4Options) {
|
|
35
|
+
return set
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const toAbsolute = (value: string | undefined) => {
|
|
39
|
+
if (!value) {
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
return path.isAbsolute(value) ? value : path.resolve(options.projectRoot, value)
|
|
43
|
+
}
|
|
44
|
+
const resolvedConfiguredBase = toAbsolute(v4Options.configuredBase)
|
|
45
|
+
const resolvedDefaultBase = toAbsolute(v4Options.base) ?? process.cwd()
|
|
46
|
+
const resolveSources = (base: string) => {
|
|
47
|
+
if (!v4Options.sources?.length) {
|
|
48
|
+
return undefined
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return v4Options.sources.map(source => ({
|
|
52
|
+
base: source.base ?? base,
|
|
53
|
+
pattern: source.pattern,
|
|
54
|
+
negated: source.negated,
|
|
55
|
+
}))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (v4Options.cssEntries.length > 0) {
|
|
59
|
+
for (const entry of v4Options.cssEntries) {
|
|
60
|
+
const filePath = path.isAbsolute(entry) ? entry : path.resolve(options.projectRoot, entry)
|
|
61
|
+
if (!(await fs.pathExists(filePath))) {
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
const css = await fs.readFile(filePath, 'utf8')
|
|
65
|
+
const entryDir = path.dirname(filePath)
|
|
66
|
+
const designSystemBases = resolvedConfiguredBase && resolvedConfiguredBase !== entryDir
|
|
67
|
+
? [entryDir, resolvedConfiguredBase]
|
|
68
|
+
: [entryDir]
|
|
69
|
+
const sourcesBase = resolvedConfiguredBase ?? entryDir
|
|
70
|
+
const sources = resolveSources(sourcesBase)
|
|
71
|
+
const firstBase = designSystemBases[0] ?? entryDir
|
|
72
|
+
const extractOptions = {
|
|
73
|
+
cwd: options.projectRoot,
|
|
74
|
+
base: firstBase,
|
|
75
|
+
baseFallbacks: designSystemBases.slice(1),
|
|
76
|
+
css,
|
|
77
|
+
...(sources === undefined ? {} : { sources }),
|
|
78
|
+
}
|
|
79
|
+
const candidates = await extractValidCandidates(extractOptions)
|
|
80
|
+
for (const candidate of candidates) {
|
|
81
|
+
if (options.filter(candidate)) {
|
|
82
|
+
set.add(candidate)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const baseForCss = resolvedConfiguredBase ?? resolvedDefaultBase
|
|
89
|
+
const sources = resolveSources(baseForCss)
|
|
90
|
+
const extractOptions = {
|
|
91
|
+
cwd: options.projectRoot,
|
|
92
|
+
base: baseForCss,
|
|
93
|
+
...(v4Options.css === undefined ? {} : { css: v4Options.css }),
|
|
94
|
+
...(sources === undefined ? {} : { sources }),
|
|
95
|
+
}
|
|
96
|
+
const candidates = await extractValidCandidates(extractOptions)
|
|
97
|
+
for (const candidate of candidates) {
|
|
98
|
+
if (options.filter(candidate)) {
|
|
99
|
+
set.add(candidate)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return set
|
|
105
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { PackageInfo } from 'local-pkg'
|
|
2
|
+
import type { NormalizedTailwindCssPatchOptions } from '../config'
|
|
3
|
+
import type { PatchStatusReport, TailwindcssRuntimeContext } from '../types'
|
|
4
|
+
import type { applyTailwindPatches } from '../install/patch-runner'
|
|
5
|
+
import { collectClassesFromContexts, collectClassesFromTailwindV4 } from '../install/class-collector'
|
|
6
|
+
import { loadRuntimeContexts } from '../install/context-registry'
|
|
7
|
+
import { applyTailwindPatches as runPatch } from '../install/patch-runner'
|
|
8
|
+
import { runTailwindBuild } from '../install/process-tailwindcss'
|
|
9
|
+
import { getPatchStatusReport } from '../install/status'
|
|
10
|
+
|
|
11
|
+
export type TailwindMajorVersion = 2 | 3 | 4
|
|
12
|
+
export type PatchResult = ReturnType<typeof applyTailwindPatches>
|
|
13
|
+
|
|
14
|
+
export interface TailwindCollector {
|
|
15
|
+
patch(): Promise<PatchResult>
|
|
16
|
+
getPatchStatus(): Promise<PatchStatusReport>
|
|
17
|
+
collectClassSet(): Promise<Set<string>>
|
|
18
|
+
getContexts(): TailwindcssRuntimeContext[]
|
|
19
|
+
getPatchSnapshot(): string
|
|
20
|
+
runTailwindBuildIfNeeded?(): Promise<void>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function resolveTailwindExecutionOptions(
|
|
24
|
+
normalized: NormalizedTailwindCssPatchOptions,
|
|
25
|
+
majorVersion: 2 | 3,
|
|
26
|
+
) {
|
|
27
|
+
const base = normalized.tailwind
|
|
28
|
+
if (majorVersion === 2 && base.v2) {
|
|
29
|
+
return {
|
|
30
|
+
cwd: base.v2.cwd ?? base.cwd ?? normalized.projectRoot,
|
|
31
|
+
config: base.v2.config ?? base.config,
|
|
32
|
+
postcssPlugin: base.v2.postcssPlugin ?? base.postcssPlugin,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (majorVersion === 3 && base.v3) {
|
|
37
|
+
return {
|
|
38
|
+
cwd: base.v3.cwd ?? base.cwd ?? normalized.projectRoot,
|
|
39
|
+
config: base.v3.config ?? base.config,
|
|
40
|
+
postcssPlugin: base.v3.postcssPlugin ?? base.postcssPlugin,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
cwd: base.cwd ?? normalized.projectRoot,
|
|
46
|
+
config: base.config,
|
|
47
|
+
postcssPlugin: base.postcssPlugin,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
abstract class BaseCollector implements TailwindCollector {
|
|
52
|
+
constructor(
|
|
53
|
+
protected readonly packageInfo: PackageInfo,
|
|
54
|
+
protected readonly options: NormalizedTailwindCssPatchOptions,
|
|
55
|
+
protected readonly majorVersion: TailwindMajorVersion,
|
|
56
|
+
) {}
|
|
57
|
+
|
|
58
|
+
async patch() {
|
|
59
|
+
return runPatch({
|
|
60
|
+
packageInfo: this.packageInfo,
|
|
61
|
+
options: this.options,
|
|
62
|
+
majorVersion: this.majorVersion,
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async getPatchStatus() {
|
|
67
|
+
return getPatchStatusReport({
|
|
68
|
+
packageInfo: this.packageInfo,
|
|
69
|
+
options: this.options,
|
|
70
|
+
majorVersion: this.majorVersion,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getContexts() {
|
|
75
|
+
return loadRuntimeContexts(
|
|
76
|
+
this.packageInfo,
|
|
77
|
+
this.majorVersion,
|
|
78
|
+
this.options.features.exposeContext.refProperty,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
abstract collectClassSet(): Promise<Set<string>>
|
|
83
|
+
abstract getPatchSnapshot(): string
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class RuntimeCollector extends BaseCollector {
|
|
87
|
+
private inFlightBuild: Promise<void> | undefined
|
|
88
|
+
|
|
89
|
+
constructor(
|
|
90
|
+
packageInfo: PackageInfo,
|
|
91
|
+
options: NormalizedTailwindCssPatchOptions,
|
|
92
|
+
majorVersion: 2 | 3,
|
|
93
|
+
private readonly snapshotFactory: () => string,
|
|
94
|
+
) {
|
|
95
|
+
super(packageInfo, options, majorVersion)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async collectClassSet() {
|
|
99
|
+
const contexts = this.getContexts()
|
|
100
|
+
return collectClassesFromContexts(contexts, this.options.filter)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getPatchSnapshot() {
|
|
104
|
+
return this.snapshotFactory()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async runTailwindBuildIfNeeded() {
|
|
108
|
+
if (this.inFlightBuild) {
|
|
109
|
+
return this.inFlightBuild
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const executionOptions = resolveTailwindExecutionOptions(this.options, this.majorVersion as 2 | 3)
|
|
113
|
+
const buildOptions = {
|
|
114
|
+
cwd: executionOptions.cwd,
|
|
115
|
+
majorVersion: this.majorVersion as 2 | 3,
|
|
116
|
+
...(executionOptions.config === undefined ? {} : { config: executionOptions.config }),
|
|
117
|
+
...(executionOptions.postcssPlugin === undefined ? {} : { postcssPlugin: executionOptions.postcssPlugin }),
|
|
118
|
+
}
|
|
119
|
+
this.inFlightBuild = runTailwindBuild(buildOptions).then(() => undefined)
|
|
120
|
+
try {
|
|
121
|
+
await this.inFlightBuild
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
this.inFlightBuild = undefined
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class TailwindV4Collector extends BaseCollector {
|
|
130
|
+
constructor(
|
|
131
|
+
packageInfo: PackageInfo,
|
|
132
|
+
options: NormalizedTailwindCssPatchOptions,
|
|
133
|
+
snapshotFactory: () => string,
|
|
134
|
+
) {
|
|
135
|
+
super(packageInfo, options, 4)
|
|
136
|
+
this.snapshotFactory = snapshotFactory
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private readonly snapshotFactory: () => string
|
|
140
|
+
|
|
141
|
+
async collectClassSet() {
|
|
142
|
+
return collectClassesFromTailwindV4(this.options)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getPatchSnapshot() {
|
|
146
|
+
return this.snapshotFactory()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { PackageInfo } from 'local-pkg'
|
|
2
|
+
import type { TailwindcssRuntimeContext } from '../types'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import fs from 'fs-extra'
|
|
5
|
+
import path from 'pathe'
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url)
|
|
8
|
+
|
|
9
|
+
function resolveRuntimeEntry(packageInfo: PackageInfo, majorVersion: 2 | 3): string | undefined {
|
|
10
|
+
const root = packageInfo.rootPath
|
|
11
|
+
|
|
12
|
+
if (majorVersion === 2) {
|
|
13
|
+
const jitIndex = path.join(root, 'lib/jit/index.js')
|
|
14
|
+
if (fs.existsSync(jitIndex)) {
|
|
15
|
+
return jitIndex
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (majorVersion === 3) {
|
|
19
|
+
const plugin = path.join(root, 'lib/plugin.js')
|
|
20
|
+
const index = path.join(root, 'lib/index.js')
|
|
21
|
+
if (fs.existsSync(plugin)) {
|
|
22
|
+
return plugin
|
|
23
|
+
}
|
|
24
|
+
if (fs.existsSync(index)) {
|
|
25
|
+
return index
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function loadRuntimeContexts(
|
|
33
|
+
packageInfo: PackageInfo,
|
|
34
|
+
majorVersion: 2 | 3 | 4,
|
|
35
|
+
refProperty: string,
|
|
36
|
+
): TailwindcssRuntimeContext[] {
|
|
37
|
+
if (majorVersion === 4) {
|
|
38
|
+
return []
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const entry = resolveRuntimeEntry(packageInfo, majorVersion)
|
|
42
|
+
if (!entry) {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const moduleExports = require(entry) as Record<string, any>
|
|
47
|
+
if (!moduleExports) {
|
|
48
|
+
return []
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const ref = moduleExports[refProperty]
|
|
52
|
+
if (!ref) {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (Array.isArray(ref)) {
|
|
57
|
+
return ref as TailwindcssRuntimeContext[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (typeof ref === 'object' && Array.isArray(ref.value)) {
|
|
61
|
+
return ref.value as TailwindcssRuntimeContext[]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return []
|
|
65
|
+
}
|