Skip to content

Commit 37159d1

Browse files
committed
chore: prepare postcss7-compat
1 parent 4256e92 commit 37159d1

File tree

9 files changed

+318
-4
lines changed

9 files changed

+318
-4
lines changed

eslint.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import { icebreaker } from '@icebreakers/eslint-config'
22

3-
export default icebreaker()
3+
export default icebreaker({}, {
4+
ignores: ['**/fixtures/**'],
5+
})

packages/tailwindcss-patch/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"@types/resolve": "^1.20.6",
6767
"@types/semver": "^7.5.8",
6868
"pkg-types": "^1.1.1",
69+
"postcss7": "npm:postcss@7",
6970
"tailwindcss": "^3.4.3",
7071
"tailwindcss2": "npm:@tailwindcss/postcss7-compat@^2.2.17"
7172
},
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import * as t from '@babel/types'
2+
import { generate, parse, traverse } from '@/babel'
3+
// crash code
4+
5+
export function inspectProcessTailwindFeaturesReturnContext(content: string) {
6+
const ast = parse(content)
7+
let hasPatched = false
8+
traverse(ast, {
9+
FunctionDeclaration(p) {
10+
const n = p.node
11+
if (n.id?.name === 'processTailwindFeatures' && n.body.body.length === 1 && t.isReturnStatement(n.body.body[0])) {
12+
const rts = n.body.body[0]
13+
if (t.isFunctionExpression(rts.argument)) {
14+
const body = rts.argument.body.body
15+
const lastStatement = body[body.length - 1]
16+
hasPatched = t.isReturnStatement(lastStatement) && t.isIdentifier(lastStatement.argument) && lastStatement.argument.name === 'context'
17+
if (!hasPatched) {
18+
// return context;
19+
const rts = t.returnStatement(t.identifier('context'))
20+
body.push(rts)
21+
}
22+
}
23+
}
24+
},
25+
})
26+
27+
return {
28+
code: hasPatched ? content : generate(ast).code,
29+
hasPatched,
30+
}
31+
}
32+
33+
export function inspectPostcssPlugin(content: string) {
34+
const ast = parse(content)
35+
const exportKey = 'contextRef'
36+
const variableName = 'contextRef'
37+
const valueKey = 'value'
38+
let hasPatched = false
39+
traverse(ast, {
40+
Program(p) {
41+
const n = p.node
42+
// find module.exports = function tailwindcss(configOrPath)
43+
const idx = n.body.findIndex((x) => {
44+
return (
45+
t.isExpressionStatement(x)
46+
&& t.isAssignmentExpression(x.expression)
47+
&& t.isMemberExpression(x.expression.left)
48+
&& t.isFunctionExpression(x.expression.right)
49+
&& x.expression.right.id?.name === 'tailwindcss'
50+
)
51+
})
52+
53+
if (idx > -1) {
54+
const prevStatement = n.body[idx - 1]
55+
const lastStatement = n.body[n.body.length - 1]
56+
const hasPatchedCondition0
57+
= prevStatement
58+
&& t.isVariableDeclaration(prevStatement)
59+
&& prevStatement.declarations.length === 1
60+
&& t.isIdentifier(prevStatement.declarations[0].id)
61+
&& prevStatement.declarations[0].id.name === variableName
62+
const hasPatchedCondition1
63+
= t.isExpressionStatement(lastStatement)
64+
&& t.isAssignmentExpression(lastStatement.expression)
65+
&& t.isIdentifier(lastStatement.expression.right)
66+
&& lastStatement.expression.right.name === variableName
67+
68+
hasPatched = hasPatchedCondition0 || hasPatchedCondition1
69+
if (!hasPatched) {
70+
// const contextRef = {
71+
// value: []
72+
// };
73+
const statement = t.variableDeclaration('const', [
74+
t.variableDeclarator(t.identifier(variableName), t.objectExpression([t.objectProperty(t.identifier(valueKey), t.arrayExpression())])),
75+
])
76+
n.body.splice(idx, 0, statement)
77+
// module.exports.contextRef = contextRef;
78+
n.body.push(
79+
t.expressionStatement(
80+
t.assignmentExpression(
81+
'=',
82+
t.memberExpression(t.memberExpression(t.identifier('module'), t.identifier('exports')), t.identifier(exportKey)),
83+
t.identifier(variableName),
84+
),
85+
),
86+
)
87+
}
88+
}
89+
},
90+
FunctionExpression(p) {
91+
if (hasPatched) {
92+
return
93+
}
94+
const n = p.node
95+
if (n.id?.name === 'tailwindcss' && n.body.body.length === 1 && t.isReturnStatement(n.body.body[0])) {
96+
const returnStatement = n.body.body[0]
97+
if (t.isObjectExpression(returnStatement.argument) && returnStatement.argument.properties.length === 2) {
98+
const properties = returnStatement.argument.properties
99+
if (t.isObjectProperty(properties[0]) && t.isObjectProperty(properties[1])) {
100+
const keyMatched = t.isIdentifier(properties[0].key) && properties[0].key.name === 'postcssPlugin'
101+
const pluginsMatched = t.isIdentifier(properties[1].key) && properties[1].key.name === 'plugins'
102+
if (
103+
pluginsMatched
104+
&& keyMatched
105+
&& t.isCallExpression(properties[1].value)
106+
&& t.isMemberExpression(properties[1].value.callee)
107+
&& t.isArrayExpression(properties[1].value.callee.object)
108+
) {
109+
const pluginsCode = properties[1].value.callee.object.elements
110+
if (pluginsCode[1] && t.isFunctionExpression(pluginsCode[1])) {
111+
const targetBlockStatement = pluginsCode[1].body
112+
113+
const lastStatement = targetBlockStatement.body[targetBlockStatement.body.length - 1]
114+
if (t.isExpressionStatement(lastStatement)) {
115+
// contextRef.value.push((0, _processTailwindFeatures.default)(context)(root, result));
116+
const newExpressionStatement = t.expressionStatement(
117+
t.callExpression(
118+
t.memberExpression(
119+
t.memberExpression(t.identifier(variableName), t.identifier('value')),
120+
121+
t.identifier('push'),
122+
),
123+
124+
[lastStatement.expression],
125+
),
126+
)
127+
targetBlockStatement.body[targetBlockStatement.body.length - 1] = newExpressionStatement
128+
}
129+
130+
const ifIdx = targetBlockStatement.body.findIndex(x => t.isIfStatement(x))
131+
if (ifIdx > -1) {
132+
const ifRoot = <t.IfStatement>targetBlockStatement.body[ifIdx]
133+
if (t.isBlockStatement(ifRoot.consequent) && ifRoot.consequent.body[1] && t.isForOfStatement(ifRoot.consequent.body[1])) {
134+
const forOf: t.ForOfStatement = ifRoot.consequent.body[1]
135+
if (t.isBlockStatement(forOf.body) && forOf.body.body.length === 1 && t.isIfStatement(forOf.body.body[0])) {
136+
const if2: t.IfStatement = forOf.body.body[0]
137+
if (t.isBlockStatement(if2.consequent) && if2.consequent.body.length === 1 && t.isExpressionStatement(if2.consequent.body[0])) {
138+
const target = if2.consequent.body[0]
139+
// contextRef.value.push((0, _processTailwindFeatures.default)(context)(root1, result));
140+
const newExpressionStatement = t.expressionStatement(
141+
t.callExpression(t.memberExpression(t.memberExpression(t.identifier(variableName), t.identifier('value')), t.identifier('push')), [target.expression]),
142+
)
143+
if2.consequent.body[0] = newExpressionStatement
144+
}
145+
}
146+
}
147+
}
148+
// clear contextRef.value
149+
targetBlockStatement.body.unshift(
150+
// contentRef.value = []
151+
// t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier(variableName), t.identifier(valueKey)), t.arrayExpression()))
152+
153+
// contentRef.value.length = 0
154+
t.expressionStatement(
155+
t.assignmentExpression(
156+
'=',
157+
t.memberExpression(t.memberExpression(t.identifier(variableName), t.identifier(valueKey)), t.identifier('length')),
158+
t.numericLiteral(0),
159+
),
160+
),
161+
)
162+
}
163+
}
164+
}
165+
}
166+
}
167+
// start = true
168+
},
169+
// BlockStatement(p) {
170+
// const n = p.node
171+
// if (start && p.parent.type === 'FunctionExpression' && !p.parent.id) {
172+
// n.body.unshift(t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier(variableName), t.identifier(valueKey)), t.arrayExpression())))
173+
// }
174+
// }
175+
})
176+
return {
177+
code: hasPatched ? content : generate(ast).code,
178+
hasPatched,
179+
}
180+
}

