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,235 @@
|
|
|
1
|
+
import type { ExposeContextTransformOptions } from './postcss-v3'
|
|
2
|
+
import * as t from '@babel/types'
|
|
3
|
+
import { generate, parse, traverse } from '../../../babel'
|
|
4
|
+
|
|
5
|
+
const IDENTIFIER_RE = /^[A-Z_$][\w$]*$/i
|
|
6
|
+
|
|
7
|
+
function toIdentifierName(property: string) {
|
|
8
|
+
if (!property) {
|
|
9
|
+
return 'contextRef'
|
|
10
|
+
}
|
|
11
|
+
const sanitized = property.replace(/[^\w$]/gu, '_')
|
|
12
|
+
if (/^\d/.test(sanitized)) {
|
|
13
|
+
return `_${sanitized}`
|
|
14
|
+
}
|
|
15
|
+
return sanitized || 'contextRef'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createExportsMember(property: string) {
|
|
19
|
+
if (IDENTIFIER_RE.test(property)) {
|
|
20
|
+
return t.memberExpression(t.identifier('exports'), t.identifier(property))
|
|
21
|
+
}
|
|
22
|
+
return t.memberExpression(t.identifier('exports'), t.stringLiteral(property), true)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function transformProcessTailwindFeaturesReturnContextV2(content: string) {
|
|
26
|
+
const ast = parse(content, {
|
|
27
|
+
sourceType: 'unambiguous',
|
|
28
|
+
})
|
|
29
|
+
let hasPatched = false
|
|
30
|
+
|
|
31
|
+
traverse(ast, {
|
|
32
|
+
FunctionDeclaration(path) {
|
|
33
|
+
const node = path.node
|
|
34
|
+
if (
|
|
35
|
+
node.id?.name !== 'processTailwindFeatures'
|
|
36
|
+
|| node.body.body.length !== 1
|
|
37
|
+
|| !t.isReturnStatement(node.body.body[0])
|
|
38
|
+
) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const returnStatement = node.body.body[0]
|
|
43
|
+
if (!t.isFunctionExpression(returnStatement.argument)) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const body = returnStatement.argument.body.body
|
|
48
|
+
const lastStatement = body[body.length - 1]
|
|
49
|
+
const alreadyReturnsContext = Boolean(
|
|
50
|
+
t.isReturnStatement(lastStatement)
|
|
51
|
+
&& t.isIdentifier(lastStatement.argument)
|
|
52
|
+
&& lastStatement.argument.name === 'context',
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
hasPatched = alreadyReturnsContext
|
|
56
|
+
if (!alreadyReturnsContext) {
|
|
57
|
+
body.push(t.returnStatement(t.identifier('context')))
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
code: hasPatched ? content : generate(ast).code,
|
|
64
|
+
hasPatched,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function transformPostcssPluginV2(content: string, options: ExposeContextTransformOptions) {
|
|
69
|
+
const refIdentifier = t.identifier(toIdentifierName(options.refProperty))
|
|
70
|
+
const exportMember = createExportsMember(options.refProperty)
|
|
71
|
+
const valueMember = t.memberExpression(refIdentifier, t.identifier('value'))
|
|
72
|
+
const ast = parse(content)
|
|
73
|
+
|
|
74
|
+
let hasPatched = false
|
|
75
|
+
|
|
76
|
+
traverse(ast, {
|
|
77
|
+
Program(path) {
|
|
78
|
+
const program = path.node
|
|
79
|
+
const index = program.body.findIndex((statement) => {
|
|
80
|
+
return t.isFunctionDeclaration(statement) && statement.id?.name === '_default'
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
if (index === -1) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const previous = program.body[index - 1]
|
|
88
|
+
const beforePrevious = program.body[index - 2]
|
|
89
|
+
|
|
90
|
+
const alreadyHasVariable = Boolean(
|
|
91
|
+
previous
|
|
92
|
+
&& t.isVariableDeclaration(previous)
|
|
93
|
+
&& previous.declarations.length === 1
|
|
94
|
+
&& (() => {
|
|
95
|
+
const declaration = previous.declarations[0]
|
|
96
|
+
return Boolean(
|
|
97
|
+
declaration
|
|
98
|
+
&& t.isIdentifier(declaration.id)
|
|
99
|
+
&& declaration.id.name === refIdentifier.name,
|
|
100
|
+
)
|
|
101
|
+
})(),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const alreadyAssignsExports = Boolean(
|
|
105
|
+
beforePrevious
|
|
106
|
+
&& t.isExpressionStatement(beforePrevious)
|
|
107
|
+
&& t.isAssignmentExpression(beforePrevious.expression)
|
|
108
|
+
&& t.isMemberExpression(beforePrevious.expression.left)
|
|
109
|
+
&& t.isIdentifier(beforePrevious.expression.right)
|
|
110
|
+
&& beforePrevious.expression.right.name === refIdentifier.name
|
|
111
|
+
&& generate(beforePrevious.expression.left).code === generate(exportMember).code,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
hasPatched = alreadyHasVariable && alreadyAssignsExports
|
|
115
|
+
|
|
116
|
+
if (!alreadyHasVariable) {
|
|
117
|
+
program.body.splice(
|
|
118
|
+
index,
|
|
119
|
+
0,
|
|
120
|
+
t.variableDeclaration('var', [
|
|
121
|
+
t.variableDeclarator(
|
|
122
|
+
refIdentifier,
|
|
123
|
+
t.objectExpression([
|
|
124
|
+
t.objectProperty(t.identifier('value'), t.arrayExpression()),
|
|
125
|
+
]),
|
|
126
|
+
),
|
|
127
|
+
]),
|
|
128
|
+
t.expressionStatement(
|
|
129
|
+
t.assignmentExpression('=', exportMember, refIdentifier),
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
FunctionDeclaration(path) {
|
|
135
|
+
if (hasPatched) {
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const fn = path.node
|
|
140
|
+
if (fn.id?.name !== '_default') {
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (fn.body.body.length !== 1 || !t.isReturnStatement(fn.body.body[0])) {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const returnStatement = fn.body.body[0]
|
|
149
|
+
if (
|
|
150
|
+
!t.isCallExpression(returnStatement.argument)
|
|
151
|
+
|| !t.isMemberExpression(returnStatement.argument.callee)
|
|
152
|
+
|| !t.isArrayExpression(returnStatement.argument.callee.object)
|
|
153
|
+
) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const fnExpression = returnStatement.argument.callee.object.elements[1]
|
|
158
|
+
if (!fnExpression || !t.isFunctionExpression(fnExpression)) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const block = fnExpression.body
|
|
163
|
+
const statements = block.body
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
t.isExpressionStatement(statements[0])
|
|
167
|
+
&& t.isAssignmentExpression(statements[0].expression)
|
|
168
|
+
&& t.isNumericLiteral(statements[0].expression.right)
|
|
169
|
+
) {
|
|
170
|
+
hasPatched = true
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const lastStatement = statements[statements.length - 1]
|
|
175
|
+
if (
|
|
176
|
+
lastStatement
|
|
177
|
+
&& t.isExpressionStatement(lastStatement)
|
|
178
|
+
) {
|
|
179
|
+
statements[statements.length - 1] = t.expressionStatement(
|
|
180
|
+
t.callExpression(
|
|
181
|
+
t.memberExpression(valueMember, t.identifier('push')),
|
|
182
|
+
[lastStatement.expression],
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const index = statements.findIndex(statement => t.isIfStatement(statement))
|
|
188
|
+
if (index > -1) {
|
|
189
|
+
const ifStatement = statements[index] as t.IfStatement
|
|
190
|
+
if (
|
|
191
|
+
t.isBlockStatement(ifStatement.consequent)
|
|
192
|
+
&& ifStatement.consequent.body[1]
|
|
193
|
+
&& t.isForOfStatement(ifStatement.consequent.body[1])
|
|
194
|
+
) {
|
|
195
|
+
const forOf = ifStatement.consequent.body[1]
|
|
196
|
+
if (
|
|
197
|
+
t.isBlockStatement(forOf.body)
|
|
198
|
+
&& forOf.body.body.length === 1
|
|
199
|
+
) {
|
|
200
|
+
const nestedIf = forOf.body.body[0]
|
|
201
|
+
if (
|
|
202
|
+
nestedIf
|
|
203
|
+
&& t.isIfStatement(nestedIf)
|
|
204
|
+
&& t.isBlockStatement(nestedIf.consequent)
|
|
205
|
+
&& nestedIf.consequent.body.length === 1
|
|
206
|
+
&& t.isExpressionStatement(nestedIf.consequent.body[0])
|
|
207
|
+
) {
|
|
208
|
+
nestedIf.consequent.body[0] = t.expressionStatement(
|
|
209
|
+
t.callExpression(
|
|
210
|
+
t.memberExpression(valueMember, t.identifier('push')),
|
|
211
|
+
[nestedIf.consequent.body[0].expression],
|
|
212
|
+
),
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
statements.unshift(
|
|
220
|
+
t.expressionStatement(
|
|
221
|
+
t.assignmentExpression(
|
|
222
|
+
'=',
|
|
223
|
+
t.memberExpression(valueMember, t.identifier('length')),
|
|
224
|
+
t.numericLiteral(0),
|
|
225
|
+
),
|
|
226
|
+
),
|
|
227
|
+
)
|
|
228
|
+
},
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
code: hasPatched ? content : generate(ast).code,
|
|
233
|
+
hasPatched,
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import * as t from '@babel/types'
|
|
2
|
+
import { generate, parse, traverse } from '../../../babel'
|
|
3
|
+
|
|
4
|
+
export interface ExposeContextTransformOptions {
|
|
5
|
+
refProperty: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const IDENTIFIER_RE = /^[A-Z_$][\w$]*$/i
|
|
9
|
+
|
|
10
|
+
function toIdentifierName(property: string) {
|
|
11
|
+
if (!property) {
|
|
12
|
+
return 'contextRef'
|
|
13
|
+
}
|
|
14
|
+
const sanitized = property.replace(/[^\w$]/gu, '_')
|
|
15
|
+
if (/^\d/.test(sanitized)) {
|
|
16
|
+
return `_${sanitized}`
|
|
17
|
+
}
|
|
18
|
+
return sanitized || 'contextRef'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createModuleExportsMember(property: string) {
|
|
22
|
+
const object = t.memberExpression(t.identifier('module'), t.identifier('exports'))
|
|
23
|
+
if (IDENTIFIER_RE.test(property)) {
|
|
24
|
+
return t.memberExpression(object, t.identifier(property))
|
|
25
|
+
}
|
|
26
|
+
return t.memberExpression(object, t.stringLiteral(property), true)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function transformProcessTailwindFeaturesReturnContext(content: string) {
|
|
30
|
+
const ast = parse(content)
|
|
31
|
+
let hasPatched = false
|
|
32
|
+
|
|
33
|
+
traverse(ast, {
|
|
34
|
+
FunctionDeclaration(path) {
|
|
35
|
+
const node = path.node
|
|
36
|
+
if (
|
|
37
|
+
node.id?.name !== 'processTailwindFeatures'
|
|
38
|
+
|| node.body.body.length !== 1
|
|
39
|
+
) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const [returnStatement] = node.body.body
|
|
44
|
+
if (
|
|
45
|
+
!t.isReturnStatement(returnStatement)
|
|
46
|
+
|| !t.isFunctionExpression(returnStatement.argument)
|
|
47
|
+
) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const expression = returnStatement.argument
|
|
52
|
+
const body = expression.body.body
|
|
53
|
+
const lastStatement = body[body.length - 1]
|
|
54
|
+
const alreadyReturnsContext = Boolean(
|
|
55
|
+
t.isReturnStatement(lastStatement)
|
|
56
|
+
&& t.isIdentifier(lastStatement.argument)
|
|
57
|
+
&& lastStatement.argument.name === 'context',
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
hasPatched = alreadyReturnsContext
|
|
61
|
+
if (!alreadyReturnsContext) {
|
|
62
|
+
body.push(t.returnStatement(t.identifier('context')))
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
code: hasPatched ? content : generate(ast).code,
|
|
69
|
+
hasPatched,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function transformPostcssPlugin(content: string, { refProperty }: ExposeContextTransformOptions) {
|
|
74
|
+
const ast = parse(content)
|
|
75
|
+
const refIdentifier = t.identifier(toIdentifierName(refProperty))
|
|
76
|
+
const moduleExportsMember = createModuleExportsMember(refProperty)
|
|
77
|
+
const valueMember = t.memberExpression(refIdentifier, t.identifier('value'))
|
|
78
|
+
|
|
79
|
+
let hasPatched = false
|
|
80
|
+
|
|
81
|
+
traverse(ast, {
|
|
82
|
+
Program(path) {
|
|
83
|
+
const program = path.node
|
|
84
|
+
const index = program.body.findIndex((statement) => {
|
|
85
|
+
return (
|
|
86
|
+
t.isExpressionStatement(statement)
|
|
87
|
+
&& t.isAssignmentExpression(statement.expression)
|
|
88
|
+
&& t.isMemberExpression(statement.expression.left)
|
|
89
|
+
&& t.isFunctionExpression(statement.expression.right)
|
|
90
|
+
&& statement.expression.right.id?.name === 'tailwindcss'
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if (index === -1) {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const previousStatement = program.body[index - 1]
|
|
99
|
+
const lastStatement = program.body[program.body.length - 1]
|
|
100
|
+
const alreadyHasVariable = Boolean(
|
|
101
|
+
previousStatement
|
|
102
|
+
&& t.isVariableDeclaration(previousStatement)
|
|
103
|
+
&& previousStatement.declarations.length === 1
|
|
104
|
+
&& (() => {
|
|
105
|
+
const declaration = previousStatement.declarations[0]
|
|
106
|
+
return Boolean(
|
|
107
|
+
declaration
|
|
108
|
+
&& t.isIdentifier(declaration.id)
|
|
109
|
+
&& declaration.id.name === refIdentifier.name,
|
|
110
|
+
)
|
|
111
|
+
})(),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
const alreadyAssignsModuleExports = Boolean(
|
|
115
|
+
t.isExpressionStatement(lastStatement)
|
|
116
|
+
&& t.isAssignmentExpression(lastStatement.expression)
|
|
117
|
+
&& t.isMemberExpression(lastStatement.expression.left)
|
|
118
|
+
&& t.isIdentifier(lastStatement.expression.right)
|
|
119
|
+
&& lastStatement.expression.right.name === refIdentifier.name
|
|
120
|
+
&& generate(lastStatement.expression.left).code === generate(moduleExportsMember).code,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
hasPatched = alreadyHasVariable && alreadyAssignsModuleExports
|
|
124
|
+
|
|
125
|
+
if (!alreadyHasVariable) {
|
|
126
|
+
program.body.splice(
|
|
127
|
+
index,
|
|
128
|
+
0,
|
|
129
|
+
t.variableDeclaration('const', [
|
|
130
|
+
t.variableDeclarator(
|
|
131
|
+
refIdentifier,
|
|
132
|
+
t.objectExpression([
|
|
133
|
+
t.objectProperty(t.identifier('value'), t.arrayExpression()),
|
|
134
|
+
]),
|
|
135
|
+
),
|
|
136
|
+
]),
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!alreadyAssignsModuleExports) {
|
|
141
|
+
program.body.push(
|
|
142
|
+
t.expressionStatement(
|
|
143
|
+
t.assignmentExpression('=', moduleExportsMember, refIdentifier),
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
FunctionExpression(path) {
|
|
149
|
+
if (hasPatched) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
const fn = path.node
|
|
153
|
+
if (fn.id?.name !== 'tailwindcss' || fn.body.body.length !== 1) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const [returnStatement] = fn.body.body
|
|
158
|
+
if (!returnStatement || !t.isReturnStatement(returnStatement) || !t.isObjectExpression(returnStatement.argument)) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const properties = returnStatement.argument.properties
|
|
163
|
+
if (properties.length !== 2) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const pluginsProperty = properties.find(
|
|
168
|
+
prop => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'plugins',
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
!pluginsProperty
|
|
173
|
+
|| !t.isObjectProperty(pluginsProperty)
|
|
174
|
+
|| !t.isCallExpression(pluginsProperty.value)
|
|
175
|
+
|| !t.isMemberExpression(pluginsProperty.value.callee)
|
|
176
|
+
|| !t.isArrayExpression(pluginsProperty.value.callee.object)
|
|
177
|
+
) {
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const pluginsArray = pluginsProperty.value.callee.object.elements
|
|
182
|
+
|
|
183
|
+
const targetPlugin = pluginsArray[1]
|
|
184
|
+
if (!targetPlugin || !t.isFunctionExpression(targetPlugin)) {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const block = targetPlugin.body
|
|
189
|
+
const statements = block.body
|
|
190
|
+
const last = statements[statements.length - 1]
|
|
191
|
+
|
|
192
|
+
if (
|
|
193
|
+
last
|
|
194
|
+
&& t.isExpressionStatement(last)
|
|
195
|
+
) {
|
|
196
|
+
statements[statements.length - 1] = t.expressionStatement(
|
|
197
|
+
t.callExpression(
|
|
198
|
+
t.memberExpression(valueMember, t.identifier('push')),
|
|
199
|
+
[last.expression],
|
|
200
|
+
),
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const index = statements.findIndex(s => t.isIfStatement(s))
|
|
205
|
+
if (index > -1) {
|
|
206
|
+
const ifStatement = statements[index] as t.IfStatement
|
|
207
|
+
if (t.isBlockStatement(ifStatement.consequent)) {
|
|
208
|
+
const [, second] = ifStatement.consequent.body
|
|
209
|
+
if (
|
|
210
|
+
second
|
|
211
|
+
&& t.isForOfStatement(second)
|
|
212
|
+
&& t.isBlockStatement(second.body)
|
|
213
|
+
) {
|
|
214
|
+
const bodyStatement = second.body.body[0]
|
|
215
|
+
if (
|
|
216
|
+
bodyStatement
|
|
217
|
+
&& t.isIfStatement(bodyStatement)
|
|
218
|
+
&& t.isBlockStatement(bodyStatement.consequent)
|
|
219
|
+
&& bodyStatement.consequent.body.length === 1
|
|
220
|
+
&& t.isExpressionStatement(bodyStatement.consequent.body[0])
|
|
221
|
+
) {
|
|
222
|
+
bodyStatement.consequent.body[0] = t.expressionStatement(
|
|
223
|
+
t.callExpression(
|
|
224
|
+
t.memberExpression(valueMember, t.identifier('push')),
|
|
225
|
+
[bodyStatement.consequent.body[0].expression],
|
|
226
|
+
),
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
statements.unshift(
|
|
234
|
+
t.expressionStatement(
|
|
235
|
+
t.assignmentExpression(
|
|
236
|
+
'=',
|
|
237
|
+
t.memberExpression(valueMember, t.identifier('length')),
|
|
238
|
+
t.numericLiteral(0),
|
|
239
|
+
),
|
|
240
|
+
),
|
|
241
|
+
)
|
|
242
|
+
},
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
code: hasPatched ? content : generate(ast).code,
|
|
247
|
+
hasPatched,
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { ArrayExpression, StringLiteral } from '@babel/types'
|
|
2
|
+
import type { NormalizedExtendLengthUnitsOptions } from '../../options/types'
|
|
3
|
+
import * as t from '@babel/types'
|
|
4
|
+
import fs from 'fs-extra'
|
|
5
|
+
import path from 'pathe'
|
|
6
|
+
import { generate, parse, traverse } from '../../babel'
|
|
7
|
+
import logger from '../../logger'
|
|
8
|
+
import { spliceChangesIntoString } from '../../utils'
|
|
9
|
+
|
|
10
|
+
interface FindArrayExpressionResult {
|
|
11
|
+
arrayRef?: ArrayExpression
|
|
12
|
+
changed: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function updateLengthUnitsArray(content: string, options: NormalizedExtendLengthUnitsOptions): FindArrayExpressionResult {
|
|
16
|
+
const { variableName = 'lengthUnits', units } = options
|
|
17
|
+
const ast = parse(content)
|
|
18
|
+
|
|
19
|
+
let arrayRef: ArrayExpression | undefined
|
|
20
|
+
let changed = false
|
|
21
|
+
|
|
22
|
+
traverse(ast, {
|
|
23
|
+
Identifier(path) {
|
|
24
|
+
if (
|
|
25
|
+
path.node.name === variableName
|
|
26
|
+
&& t.isVariableDeclarator(path.parent)
|
|
27
|
+
&& t.isArrayExpression(path.parent.init)
|
|
28
|
+
) {
|
|
29
|
+
arrayRef = path.parent.init
|
|
30
|
+
const existing = new Set(
|
|
31
|
+
path.parent.init.elements.map(element => (t.isStringLiteral(element) ? (element as StringLiteral).value : undefined)).filter(Boolean),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
for (const unit of units) {
|
|
35
|
+
if (!existing.has(unit)) {
|
|
36
|
+
path.parent.init.elements = path.parent.init.elements.map((element) => {
|
|
37
|
+
if (t.isStringLiteral(element)) {
|
|
38
|
+
return t.stringLiteral(element.value)
|
|
39
|
+
}
|
|
40
|
+
return element
|
|
41
|
+
})
|
|
42
|
+
path.parent.init.elements.push(t.stringLiteral(unit))
|
|
43
|
+
changed = true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
...(arrayRef === undefined ? {} : { arrayRef }),
|
|
52
|
+
changed,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function applyExtendLengthUnitsPatchV3(rootDir: string, options: NormalizedExtendLengthUnitsOptions) {
|
|
57
|
+
if (!options.enabled) {
|
|
58
|
+
return { changed: false, code: undefined }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const opts: NormalisedV3Options = {
|
|
62
|
+
...options,
|
|
63
|
+
lengthUnitsFilePath: options.lengthUnitsFilePath ?? 'lib/util/dataTypes.js',
|
|
64
|
+
variableName: options.variableName ?? 'lengthUnits',
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const dataTypesFilePath = path.resolve(rootDir, opts.lengthUnitsFilePath)
|
|
68
|
+
const exists = fs.existsSync(dataTypesFilePath)
|
|
69
|
+
|
|
70
|
+
if (!exists) {
|
|
71
|
+
return { changed: false, code: undefined }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const content = fs.readFileSync(dataTypesFilePath, 'utf8')
|
|
75
|
+
const { arrayRef, changed } = updateLengthUnitsArray(content, opts)
|
|
76
|
+
|
|
77
|
+
if (!arrayRef || !changed) {
|
|
78
|
+
return { changed: false, code: undefined }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const { code } = generate(arrayRef, {
|
|
82
|
+
jsescOption: { quotes: 'single' },
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
if (arrayRef.start != null && arrayRef.end != null) {
|
|
86
|
+
const nextCode = `${content.slice(0, arrayRef.start)}${code}${content.slice(arrayRef.end)}`
|
|
87
|
+
if (opts.overwrite) {
|
|
88
|
+
const target = opts.destPath ? path.resolve(opts.destPath) : dataTypesFilePath
|
|
89
|
+
fs.writeFileSync(target, nextCode, 'utf8')
|
|
90
|
+
logger.success('Patched Tailwind CSS length unit list (v3).')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
changed: true,
|
|
95
|
+
code: nextCode,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
changed: false,
|
|
101
|
+
code: undefined,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface NormalisedV3Options extends NormalizedExtendLengthUnitsOptions {
|
|
106
|
+
lengthUnitsFilePath: string
|
|
107
|
+
variableName: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface V4FilePatch {
|
|
111
|
+
file: string
|
|
112
|
+
code: string
|
|
113
|
+
hasPatched: boolean
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface V4Candidate extends V4FilePatch {
|
|
117
|
+
match: RegExpExecArray
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function applyExtendLengthUnitsPatchV4(rootDir: string, options: NormalizedExtendLengthUnitsOptions) {
|
|
121
|
+
if (!options.enabled) {
|
|
122
|
+
return { files: [], changed: false }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const opts: NormalisedV4Options = { ...options }
|
|
126
|
+
|
|
127
|
+
const distDir = path.resolve(rootDir, 'dist')
|
|
128
|
+
if (!fs.existsSync(distDir)) {
|
|
129
|
+
return { files: [], changed: false }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const entries = fs.readdirSync(distDir)
|
|
133
|
+
const chunkNames = entries.filter(entry => entry.endsWith('.js') || entry.endsWith('.mjs'))
|
|
134
|
+
const pattern = /\[\s*["']cm["'],\s*["']mm["'],[\w,"']+\]/
|
|
135
|
+
|
|
136
|
+
const candidates = chunkNames.map((chunkName) => {
|
|
137
|
+
const file = path.join(distDir, chunkName)
|
|
138
|
+
const code = fs.readFileSync(file, 'utf8')
|
|
139
|
+
const match = pattern.exec(code)
|
|
140
|
+
if (!match) {
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
file,
|
|
145
|
+
code,
|
|
146
|
+
match,
|
|
147
|
+
hasPatched: false,
|
|
148
|
+
}
|
|
149
|
+
}).filter((candidate): candidate is V4Candidate => candidate !== null)
|
|
150
|
+
|
|
151
|
+
for (const item of candidates) {
|
|
152
|
+
const { code, file, match } = item
|
|
153
|
+
const ast = parse(match[0], { sourceType: 'unambiguous' })
|
|
154
|
+
|
|
155
|
+
traverse(ast, {
|
|
156
|
+
ArrayExpression(path) {
|
|
157
|
+
for (const unit of opts.units) {
|
|
158
|
+
if (path.node.elements.some(element => t.isStringLiteral(element) && element.value === unit)) {
|
|
159
|
+
item.hasPatched = true
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
path.node.elements.push(t.stringLiteral(unit))
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (item.hasPatched) {
|
|
168
|
+
continue
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const { code: replacement } = generate(ast, { minified: true })
|
|
172
|
+
const start = match.index ?? 0
|
|
173
|
+
const end = start + match[0].length
|
|
174
|
+
item.code = spliceChangesIntoString(code, [
|
|
175
|
+
{
|
|
176
|
+
start,
|
|
177
|
+
end,
|
|
178
|
+
replacement: replacement.endsWith(';') ? replacement.slice(0, -1) : replacement,
|
|
179
|
+
},
|
|
180
|
+
])
|
|
181
|
+
|
|
182
|
+
if (opts.overwrite) {
|
|
183
|
+
fs.writeFileSync(file, item.code, 'utf8')
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (candidates.some(file => !file.hasPatched)) {
|
|
188
|
+
logger.success('Patched Tailwind CSS length unit list (v4).')
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
changed: candidates.some(file => !file.hasPatched),
|
|
193
|
+
files: candidates,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface NormalisedV4Options extends NormalizedExtendLengthUnitsOptions {}
|