packages/tailwindcss-patch/src/core/runtime-patcher.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import path from 'node:path'
22
import fs from 'node:fs'
3+
import process from 'node:process'
34
import { gte } from 'semver'
45
import type { PackageJson } from 'pkg-types'
56
import { defu } from 'defu'
@@ -48,7 +49,7 @@ export function createPatch(opt: InternalPatchOptions) {
4849
}
4950
}
5051

51-
export function monkeyPatchForExposingContext(twDir: string, opt: InternalPatchOptions) {
52+
export function monkeyPatchForExposingContextV3(twDir: string, opt: InternalPatchOptions) {
5253
const processTailwindFeaturesFilePath = path.resolve(twDir, 'lib/processTailwindFeatures.js')
5354

5455
const processTailwindFeaturesContent = ensureFileContent(processTailwindFeaturesFilePath)
@@ -84,13 +85,19 @@ export function monkeyPatchForExposingContext(twDir: string, opt: InternalPatchO
8485

8586
export function internalPatch(pkgJsonPath: string | undefined, options: InternalPatchOptions): any | undefined {
8687
if (pkgJsonPath) {
88+
// eslint-disable-next-line ts/no-var-requires, ts/no-require-imports
8789
const pkgJson = require(pkgJsonPath) as PackageJson
8890
const twDir = path.dirname(pkgJsonPath)
8991
if (gte(pkgJson.version!, '3.0.0')) {
9092
options.version = pkgJson.version
91-
const result = monkeyPatchForExposingContext(twDir, options)
93+
const result = monkeyPatchForExposingContextV3(twDir, options)
9294
return result
9395
}
96+
else if (gte(pkgJson.version!, '2.0.0')) {
97+
options.version = pkgJson.version
98+
// const result = monkeyPatchForExposingContext(twDir, options)
99+
// return result
100+
}
94101
// no sth
95102
}
96103
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`postcss7-compat > common 1`] = `""`;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = _default;
7+
8+
var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext"));
9+
10+
var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext"));
11+
12+
var _sharedState = require("./lib/sharedState");
13+
14+
var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
15+
16+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17+
18+
function _default(configOrPath = {}) {
19+
return [_sharedState.env.DEBUG && function (root) {
20+
console.log('\n');
21+
console.time('JIT TOTAL');
22+
return root;
23+
}, function (root, result) {
24+
let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath);
25+
(0, _processTailwindFeatures.default)(setupContext)(root, result);
26+
}, _sharedState.env.DEBUG && function (root) {
27+
console.timeEnd('JIT TOTAL');
28+
console.log('\n');
29+
return root;
30+
}].filter(Boolean);
31+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = processTailwindFeatures;
7+
8+
var _normalizeTailwindDirectives = _interopRequireDefault(require("./lib/normalizeTailwindDirectives"));
9+
10+
var _expandTailwindAtRules = _interopRequireDefault(require("./lib/expandTailwindAtRules"));
11+
12+
var _expandApplyAtRules = _interopRequireDefault(require("./lib/expandApplyAtRules"));
13+
14+
var _evaluateTailwindFunctions = _interopRequireDefault(require("../lib/evaluateTailwindFunctions"));
15+
16+
var _substituteScreenAtRules = _interopRequireDefault(require("../lib/substituteScreenAtRules"));
17+
18+
var _resolveDefaultsAtRules = _interopRequireDefault(require("./lib/resolveDefaultsAtRules"));
19+
20+
var _collapseAdjacentRules = _interopRequireDefault(require("./lib/collapseAdjacentRules"));
21+
22+
var _setupContextUtils = require("./lib/setupContextUtils");
23+
24+
var _log = _interopRequireDefault(require("../util/log"));
25+
26+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27+
28+
let warned = false;
29+
30+
function processTailwindFeatures(setupContext) {
31+
return function (root, result) {
32+
if (!warned) {
33+
_log.default.warn([`You have enabled the JIT engine which is currently in preview.`, 'Preview features are not covered by semver, may introduce breaking changes, and can change at any time.']);
34+
35+
warned = true;
36+
}
37+
38+
let tailwindDirectives = (0, _normalizeTailwindDirectives.default)(root);
39+
let
40+
= setupContext({
41+
tailwindDirectives,
42+
43+
registerDependency(dependency) {
44+
result.messages.push({
45+
plugin: 'tailwindcss',
46+
parent: result.opts.from,
47+
...dependency
48+
});
49+
},
50+
51+
createContext(tailwindConfig, changedContent) {
52+
return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, tailwindDirectives, root);
53+
}
54+
55+
})(root, result);
56+
57+
if (context.tailwindConfig.separator === '-') {
58+
throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead.");
59+
}
60+
61+
(0, _expandTailwindAtRules.default)(context)(root, result);
62+
(0, _expandApplyAtRules.default)(context)(root, result);
63+
(0, _evaluateTailwindFunctions.default)(context)(root, result);
64+
(0, _substituteScreenAtRules.default)(context)(root, result);
65+
(0, _resolveDefaultsAtRules.default)(context)(root, result);
66+
(0, _collapseAdjacentRules.default)(context)(root, result);
67+
};
68+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import postcss from 'postcss7'
2+
// @ts-ignore
3+
// import tailwindcss from 'tailwindcss2'
4+
5+
describe('postcss7-compat', () => {
6+
it('common', () => {
7+
// const x = require('tailwindcss2') // ()
8+
// {
9+
// mode: 'jit',
10+
// corePlugins: {
11+
// preflight: false,
12+
// },
13+
// }
14+
// const { css } = postcss([x]).process(`@tailwind base;
15+
// @tailwind components;
16+
// @tailwind utilities;`)
17+
// expect(css).toMatchSnapshot()
18+
})
19+
})

pnpm-lock.yaml

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)