domflax 0.1.2 → 0.2.0
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 +66 -31
- package/dist/chunk-EYQXQQQH.js +336 -0
- package/dist/chunk-EYQXQQQH.js.map +1 -0
- package/dist/{chunk-DNHOGPYV.js → chunk-FPT4EJ6Q.js} +1100 -1551
- package/dist/chunk-FPT4EJ6Q.js.map +1 -0
- package/dist/chunk-JBM3MJRM.js +382 -0
- package/dist/chunk-JBM3MJRM.js.map +1 -0
- package/dist/{chunk-DWLB7FRR.js → chunk-TTJEXWAC.js} +322 -9
- package/dist/chunk-TTJEXWAC.js.map +1 -0
- package/dist/{chunk-6WVVF6AD.js → chunk-U5GOONKV.js} +5 -2
- package/dist/{chunk-6WVVF6AD.js.map → chunk-U5GOONKV.js.map} +1 -1
- package/dist/cli.cjs +3010 -2789
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +268 -232
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1684 -1649
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +255 -498
- package/dist/index.d.ts +255 -498
- package/dist/index.js +17 -37
- package/dist/{pattern-F5xBtIE-.d.cts → pattern-DotR_dHs.d.cts} +1 -1
- package/dist/pattern-kit.cjs +60 -1
- package/dist/pattern-kit.cjs.map +1 -1
- package/dist/pattern-kit.d.cts +2 -2
- package/dist/pattern-kit.d.ts +2 -2
- package/dist/pattern-kit.js +2 -2
- package/dist/{pattern-CV607P87.d.ts → pattern-urm5uuwj.d.ts} +1 -1
- package/dist/{resolve-ops-DIwEelH-.d.ts → resolve-ops-D8aQina5.d.cts} +20 -0
- package/dist/{resolve-ops-DIwEelH-.d.cts → resolve-ops-D8aQina5.d.ts} +20 -0
- package/dist/verify.d.cts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/dist/webpack-loader.cjs +1615 -1633
- package/dist/webpack-loader.cjs.map +1 -1
- package/dist/webpack-loader.d.cts +8 -2
- package/dist/webpack-loader.d.ts +8 -2
- package/dist/webpack-loader.js +8 -5
- package/dist/webpack-loader.js.map +1 -1
- package/dist/worker.cjs +5337 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +2 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +72 -0
- package/dist/worker.js.map +1 -0
- package/package.json +4 -2
- package/dist/chunk-DNHOGPYV.js.map +0 -1
- package/dist/chunk-DOQEBGWB.js +0 -188
- package/dist/chunk-DOQEBGWB.js.map +0 -1
- package/dist/chunk-DWLB7FRR.js.map +0 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BASE_CONDITION,
|
|
3
|
-
BASE_CONDITION_KEY,
|
|
4
|
-
and,
|
|
5
|
-
computed,
|
|
6
3
|
conditionKey,
|
|
4
|
+
createComment,
|
|
7
5
|
createDocument,
|
|
8
6
|
createElement,
|
|
9
7
|
createExpr,
|
|
@@ -14,17 +12,174 @@ import {
|
|
|
14
12
|
emptyClassList,
|
|
15
13
|
emptyStyleMap,
|
|
16
14
|
hasDynamicClasses,
|
|
17
|
-
|
|
15
|
+
minStringCover,
|
|
18
16
|
normalizer,
|
|
19
17
|
not,
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
styleMapTuples,
|
|
19
|
+
tupleKey
|
|
20
|
+
} from "./chunk-TTJEXWAC.js";
|
|
22
21
|
import {
|
|
23
22
|
__filename,
|
|
24
23
|
init_esm_shims
|
|
25
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-U5GOONKV.js";
|
|
26
25
|
|
|
27
|
-
// ../patterns/src/library/
|
|
26
|
+
// ../patterns/src/library/flex/flex-center-wrapper.pattern.ts
|
|
27
|
+
init_esm_shims();
|
|
28
|
+
var flexCenterWrapper = definePattern({
|
|
29
|
+
name: "flex-center-wrapper",
|
|
30
|
+
category: "flatten/flex/flex-center-wrapper",
|
|
31
|
+
safety: 2,
|
|
32
|
+
doc: {
|
|
33
|
+
title: "Flatten flex-centering wrapper",
|
|
34
|
+
summary: "A div that only centers a single child (display:flex; align-items:center; justify-content:center) is removed; the child gains place-self:center.",
|
|
35
|
+
before: '<div style="display:flex;align-items:center;justify-content:center"><Child/></div>',
|
|
36
|
+
after: '<Child style="place-self:center"/>',
|
|
37
|
+
safetyRationale: "Wrapper paints nothing, carries no ref/handlers/dynamic children, and is not a combinator subject; inheritable styles are folded onto the child before removal."
|
|
38
|
+
},
|
|
39
|
+
match: {
|
|
40
|
+
tag: "div",
|
|
41
|
+
style: { display: "flex", alignItems: "center", justifyContent: "center" },
|
|
42
|
+
onlyChild: "element",
|
|
43
|
+
paintsNothing: true
|
|
44
|
+
},
|
|
45
|
+
rewrite: {
|
|
46
|
+
flattenInto: "child",
|
|
47
|
+
childGains: { placeSelf: "center" }
|
|
48
|
+
},
|
|
49
|
+
// Collapsing a flex-centering wrapper to `place-self:center` on the child is render-identical ONLY
|
|
50
|
+
// when the child's NEW parent is a statically-known GRID that lets the wrapper fill its area (there
|
|
51
|
+
// `place-self`'s align-self AND justify-self both take effect). Under that ONE context the flatten is
|
|
52
|
+
// classified `provably-safe` and commits; under a flex/block/unknown parent — or when the wrapper
|
|
53
|
+
// drops any own style — it stays `needs-verification` and the conservative production gate PRESERVES
|
|
54
|
+
// it. Op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is additionally
|
|
55
|
+
// asserted by the invariant suite over every pattern.
|
|
56
|
+
test: {
|
|
57
|
+
cases: [
|
|
58
|
+
{
|
|
59
|
+
name: "grid parent \u2192 flattened (child gains place-self-center)",
|
|
60
|
+
before: '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
61
|
+
after: '<div className="grid"><span className="bg-red-200 place-self-center">x</span></div>'
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
noMatch: [
|
|
65
|
+
// Non-grid (flex) parent (document root): `justify-self` is ignored in flex → not provably safe.
|
|
66
|
+
'<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
67
|
+
// Grid parent, but the wrapper drops padding when removed → not layout-neutral (rule 3).
|
|
68
|
+
'<div className="grid"><div className="p-4 flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
69
|
+
// Grid parent forcing place-items-center: the wrapper would not fill its area → fill guard skips.
|
|
70
|
+
'<div className="grid place-items-center"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
71
|
+
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
72
|
+
'<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ../patterns/src/library/fragment/redundant-fragment.pattern.ts
|
|
78
|
+
init_esm_shims();
|
|
79
|
+
function parentIsRedundantFragment(node, ctx) {
|
|
80
|
+
const el = node;
|
|
81
|
+
if (el.kind !== "element") return false;
|
|
82
|
+
const parentId = el.parent;
|
|
83
|
+
if (parentId == null) return false;
|
|
84
|
+
const parent = ctx.doc.nodes.get(parentId);
|
|
85
|
+
if (!parent || parent.kind !== "fragment") return false;
|
|
86
|
+
if (parent.parent == null) return false;
|
|
87
|
+
if (parent.children.length !== 1) return false;
|
|
88
|
+
const m = parent.meta;
|
|
89
|
+
if (m.hasKey || m.hasRef || m.hasEventHandlers || m.hasDynamicChildren || m.hasDangerousHtml || m.hasSpreadAttrs || m.isComponent) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (m.targetedByCombinator || m.targetedByStructuralPseudo) return false;
|
|
93
|
+
const fid = parentId;
|
|
94
|
+
if (ctx.selectors.targetedByCombinator(fid) || ctx.selectors.targetedByStructuralPseudo(fid)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (ctx.selectors.reparentImpact(fid).size > 0) return false;
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
var redundantFragment = definePattern({
|
|
101
|
+
name: "redundant-fragment",
|
|
102
|
+
category: "flatten/fragment/redundant-fragment",
|
|
103
|
+
safety: 1,
|
|
104
|
+
doc: {
|
|
105
|
+
title: "Flatten redundant single-child fragment",
|
|
106
|
+
summary: "A fragment whose only child is a single node is removed; the child is spliced up into the fragment's slot, preserving its IRNodeId, siblings, attributes and the CSS cascade.",
|
|
107
|
+
before: "<><Child/></>",
|
|
108
|
+
after: "<Child/>",
|
|
109
|
+
safetyRationale: "A fragment paints nothing and renders no box; with exactly one child its removal changes no sibling/structural-pseudo match-set. Keyed fragments and fragments carrying ref/handlers/dynamic-children/raw-html/spread are excluded as opacity barriers."
|
|
110
|
+
},
|
|
111
|
+
match: parentIsRedundantFragment,
|
|
112
|
+
rewrite: (ctx, rw) => {
|
|
113
|
+
const parentId = ctx.node.parent;
|
|
114
|
+
if (parentId == null) return null;
|
|
115
|
+
const fragment = ctx.doc.nodes.get(parentId);
|
|
116
|
+
if (!fragment || fragment.kind !== "fragment") return null;
|
|
117
|
+
return [rw.unwrap(fragment)];
|
|
118
|
+
},
|
|
119
|
+
test: {
|
|
120
|
+
cases: [
|
|
121
|
+
{
|
|
122
|
+
// A fragment renders no box, so unwrapping a single-child fragment is always layout-identical
|
|
123
|
+
// → a provably-safe flatten: the child is spliced up into the fragment's slot.
|
|
124
|
+
before: '<><span className="bg-red-200">Hi</span></>',
|
|
125
|
+
after: '<span className="bg-red-200">Hi</span>'
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
noMatch: [
|
|
129
|
+
// Two children ⇒ not a single-child fragment, so the fragment is load-bearing and stays.
|
|
130
|
+
'<><span className="bg-red-200">A</span><span className="bg-green-200">B</span></>'
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ../patterns/src/library/grid/grid-center-wrapper.pattern.ts
|
|
136
|
+
init_esm_shims();
|
|
137
|
+
var gridCenterWrapper = definePattern({
|
|
138
|
+
name: "grid-center-wrapper",
|
|
139
|
+
category: "flatten/grid/grid-center-wrapper",
|
|
140
|
+
safety: 2,
|
|
141
|
+
doc: {
|
|
142
|
+
title: "Flatten grid-centering wrapper",
|
|
143
|
+
summary: "A div that only centers a single child (display:grid; align-items:center; justify-content:center) is removed; the child gains place-self:center.",
|
|
144
|
+
before: '<div style="display:grid;align-items:center;justify-content:center"><Child/></div>',
|
|
145
|
+
after: '<Child style="place-self:center"/>',
|
|
146
|
+
safetyRationale: "Wrapper paints nothing, carries no ref/handlers/dynamic children, and is not a combinator subject; inheritable styles are folded onto the child before removal. The place-self:center collapse is committed by the gate only under a statically-known filling grid parent."
|
|
147
|
+
},
|
|
148
|
+
match: {
|
|
149
|
+
tag: "div",
|
|
150
|
+
style: { display: "grid", alignItems: "center", justifyContent: "center" },
|
|
151
|
+
onlyChild: "element",
|
|
152
|
+
paintsNothing: true
|
|
153
|
+
},
|
|
154
|
+
rewrite: {
|
|
155
|
+
flattenInto: "child",
|
|
156
|
+
childGains: { placeSelf: "center" }
|
|
157
|
+
},
|
|
158
|
+
// Like `flex-center-wrapper`, collapsing to `place-self:center` is render-identical ONLY when the
|
|
159
|
+
// child's NEW parent is a statically-known GRID that lets the wrapper fill its area (there both halves
|
|
160
|
+
// of place-self take effect). Under that ONE context the flatten is `provably-safe` and commits; under
|
|
161
|
+
// a flex/block/unknown parent — or when the wrapper drops any own style — it stays `needs-verification`
|
|
162
|
+
// and the conservative production gate PRESERVES it. Op-level correctness is asserted by the invariant suite.
|
|
163
|
+
test: {
|
|
164
|
+
cases: [
|
|
165
|
+
{
|
|
166
|
+
name: "grid parent \u2192 flattened (child gains place-self-center)",
|
|
167
|
+
before: '<div className="grid"><div className="grid items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
168
|
+
after: '<div className="grid"><span className="bg-red-200 place-self-center">x</span></div>'
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
noMatch: [
|
|
172
|
+
// Non-grid (document-root) parent: justify-self is ignored outside a grid → not provably safe.
|
|
173
|
+
'<div className="grid justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
174
|
+
// Grid parent, but the wrapper drops padding when removed → not layout-neutral, preserved.
|
|
175
|
+
'<div className="grid"><div className="p-4 grid items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
176
|
+
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
177
|
+
'<div className="grid justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// ../patterns/src/library/wrapper/display-contents-wrapper.pattern.ts
|
|
28
183
|
init_esm_shims();
|
|
29
184
|
function asEl(node) {
|
|
30
185
|
const n = node;
|
|
@@ -49,7 +204,7 @@ var targetedByStructuralPseudo = (node, ctx) => {
|
|
|
49
204
|
};
|
|
50
205
|
var displayContentsWrapper = definePattern({
|
|
51
206
|
name: "display-contents-wrapper",
|
|
52
|
-
category: "flatten/display-contents-wrapper",
|
|
207
|
+
category: "flatten/wrapper/display-contents-wrapper",
|
|
53
208
|
safety: 2,
|
|
54
209
|
doc: {
|
|
55
210
|
title: "Flatten display:contents wrapper",
|
|
@@ -89,7 +244,7 @@ var displayContentsWrapper = definePattern({
|
|
|
89
244
|
}
|
|
90
245
|
});
|
|
91
246
|
|
|
92
|
-
// ../patterns/src/library/
|
|
247
|
+
// ../patterns/src/library/wrapper/empty-style-div.pattern.ts
|
|
93
248
|
init_esm_shims();
|
|
94
249
|
function asEl2(node) {
|
|
95
250
|
const n = node;
|
|
@@ -122,7 +277,7 @@ var hasNonBlockDisplay = (node, ctx) => {
|
|
|
122
277
|
};
|
|
123
278
|
var emptyStyleDiv = definePattern({
|
|
124
279
|
name: "empty-style-div",
|
|
125
|
-
category: "flatten/empty-style-div",
|
|
280
|
+
category: "flatten/wrapper/empty-style-div",
|
|
126
281
|
safety: 1,
|
|
127
282
|
doc: {
|
|
128
283
|
title: "Flatten empty-style div wrapper",
|
|
@@ -161,330 +316,67 @@ var emptyStyleDiv = definePattern({
|
|
|
161
316
|
}
|
|
162
317
|
});
|
|
163
318
|
|
|
164
|
-
// ../patterns/src/library/
|
|
165
|
-
init_esm_shims();
|
|
166
|
-
var flexCenterWrapper = definePattern({
|
|
167
|
-
name: "flex-center-wrapper",
|
|
168
|
-
category: "flatten/flex-center-wrapper",
|
|
169
|
-
safety: 2,
|
|
170
|
-
doc: {
|
|
171
|
-
title: "Flatten flex-centering wrapper",
|
|
172
|
-
summary: "A div that only centers a single child (display:flex; align-items:center; justify-content:center) is removed; the child gains place-self:center.",
|
|
173
|
-
before: '<div style="display:flex;align-items:center;justify-content:center"><Child/></div>',
|
|
174
|
-
after: '<Child style="place-self:center"/>',
|
|
175
|
-
safetyRationale: "Wrapper paints nothing, carries no ref/handlers/dynamic children, and is not a combinator subject; inheritable styles are folded onto the child before removal."
|
|
176
|
-
},
|
|
177
|
-
match: {
|
|
178
|
-
tag: "div",
|
|
179
|
-
style: { display: "flex", alignItems: "center", justifyContent: "center" },
|
|
180
|
-
onlyChild: "element",
|
|
181
|
-
paintsNothing: true
|
|
182
|
-
},
|
|
183
|
-
rewrite: {
|
|
184
|
-
flattenInto: "child",
|
|
185
|
-
childGains: { placeSelf: "center" }
|
|
186
|
-
},
|
|
187
|
-
// Collapsing a flex-centering wrapper to `place-self:center` on the child only stays centered when
|
|
188
|
-
// the child's NEW parent is flex/grid; moreover the wrapper's own `display:flex` establishes a
|
|
189
|
-
// formatting context. Both make this a `needs-verification` flatten, which the conservative
|
|
190
|
-
// production gate (`'provably-safe'`, used by the harness) intentionally REVERTS — so every case
|
|
191
|
-
// here is a no-match: the wrapper is preserved. Op-level rewrite correctness (purity, id-preserving
|
|
192
|
-
// unwrap, opacity-barrier safety) is still asserted by the invariant suite over every pattern.
|
|
193
|
-
test: {
|
|
194
|
-
noMatch: [
|
|
195
|
-
// Even under a static flex/grid parent the centering flatten is not provably layout-neutral
|
|
196
|
-
// (the wrapper itself establishes a flex formatting context) → left unchanged.
|
|
197
|
-
'<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
198
|
-
// Non-flex/grid parent (document root): place-self centering would not hold → left unchanged.
|
|
199
|
-
'<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
200
|
-
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
201
|
-
'<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
202
|
-
]
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// ../patterns/src/library/flatten/inline-flex-center-wrapper.pattern.ts
|
|
207
|
-
init_esm_shims();
|
|
208
|
-
var inlineFlexCenterWrapper = definePattern({
|
|
209
|
-
name: "inline-flex-center-wrapper",
|
|
210
|
-
category: "flatten/inline-flex-center-wrapper",
|
|
211
|
-
safety: 2,
|
|
212
|
-
doc: {
|
|
213
|
-
title: "Flatten inline-flex-centering wrapper",
|
|
214
|
-
summary: "A div that only centers a single child (display:inline-flex; align-items:center; justify-content:center) is removed; the child gains place-self:center.",
|
|
215
|
-
before: '<div style="display:inline-flex;align-items:center;justify-content:center"><Child/></div>',
|
|
216
|
-
after: '<Child style="place-self:center"/>',
|
|
217
|
-
safetyRationale: "Wrapper paints nothing, carries no ref/handlers/dynamic children, and is not a combinator subject; inheritable styles are folded onto the child before removal."
|
|
218
|
-
},
|
|
219
|
-
match: {
|
|
220
|
-
tag: "div",
|
|
221
|
-
style: { display: "inline-flex", alignItems: "center", justifyContent: "center" },
|
|
222
|
-
onlyChild: "element",
|
|
223
|
-
paintsNothing: true
|
|
224
|
-
},
|
|
225
|
-
rewrite: {
|
|
226
|
-
flattenInto: "child",
|
|
227
|
-
childGains: { placeSelf: "center" }
|
|
228
|
-
},
|
|
229
|
-
// Like its block-level sibling, this centering flatten is `needs-verification` (the wrapper's own
|
|
230
|
-
// `display:inline-flex` establishes a formatting context, and place-self centering only holds under
|
|
231
|
-
// a flex/grid parent), so the conservative production gate (`'provably-safe'`) REVERTS it — every
|
|
232
|
-
// case here is a no-match. Op-level correctness is covered by the invariant suite.
|
|
233
|
-
test: {
|
|
234
|
-
noMatch: [
|
|
235
|
-
// Even under a static flex/grid parent the centering flatten is not provably layout-neutral.
|
|
236
|
-
'<div className="grid"><div className="inline-flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
237
|
-
// Non-flex/grid parent (document root) → left unchanged.
|
|
238
|
-
'<div className="inline-flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
239
|
-
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
240
|
-
'<div className="inline-flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
241
|
-
]
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// ../patterns/src/library/flatten/nested-flex-merge.pattern.ts
|
|
246
|
-
init_esm_shims();
|
|
247
|
-
function baseConditionStyleMap(decls) {
|
|
248
|
-
const map = /* @__PURE__ */ new Map();
|
|
249
|
-
for (const [prop, value] of decls) {
|
|
250
|
-
for (const decl of normalizer.normalizeDeclaration(prop, value, false)) {
|
|
251
|
-
map.set(decl.property, decl);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const block = { condition: BASE_CONDITION, decls: map };
|
|
255
|
-
const blocks = /* @__PURE__ */ new Map([[conditionKey(BASE_CONDITION), block]]);
|
|
256
|
-
return { blocks };
|
|
257
|
-
}
|
|
258
|
-
var DISPLAY_FLEX = baseConditionStyleMap([["display", "flex"]]);
|
|
259
|
-
var FLEX_CONTAINER_PROPERTIES = /* @__PURE__ */ new Set([
|
|
260
|
-
"display",
|
|
261
|
-
"flex-direction",
|
|
262
|
-
"flex-wrap",
|
|
263
|
-
"justify-content",
|
|
264
|
-
"align-items",
|
|
265
|
-
"align-content",
|
|
266
|
-
"place-content",
|
|
267
|
-
"place-items",
|
|
268
|
-
"row-gap",
|
|
269
|
-
"column-gap"
|
|
270
|
-
]);
|
|
271
|
-
function outerMergeSafe(sm) {
|
|
272
|
-
const norm = normalizer.normalizeStyleMap(sm);
|
|
273
|
-
for (const block of norm.blocks.values()) {
|
|
274
|
-
for (const decl of block.decls.values()) {
|
|
275
|
-
if (FLEX_CONTAINER_PROPERTIES.has(String(decl.property))) continue;
|
|
276
|
-
if (decl.inherited) continue;
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
function flexConflict(outer, inner) {
|
|
283
|
-
const a = normalizer.normalizeStyleMap(outer);
|
|
284
|
-
const b = normalizer.normalizeStyleMap(inner);
|
|
285
|
-
for (const [key, blockA] of a.blocks) {
|
|
286
|
-
const blockB = b.blocks.get(key);
|
|
287
|
-
if (!blockB) continue;
|
|
288
|
-
for (const [prop, declA] of blockA.decls) {
|
|
289
|
-
if (!FLEX_CONTAINER_PROPERTIES.has(String(prop))) continue;
|
|
290
|
-
const declB = blockB.decls.get(prop);
|
|
291
|
-
if (declB && declB.value !== declA.value) return true;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
function extractFlexStyle(sm) {
|
|
297
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
298
|
-
for (const [key, block] of sm.blocks) {
|
|
299
|
-
const decls = /* @__PURE__ */ new Map();
|
|
300
|
-
for (const [prop, decl] of block.decls) {
|
|
301
|
-
if (FLEX_CONTAINER_PROPERTIES.has(String(prop))) decls.set(prop, decl);
|
|
302
|
-
}
|
|
303
|
-
if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
|
|
304
|
-
}
|
|
305
|
-
return { blocks };
|
|
306
|
-
}
|
|
307
|
-
var isInnerFlex = and(
|
|
308
|
-
isElement("div"),
|
|
309
|
-
computed(DISPLAY_FLEX),
|
|
310
|
-
not(targetedByCombinator)
|
|
311
|
-
);
|
|
312
|
-
var nestedFlexMerge = definePattern({
|
|
313
|
-
name: "nested-flex-merge",
|
|
314
|
-
category: "flatten/nested-flex-merge",
|
|
315
|
-
safety: 2,
|
|
316
|
-
doc: {
|
|
317
|
-
title: "Merge nested flex containers",
|
|
318
|
-
summary: "A flex container whose only child is itself a flex container with non-conflicting flex properties is collapsed into one; the wrapper is removed and its flex declarations merge onto the surviving child.",
|
|
319
|
-
before: '<div style="display:flex;align-items:center;gap:8px"><div style="display:flex;flex-direction:column"/></div>',
|
|
320
|
-
after: '<div style="display:flex;flex-direction:column;align-items:center;gap:8px"/>',
|
|
321
|
-
safetyRationale: "The wrapper paints nothing, declares only flex-container/inheritable properties, carries no ref/handlers/dynamic children, and is not a combinator subject; the two containers do not conflict on any flex property, so the union is unambiguous and lossless."
|
|
322
|
-
},
|
|
323
|
-
match: {
|
|
324
|
-
tag: "div",
|
|
325
|
-
style: { display: "flex" },
|
|
326
|
-
onlyChild: "element",
|
|
327
|
-
paintsNothing: true
|
|
328
|
-
},
|
|
329
|
-
rewrite: (ctx, rw) => {
|
|
330
|
-
const outer = ctx.node;
|
|
331
|
-
const inner = ctx.onlyElementChild();
|
|
332
|
-
if (!inner) return null;
|
|
333
|
-
if (!isInnerFlex(inner, ctx)) return null;
|
|
334
|
-
const outerStyle = ctx.computed();
|
|
335
|
-
const innerStyle = ctx.computedOf(inner);
|
|
336
|
-
if (!outerMergeSafe(outerStyle)) return null;
|
|
337
|
-
if (flexConflict(outerStyle, innerStyle)) return null;
|
|
338
|
-
return [
|
|
339
|
-
// 1. Preserve inheritable values (color/font/…) by folding them onto the child first.
|
|
340
|
-
rw.foldInheritedStyles(outer, inner, { conditions: "all" }),
|
|
341
|
-
// 2. Transfer the wrapper's flex-container declarations onto the child (target-wins keeps the
|
|
342
|
-
// child's value for any shared property — identical anyway, we proved non-conflict).
|
|
343
|
-
rw.mergeStyle(inner, null, extractFlexStyle(outerStyle), "target-wins"),
|
|
344
|
-
// 3. Remove the wrapper (structural-safe; hoists the child and preserves its IRNodeId).
|
|
345
|
-
rw.unwrap(outer)
|
|
346
|
-
];
|
|
347
|
-
},
|
|
348
|
-
// Merging the outer flex container into the inner removes the outer's box, but a `display:flex`
|
|
349
|
-
// wrapper establishes a formatting context, so this is a `needs-verification` flatten that the
|
|
350
|
-
// conservative production gate (`'provably-safe'`) REVERTS — every case here is a no-match. The
|
|
351
|
-
// merge's op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is asserted
|
|
352
|
-
// by the invariant suite over every pattern.
|
|
353
|
-
test: {
|
|
354
|
-
noMatch: [
|
|
355
|
-
// The merge is real but not provably layout-neutral (the wrapper establishes a flex context),
|
|
356
|
-
// so under the conservative gate the nested containers are left in place.
|
|
357
|
-
'<div className="flex items-center gap-2" data-x="1"><div className="flex flex-col">X</div></div>',
|
|
358
|
-
// A non-flex wrapper does not match the flex-container signature → left unchanged anyway.
|
|
359
|
-
'<div className="block bg-blue-500"><div className="flex flex-col">X</div></div>'
|
|
360
|
-
]
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
// ../patterns/src/library/flatten/nested-grid-merge.pattern.ts
|
|
319
|
+
// ../patterns/src/library/wrapper/inherited-only-wrapper.pattern.ts
|
|
365
320
|
init_esm_shims();
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
"grid-template-columns",
|
|
381
|
-
"grid-template-rows",
|
|
382
|
-
"grid-template-areas",
|
|
383
|
-
"grid-auto-columns",
|
|
384
|
-
"grid-auto-rows",
|
|
385
|
-
"grid-auto-flow",
|
|
386
|
-
"justify-content",
|
|
387
|
-
"align-content",
|
|
388
|
-
"place-content",
|
|
389
|
-
"justify-items",
|
|
390
|
-
"align-items",
|
|
391
|
-
"place-items",
|
|
392
|
-
"row-gap",
|
|
393
|
-
"column-gap"
|
|
394
|
-
]);
|
|
395
|
-
function outerMergeSafe2(sm) {
|
|
396
|
-
const norm = normalizer.normalizeStyleMap(sm);
|
|
397
|
-
for (const block of norm.blocks.values()) {
|
|
321
|
+
var INERT_HOST_TAGS = /* @__PURE__ */ new Set(["div", "span"]);
|
|
322
|
+
var isInertHostTag = (node) => {
|
|
323
|
+
const n = node;
|
|
324
|
+
if (n.kind !== "element") return false;
|
|
325
|
+
return INERT_HOST_TAGS.has(String(n.tag).toLowerCase());
|
|
326
|
+
};
|
|
327
|
+
var isComponentNode2 = (node) => {
|
|
328
|
+
const n = node;
|
|
329
|
+
return n.kind === "element" ? n.meta.isComponent : false;
|
|
330
|
+
};
|
|
331
|
+
var hasOnlyInheritedStyle = (node, ctx) => {
|
|
332
|
+
const sm = normalizer.normalizeStyleMap(ctx.computed());
|
|
333
|
+
let sawAny = false;
|
|
334
|
+
for (const block of sm.blocks.values()) {
|
|
398
335
|
for (const decl of block.decls.values()) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return false;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
function gridConflict(outer, inner) {
|
|
407
|
-
const a = normalizer.normalizeStyleMap(outer);
|
|
408
|
-
const b = normalizer.normalizeStyleMap(inner);
|
|
409
|
-
for (const [key, blockA] of a.blocks) {
|
|
410
|
-
const blockB = b.blocks.get(key);
|
|
411
|
-
if (!blockB) continue;
|
|
412
|
-
for (const [prop, declA] of blockA.decls) {
|
|
413
|
-
if (!GRID_CONTAINER_PROPERTIES.has(String(prop))) continue;
|
|
414
|
-
const declB = blockB.decls.get(prop);
|
|
415
|
-
if (declB && declB.value !== declA.value) return true;
|
|
336
|
+
sawAny = true;
|
|
337
|
+
const inherited = decl.inherited || normalizer.inherited.isInherited(decl.property);
|
|
338
|
+
if (!inherited) return false;
|
|
416
339
|
}
|
|
417
340
|
}
|
|
418
|
-
return
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const decls = /* @__PURE__ */ new Map();
|
|
424
|
-
for (const [prop, decl] of block.decls) {
|
|
425
|
-
if (GRID_CONTAINER_PROPERTIES.has(String(prop))) decls.set(prop, decl);
|
|
426
|
-
}
|
|
427
|
-
if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
|
|
428
|
-
}
|
|
429
|
-
return { blocks };
|
|
430
|
-
}
|
|
431
|
-
var isInnerGrid = and(
|
|
432
|
-
isElement("div"),
|
|
433
|
-
computed(DISPLAY_GRID),
|
|
434
|
-
not(targetedByCombinator)
|
|
435
|
-
);
|
|
436
|
-
var nestedGridMerge = definePattern({
|
|
437
|
-
name: "nested-grid-merge",
|
|
438
|
-
category: "flatten/nested-grid-merge",
|
|
341
|
+
return sawAny;
|
|
342
|
+
};
|
|
343
|
+
var inheritedOnlyWrapper = definePattern({
|
|
344
|
+
name: "inherited-only-wrapper",
|
|
345
|
+
category: "flatten/wrapper/inherited-only-wrapper",
|
|
439
346
|
safety: 2,
|
|
440
347
|
doc: {
|
|
441
|
-
title: "
|
|
442
|
-
summary: "A
|
|
443
|
-
before: '<div style="
|
|
444
|
-
after: '<
|
|
445
|
-
safetyRationale: "
|
|
348
|
+
title: "Flatten inherited-only styling wrapper",
|
|
349
|
+
summary: "A paint-free wrapper whose only own declarations are inherited properties (text-align, color, font-*, \u2026) is removed; its inherited style is folded onto the sole child, which keeps the same inherited values for the whole subtree.",
|
|
350
|
+
before: '<div style="text-align:center"><Child/></div>',
|
|
351
|
+
after: '<Child style="text-align:center"/>',
|
|
352
|
+
safetyRationale: "Inherited properties reach descendants purely through inheritance, so folding them onto the child and removing the box is render-identical. The wrapper carries nothing non-inherited, establishes no box/formatting/stacking context, and is guarded by the auto-applied opacity-barrier + selector-safety set."
|
|
446
353
|
},
|
|
447
354
|
match: {
|
|
448
|
-
tag: "div",
|
|
449
|
-
style: { display: "grid" },
|
|
450
355
|
onlyChild: "element",
|
|
451
|
-
paintsNothing: true
|
|
452
|
-
|
|
453
|
-
rewrite: (ctx, rw) => {
|
|
454
|
-
const outer = ctx.node;
|
|
455
|
-
const inner = ctx.onlyElementChild();
|
|
456
|
-
if (!inner) return null;
|
|
457
|
-
if (!isInnerGrid(inner, ctx)) return null;
|
|
458
|
-
const outerStyle = ctx.computed();
|
|
459
|
-
const innerStyle = ctx.computedOf(inner);
|
|
460
|
-
if (!outerMergeSafe2(outerStyle)) return null;
|
|
461
|
-
if (gridConflict(outerStyle, innerStyle)) return null;
|
|
462
|
-
return [
|
|
463
|
-
// 1. Preserve inheritable values (color/font/…) by folding them onto the child first.
|
|
464
|
-
rw.foldInheritedStyles(outer, inner, { conditions: "all" }),
|
|
465
|
-
// 2. Transfer the wrapper's grid-container declarations onto the child (target-wins keeps the
|
|
466
|
-
// child's value for any shared property — identical anyway, we proved non-conflict).
|
|
467
|
-
rw.mergeStyle(inner, null, extractGridStyle(outerStyle), "target-wins"),
|
|
468
|
-
// 3. Remove the wrapper (structural-safe; hoists the child and preserves its IRNodeId).
|
|
469
|
-
rw.unwrap(outer)
|
|
470
|
-
];
|
|
356
|
+
paintsNothing: true,
|
|
357
|
+
where: [isInertHostTag, not(isComponentNode2), hasOnlyInheritedStyle]
|
|
471
358
|
},
|
|
472
|
-
|
|
473
|
-
// establishes a formatting context, so it is a `needs-verification` flatten that the conservative
|
|
474
|
-
// production gate (`'provably-safe'`) REVERTS — every case here is a no-match. Op-level correctness
|
|
475
|
-
// is asserted by the invariant suite over every pattern.
|
|
359
|
+
rewrite: { flattenInto: "child" },
|
|
476
360
|
test: {
|
|
361
|
+
cases: [
|
|
362
|
+
{
|
|
363
|
+
// `text-align:center` is inherited → folded onto the child; the paint-free wrapper is removed.
|
|
364
|
+
before: '<div className="text-center"><p className="bg-red-200">x</p></div>',
|
|
365
|
+
after: '<p className="bg-red-200 text-center">x</p>'
|
|
366
|
+
}
|
|
367
|
+
],
|
|
477
368
|
noMatch: [
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
'<div className="
|
|
481
|
-
// A
|
|
482
|
-
|
|
369
|
+
// `p-4` is a NON-inherited padding: removing the box would drop it, so the flatten-safety gate
|
|
370
|
+
// reverts the unwrap and the wrapper is left unchanged.
|
|
371
|
+
'<div className="p-4"><p className="bg-red-200">x</p></div>',
|
|
372
|
+
// A `<p>` wrapper is NOT an inert host box: its UA default display/margins are not captured in the
|
|
373
|
+
// class-derived computed style, so removing it is not provably layout-neutral → left unchanged.
|
|
374
|
+
'<p className="text-center"><span className="bg-red-200">x</span></p>'
|
|
483
375
|
]
|
|
484
376
|
}
|
|
485
377
|
});
|
|
486
378
|
|
|
487
|
-
// ../patterns/src/library/
|
|
379
|
+
// ../patterns/src/library/wrapper/passthrough-wrapper.pattern.ts
|
|
488
380
|
init_esm_shims();
|
|
489
381
|
function metaOf2(node) {
|
|
490
382
|
const n = node;
|
|
@@ -500,7 +392,7 @@ var establishesContext = (node) => {
|
|
|
500
392
|
return m.establishesBox || m.establishesFormattingContext || m.establishesStackingContext || m.isContainingBlock || m.declaresCustomProperties;
|
|
501
393
|
};
|
|
502
394
|
var hasSpreadAttrs2 = (node) => metaOf2(node)?.hasSpreadAttrs ?? false;
|
|
503
|
-
var
|
|
395
|
+
var isComponentNode3 = (node) => metaOf2(node)?.isComponent ?? false;
|
|
504
396
|
var hasOwnAttrs2 = (node) => {
|
|
505
397
|
const el = elementOf(node);
|
|
506
398
|
if (!el) return false;
|
|
@@ -514,7 +406,7 @@ var targetedByStructuralPseudo3 = (node, ctx) => {
|
|
|
514
406
|
};
|
|
515
407
|
var passthroughWrapper = definePattern({
|
|
516
408
|
name: "passthrough-wrapper",
|
|
517
|
-
category: "flatten/passthrough-wrapper",
|
|
409
|
+
category: "flatten/wrapper/passthrough-wrapper",
|
|
518
410
|
safety: 2,
|
|
519
411
|
doc: {
|
|
520
412
|
title: "Flatten passthrough wrapper",
|
|
@@ -532,7 +424,7 @@ var passthroughWrapper = definePattern({
|
|
|
532
424
|
not(hasOwnAttrs2),
|
|
533
425
|
not(hasDynamicClasses),
|
|
534
426
|
not(hasSpreadAttrs2),
|
|
535
|
-
not(
|
|
427
|
+
not(isComponentNode3),
|
|
536
428
|
not(targetedByStructuralPseudo3)
|
|
537
429
|
]
|
|
538
430
|
},
|
|
@@ -556,69 +448,11 @@ var passthroughWrapper = definePattern({
|
|
|
556
448
|
}
|
|
557
449
|
});
|
|
558
450
|
|
|
559
|
-
// ../patterns/src/library/
|
|
451
|
+
// ../patterns/src/library/wrapper/redundant-inline-wrapper.pattern.ts
|
|
560
452
|
init_esm_shims();
|
|
561
|
-
function
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
const parentId = el.parent;
|
|
565
|
-
if (parentId == null) return false;
|
|
566
|
-
const parent = ctx.doc.nodes.get(parentId);
|
|
567
|
-
if (!parent || parent.kind !== "fragment") return false;
|
|
568
|
-
if (parent.parent == null) return false;
|
|
569
|
-
if (parent.children.length !== 1) return false;
|
|
570
|
-
const m = parent.meta;
|
|
571
|
-
if (m.hasKey || m.hasRef || m.hasEventHandlers || m.hasDynamicChildren || m.hasDangerousHtml || m.hasSpreadAttrs || m.isComponent) {
|
|
572
|
-
return false;
|
|
573
|
-
}
|
|
574
|
-
if (m.targetedByCombinator || m.targetedByStructuralPseudo) return false;
|
|
575
|
-
const fid = parentId;
|
|
576
|
-
if (ctx.selectors.targetedByCombinator(fid) || ctx.selectors.targetedByStructuralPseudo(fid)) {
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
if (ctx.selectors.reparentImpact(fid).size > 0) return false;
|
|
580
|
-
return true;
|
|
581
|
-
}
|
|
582
|
-
var redundantFragment = definePattern({
|
|
583
|
-
name: "redundant-fragment",
|
|
584
|
-
category: "flatten/redundant-fragment",
|
|
585
|
-
safety: 1,
|
|
586
|
-
doc: {
|
|
587
|
-
title: "Flatten redundant single-child fragment",
|
|
588
|
-
summary: "A fragment whose only child is a single node is removed; the child is spliced up into the fragment's slot, preserving its IRNodeId, siblings, attributes and the CSS cascade.",
|
|
589
|
-
before: "<><Child/></>",
|
|
590
|
-
after: "<Child/>",
|
|
591
|
-
safetyRationale: "A fragment paints nothing and renders no box; with exactly one child its removal changes no sibling/structural-pseudo match-set. Keyed fragments and fragments carrying ref/handlers/dynamic-children/raw-html/spread are excluded as opacity barriers."
|
|
592
|
-
},
|
|
593
|
-
match: parentIsRedundantFragment,
|
|
594
|
-
rewrite: (ctx, rw) => {
|
|
595
|
-
const parentId = ctx.node.parent;
|
|
596
|
-
if (parentId == null) return null;
|
|
597
|
-
const fragment = ctx.doc.nodes.get(parentId);
|
|
598
|
-
if (!fragment || fragment.kind !== "fragment") return null;
|
|
599
|
-
return [rw.unwrap(fragment)];
|
|
600
|
-
},
|
|
601
|
-
test: {
|
|
602
|
-
cases: [
|
|
603
|
-
{
|
|
604
|
-
// A fragment renders no box, so unwrapping a single-child fragment is always layout-identical
|
|
605
|
-
// → a provably-safe flatten: the child is spliced up into the fragment's slot.
|
|
606
|
-
before: '<><span className="bg-red-200">Hi</span></>',
|
|
607
|
-
after: '<span className="bg-red-200">Hi</span>'
|
|
608
|
-
}
|
|
609
|
-
],
|
|
610
|
-
noMatch: [
|
|
611
|
-
// Two children ⇒ not a single-child fragment, so the fragment is load-bearing and stays.
|
|
612
|
-
'<><span className="bg-red-200">A</span><span className="bg-green-200">B</span></>'
|
|
613
|
-
]
|
|
614
|
-
}
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
// ../patterns/src/library/flatten/redundant-inline-wrapper.pattern.ts
|
|
618
|
-
init_esm_shims();
|
|
619
|
-
function asEl3(node) {
|
|
620
|
-
const n = node;
|
|
621
|
-
return n.kind === "element" ? n : null;
|
|
453
|
+
function asEl3(node) {
|
|
454
|
+
const n = node;
|
|
455
|
+
return n.kind === "element" ? n : null;
|
|
622
456
|
}
|
|
623
457
|
function metaOf3(node) {
|
|
624
458
|
return asEl3(node)?.meta ?? null;
|
|
@@ -629,7 +463,7 @@ var establishesContext2 = (node) => {
|
|
|
629
463
|
return m.establishesBox || m.establishesFormattingContext || m.establishesStackingContext || m.isContainingBlock || m.declaresCustomProperties;
|
|
630
464
|
};
|
|
631
465
|
var hasSpreadAttrs3 = (node) => metaOf3(node)?.hasSpreadAttrs ?? false;
|
|
632
|
-
var
|
|
466
|
+
var isComponentNode4 = (node) => metaOf3(node)?.isComponent ?? false;
|
|
633
467
|
var hasOwnAttrs3 = (node) => {
|
|
634
468
|
const el = asEl3(node);
|
|
635
469
|
if (!el) return false;
|
|
@@ -654,7 +488,7 @@ var hasNonInlineDisplay = (node, ctx) => {
|
|
|
654
488
|
};
|
|
655
489
|
var redundantInlineWrapper = definePattern({
|
|
656
490
|
name: "redundant-inline-wrapper",
|
|
657
|
-
category: "flatten/redundant-inline-wrapper",
|
|
491
|
+
category: "flatten/wrapper/redundant-inline-wrapper",
|
|
658
492
|
safety: 2,
|
|
659
493
|
doc: {
|
|
660
494
|
title: "Flatten redundant inline wrapper",
|
|
@@ -673,7 +507,7 @@ var redundantInlineWrapper = definePattern({
|
|
|
673
507
|
not(hasOwnAttrs3),
|
|
674
508
|
not(hasDynamicClasses),
|
|
675
509
|
not(hasSpreadAttrs3),
|
|
676
|
-
not(
|
|
510
|
+
not(isComponentNode4),
|
|
677
511
|
not(targetedByStructuralPseudo4)
|
|
678
512
|
]
|
|
679
513
|
},
|
|
@@ -698,1079 +532,17 @@ var redundantInlineWrapper = definePattern({
|
|
|
698
532
|
}
|
|
699
533
|
});
|
|
700
534
|
|
|
701
|
-
// ../patterns/src/library/compress/border-radius-shorthand.pattern.ts
|
|
702
|
-
init_esm_shims();
|
|
703
|
-
var CORNERS = [
|
|
704
|
-
"border-top-left-radius",
|
|
705
|
-
"border-top-right-radius",
|
|
706
|
-
"border-bottom-right-radius",
|
|
707
|
-
"border-bottom-left-radius"
|
|
708
|
-
];
|
|
709
|
-
var CORNER_SET = new Set(CORNERS);
|
|
710
|
-
var BASE_KEY = conditionKey(BASE_CONDITION);
|
|
711
|
-
var RADIUS = "border-radius";
|
|
712
|
-
var NON_COLLAPSIBLE_VALUES = /* @__PURE__ */ new Set([
|
|
713
|
-
"initial",
|
|
714
|
-
"inherit",
|
|
715
|
-
"unset",
|
|
716
|
-
"revert",
|
|
717
|
-
"revert-layer"
|
|
718
|
-
]);
|
|
719
|
-
function analyzeRadius(sm) {
|
|
720
|
-
const block = sm.blocks.get(BASE_KEY);
|
|
721
|
-
if (!block) return null;
|
|
722
|
-
const corners = [];
|
|
723
|
-
for (const corner of CORNERS) {
|
|
724
|
-
const decl = block.decls.get(corner);
|
|
725
|
-
if (!decl) return null;
|
|
726
|
-
corners.push(decl);
|
|
727
|
-
}
|
|
728
|
-
const important = corners[0].important;
|
|
729
|
-
if (!corners.every((d) => d.important === important)) return null;
|
|
730
|
-
const value = String(corners[0].value);
|
|
731
|
-
if (NON_COLLAPSIBLE_VALUES.has(value)) return null;
|
|
732
|
-
if (!corners.every((d) => String(d.value) === value)) return null;
|
|
733
|
-
const relative = corners.some((d) => d.relativeToParent);
|
|
734
|
-
return { value, important, relative };
|
|
735
|
-
}
|
|
736
|
-
function withFoldedRadius(sm, fold) {
|
|
737
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
738
|
-
for (const [key, block] of sm.blocks) {
|
|
739
|
-
if (key !== BASE_KEY) {
|
|
740
|
-
blocks.set(key, block);
|
|
741
|
-
continue;
|
|
742
|
-
}
|
|
743
|
-
const decls = /* @__PURE__ */ new Map();
|
|
744
|
-
for (const [prop, decl] of block.decls) {
|
|
745
|
-
if (CORNER_SET.has(String(prop))) continue;
|
|
746
|
-
decls.set(prop, decl);
|
|
747
|
-
}
|
|
748
|
-
const shorthand = {
|
|
749
|
-
property: RADIUS,
|
|
750
|
-
value: fold.value,
|
|
751
|
-
important: fold.important,
|
|
752
|
-
relativeToParent: fold.relative,
|
|
753
|
-
inherited: false
|
|
754
|
-
// border-radius is never inherited
|
|
755
|
-
};
|
|
756
|
-
decls.set(shorthand.property, shorthand);
|
|
757
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
758
|
-
}
|
|
759
|
-
return { blocks };
|
|
760
|
-
}
|
|
761
|
-
var borderRadiusShorthand = definePattern({
|
|
762
|
-
name: "border-radius-shorthand",
|
|
763
|
-
category: "compress/border-radius-shorthand",
|
|
764
|
-
safety: 1,
|
|
765
|
-
doc: {
|
|
766
|
-
title: "Collapse equal corner radii into border-radius",
|
|
767
|
-
summary: "An element whose four corner radii (border-*-radius longhands) are all equal is rewritten to the single Tailwind rounded-* utility (border-radius === the four equal corners).",
|
|
768
|
-
before: '<div class="rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-lg"/>',
|
|
769
|
-
after: '<div class="rounded-lg"/>',
|
|
770
|
-
safetyRationale: "`border-radius` is value-identical to four equal corner radii \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
771
|
-
},
|
|
772
|
-
rewrite: {
|
|
773
|
-
rewriteClasses(computed2) {
|
|
774
|
-
const fold = analyzeRadius(computed2);
|
|
775
|
-
return fold ? withFoldedRadius(computed2, fold) : null;
|
|
776
|
-
}
|
|
777
|
-
},
|
|
778
|
-
test: {
|
|
779
|
-
cases: [
|
|
780
|
-
{
|
|
781
|
-
// The four equal corner longhands collapse to a `border-radius` decl at the IR level; the
|
|
782
|
-
// minimizing reverse-emit then picks the single shortest utility (`rounded-lg`) that reproduces
|
|
783
|
-
// it, replacing the four `rounded-{tl,tr,br,bl}-lg` tokens. `bg-red-200` is preserved.
|
|
784
|
-
before: '<div className="rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-lg bg-red-200">box</div>',
|
|
785
|
-
after: '<div className="bg-red-200 rounded-lg">box</div>'
|
|
786
|
-
}
|
|
787
|
-
],
|
|
788
|
-
// Corners differ (top corners vs bottom corners) → no all-equal collapse.
|
|
789
|
-
noMatch: ['<div className="rounded-t-lg rounded-b-sm bg-red-200">box</div>']
|
|
790
|
-
}
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
// ../patterns/src/library/compress/border-shorthand.pattern.ts
|
|
794
|
-
init_esm_shims();
|
|
795
|
-
var WIDTH_SIDES = [
|
|
796
|
-
"border-top-width",
|
|
797
|
-
"border-right-width",
|
|
798
|
-
"border-bottom-width",
|
|
799
|
-
"border-left-width"
|
|
800
|
-
];
|
|
801
|
-
var WIDTH_SIDE_SET = new Set(WIDTH_SIDES);
|
|
802
|
-
var BASE_KEY2 = conditionKey(BASE_CONDITION);
|
|
803
|
-
var BORDER_WIDTH = "border-width";
|
|
804
|
-
function analyzeWidth(sm) {
|
|
805
|
-
const block = sm.blocks.get(BASE_KEY2);
|
|
806
|
-
if (!block) return null;
|
|
807
|
-
const sides = [];
|
|
808
|
-
for (const side of WIDTH_SIDES) {
|
|
809
|
-
const decl = block.decls.get(side);
|
|
810
|
-
if (!decl) return null;
|
|
811
|
-
sides.push(decl);
|
|
812
|
-
}
|
|
813
|
-
const [top, right, bottom, left] = sides;
|
|
814
|
-
if (!(top.important === right.important && right.important === bottom.important && bottom.important === left.important)) {
|
|
815
|
-
return null;
|
|
816
|
-
}
|
|
817
|
-
const tv = String(top.value);
|
|
818
|
-
const rv = String(right.value);
|
|
819
|
-
const bv = String(bottom.value);
|
|
820
|
-
const lv = String(left.value);
|
|
821
|
-
if (tv !== bv || lv !== rv) return null;
|
|
822
|
-
const value = tv === lv ? tv : `${tv} ${lv}`;
|
|
823
|
-
const relative = sides.some((d) => d.relativeToParent);
|
|
824
|
-
return { value, important: top.important, relative };
|
|
825
|
-
}
|
|
826
|
-
function withFoldedWidth(sm, fold) {
|
|
827
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
828
|
-
for (const [key, block] of sm.blocks) {
|
|
829
|
-
if (key !== BASE_KEY2) {
|
|
830
|
-
blocks.set(key, block);
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
const decls = /* @__PURE__ */ new Map();
|
|
834
|
-
for (const [prop, decl] of block.decls) {
|
|
835
|
-
if (WIDTH_SIDE_SET.has(String(prop))) continue;
|
|
836
|
-
decls.set(prop, decl);
|
|
837
|
-
}
|
|
838
|
-
const shorthand = {
|
|
839
|
-
property: BORDER_WIDTH,
|
|
840
|
-
value: fold.value,
|
|
841
|
-
important: fold.important,
|
|
842
|
-
relativeToParent: fold.relative,
|
|
843
|
-
inherited: false
|
|
844
|
-
// border-width is never inherited
|
|
845
|
-
};
|
|
846
|
-
decls.set(shorthand.property, shorthand);
|
|
847
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
848
|
-
}
|
|
849
|
-
return { blocks };
|
|
850
|
-
}
|
|
851
|
-
var borderShorthand = definePattern({
|
|
852
|
-
name: "border-shorthand",
|
|
853
|
-
category: "compress/border-shorthand",
|
|
854
|
-
safety: 1,
|
|
855
|
-
doc: {
|
|
856
|
-
title: "Collapse border-width longhands to shorthand",
|
|
857
|
-
summary: "Equal border width on all four sides (or matching x/y pairs) expressed as separate longhand declarations is collapsed to the shortest equivalent border-width shorthand (border-* / border-x-* border-y-*).",
|
|
858
|
-
before: '<div class="border-t-2 border-r-2 border-b-2 border-l-2"/>',
|
|
859
|
-
after: '<div class="border-2"/>',
|
|
860
|
-
safetyRationale: "A value-preserving re-serialization of the same computed border widths (style/color longhands untouched) \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
861
|
-
},
|
|
862
|
-
rewrite: {
|
|
863
|
-
rewriteClasses(computed2) {
|
|
864
|
-
const fold = analyzeWidth(computed2);
|
|
865
|
-
return fold ? withFoldedWidth(computed2, fold) : null;
|
|
866
|
-
}
|
|
867
|
-
},
|
|
868
|
-
test: {
|
|
869
|
-
cases: [
|
|
870
|
-
{
|
|
871
|
-
// The four equal width longhands collapse to a `border-width` shorthand at the IR level, and the
|
|
872
|
-
// minimizing reverse-emit picks the single shortest utility (`border-2`) that reproduces it,
|
|
873
|
-
// replacing the four `border-{t,r,b,l}-2` tokens. `bg-red-200` is preserved.
|
|
874
|
-
before: '<div className="border-t-2 border-r-2 border-b-2 border-l-2 bg-red-200">box</div>',
|
|
875
|
-
after: '<div className="bg-red-200 border-2">box</div>'
|
|
876
|
-
}
|
|
877
|
-
],
|
|
878
|
-
// Asymmetric widths (top != bottom) cannot fold into a shorthand.
|
|
879
|
-
noMatch: ['<div className="border-t-2 border-r-4 border-b-8 border-l-4 bg-red-200">box</div>']
|
|
880
|
-
}
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
// ../patterns/src/library/compress/dedupe-classes.pattern.ts
|
|
884
|
-
init_esm_shims();
|
|
885
|
-
function findRedundantClasses(computed2) {
|
|
886
|
-
const winners = /* @__PURE__ */ new Set();
|
|
887
|
-
const shadowed = /* @__PURE__ */ new Set();
|
|
888
|
-
for (const block of computed2.blocks.values()) {
|
|
889
|
-
for (const decl of block.decls.values()) {
|
|
890
|
-
if (decl.origin && decl.origin.kind === "class") winners.add(decl.origin.className);
|
|
891
|
-
for (const o of decl.shadowed ?? []) {
|
|
892
|
-
if (o.kind === "class") shadowed.add(o.className);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
return { winners, shadowed };
|
|
897
|
-
}
|
|
898
|
-
var dedupeClasses = definePattern({
|
|
899
|
-
name: "dedupe-classes",
|
|
900
|
-
category: "compress/dedupe-classes",
|
|
901
|
-
safety: 1,
|
|
902
|
-
doc: {
|
|
903
|
-
title: "Dedupe fully-overridden class tokens",
|
|
904
|
-
summary: "Drops class tokens whose every declaration is overridden by a later token resolving to the same property; the surviving token set produces a byte-for-byte identical computed style.",
|
|
905
|
-
before: '<p class="text-sm text-lg" />',
|
|
906
|
-
after: '<p class="text-lg" />',
|
|
907
|
-
safetyRationale: "A fully-overridden token contributes nothing to the computed style in any condition, so removing it changes no pixels \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
908
|
-
},
|
|
909
|
-
rewrite: {
|
|
910
|
-
dropClasses(computed2, ctx) {
|
|
911
|
-
const { winners, shadowed } = findRedundantClasses(computed2);
|
|
912
|
-
const drop = /* @__PURE__ */ new Set();
|
|
913
|
-
for (const cls of shadowed) {
|
|
914
|
-
if (winners.has(cls)) continue;
|
|
915
|
-
if (!ctx.resolver.selectorUsage(cls).droppable) continue;
|
|
916
|
-
drop.add(cls);
|
|
917
|
-
}
|
|
918
|
-
return drop;
|
|
919
|
-
}
|
|
920
|
-
},
|
|
921
|
-
test: {
|
|
922
|
-
cases: [
|
|
923
|
-
{
|
|
924
|
-
// `text-sm` is fully overridden by `text-lg` (both set font-size + line-height). The resolver
|
|
925
|
-
// records that shadowing in provenance and reports the Tailwind utility as droppable, so the
|
|
926
|
-
// pattern drops `text-sm`; the reverse-emit then re-derives the minimal set (`text-lg`).
|
|
927
|
-
before: '<p className="text-sm text-lg">Hi</p>',
|
|
928
|
-
after: '<p className="text-lg">Hi</p>'
|
|
929
|
-
}
|
|
930
|
-
],
|
|
931
|
-
// Both tokens win a distinct property (no full override) → nothing to dedupe.
|
|
932
|
-
noMatch: ['<p className="text-lg font-bold">Hi</p>']
|
|
933
|
-
}
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
// ../patterns/src/library/compress/gap-shorthand.pattern.ts
|
|
937
|
-
init_esm_shims();
|
|
938
|
-
var ROW_GAP = "row-gap";
|
|
939
|
-
var COLUMN_GAP = "column-gap";
|
|
940
|
-
var GAP = "gap";
|
|
941
|
-
var BASE_KEY3 = conditionKey(BASE_CONDITION);
|
|
942
|
-
function withGapShorthand(sm, gapDecl) {
|
|
943
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
944
|
-
for (const [key, block] of sm.blocks) {
|
|
945
|
-
if (key !== BASE_KEY3) {
|
|
946
|
-
blocks.set(key, block);
|
|
947
|
-
continue;
|
|
948
|
-
}
|
|
949
|
-
const decls = /* @__PURE__ */ new Map();
|
|
950
|
-
for (const [prop, decl] of block.decls) {
|
|
951
|
-
if (prop === ROW_GAP || prop === COLUMN_GAP) continue;
|
|
952
|
-
decls.set(prop, decl);
|
|
953
|
-
}
|
|
954
|
-
decls.set(gapDecl.property, gapDecl);
|
|
955
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
956
|
-
}
|
|
957
|
-
return { blocks };
|
|
958
|
-
}
|
|
959
|
-
var gapShorthand = definePattern({
|
|
960
|
-
name: "gap-shorthand",
|
|
961
|
-
category: "compress/gap-shorthand",
|
|
962
|
-
safety: 1,
|
|
963
|
-
doc: {
|
|
964
|
-
title: "Collapse equal row/column gap into the `gap` shorthand",
|
|
965
|
-
summary: "An element whose computed row-gap and column-gap are equal has the two axis longhands collapsed into a single-value `gap` shorthand (Tailwind gap-x-* gap-y-* \u2192 gap-*).",
|
|
966
|
-
before: '<div style="row-gap:16px;column-gap:16px"/>',
|
|
967
|
-
after: '<div style="gap:16px"/>',
|
|
968
|
-
safetyRationale: "A single-value `gap` is value-identical to an equal row-gap+column-gap pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
969
|
-
},
|
|
970
|
-
rewrite: {
|
|
971
|
-
rewriteClasses(computed2) {
|
|
972
|
-
const base = computed2.blocks.get(BASE_KEY3);
|
|
973
|
-
if (!base) return null;
|
|
974
|
-
const rowGap = base.decls.get(ROW_GAP);
|
|
975
|
-
const colGap = base.decls.get(COLUMN_GAP);
|
|
976
|
-
if (!rowGap || !colGap) return null;
|
|
977
|
-
if (rowGap.important !== colGap.important) return null;
|
|
978
|
-
if (rowGap.value !== colGap.value) return null;
|
|
979
|
-
const gapDecl = {
|
|
980
|
-
property: GAP,
|
|
981
|
-
value: rowGap.value,
|
|
982
|
-
important: rowGap.important,
|
|
983
|
-
relativeToParent: rowGap.relativeToParent || colGap.relativeToParent,
|
|
984
|
-
inherited: false
|
|
985
|
-
// gap is not an inherited property
|
|
986
|
-
};
|
|
987
|
-
return withGapShorthand(computed2, gapDecl);
|
|
988
|
-
}
|
|
989
|
-
},
|
|
990
|
-
test: {
|
|
991
|
-
cases: [
|
|
992
|
-
{
|
|
993
|
-
// Equal row/column gap collapse to a `gap` decl at the IR level; the minimizing reverse-emit
|
|
994
|
-
// re-expands `gap` to row-gap+column-gap and picks the single utility covering both (`gap-4`),
|
|
995
|
-
// replacing the `gap-x-4`+`gap-y-4` pair. `bg-red-200` is preserved.
|
|
996
|
-
before: '<div className="gap-x-4 gap-y-4 bg-red-200">box</div>',
|
|
997
|
-
after: '<div className="bg-red-200 gap-4">box</div>'
|
|
998
|
-
}
|
|
999
|
-
],
|
|
1000
|
-
// Unequal axes (row-gap != column-gap) have no single-value `gap` equivalent → not collapsed.
|
|
1001
|
-
noMatch: ['<div className="gap-x-2 gap-y-4 bg-red-200">box</div>']
|
|
1002
|
-
}
|
|
1003
|
-
});
|
|
1004
|
-
|
|
1005
|
-
// ../patterns/src/library/compress/inset-shorthand.pattern.ts
|
|
1006
|
-
init_esm_shims();
|
|
1007
|
-
var TOP = "top";
|
|
1008
|
-
var RIGHT = "right";
|
|
1009
|
-
var BOTTOM = "bottom";
|
|
1010
|
-
var LEFT = "left";
|
|
1011
|
-
var INSET = "inset";
|
|
1012
|
-
var INSET_BLOCK = "inset-block";
|
|
1013
|
-
var INSET_INLINE = "inset-inline";
|
|
1014
|
-
function sameSide(a, b) {
|
|
1015
|
-
return a !== void 0 && b !== void 0 && a.value === b.value && a.important === b.important;
|
|
1016
|
-
}
|
|
1017
|
-
function asProperty(src, property) {
|
|
1018
|
-
return { ...src, property, inherited: normalizer.inherited.isInherited(property) };
|
|
1019
|
-
}
|
|
1020
|
-
function withBaseDecls(src, baseDecls) {
|
|
1021
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1022
|
-
for (const [key, block] of src.blocks) {
|
|
1023
|
-
const decls = key === BASE_CONDITION_KEY ? baseDecls : new Map(block.decls);
|
|
1024
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1025
|
-
}
|
|
1026
|
-
return { blocks };
|
|
1027
|
-
}
|
|
1028
|
-
var insetShorthand = definePattern({
|
|
1029
|
-
name: "inset-shorthand",
|
|
1030
|
-
category: "compress/inset-shorthand",
|
|
1031
|
-
safety: 2,
|
|
1032
|
-
doc: {
|
|
1033
|
-
title: "Compress inset longhands into a shorthand",
|
|
1034
|
-
summary: "top/right/bottom/left set to one value collapse to `inset`; a matching top/bottom or left/right pair collapses to `inset-block` / `inset-inline` (Tailwind inset-y / inset-x).",
|
|
1035
|
-
before: '<div style="top:10px;right:10px;bottom:10px;left:10px"/>',
|
|
1036
|
-
after: '<div style="inset:10px"/>',
|
|
1037
|
-
safetyRationale: "Meaning-preserving inset shorthand compaction \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1038
|
-
},
|
|
1039
|
-
rewrite: {
|
|
1040
|
-
rewriteClasses(computed2) {
|
|
1041
|
-
const base = computed2.blocks.get(BASE_CONDITION_KEY);
|
|
1042
|
-
if (!base) return null;
|
|
1043
|
-
const top = base.decls.get(TOP);
|
|
1044
|
-
const right = base.decls.get(RIGHT);
|
|
1045
|
-
const bottom = base.decls.get(BOTTOM);
|
|
1046
|
-
const left = base.decls.get(LEFT);
|
|
1047
|
-
const next = new Map(base.decls);
|
|
1048
|
-
if (top && sameSide(top, right) && sameSide(top, bottom) && sameSide(top, left)) {
|
|
1049
|
-
next.delete(TOP);
|
|
1050
|
-
next.delete(RIGHT);
|
|
1051
|
-
next.delete(BOTTOM);
|
|
1052
|
-
next.delete(LEFT);
|
|
1053
|
-
next.set(INSET, asProperty(top, INSET));
|
|
1054
|
-
} else {
|
|
1055
|
-
let collapsed = false;
|
|
1056
|
-
if (sameSide(top, bottom)) {
|
|
1057
|
-
next.delete(TOP);
|
|
1058
|
-
next.delete(BOTTOM);
|
|
1059
|
-
next.set(INSET_BLOCK, asProperty(top, INSET_BLOCK));
|
|
1060
|
-
collapsed = true;
|
|
1061
|
-
}
|
|
1062
|
-
if (sameSide(left, right)) {
|
|
1063
|
-
next.delete(LEFT);
|
|
1064
|
-
next.delete(RIGHT);
|
|
1065
|
-
next.set(INSET_INLINE, asProperty(left, INSET_INLINE));
|
|
1066
|
-
collapsed = true;
|
|
1067
|
-
}
|
|
1068
|
-
if (!collapsed) return null;
|
|
1069
|
-
}
|
|
1070
|
-
return withBaseDecls(computed2, next);
|
|
1071
|
-
}
|
|
1072
|
-
},
|
|
1073
|
-
test: {
|
|
1074
|
-
cases: [
|
|
1075
|
-
{
|
|
1076
|
-
// The four equal inset longhands collapse to an `inset` shorthand at the IR level; the
|
|
1077
|
-
// minimizing reverse-emit expands it back to top/right/bottom/left and picks the single utility
|
|
1078
|
-
// covering all four (`inset-0`), replacing the four physical-side tokens. `bg-red-200` survives.
|
|
1079
|
-
before: '<div className="top-0 right-0 bottom-0 left-0 bg-red-200">box</div>',
|
|
1080
|
-
after: '<div className="bg-red-200 inset-0">box</div>'
|
|
1081
|
-
}
|
|
1082
|
-
],
|
|
1083
|
-
// No matching inset pair (all four distinct) → nothing collapses.
|
|
1084
|
-
noMatch: ['<div className="top-0 right-1 bottom-2 left-3 bg-red-200">box</div>']
|
|
1085
|
-
}
|
|
1086
|
-
});
|
|
1087
|
-
|
|
1088
|
-
// ../patterns/src/library/compress/margin-shorthand.pattern.ts
|
|
1089
|
-
init_esm_shims();
|
|
1090
|
-
var MARGIN_SIDES = [
|
|
1091
|
-
"margin-top",
|
|
1092
|
-
"margin-right",
|
|
1093
|
-
"margin-bottom",
|
|
1094
|
-
"margin-left"
|
|
1095
|
-
];
|
|
1096
|
-
var MARGIN_SIDE_SET = new Set(MARGIN_SIDES);
|
|
1097
|
-
var BASE_KEY4 = conditionKey(BASE_CONDITION);
|
|
1098
|
-
function collapseMarginValue(top, right, bottom, left) {
|
|
1099
|
-
if (right === left) {
|
|
1100
|
-
if (top === bottom) {
|
|
1101
|
-
return top === right ? top : `${top} ${right}`;
|
|
1102
|
-
}
|
|
1103
|
-
return `${top} ${right} ${bottom}`;
|
|
1104
|
-
}
|
|
1105
|
-
return `${top} ${right} ${bottom} ${left}`;
|
|
1106
|
-
}
|
|
1107
|
-
function withFoldedMargin(sm, marginDecl) {
|
|
1108
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1109
|
-
for (const [key, block] of sm.blocks) {
|
|
1110
|
-
if (key !== BASE_KEY4) {
|
|
1111
|
-
blocks.set(key, block);
|
|
1112
|
-
continue;
|
|
1113
|
-
}
|
|
1114
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1115
|
-
for (const [prop, decl] of block.decls) {
|
|
1116
|
-
if (!MARGIN_SIDE_SET.has(String(prop))) decls.set(prop, decl);
|
|
1117
|
-
}
|
|
1118
|
-
decls.set(marginDecl.property, marginDecl);
|
|
1119
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1120
|
-
}
|
|
1121
|
-
return { blocks };
|
|
1122
|
-
}
|
|
1123
|
-
var marginShorthand = definePattern({
|
|
1124
|
-
name: "margin-shorthand",
|
|
1125
|
-
category: "compress/margin-shorthand",
|
|
1126
|
-
safety: 2,
|
|
1127
|
-
doc: {
|
|
1128
|
-
title: "Compress margin longhands into the `margin` shorthand",
|
|
1129
|
-
summary: "An element with margin-top/right/bottom/left all set has them collapsed into the shortest legal `margin` shorthand (the m / mx / my forms); meaning is preserved, declaration count drops.",
|
|
1130
|
-
before: '<div style="margin-top:8px;margin-right:8px;margin-bottom:8px;margin-left:8px"/>',
|
|
1131
|
-
after: '<div style="margin:8px"/>',
|
|
1132
|
-
safetyRationale: "A pure representation change of the same computed margins (no pixels move) \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1133
|
-
},
|
|
1134
|
-
rewrite: {
|
|
1135
|
-
rewriteClasses(computed2) {
|
|
1136
|
-
const base = computed2.blocks.get(BASE_KEY4);
|
|
1137
|
-
if (!base) return null;
|
|
1138
|
-
const sides = MARGIN_SIDES.map((p) => base.decls.get(p));
|
|
1139
|
-
if (sides.some((d) => d === void 0)) return null;
|
|
1140
|
-
const [mt, mr, mb, ml] = sides;
|
|
1141
|
-
if (mt.important || mr.important || mb.important || ml.important) return null;
|
|
1142
|
-
const value = collapseMarginValue(
|
|
1143
|
-
String(mt.value),
|
|
1144
|
-
String(mr.value),
|
|
1145
|
-
String(mb.value),
|
|
1146
|
-
String(ml.value)
|
|
1147
|
-
);
|
|
1148
|
-
const marginDecl = {
|
|
1149
|
-
property: "margin",
|
|
1150
|
-
value,
|
|
1151
|
-
important: false,
|
|
1152
|
-
relativeToParent: mt.relativeToParent || mr.relativeToParent || mb.relativeToParent || ml.relativeToParent,
|
|
1153
|
-
inherited: false
|
|
1154
|
-
// margin is not an inherited property
|
|
1155
|
-
};
|
|
1156
|
-
return withFoldedMargin(computed2, marginDecl);
|
|
1157
|
-
}
|
|
1158
|
-
},
|
|
1159
|
-
test: {
|
|
1160
|
-
cases: [
|
|
1161
|
-
{
|
|
1162
|
-
// The four equal margin longhands collapse to a `margin` shorthand at the IR level, and the
|
|
1163
|
-
// minimizing reverse-emit picks the single shortest utility (`m-2`) reproducing it, replacing
|
|
1164
|
-
// the four `m{t,r,b,l}-2` tokens. `bg-red-200` is preserved.
|
|
1165
|
-
before: '<div className="mt-2 mr-2 mb-2 ml-2 bg-red-200">box</div>',
|
|
1166
|
-
after: '<div className="bg-red-200 m-2">box</div>'
|
|
1167
|
-
}
|
|
1168
|
-
],
|
|
1169
|
-
// Only two margin sides set → the four-longhand `margin` collapse does not apply.
|
|
1170
|
-
noMatch: ['<div className="mt-2 mb-2 bg-red-200">box</div>']
|
|
1171
|
-
}
|
|
1172
|
-
});
|
|
1173
|
-
|
|
1174
|
-
// ../patterns/src/library/compress/overflow-shorthand.pattern.ts
|
|
1175
|
-
init_esm_shims();
|
|
1176
|
-
var OVERFLOW_X = "overflow-x";
|
|
1177
|
-
var OVERFLOW_Y = "overflow-y";
|
|
1178
|
-
var OVERFLOW = "overflow";
|
|
1179
|
-
var BASE_KEY5 = conditionKey(BASE_CONDITION);
|
|
1180
|
-
function withOverflowShorthand(sm, overflowDecl) {
|
|
1181
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1182
|
-
for (const [key, block] of sm.blocks) {
|
|
1183
|
-
if (key !== BASE_KEY5) {
|
|
1184
|
-
blocks.set(key, block);
|
|
1185
|
-
continue;
|
|
1186
|
-
}
|
|
1187
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1188
|
-
for (const [prop, decl] of block.decls) {
|
|
1189
|
-
if (prop === OVERFLOW_X || prop === OVERFLOW_Y) continue;
|
|
1190
|
-
decls.set(prop, decl);
|
|
1191
|
-
}
|
|
1192
|
-
decls.set(overflowDecl.property, overflowDecl);
|
|
1193
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1194
|
-
}
|
|
1195
|
-
return { blocks };
|
|
1196
|
-
}
|
|
1197
|
-
var overflowShorthand = definePattern({
|
|
1198
|
-
name: "overflow-shorthand",
|
|
1199
|
-
category: "compress/overflow-shorthand",
|
|
1200
|
-
safety: 1,
|
|
1201
|
-
doc: {
|
|
1202
|
-
title: "Collapse equal overflow axes into the `overflow` shorthand",
|
|
1203
|
-
summary: "An element whose computed overflow-x and overflow-y are equal has the two axis longhands collapsed into a single `overflow` shorthand (Tailwind overflow-x-* overflow-y-* \u2192 overflow-*).",
|
|
1204
|
-
before: '<div style="overflow-x:auto;overflow-y:auto"/>',
|
|
1205
|
-
after: '<div style="overflow:auto"/>',
|
|
1206
|
-
safetyRationale: "A single-keyword `overflow` is value-identical to equal overflow-x+overflow-y \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1207
|
-
},
|
|
1208
|
-
rewrite: {
|
|
1209
|
-
rewriteClasses(computed2) {
|
|
1210
|
-
const base = computed2.blocks.get(BASE_KEY5);
|
|
1211
|
-
if (!base) return null;
|
|
1212
|
-
const overflowX = base.decls.get(OVERFLOW_X);
|
|
1213
|
-
const overflowY = base.decls.get(OVERFLOW_Y);
|
|
1214
|
-
if (!overflowX || !overflowY) return null;
|
|
1215
|
-
if (overflowX.important !== overflowY.important) return null;
|
|
1216
|
-
if (overflowX.value !== overflowY.value) return null;
|
|
1217
|
-
const overflowDecl = {
|
|
1218
|
-
property: OVERFLOW,
|
|
1219
|
-
value: overflowX.value,
|
|
1220
|
-
important: overflowX.important,
|
|
1221
|
-
relativeToParent: overflowX.relativeToParent || overflowY.relativeToParent,
|
|
1222
|
-
inherited: false
|
|
1223
|
-
// overflow is not an inherited property
|
|
1224
|
-
};
|
|
1225
|
-
return withOverflowShorthand(computed2, overflowDecl);
|
|
1226
|
-
}
|
|
1227
|
-
},
|
|
1228
|
-
test: {
|
|
1229
|
-
cases: [
|
|
1230
|
-
{
|
|
1231
|
-
// Equal overflow axes collapse to an `overflow` decl at the IR level; the minimizing
|
|
1232
|
-
// reverse-emit picks the single utility covering both (`overflow-auto`), replacing the
|
|
1233
|
-
// `overflow-x-auto`+`overflow-y-auto` pair. `bg-red-200` is preserved.
|
|
1234
|
-
before: '<div className="overflow-x-auto overflow-y-auto bg-red-200">box</div>',
|
|
1235
|
-
after: '<div className="bg-red-200 overflow-auto">box</div>'
|
|
1236
|
-
}
|
|
1237
|
-
],
|
|
1238
|
-
// Mismatched axes (overflow-x != overflow-y) have no single-keyword equivalent → not collapsed.
|
|
1239
|
-
noMatch: ['<div className="overflow-x-auto overflow-y-hidden bg-red-200">box</div>']
|
|
1240
|
-
}
|
|
1241
|
-
});
|
|
1242
|
-
|
|
1243
|
-
// ../patterns/src/library/compress/overscroll-behavior-shorthand.pattern.ts
|
|
1244
|
-
init_esm_shims();
|
|
1245
|
-
var OVERSCROLL_X = "overscroll-behavior-x";
|
|
1246
|
-
var OVERSCROLL_Y = "overscroll-behavior-y";
|
|
1247
|
-
var OVERSCROLL = "overscroll-behavior";
|
|
1248
|
-
var BASE_KEY6 = conditionKey(BASE_CONDITION);
|
|
1249
|
-
var NON_COLLAPSIBLE_VALUES2 = /* @__PURE__ */ new Set([
|
|
1250
|
-
"initial",
|
|
1251
|
-
"inherit",
|
|
1252
|
-
"unset",
|
|
1253
|
-
"revert",
|
|
1254
|
-
"revert-layer"
|
|
1255
|
-
]);
|
|
1256
|
-
function withOverscrollShorthand(sm, shorthand) {
|
|
1257
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1258
|
-
for (const [key, block] of sm.blocks) {
|
|
1259
|
-
if (key !== BASE_KEY6) {
|
|
1260
|
-
blocks.set(key, block);
|
|
1261
|
-
continue;
|
|
1262
|
-
}
|
|
1263
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1264
|
-
for (const [prop, decl] of block.decls) {
|
|
1265
|
-
if (prop === OVERSCROLL_X || prop === OVERSCROLL_Y) continue;
|
|
1266
|
-
decls.set(prop, decl);
|
|
1267
|
-
}
|
|
1268
|
-
decls.set(shorthand.property, shorthand);
|
|
1269
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1270
|
-
}
|
|
1271
|
-
return { blocks };
|
|
1272
|
-
}
|
|
1273
|
-
var overscrollBehaviorShorthand = definePattern({
|
|
1274
|
-
name: "overscroll-behavior-shorthand",
|
|
1275
|
-
category: "compress/overscroll-behavior-shorthand",
|
|
1276
|
-
safety: 1,
|
|
1277
|
-
doc: {
|
|
1278
|
-
title: "Collapse equal overscroll-behavior axes into overscroll-behavior",
|
|
1279
|
-
summary: "An element whose computed overscroll-behavior-x and overscroll-behavior-y are equal has the two axis longhands collapsed into a single `overscroll-behavior` shorthand (Tailwind overscroll-x-* overscroll-y-* \u2192 overscroll-*).",
|
|
1280
|
-
before: '<div style="overscroll-behavior-x:contain;overscroll-behavior-y:contain"/>',
|
|
1281
|
-
after: '<div class="overscroll-contain"/>',
|
|
1282
|
-
safetyRationale: "`overscroll-behavior` is value-identical to an equal x+y axis pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1283
|
-
},
|
|
1284
|
-
rewrite: {
|
|
1285
|
-
rewriteClasses(computed2) {
|
|
1286
|
-
const base = computed2.blocks.get(BASE_KEY6);
|
|
1287
|
-
if (!base) return null;
|
|
1288
|
-
const x = base.decls.get(OVERSCROLL_X);
|
|
1289
|
-
const y = base.decls.get(OVERSCROLL_Y);
|
|
1290
|
-
if (!x || !y) return null;
|
|
1291
|
-
if (x.important !== y.important) return null;
|
|
1292
|
-
const value = String(x.value);
|
|
1293
|
-
if (NON_COLLAPSIBLE_VALUES2.has(value)) return null;
|
|
1294
|
-
if (value !== String(y.value)) return null;
|
|
1295
|
-
const shorthand = {
|
|
1296
|
-
property: OVERSCROLL,
|
|
1297
|
-
value: x.value,
|
|
1298
|
-
important: x.important,
|
|
1299
|
-
relativeToParent: x.relativeToParent || y.relativeToParent,
|
|
1300
|
-
inherited: false
|
|
1301
|
-
// overscroll-behavior is not an inherited property
|
|
1302
|
-
};
|
|
1303
|
-
return withOverscrollShorthand(computed2, shorthand);
|
|
1304
|
-
}
|
|
1305
|
-
},
|
|
1306
|
-
test: {
|
|
1307
|
-
cases: [
|
|
1308
|
-
{
|
|
1309
|
-
// Equal x/y axes collapse to an `overscroll-behavior` decl at the IR level; the minimizing
|
|
1310
|
-
// reverse-emit picks the single utility covering both (`overscroll-contain`), replacing the
|
|
1311
|
-
// `overscroll-x-contain`+`overscroll-y-contain` pair. `bg-red-200` is preserved.
|
|
1312
|
-
before: '<div className="overscroll-x-contain overscroll-y-contain bg-red-200">box</div>',
|
|
1313
|
-
after: '<div className="bg-red-200 overscroll-contain">box</div>'
|
|
1314
|
-
}
|
|
1315
|
-
],
|
|
1316
|
-
// Axes differ (x != y) → no equal-axis collapse.
|
|
1317
|
-
noMatch: ['<div className="overscroll-x-contain overscroll-y-auto bg-red-200">box</div>']
|
|
1318
|
-
}
|
|
1319
|
-
});
|
|
1320
|
-
|
|
1321
|
-
// ../patterns/src/library/compress/padding-shorthand.pattern.ts
|
|
1322
|
-
init_esm_shims();
|
|
1323
|
-
var PADDING_SIDES = [
|
|
1324
|
-
"padding-top",
|
|
1325
|
-
"padding-right",
|
|
1326
|
-
"padding-bottom",
|
|
1327
|
-
"padding-left"
|
|
1328
|
-
];
|
|
1329
|
-
var PADDING_SIDE_SET = new Set(PADDING_SIDES);
|
|
1330
|
-
var BASE_KEY7 = conditionKey(BASE_CONDITION);
|
|
1331
|
-
function analyzePadding(sm) {
|
|
1332
|
-
const block = sm.blocks.get(BASE_KEY7);
|
|
1333
|
-
if (!block) return null;
|
|
1334
|
-
const sides = [];
|
|
1335
|
-
for (const side of PADDING_SIDES) {
|
|
1336
|
-
const decl = block.decls.get(side);
|
|
1337
|
-
if (!decl) return null;
|
|
1338
|
-
sides.push(decl);
|
|
1339
|
-
}
|
|
1340
|
-
const [top, right, bottom, left] = sides;
|
|
1341
|
-
if (!(top.important === right.important && right.important === bottom.important && bottom.important === left.important)) {
|
|
1342
|
-
return null;
|
|
1343
|
-
}
|
|
1344
|
-
const tv = String(top.value);
|
|
1345
|
-
const rv = String(right.value);
|
|
1346
|
-
const bv = String(bottom.value);
|
|
1347
|
-
const lv = String(left.value);
|
|
1348
|
-
if (tv !== bv || lv !== rv) return null;
|
|
1349
|
-
const value = tv === lv ? tv : `${tv} ${lv}`;
|
|
1350
|
-
const relative = sides.some((d) => d.relativeToParent);
|
|
1351
|
-
return { value, important: top.important, relative };
|
|
1352
|
-
}
|
|
1353
|
-
function withFoldedPadding(sm, fold) {
|
|
1354
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1355
|
-
for (const [key, block] of sm.blocks) {
|
|
1356
|
-
if (key !== BASE_KEY7) {
|
|
1357
|
-
blocks.set(key, block);
|
|
1358
|
-
continue;
|
|
1359
|
-
}
|
|
1360
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1361
|
-
for (const [prop, decl] of block.decls) {
|
|
1362
|
-
if (PADDING_SIDE_SET.has(String(prop))) continue;
|
|
1363
|
-
decls.set(prop, decl);
|
|
1364
|
-
}
|
|
1365
|
-
const shorthand = {
|
|
1366
|
-
property: "padding",
|
|
1367
|
-
value: fold.value,
|
|
1368
|
-
important: fold.important,
|
|
1369
|
-
relativeToParent: fold.relative,
|
|
1370
|
-
inherited: false
|
|
1371
|
-
// padding is never inherited
|
|
1372
|
-
};
|
|
1373
|
-
decls.set(shorthand.property, shorthand);
|
|
1374
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1375
|
-
}
|
|
1376
|
-
return { blocks };
|
|
1377
|
-
}
|
|
1378
|
-
var paddingShorthand = definePattern({
|
|
1379
|
-
name: "padding-shorthand",
|
|
1380
|
-
category: "compress/padding-shorthand",
|
|
1381
|
-
safety: 1,
|
|
1382
|
-
doc: {
|
|
1383
|
-
title: "Collapse padding longhands to shorthand",
|
|
1384
|
-
summary: "Equal padding on all four sides (or matching x/y pairs) expressed as separate longhand declarations is collapsed to the shortest equivalent padding shorthand (p-* / px-* py-*).",
|
|
1385
|
-
before: '<div class="pt-4 pr-4 pb-4 pl-4"/>',
|
|
1386
|
-
after: '<div class="p-4"/>',
|
|
1387
|
-
safetyRationale: "A value-preserving re-serialization of the same computed padding on the same node \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1388
|
-
},
|
|
1389
|
-
rewrite: {
|
|
1390
|
-
rewriteClasses(computed2) {
|
|
1391
|
-
const fold = analyzePadding(computed2);
|
|
1392
|
-
return fold ? withFoldedPadding(computed2, fold) : null;
|
|
1393
|
-
}
|
|
1394
|
-
},
|
|
1395
|
-
test: {
|
|
1396
|
-
cases: [
|
|
1397
|
-
{
|
|
1398
|
-
// The four equal padding longhands collapse to a `padding` shorthand at the IR level, and the
|
|
1399
|
-
// minimizing reverse-emit picks the single shortest utility (`p-4`) that reproduces it,
|
|
1400
|
-
// replacing the four `p{t,r,b,l}-4` tokens. `bg-red-200` is preserved (its order is stable).
|
|
1401
|
-
before: '<div className="pt-4 pr-4 pb-4 pl-4 bg-red-200">box</div>',
|
|
1402
|
-
after: '<div className="bg-red-200 p-4">box</div>'
|
|
1403
|
-
},
|
|
1404
|
-
{
|
|
1405
|
-
// A dynamic `{x}` child no longer blocks compress: only the element's OWN class tokens are
|
|
1406
|
-
// rewritten (px-4 py-4 → p-4); the dynamic child is untouched by a class-only change. This is
|
|
1407
|
-
// the real-app common case (most elements have dynamic content).
|
|
1408
|
-
before: '<div className="px-4 py-4">{x}</div>',
|
|
1409
|
-
after: '<div className="p-4">{x}</div>'
|
|
1410
|
-
}
|
|
1411
|
-
],
|
|
1412
|
-
// Asymmetric padding (top != bottom) cannot fold into a shorthand → left unchanged.
|
|
1413
|
-
noMatch: ['<div className="pt-2 pr-4 pb-8 pl-4 bg-red-200">box</div>']
|
|
1414
|
-
}
|
|
1415
|
-
});
|
|
1416
|
-
|
|
1417
|
-
// ../patterns/src/library/compress/place-shorthand.pattern.ts
|
|
1418
|
-
init_esm_shims();
|
|
1419
|
-
var ALIGN_ITEMS = "align-items";
|
|
1420
|
-
var JUSTIFY_ITEMS = "justify-items";
|
|
1421
|
-
var PLACE_ITEMS = "place-items";
|
|
1422
|
-
var ALIGN_CONTENT = "align-content";
|
|
1423
|
-
var JUSTIFY_CONTENT = "justify-content";
|
|
1424
|
-
var PLACE_CONTENT = "place-content";
|
|
1425
|
-
var BASE_KEY8 = conditionKey(BASE_CONDITION);
|
|
1426
|
-
function samePair(a, b) {
|
|
1427
|
-
return a !== void 0 && b !== void 0 && a.value === b.value && a.important === b.important;
|
|
1428
|
-
}
|
|
1429
|
-
function placeDecl(property, align) {
|
|
1430
|
-
return {
|
|
1431
|
-
property,
|
|
1432
|
-
value: align.value,
|
|
1433
|
-
important: align.important,
|
|
1434
|
-
relativeToParent: false,
|
|
1435
|
-
// alignment keywords (center/start/stretch/…) are not length-relative
|
|
1436
|
-
inherited: false
|
|
1437
|
-
// none of the place-* alignment properties are inherited
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
function withBaseDecls2(sm, baseDecls) {
|
|
1441
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1442
|
-
for (const [key, block] of sm.blocks) {
|
|
1443
|
-
const decls = key === BASE_KEY8 ? new Map(baseDecls) : block.decls;
|
|
1444
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1445
|
-
}
|
|
1446
|
-
return { blocks };
|
|
1447
|
-
}
|
|
1448
|
-
var placeShorthand = definePattern({
|
|
1449
|
-
name: "place-shorthand",
|
|
1450
|
-
category: "compress/place-shorthand",
|
|
1451
|
-
safety: 1,
|
|
1452
|
-
doc: {
|
|
1453
|
-
title: "Collapse matching alignment pairs into `place-*` shorthands",
|
|
1454
|
-
summary: "When align-items equals justify-items they collapse to `place-items`; when align-content equals justify-content they collapse to `place-content`. The two collapses are independent.",
|
|
1455
|
-
before: '<div style="align-items:center;justify-items:center"/>',
|
|
1456
|
-
after: '<div style="place-items:center"/>',
|
|
1457
|
-
safetyRationale: "A `place-*` shorthand is value-identical to its equal align/justify pair \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1458
|
-
},
|
|
1459
|
-
rewrite: {
|
|
1460
|
-
rewriteClasses(computed2) {
|
|
1461
|
-
const base = computed2.blocks.get(BASE_KEY8);
|
|
1462
|
-
if (!base) return null;
|
|
1463
|
-
const alignItems = base.decls.get(ALIGN_ITEMS);
|
|
1464
|
-
const justifyItems = base.decls.get(JUSTIFY_ITEMS);
|
|
1465
|
-
const alignContent = base.decls.get(ALIGN_CONTENT);
|
|
1466
|
-
const justifyContent = base.decls.get(JUSTIFY_CONTENT);
|
|
1467
|
-
const next = new Map(base.decls);
|
|
1468
|
-
let collapsed = false;
|
|
1469
|
-
if (samePair(alignItems, justifyItems)) {
|
|
1470
|
-
next.delete(ALIGN_ITEMS);
|
|
1471
|
-
next.delete(JUSTIFY_ITEMS);
|
|
1472
|
-
next.set(PLACE_ITEMS, placeDecl(PLACE_ITEMS, alignItems));
|
|
1473
|
-
collapsed = true;
|
|
1474
|
-
}
|
|
1475
|
-
if (samePair(alignContent, justifyContent)) {
|
|
1476
|
-
next.delete(ALIGN_CONTENT);
|
|
1477
|
-
next.delete(JUSTIFY_CONTENT);
|
|
1478
|
-
next.set(PLACE_CONTENT, placeDecl(PLACE_CONTENT, alignContent));
|
|
1479
|
-
collapsed = true;
|
|
1480
|
-
}
|
|
1481
|
-
if (!collapsed) return null;
|
|
1482
|
-
return withBaseDecls2(computed2, next);
|
|
1483
|
-
}
|
|
1484
|
-
},
|
|
1485
|
-
test: {
|
|
1486
|
-
cases: [
|
|
1487
|
-
{
|
|
1488
|
-
// The matching items pair collapses to a `place-items` decl at the IR level; the minimizing
|
|
1489
|
-
// reverse-emit picks the single utility covering both (`place-items-center`), replacing the
|
|
1490
|
-
// `items-center`+`justify-items-center` pair. `bg-red-200` is preserved.
|
|
1491
|
-
before: '<div className="items-center justify-items-center bg-red-200">box</div>',
|
|
1492
|
-
after: '<div className="bg-red-200 place-items-center">box</div>'
|
|
1493
|
-
}
|
|
1494
|
-
],
|
|
1495
|
-
// Mismatched alignment (align-items != justify-items, no content pair) → nothing collapses.
|
|
1496
|
-
noMatch: ['<div className="items-center justify-items-start bg-red-200">box</div>']
|
|
1497
|
-
}
|
|
1498
|
-
});
|
|
1499
|
-
|
|
1500
|
-
// ../patterns/src/library/compress/scroll-margin-shorthand.pattern.ts
|
|
1501
|
-
init_esm_shims();
|
|
1502
|
-
var SCROLL_MARGIN_SIDES = [
|
|
1503
|
-
"scroll-margin-top",
|
|
1504
|
-
"scroll-margin-right",
|
|
1505
|
-
"scroll-margin-bottom",
|
|
1506
|
-
"scroll-margin-left"
|
|
1507
|
-
];
|
|
1508
|
-
var SIDE_SET = new Set(SCROLL_MARGIN_SIDES);
|
|
1509
|
-
var BASE_KEY9 = conditionKey(BASE_CONDITION);
|
|
1510
|
-
var SCROLL_MARGIN = "scroll-margin";
|
|
1511
|
-
var NON_COLLAPSIBLE_VALUES3 = /* @__PURE__ */ new Set([
|
|
1512
|
-
"initial",
|
|
1513
|
-
"inherit",
|
|
1514
|
-
"unset",
|
|
1515
|
-
"revert",
|
|
1516
|
-
"revert-layer"
|
|
1517
|
-
]);
|
|
1518
|
-
function analyzeScrollMargin(sm) {
|
|
1519
|
-
const block = sm.blocks.get(BASE_KEY9);
|
|
1520
|
-
if (!block) return null;
|
|
1521
|
-
const sides = [];
|
|
1522
|
-
for (const side of SCROLL_MARGIN_SIDES) {
|
|
1523
|
-
const decl = block.decls.get(side);
|
|
1524
|
-
if (!decl) return null;
|
|
1525
|
-
sides.push(decl);
|
|
1526
|
-
}
|
|
1527
|
-
const important = sides[0].important;
|
|
1528
|
-
if (!sides.every((d) => d.important === important)) return null;
|
|
1529
|
-
const value = String(sides[0].value);
|
|
1530
|
-
if (NON_COLLAPSIBLE_VALUES3.has(value)) return null;
|
|
1531
|
-
if (!sides.every((d) => String(d.value) === value)) return null;
|
|
1532
|
-
const relative = sides.some((d) => d.relativeToParent);
|
|
1533
|
-
return { value, important, relative };
|
|
1534
|
-
}
|
|
1535
|
-
function withFoldedScrollMargin(sm, fold) {
|
|
1536
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1537
|
-
for (const [key, block] of sm.blocks) {
|
|
1538
|
-
if (key !== BASE_KEY9) {
|
|
1539
|
-
blocks.set(key, block);
|
|
1540
|
-
continue;
|
|
1541
|
-
}
|
|
1542
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1543
|
-
for (const [prop, decl] of block.decls) {
|
|
1544
|
-
if (SIDE_SET.has(String(prop))) continue;
|
|
1545
|
-
decls.set(prop, decl);
|
|
1546
|
-
}
|
|
1547
|
-
const shorthand = {
|
|
1548
|
-
property: SCROLL_MARGIN,
|
|
1549
|
-
value: fold.value,
|
|
1550
|
-
important: fold.important,
|
|
1551
|
-
relativeToParent: fold.relative,
|
|
1552
|
-
inherited: false
|
|
1553
|
-
// scroll-margin is never inherited
|
|
1554
|
-
};
|
|
1555
|
-
decls.set(shorthand.property, shorthand);
|
|
1556
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1557
|
-
}
|
|
1558
|
-
return { blocks };
|
|
1559
|
-
}
|
|
1560
|
-
var scrollMarginShorthand = definePattern({
|
|
1561
|
-
name: "scroll-margin-shorthand",
|
|
1562
|
-
category: "compress/scroll-margin-shorthand",
|
|
1563
|
-
safety: 1,
|
|
1564
|
-
doc: {
|
|
1565
|
-
title: "Collapse equal scroll-margin sides into scroll-margin",
|
|
1566
|
-
summary: "An element whose four scroll-margin sides are all equal is rewritten to the single Tailwind scroll-m-* utility (scroll-margin === the four equal sides).",
|
|
1567
|
-
before: '<div class="scroll-mt-4 scroll-mr-4 scroll-mb-4 scroll-ml-4"/>',
|
|
1568
|
-
after: '<div class="scroll-m-4"/>',
|
|
1569
|
-
safetyRationale: "`scroll-margin` is value-identical to four equal scroll-margin sides \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1570
|
-
},
|
|
1571
|
-
rewrite: {
|
|
1572
|
-
rewriteClasses(computed2) {
|
|
1573
|
-
const fold = analyzeScrollMargin(computed2);
|
|
1574
|
-
return fold ? withFoldedScrollMargin(computed2, fold) : null;
|
|
1575
|
-
}
|
|
1576
|
-
},
|
|
1577
|
-
test: {
|
|
1578
|
-
cases: [
|
|
1579
|
-
{
|
|
1580
|
-
// The four equal scroll-margin longhands collapse to a `scroll-margin` decl at the IR level; the
|
|
1581
|
-
// minimizing reverse-emit then picks the single shortest utility (`scroll-m-4`) that reproduces
|
|
1582
|
-
// it, replacing the four `scroll-m{t,r,b,l}-4` tokens. `bg-red-200` is preserved.
|
|
1583
|
-
before: '<div className="scroll-mt-4 scroll-mr-4 scroll-mb-4 scroll-ml-4 bg-red-200">box</div>',
|
|
1584
|
-
after: '<div className="bg-red-200 scroll-m-4">box</div>'
|
|
1585
|
-
}
|
|
1586
|
-
],
|
|
1587
|
-
// Sides differ (top != bottom) → no all-equal collapse.
|
|
1588
|
-
noMatch: ['<div className="scroll-mt-2 scroll-mr-4 scroll-mb-8 scroll-ml-4 bg-red-200">box</div>']
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
|
|
1592
|
-
// ../patterns/src/library/compress/scroll-padding-shorthand.pattern.ts
|
|
1593
|
-
init_esm_shims();
|
|
1594
|
-
var SCROLL_PADDING_SIDES = [
|
|
1595
|
-
"scroll-padding-top",
|
|
1596
|
-
"scroll-padding-right",
|
|
1597
|
-
"scroll-padding-bottom",
|
|
1598
|
-
"scroll-padding-left"
|
|
1599
|
-
];
|
|
1600
|
-
var SIDE_SET2 = new Set(SCROLL_PADDING_SIDES);
|
|
1601
|
-
var BASE_KEY10 = conditionKey(BASE_CONDITION);
|
|
1602
|
-
var SCROLL_PADDING = "scroll-padding";
|
|
1603
|
-
var NON_COLLAPSIBLE_VALUES4 = /* @__PURE__ */ new Set([
|
|
1604
|
-
"initial",
|
|
1605
|
-
"inherit",
|
|
1606
|
-
"unset",
|
|
1607
|
-
"revert",
|
|
1608
|
-
"revert-layer"
|
|
1609
|
-
]);
|
|
1610
|
-
function analyzeScrollPadding(sm) {
|
|
1611
|
-
const block = sm.blocks.get(BASE_KEY10);
|
|
1612
|
-
if (!block) return null;
|
|
1613
|
-
const sides = [];
|
|
1614
|
-
for (const side of SCROLL_PADDING_SIDES) {
|
|
1615
|
-
const decl = block.decls.get(side);
|
|
1616
|
-
if (!decl) return null;
|
|
1617
|
-
sides.push(decl);
|
|
1618
|
-
}
|
|
1619
|
-
const important = sides[0].important;
|
|
1620
|
-
if (!sides.every((d) => d.important === important)) return null;
|
|
1621
|
-
const value = String(sides[0].value);
|
|
1622
|
-
if (NON_COLLAPSIBLE_VALUES4.has(value)) return null;
|
|
1623
|
-
if (!sides.every((d) => String(d.value) === value)) return null;
|
|
1624
|
-
const relative = sides.some((d) => d.relativeToParent);
|
|
1625
|
-
return { value, important, relative };
|
|
1626
|
-
}
|
|
1627
|
-
function withFoldedScrollPadding(sm, fold) {
|
|
1628
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1629
|
-
for (const [key, block] of sm.blocks) {
|
|
1630
|
-
if (key !== BASE_KEY10) {
|
|
1631
|
-
blocks.set(key, block);
|
|
1632
|
-
continue;
|
|
1633
|
-
}
|
|
1634
|
-
const decls = /* @__PURE__ */ new Map();
|
|
1635
|
-
for (const [prop, decl] of block.decls) {
|
|
1636
|
-
if (SIDE_SET2.has(String(prop))) continue;
|
|
1637
|
-
decls.set(prop, decl);
|
|
1638
|
-
}
|
|
1639
|
-
const shorthand = {
|
|
1640
|
-
property: SCROLL_PADDING,
|
|
1641
|
-
value: fold.value,
|
|
1642
|
-
important: fold.important,
|
|
1643
|
-
relativeToParent: fold.relative,
|
|
1644
|
-
inherited: false
|
|
1645
|
-
// scroll-padding is never inherited
|
|
1646
|
-
};
|
|
1647
|
-
decls.set(shorthand.property, shorthand);
|
|
1648
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1649
|
-
}
|
|
1650
|
-
return { blocks };
|
|
1651
|
-
}
|
|
1652
|
-
var scrollPaddingShorthand = definePattern({
|
|
1653
|
-
name: "scroll-padding-shorthand",
|
|
1654
|
-
category: "compress/scroll-padding-shorthand",
|
|
1655
|
-
safety: 1,
|
|
1656
|
-
doc: {
|
|
1657
|
-
title: "Collapse equal scroll-padding sides into scroll-padding",
|
|
1658
|
-
summary: "An element whose four scroll-padding sides are all equal is rewritten to the single Tailwind scroll-p-* utility (scroll-padding === the four equal sides).",
|
|
1659
|
-
before: '<div class="scroll-pt-4 scroll-pr-4 scroll-pb-4 scroll-pl-4"/>',
|
|
1660
|
-
after: '<div class="scroll-p-4"/>',
|
|
1661
|
-
safetyRationale: "`scroll-padding` is value-identical to four equal scroll-padding sides \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1662
|
-
},
|
|
1663
|
-
rewrite: {
|
|
1664
|
-
rewriteClasses(computed2) {
|
|
1665
|
-
const fold = analyzeScrollPadding(computed2);
|
|
1666
|
-
return fold ? withFoldedScrollPadding(computed2, fold) : null;
|
|
1667
|
-
}
|
|
1668
|
-
},
|
|
1669
|
-
test: {
|
|
1670
|
-
cases: [
|
|
1671
|
-
{
|
|
1672
|
-
// The four equal scroll-padding longhands collapse to a `scroll-padding` decl at the IR level;
|
|
1673
|
-
// the minimizing reverse-emit then picks the single shortest utility (`scroll-p-4`) that
|
|
1674
|
-
// reproduces it, replacing the four `scroll-p{t,r,b,l}-4` tokens. `bg-red-200` is preserved.
|
|
1675
|
-
before: '<div className="scroll-pt-4 scroll-pr-4 scroll-pb-4 scroll-pl-4 bg-red-200">box</div>',
|
|
1676
|
-
after: '<div className="bg-red-200 scroll-p-4">box</div>'
|
|
1677
|
-
}
|
|
1678
|
-
],
|
|
1679
|
-
// Sides differ (top != bottom) → no all-equal collapse.
|
|
1680
|
-
noMatch: ['<div className="scroll-pt-2 scroll-pr-4 scroll-pb-8 scroll-pl-4 bg-red-200">box</div>']
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
|
|
1684
|
-
// ../patterns/src/library/compress/size-shorthand.pattern.ts
|
|
1685
|
-
init_esm_shims();
|
|
1686
|
-
var WIDTH = "width";
|
|
1687
|
-
var HEIGHT = "height";
|
|
1688
|
-
var SIZE = "size";
|
|
1689
|
-
var NON_COLLAPSIBLE_VALUES5 = /* @__PURE__ */ new Set(["auto", "initial", "unset"]);
|
|
1690
|
-
function baseBlock(sm) {
|
|
1691
|
-
return sm.blocks.get(conditionKey(BASE_CONDITION));
|
|
1692
|
-
}
|
|
1693
|
-
function withSizeShorthand(sm, value, important) {
|
|
1694
|
-
const baseKey = conditionKey(BASE_CONDITION);
|
|
1695
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
1696
|
-
for (const [key, block] of sm.blocks) {
|
|
1697
|
-
if (key !== baseKey) {
|
|
1698
|
-
blocks.set(key, block);
|
|
1699
|
-
continue;
|
|
1700
|
-
}
|
|
1701
|
-
const decls = new Map(block.decls);
|
|
1702
|
-
decls.delete(WIDTH);
|
|
1703
|
-
decls.delete(HEIGHT);
|
|
1704
|
-
for (const decl of normalizer.normalizeDeclaration(String(SIZE), value, important)) {
|
|
1705
|
-
decls.set(decl.property, decl);
|
|
1706
|
-
}
|
|
1707
|
-
blocks.set(key, { condition: block.condition, decls });
|
|
1708
|
-
}
|
|
1709
|
-
return { blocks };
|
|
1710
|
-
}
|
|
1711
|
-
var sizeShorthand = definePattern({
|
|
1712
|
-
name: "size-shorthand",
|
|
1713
|
-
category: "compress/size-shorthand",
|
|
1714
|
-
safety: 2,
|
|
1715
|
-
doc: {
|
|
1716
|
-
title: "Collapse equal width/height into size-*",
|
|
1717
|
-
summary: "An element whose computed width and height are equal is rewritten to the single Tailwind size-* utility (size-* === width + height at the same value).",
|
|
1718
|
-
before: '<div style="width:1rem;height:1rem"/>',
|
|
1719
|
-
after: '<div class="size-4"/>',
|
|
1720
|
-
safetyRationale: "`size-*` is value-identical to equal width+height \u2014 a class-only change. It is safe even on an element with a ref, event handler, dynamic child, or dangerouslySetInnerHTML \u2014 a className rewrite touches none of them; only a dynamic/opaque class list or a combinator-subject class is excluded, so no behaviour or project selector is disturbed."
|
|
1721
|
-
},
|
|
1722
|
-
rewrite: {
|
|
1723
|
-
rewriteClasses(computed2) {
|
|
1724
|
-
const base = baseBlock(computed2);
|
|
1725
|
-
const w = base?.decls.get(WIDTH);
|
|
1726
|
-
const h = base?.decls.get(HEIGHT);
|
|
1727
|
-
if (!w || !h) return null;
|
|
1728
|
-
if (w.important !== h.important) return null;
|
|
1729
|
-
if (NON_COLLAPSIBLE_VALUES5.has(String(w.value))) return null;
|
|
1730
|
-
if (w.value !== h.value) return null;
|
|
1731
|
-
return withSizeShorthand(computed2, String(w.value), w.important);
|
|
1732
|
-
}
|
|
1733
|
-
},
|
|
1734
|
-
test: {
|
|
1735
|
-
cases: [
|
|
1736
|
-
{
|
|
1737
|
-
// Equal width/height collapse to a `size` decl at the IR level; the minimizing reverse-emit
|
|
1738
|
-
// expands `size` back to width+height, finds the single utility covering both (`size-10`), and
|
|
1739
|
-
// replaces the `h-10`+`w-10` pair with it. `bg-red-200` is preserved.
|
|
1740
|
-
before: '<div className="h-10 w-10 bg-red-200">box</div>',
|
|
1741
|
-
after: '<div className="bg-red-200 size-10">box</div>'
|
|
1742
|
-
}
|
|
1743
|
-
],
|
|
1744
|
-
// Width and height differ → no equal-axis collapse.
|
|
1745
|
-
noMatch: ['<div className="h-10 w-20 bg-red-200">box</div>']
|
|
1746
|
-
}
|
|
1747
|
-
});
|
|
1748
|
-
|
|
1749
535
|
// ../patterns/src/_registry.generated.ts
|
|
1750
536
|
init_esm_shims();
|
|
1751
537
|
var builtinPatterns = [
|
|
538
|
+
flexCenterWrapper,
|
|
539
|
+
redundantFragment,
|
|
540
|
+
gridCenterWrapper,
|
|
1752
541
|
displayContentsWrapper,
|
|
1753
542
|
emptyStyleDiv,
|
|
1754
|
-
|
|
1755
|
-
inlineFlexCenterWrapper,
|
|
1756
|
-
nestedFlexMerge,
|
|
1757
|
-
nestedGridMerge,
|
|
543
|
+
inheritedOnlyWrapper,
|
|
1758
544
|
passthroughWrapper,
|
|
1759
|
-
|
|
1760
|
-
redundantInlineWrapper,
|
|
1761
|
-
borderRadiusShorthand,
|
|
1762
|
-
borderShorthand,
|
|
1763
|
-
dedupeClasses,
|
|
1764
|
-
gapShorthand,
|
|
1765
|
-
insetShorthand,
|
|
1766
|
-
marginShorthand,
|
|
1767
|
-
overflowShorthand,
|
|
1768
|
-
overscrollBehaviorShorthand,
|
|
1769
|
-
paddingShorthand,
|
|
1770
|
-
placeShorthand,
|
|
1771
|
-
scrollMarginShorthand,
|
|
1772
|
-
scrollPaddingShorthand,
|
|
1773
|
-
sizeShorthand
|
|
545
|
+
redundantInlineWrapper
|
|
1774
546
|
];
|
|
1775
547
|
|
|
1776
548
|
// ../patterns/src/index.ts
|
|
@@ -1830,16 +602,317 @@ function synthesizeResidual(remaining, ctx) {
|
|
|
1830
602
|
}
|
|
1831
603
|
|
|
1832
604
|
// ../resolver-tailwind/src/tailwind/engine.ts
|
|
1833
|
-
init_esm_shims();
|
|
1834
|
-
import { createRequire } from "module";
|
|
1835
|
-
import * as
|
|
605
|
+
init_esm_shims();
|
|
606
|
+
import { createRequire } from "module";
|
|
607
|
+
import * as path3 from "path";
|
|
608
|
+
|
|
609
|
+
// ../resolver-tailwind/src/tailwind/engine-v4.ts
|
|
610
|
+
init_esm_shims();
|
|
611
|
+
import { readdirSync, readFileSync, statSync } from "fs";
|
|
612
|
+
import * as path2 from "path";
|
|
613
|
+
|
|
614
|
+
// ../resolver-tailwind/src/tailwind/v4-bridge.ts
|
|
615
|
+
init_esm_shims();
|
|
616
|
+
import { execFileSync } from "child_process";
|
|
617
|
+
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
618
|
+
import { tmpdir } from "os";
|
|
619
|
+
import * as path from "path";
|
|
620
|
+
var CHILD_SOURCE = String.raw`
|
|
621
|
+
import { createRequire } from 'node:module';
|
|
622
|
+
import { pathToFileURL } from 'node:url';
|
|
623
|
+
import * as fs from 'node:fs';
|
|
624
|
+
import * as path from 'node:path';
|
|
625
|
+
|
|
626
|
+
function out(obj) { process.stdout.write(JSON.stringify(obj)); process.exit(0); }
|
|
627
|
+
|
|
628
|
+
let payload;
|
|
629
|
+
try { payload = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); }
|
|
630
|
+
catch { out({ ok: false }); }
|
|
631
|
+
|
|
632
|
+
const projectRoot = payload.projectRoot;
|
|
633
|
+
const entries = payload.entries || [];
|
|
634
|
+
const req = createRequire(path.join(projectRoot, '__domflax_tw4__.js'));
|
|
635
|
+
|
|
636
|
+
async function importFrom(id) {
|
|
637
|
+
const resolved = req.resolve(id);
|
|
638
|
+
return import(pathToFileURL(resolved).href);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// Primary loader: @tailwindcss/node (the companion every v4 build tool installs). It resolves
|
|
642
|
+
// '@import "tailwindcss"' and @theme against the project on disk.
|
|
643
|
+
async function loadViaNode() {
|
|
644
|
+
let mod;
|
|
645
|
+
try { mod = await importFrom('@tailwindcss/node'); } catch { return null; }
|
|
646
|
+
if (!mod || typeof mod.__unstable__loadDesignSystem !== 'function') return null;
|
|
647
|
+
for (const e of entries) {
|
|
648
|
+
try { return await mod.__unstable__loadDesignSystem(e.css, { base: e.base }); } catch {}
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Secondary loader: bare 'tailwindcss' with a filesystem stylesheet resolver (best-effort).
|
|
654
|
+
async function loadViaCore() {
|
|
655
|
+
let tw;
|
|
656
|
+
try { tw = await importFrom('tailwindcss'); } catch { return null; }
|
|
657
|
+
if (!tw || typeof tw.__unstable__loadDesignSystem !== 'function') return null;
|
|
658
|
+
const loadStylesheet = async (id, base) => {
|
|
659
|
+
const r = createRequire(path.join(base, '__domflax_tw4__.js'));
|
|
660
|
+
let p;
|
|
661
|
+
const tries = id === 'tailwindcss' ? ['tailwindcss/index.css', 'tailwindcss'] : [id, id + '/index.css'];
|
|
662
|
+
for (const t of tries) { try { p = r.resolve(t); break; } catch {} }
|
|
663
|
+
if (!p) p = path.resolve(base, id);
|
|
664
|
+
return { path: p, base: path.dirname(p), content: fs.readFileSync(p, 'utf8') };
|
|
665
|
+
};
|
|
666
|
+
const loadModule = async (id, base) => {
|
|
667
|
+
const r = createRequire(path.join(base, '__domflax_tw4__.js'));
|
|
668
|
+
const p = r.resolve(id);
|
|
669
|
+
return { path: p, base: path.dirname(p), module: (await import(pathToFileURL(p).href)).default };
|
|
670
|
+
};
|
|
671
|
+
for (const e of entries) {
|
|
672
|
+
try { return await tw.__unstable__loadDesignSystem(e.css, { base: e.base, loadStylesheet, loadModule }); } catch {}
|
|
673
|
+
}
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const ds = (await loadViaNode()) || (await loadViaCore());
|
|
678
|
+
if (!ds) out({ ok: false });
|
|
679
|
+
|
|
680
|
+
let names = [];
|
|
681
|
+
try {
|
|
682
|
+
names = ds.getClassList().map((e) => (Array.isArray(e) ? e[0] : e)).filter((n) => typeof n === 'string');
|
|
683
|
+
} catch { out({ ok: false }); }
|
|
684
|
+
|
|
685
|
+
let css = [];
|
|
686
|
+
try { css = ds.candidatesToCss(names); } catch { out({ ok: false }); }
|
|
687
|
+
|
|
688
|
+
const result = [];
|
|
689
|
+
for (let i = 0; i < names.length; i += 1) {
|
|
690
|
+
const c = css[i];
|
|
691
|
+
if (typeof c === 'string' && c.length > 0) result.push([names[i], c]);
|
|
692
|
+
}
|
|
693
|
+
out({ ok: true, entries: result });
|
|
694
|
+
`;
|
|
695
|
+
function runV4Bridge(payload) {
|
|
696
|
+
let dir = null;
|
|
697
|
+
try {
|
|
698
|
+
dir = mkdtempSync(path.join(tmpdir(), "domflax-tw4-"));
|
|
699
|
+
const scriptPath = path.join(dir, "bridge.mjs");
|
|
700
|
+
const payloadPath = path.join(dir, "payload.json");
|
|
701
|
+
writeFileSync(scriptPath, CHILD_SOURCE, "utf8");
|
|
702
|
+
writeFileSync(payloadPath, JSON.stringify(payload), "utf8");
|
|
703
|
+
const stdout = execFileSync(process.execPath, [scriptPath, payloadPath], {
|
|
704
|
+
cwd: payload.projectRoot,
|
|
705
|
+
encoding: "utf8",
|
|
706
|
+
timeout: 9e4,
|
|
707
|
+
maxBuffer: 256 * 1024 * 1024,
|
|
708
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
709
|
+
});
|
|
710
|
+
const parsed = JSON.parse(stdout);
|
|
711
|
+
if (!parsed.ok || !Array.isArray(parsed.entries) || parsed.entries.length === 0) return null;
|
|
712
|
+
const entries = parsed.entries.filter(
|
|
713
|
+
(e) => Array.isArray(e) && typeof e[0] === "string" && typeof e[1] === "string"
|
|
714
|
+
);
|
|
715
|
+
return entries.length > 0 ? { entries } : null;
|
|
716
|
+
} catch {
|
|
717
|
+
return null;
|
|
718
|
+
} finally {
|
|
719
|
+
if (dir) {
|
|
720
|
+
try {
|
|
721
|
+
rmSync(dir, { recursive: true, force: true });
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// ../resolver-tailwind/src/tailwind/v4-css.ts
|
|
729
|
+
init_esm_shims();
|
|
730
|
+
function stripComments(src) {
|
|
731
|
+
return src.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
732
|
+
}
|
|
733
|
+
function toDecl(buffer) {
|
|
734
|
+
const buf = buffer.trim();
|
|
735
|
+
if (buf.length === 0 || buf[0] === "@") return null;
|
|
736
|
+
const colon = buf.indexOf(":");
|
|
737
|
+
if (colon <= 0) return null;
|
|
738
|
+
const prop = buf.slice(0, colon).trim();
|
|
739
|
+
let value = buf.slice(colon + 1).trim();
|
|
740
|
+
if (prop.length === 0 || value.length === 0) return null;
|
|
741
|
+
let important = false;
|
|
742
|
+
const bang = /!\s*important\s*$/i.exec(value);
|
|
743
|
+
if (bang) {
|
|
744
|
+
important = true;
|
|
745
|
+
value = value.slice(0, bang.index).trim();
|
|
746
|
+
}
|
|
747
|
+
return { type: "decl", prop, value, important };
|
|
748
|
+
}
|
|
749
|
+
function splitAtRule(prelude) {
|
|
750
|
+
const m = /^@([A-Za-z-]+)\s*([\s\S]*)$/.exec(prelude);
|
|
751
|
+
if (!m) return { name: prelude.slice(1).trim(), params: "" };
|
|
752
|
+
return { name: m[1].toLowerCase(), params: m[2].trim() };
|
|
753
|
+
}
|
|
754
|
+
function parseBlock(src, start) {
|
|
755
|
+
const nodes = [];
|
|
756
|
+
let buf = "";
|
|
757
|
+
let i = start;
|
|
758
|
+
while (i < src.length) {
|
|
759
|
+
const c = src[i];
|
|
760
|
+
if (c === "{") {
|
|
761
|
+
const prelude = buf.trim();
|
|
762
|
+
buf = "";
|
|
763
|
+
const inner = parseBlock(src, i + 1);
|
|
764
|
+
i = inner.next;
|
|
765
|
+
if (prelude.startsWith("@")) {
|
|
766
|
+
const { name, params } = splitAtRule(prelude);
|
|
767
|
+
nodes.push({ type: "atrule", name, params, nodes: inner.nodes });
|
|
768
|
+
} else if (prelude.length > 0) {
|
|
769
|
+
nodes.push({ type: "rule", selector: prelude, nodes: inner.nodes });
|
|
770
|
+
}
|
|
771
|
+
} else if (c === "}") {
|
|
772
|
+
const d = toDecl(buf);
|
|
773
|
+
if (d) nodes.push(d);
|
|
774
|
+
return { nodes, next: i + 1 };
|
|
775
|
+
} else if (c === ";") {
|
|
776
|
+
const d = toDecl(buf);
|
|
777
|
+
if (d) nodes.push(d);
|
|
778
|
+
buf = "";
|
|
779
|
+
i += 1;
|
|
780
|
+
} else {
|
|
781
|
+
buf += c;
|
|
782
|
+
i += 1;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
const tail = toDecl(buf);
|
|
786
|
+
if (tail) nodes.push(tail);
|
|
787
|
+
return { nodes, next: i };
|
|
788
|
+
}
|
|
789
|
+
function resolveNesting(child, parent) {
|
|
790
|
+
const c = child.trim();
|
|
791
|
+
if (parent.length === 0) return c;
|
|
792
|
+
if (c.includes("&")) return c.split("&").join(parent);
|
|
793
|
+
return `${parent} ${c}`;
|
|
794
|
+
}
|
|
795
|
+
var DROP_ATRULES = /* @__PURE__ */ new Set(["property", "keyframes", "font-face", "charset", "import"]);
|
|
796
|
+
function flattenNodes(nodes, selector, at, out) {
|
|
797
|
+
const own = [];
|
|
798
|
+
for (const n of nodes) if (n.type === "decl") own.push(n);
|
|
799
|
+
if (own.length > 0 && selector.length > 0) out.push({ selector, at: [...at], decls: own });
|
|
800
|
+
for (const n of nodes) {
|
|
801
|
+
if (n.type === "rule") {
|
|
802
|
+
flattenNodes(n.nodes, resolveNesting(n.selector, selector), at, out);
|
|
803
|
+
} else if (n.type === "atrule") {
|
|
804
|
+
if (n.name === "media") {
|
|
805
|
+
flattenNodes(n.nodes, selector, [...at, { name: "media", params: n.params }], out);
|
|
806
|
+
} else if (n.name === "layer") {
|
|
807
|
+
flattenNodes(n.nodes, selector, at, out);
|
|
808
|
+
} else if (!DROP_ATRULES.has(n.name)) {
|
|
809
|
+
flattenNodes(n.nodes, selector, [...at, { name: n.name, params: n.params }], out);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function leafToNode(leaf) {
|
|
815
|
+
const declNodes = leaf.decls.map((d) => ({
|
|
816
|
+
type: "decl",
|
|
817
|
+
prop: d.prop,
|
|
818
|
+
value: d.value,
|
|
819
|
+
important: d.important
|
|
820
|
+
}));
|
|
821
|
+
let node = { type: "rule", selector: leaf.selector, nodes: declNodes };
|
|
822
|
+
for (let i = leaf.at.length - 1; i >= 0; i -= 1) {
|
|
823
|
+
node = { type: "atrule", name: leaf.at[i].name, params: leaf.at[i].params, nodes: [node] };
|
|
824
|
+
}
|
|
825
|
+
return node;
|
|
826
|
+
}
|
|
827
|
+
function parseUtilityCss(css) {
|
|
828
|
+
try {
|
|
829
|
+
const { nodes } = parseBlock(stripComments(css), 0);
|
|
830
|
+
const leaves = [];
|
|
831
|
+
flattenNodes(nodes, "", [], leaves);
|
|
832
|
+
return leaves.map(leafToNode);
|
|
833
|
+
} catch {
|
|
834
|
+
return [];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// ../resolver-tailwind/src/tailwind/engine-v4.ts
|
|
839
|
+
var SEARCH_DIRS = ["", "src", "app", "styles", "src/styles", "src/app", "app/styles", "assets/css", "css"];
|
|
840
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", "out", ".next", "coverage"]);
|
|
841
|
+
var ENTRY_RE = /@import\s+["']tailwindcss["']|@tailwind\b|@theme\b/;
|
|
842
|
+
function scanDir(dir) {
|
|
843
|
+
let names;
|
|
844
|
+
try {
|
|
845
|
+
names = readdirSync(dir);
|
|
846
|
+
} catch {
|
|
847
|
+
return null;
|
|
848
|
+
}
|
|
849
|
+
for (const name of names) {
|
|
850
|
+
if (!name.toLowerCase().endsWith(".css")) continue;
|
|
851
|
+
const file = path2.join(dir, name);
|
|
852
|
+
try {
|
|
853
|
+
if (!statSync(file).isFile()) continue;
|
|
854
|
+
const css = readFileSync(file, "utf8");
|
|
855
|
+
if (ENTRY_RE.test(css)) return { css, base: path2.dirname(file) };
|
|
856
|
+
} catch {
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return null;
|
|
860
|
+
}
|
|
861
|
+
function findCssEntries(projectRoot) {
|
|
862
|
+
const out = [];
|
|
863
|
+
const seen = /* @__PURE__ */ new Set();
|
|
864
|
+
for (const rel of SEARCH_DIRS) {
|
|
865
|
+
const dir = path2.resolve(projectRoot, rel);
|
|
866
|
+
if (seen.has(dir) || [...SKIP_DIRS].some((s) => dir.includes(`${path2.sep}${s}`))) continue;
|
|
867
|
+
seen.add(dir);
|
|
868
|
+
const hit = scanDir(dir);
|
|
869
|
+
if (hit) {
|
|
870
|
+
out.push(hit);
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
out.push({ css: '@import "tailwindcss";', base: projectRoot });
|
|
875
|
+
return out;
|
|
876
|
+
}
|
|
877
|
+
function makeV4Engine(entries, version) {
|
|
878
|
+
const cssByClass = new Map(entries.map(([name, css]) => [name, css]));
|
|
879
|
+
const nodeCache = /* @__PURE__ */ new Map();
|
|
880
|
+
const nodesFor = (token) => {
|
|
881
|
+
let cached = nodeCache.get(token);
|
|
882
|
+
if (!cached) {
|
|
883
|
+
const css = cssByClass.get(token);
|
|
884
|
+
cached = css ? parseUtilityCss(css) : [];
|
|
885
|
+
nodeCache.set(token, cached);
|
|
886
|
+
}
|
|
887
|
+
return cached;
|
|
888
|
+
};
|
|
889
|
+
return {
|
|
890
|
+
version,
|
|
891
|
+
context: {
|
|
892
|
+
// The resolver keeps only string entries; we hand it the concrete class names directly.
|
|
893
|
+
getClassList: () => [...cssByClass.keys()]
|
|
894
|
+
},
|
|
895
|
+
generate(candidates) {
|
|
896
|
+
const out = [];
|
|
897
|
+
for (const c of candidates) for (const n of nodesFor(c)) out.push(n);
|
|
898
|
+
return out;
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
function loadV4Engine(projectRoot, version) {
|
|
903
|
+
const snapshot = runV4Bridge({ projectRoot, entries: findCssEntries(projectRoot) });
|
|
904
|
+
if (!snapshot) return null;
|
|
905
|
+
return makeV4Engine(snapshot.entries, version);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// ../resolver-tailwind/src/tailwind/engine.ts
|
|
1836
909
|
function moduleBase() {
|
|
1837
910
|
return typeof __filename === "string" ? __filename : import.meta.url;
|
|
1838
911
|
}
|
|
1839
912
|
function projectRequire(projectRoot) {
|
|
1840
913
|
const bases = [];
|
|
1841
|
-
if (projectRoot) bases.push(
|
|
1842
|
-
bases.push(
|
|
914
|
+
if (projectRoot) bases.push(path3.join(projectRoot, "__domflax__.js"));
|
|
915
|
+
bases.push(path3.join(process.cwd(), "__domflax__.js"));
|
|
1843
916
|
bases.push(moduleBase());
|
|
1844
917
|
for (const base of bases) {
|
|
1845
918
|
try {
|
|
@@ -1851,14 +924,36 @@ function projectRequire(projectRoot) {
|
|
|
1851
924
|
}
|
|
1852
925
|
return null;
|
|
1853
926
|
}
|
|
927
|
+
var FIRST_UNSUPPORTED_MAJOR = 4;
|
|
928
|
+
function majorOf(version) {
|
|
929
|
+
const m = /^\s*(\d+)/.exec(version);
|
|
930
|
+
return m ? Number(m[1]) : null;
|
|
931
|
+
}
|
|
1854
932
|
function loadEngine(options) {
|
|
1855
933
|
const req = projectRequire(options.projectRoot);
|
|
1856
|
-
if (!req) return null;
|
|
934
|
+
if (!req) return { engine: null, version: null, unsupportedMajor: null };
|
|
935
|
+
let version = null;
|
|
936
|
+
try {
|
|
937
|
+
version = req("tailwindcss/package.json").version;
|
|
938
|
+
} catch {
|
|
939
|
+
return { engine: null, version: null, unsupportedMajor: null };
|
|
940
|
+
}
|
|
941
|
+
const major = majorOf(version);
|
|
942
|
+
if (major !== null && major >= FIRST_UNSUPPORTED_MAJOR) {
|
|
943
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
944
|
+
let v4 = null;
|
|
945
|
+
try {
|
|
946
|
+
v4 = loadV4Engine(projectRoot, version);
|
|
947
|
+
} catch {
|
|
948
|
+
v4 = null;
|
|
949
|
+
}
|
|
950
|
+
if (v4) return { engine: v4, version, unsupportedMajor: null };
|
|
951
|
+
return { engine: null, version, unsupportedMajor: major };
|
|
952
|
+
}
|
|
1857
953
|
try {
|
|
1858
954
|
const resolveConfig = req("tailwindcss/resolveConfig.js");
|
|
1859
955
|
const { createContext } = req("tailwindcss/lib/lib/setupContextUtils.js");
|
|
1860
956
|
const { generateRules } = req("tailwindcss/lib/lib/generateRules.js");
|
|
1861
|
-
const pkg = req("tailwindcss/package.json");
|
|
1862
957
|
let userConfig = options.config ?? { content: [{ raw: "" }] };
|
|
1863
958
|
if (options.configPath !== void 0) {
|
|
1864
959
|
const loadConfig = req("tailwindcss/loadConfig.js");
|
|
@@ -1867,15 +962,19 @@ function loadEngine(options) {
|
|
|
1867
962
|
const resolved = resolveConfig(userConfig);
|
|
1868
963
|
const context = createContext(resolved);
|
|
1869
964
|
return {
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
965
|
+
engine: {
|
|
966
|
+
version,
|
|
967
|
+
context,
|
|
968
|
+
generate(candidates) {
|
|
969
|
+
const rules = generateRules(new Set(candidates), context);
|
|
970
|
+
return rules.map(([, node]) => node);
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
version,
|
|
974
|
+
unsupportedMajor: null
|
|
1876
975
|
};
|
|
1877
976
|
} catch {
|
|
1878
|
-
return null;
|
|
977
|
+
return { engine: null, version, unsupportedMajor: null };
|
|
1879
978
|
}
|
|
1880
979
|
}
|
|
1881
980
|
|
|
@@ -2061,22 +1160,39 @@ var DROPPABLE_USAGE = {
|
|
|
2061
1160
|
};
|
|
2062
1161
|
|
|
2063
1162
|
// ../resolver-tailwind/src/tailwind/resolver.ts
|
|
1163
|
+
var warnedUnsupported = /* @__PURE__ */ new Set();
|
|
2064
1164
|
var TailwindResolver = class {
|
|
2065
1165
|
id = "tailwind";
|
|
2066
1166
|
provider;
|
|
2067
1167
|
fingerprint;
|
|
1168
|
+
/**
|
|
1169
|
+
* SAFETY (Layer 1): the detected Tailwind MAJOR when the project's version is one this resolver
|
|
1170
|
+
* cannot drive (v4+), else `null`. When set, {@link resolve} reports every token as unknown, so
|
|
1171
|
+
* downstream files are left unchanged (never mis-optimized). Exposed for diagnostics/tests.
|
|
1172
|
+
*/
|
|
1173
|
+
unsupportedMajor;
|
|
2068
1174
|
#engine;
|
|
2069
1175
|
/** Per-token extraction cache (engine output is pure for a fixed config). */
|
|
2070
1176
|
#tokenCache = /* @__PURE__ */ new Map();
|
|
2071
1177
|
/** Per-class-set forward-resolution cache. */
|
|
2072
1178
|
#resolveCache = /* @__PURE__ */ new Map();
|
|
2073
|
-
/** Lazily built reverse index for {@link emit}. */
|
|
1179
|
+
/** Lazily built reverse index for the greedy {@link emit} fallback. */
|
|
2074
1180
|
#reverseIndex = null;
|
|
1181
|
+
/** Lazily built cover vocabulary (base-condition tuple sets) for the exact-cover engine. */
|
|
1182
|
+
#coverVocab = null;
|
|
2075
1183
|
constructor(config = {}) {
|
|
2076
|
-
|
|
2077
|
-
this
|
|
1184
|
+
const loaded = loadEngine(config);
|
|
1185
|
+
this.#engine = loaded.engine;
|
|
1186
|
+
this.unsupportedMajor = loaded.unsupportedMajor;
|
|
1187
|
+
this.provider = config.provider ?? (loaded.version ? `tailwindcss@${loaded.version}` : "tailwindcss");
|
|
2078
1188
|
const seed = JSON.stringify(config.config ?? {}) + (config.configPath ?? "");
|
|
2079
1189
|
this.fingerprint = config.fingerprint ?? `${this.provider}/${fnv1a(seed)}`;
|
|
1190
|
+
if (this.unsupportedMajor !== null && !warnedUnsupported.has(this.provider)) {
|
|
1191
|
+
warnedUnsupported.add(this.provider);
|
|
1192
|
+
console.warn(
|
|
1193
|
+
`domflax: detected Tailwind v${this.unsupportedMajor} (${this.provider}) but could not load its design system (is @tailwindcss/node installed?); classes cannot be resolved, so files are left unchanged to avoid unsafe edits.`
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
2080
1196
|
}
|
|
2081
1197
|
/** Engine-backed, cached single-token extraction. */
|
|
2082
1198
|
#extract(token) {
|
|
@@ -2185,9 +1301,75 @@ var TailwindResolver = class {
|
|
|
2185
1301
|
this.#reverseIndex = index;
|
|
2186
1302
|
return index;
|
|
2187
1303
|
}
|
|
1304
|
+
/**
|
|
1305
|
+
* The cover vocabulary: every base-condition, plain-subject utility mapped to the {@link tupleKey}s
|
|
1306
|
+
* of its full normalized-longhand declaration set. Built once from a SINGLE engine `generate` over
|
|
1307
|
+
* the enumerable class list (grouped by selector), so it is the same cost as {@link #buildReverseIndex}.
|
|
1308
|
+
* This is what the provider-uniform exact-cover engine searches; the element's own droppable tokens
|
|
1309
|
+
* are members of it, guaranteeing feasibility. Variant / combinator / pseudo utilities are excluded
|
|
1310
|
+
* (their effect is not the element's own base box), so a target carrying such conditions simply finds
|
|
1311
|
+
* no cover and falls back to the greedy emit.
|
|
1312
|
+
*/
|
|
1313
|
+
#buildCoverVocab() {
|
|
1314
|
+
if (this.#coverVocab) return this.#coverVocab;
|
|
1315
|
+
const baseCk = String(conditionKey(BASE_CONDITION));
|
|
1316
|
+
const out = [];
|
|
1317
|
+
if (this.#engine) {
|
|
1318
|
+
try {
|
|
1319
|
+
const classes = this.#engine.context.getClassList().filter((c) => typeof c === "string");
|
|
1320
|
+
const nodes = this.#engine.generate(classes);
|
|
1321
|
+
for (const node of nodes) {
|
|
1322
|
+
if (node.type !== "rule") continue;
|
|
1323
|
+
const rule = node;
|
|
1324
|
+
const parsed = parseSelector(rule.selector);
|
|
1325
|
+
if (parsed.kind !== "simple" || parsed.states.length > 0 || parsed.pseudoElement !== "") {
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
const className = unescapeClass(rule.selector);
|
|
1329
|
+
if (className === null) continue;
|
|
1330
|
+
const tuples = [];
|
|
1331
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1332
|
+
for (const child of rule.nodes ?? []) {
|
|
1333
|
+
if (child.type !== "decl") continue;
|
|
1334
|
+
const d = child;
|
|
1335
|
+
if (typeof d.value !== "string") continue;
|
|
1336
|
+
for (const decl of normalizer.normalizeDeclaration(d.prop, d.value, d.important === true)) {
|
|
1337
|
+
const k = tupleKey(baseCk, String(decl.property), String(decl.value), decl.important);
|
|
1338
|
+
if (!seen.has(k)) {
|
|
1339
|
+
seen.add(k);
|
|
1340
|
+
tuples.push(k);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
if (tuples.length > 0) out.push({ token: className, tuples });
|
|
1345
|
+
}
|
|
1346
|
+
} catch {
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
this.#coverVocab = out;
|
|
1350
|
+
return out;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Try the minimal-string exact-cover engine over the WHOLE utility vocabulary. On success the chosen
|
|
1354
|
+
* set is verified by the mandatory CORRECTNESS BACKSTOP — re-resolve it and assert it reproduces the
|
|
1355
|
+
* target's tuples EXACTLY — before it is returned; any mismatch (or no cover / oversize universe)
|
|
1356
|
+
* yields `null` so {@link emit} uses its greedy fallback. Never returns a set that misrepresents `U`.
|
|
1357
|
+
*/
|
|
1358
|
+
#tryCover(normalized, norm) {
|
|
1359
|
+
const universe = styleMapTuples(normalized, norm);
|
|
1360
|
+
if (universe.length === 0) return { classes: [], exact: true, warnings: [] };
|
|
1361
|
+
const chosen = minStringCover(universe, this.#buildCoverVocab());
|
|
1362
|
+
if (!chosen || chosen.length === 0) return null;
|
|
1363
|
+
const reTuples = new Set(styleMapTuples(this.resolve({ classes: chosen }).styles, norm));
|
|
1364
|
+
if (reTuples.size !== universe.length) return null;
|
|
1365
|
+
for (const t of universe) if (!reTuples.has(t)) return null;
|
|
1366
|
+
return { classes: chosen, exact: true, warnings: [] };
|
|
1367
|
+
}
|
|
2188
1368
|
emit(styles, ctx) {
|
|
2189
1369
|
const norm = ctx.normalizer ?? normalizer;
|
|
2190
1370
|
const normalized = norm.normalizeStyleMap(styles);
|
|
1371
|
+
const cover = this.#tryCover(normalized, norm);
|
|
1372
|
+
if (cover) return cover;
|
|
2191
1373
|
const base = normalized.blocks.get(conditionKey(BASE_CONDITION));
|
|
2192
1374
|
if (!base || base.decls.size === 0) return { classes: [], exact: true, warnings: [] };
|
|
2193
1375
|
const hasNonBase = normalized.blocks.size > 1;
|
|
@@ -2217,13 +1399,13 @@ var TailwindResolver = class {
|
|
|
2217
1399
|
let bestCover = 0;
|
|
2218
1400
|
for (const entry of candidates) {
|
|
2219
1401
|
const [token, declMap] = entry;
|
|
2220
|
-
let
|
|
2221
|
-
for (const prop of declMap.keys()) if (remaining.has(prop))
|
|
2222
|
-
if (
|
|
2223
|
-
const better = best === null ||
|
|
1402
|
+
let cover2 = 0;
|
|
1403
|
+
for (const prop of declMap.keys()) if (remaining.has(prop)) cover2 += 1;
|
|
1404
|
+
if (cover2 === 0) continue;
|
|
1405
|
+
const better = best === null || cover2 > bestCover || cover2 === bestCover && declMap.size < best[1].size || cover2 === bestCover && declMap.size === best[1].size && token < best[0];
|
|
2224
1406
|
if (better) {
|
|
2225
1407
|
best = entry;
|
|
2226
|
-
bestCover =
|
|
1408
|
+
bestCover = cover2;
|
|
2227
1409
|
}
|
|
2228
1410
|
}
|
|
2229
1411
|
if (!best) break;
|
|
@@ -2302,14 +1484,14 @@ var LEGACY_PSEUDO_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
|
2302
1484
|
// ../resolver-css/src/engine.ts
|
|
2303
1485
|
init_esm_shims();
|
|
2304
1486
|
import { createRequire as createRequire2 } from "module";
|
|
2305
|
-
import * as
|
|
1487
|
+
import * as path4 from "path";
|
|
2306
1488
|
function moduleBase2() {
|
|
2307
1489
|
return typeof __filename === "string" ? __filename : import.meta.url;
|
|
2308
1490
|
}
|
|
2309
1491
|
function loadPostcssEngine(projectRoot) {
|
|
2310
1492
|
const bases = [];
|
|
2311
|
-
if (projectRoot) bases.push(
|
|
2312
|
-
bases.push(
|
|
1493
|
+
if (projectRoot) bases.push(path4.join(projectRoot, "__domflax__.js"));
|
|
1494
|
+
bases.push(path4.join(process.cwd(), "__domflax__.js"));
|
|
2313
1495
|
bases.push(moduleBase2());
|
|
2314
1496
|
for (const base of bases) {
|
|
2315
1497
|
try {
|
|
@@ -2364,15 +1546,15 @@ function collectDecls(rule) {
|
|
|
2364
1546
|
|
|
2365
1547
|
// ../resolver-css/src/misc-helpers.ts
|
|
2366
1548
|
init_esm_shims();
|
|
2367
|
-
import { readFileSync } from "fs";
|
|
1549
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
2368
1550
|
function isPlainClassToken(token) {
|
|
2369
1551
|
return token.length > 0 && !/[\s.#>+~:[\]()]/.test(token);
|
|
2370
1552
|
}
|
|
2371
|
-
function readCssPath(
|
|
1553
|
+
function readCssPath(path5) {
|
|
2372
1554
|
try {
|
|
2373
|
-
return { id:
|
|
1555
|
+
return { id: path5, css: readFileSync2(path5, "utf8") };
|
|
2374
1556
|
} catch (cause) {
|
|
2375
|
-
throw new Error(`resolver-css: cannot read CSS file "${
|
|
1557
|
+
throw new Error(`resolver-css: cannot read CSS file "${path5}"`, { cause });
|
|
2376
1558
|
}
|
|
2377
1559
|
}
|
|
2378
1560
|
function deriveFingerprint(provider, files) {
|
|
@@ -2428,6 +1610,8 @@ var CustomCSSResolver = class {
|
|
|
2428
1610
|
/** Distinct COMPLEX selectors (combinator or structural pseudo), sorted. */
|
|
2429
1611
|
#complex;
|
|
2430
1612
|
#reverse = null;
|
|
1613
|
+
/** Lazily built cover vocabulary (full condition-keyed tuple sets) for the exact-cover engine. */
|
|
1614
|
+
#coverVocab = null;
|
|
2431
1615
|
constructor(cssFiles = [], options = {}) {
|
|
2432
1616
|
ensurePostcss(options.projectRoot);
|
|
2433
1617
|
const fromDisk = (options.files ?? []).map(readCssPath);
|
|
@@ -2460,8 +1644,23 @@ var CustomCSSResolver = class {
|
|
|
2460
1644
|
}
|
|
2461
1645
|
emit(styles, ctx) {
|
|
2462
1646
|
const norm = ctx.normalizer ?? normalizer;
|
|
1647
|
+
const normalized = norm.normalizeStyleMap(styles);
|
|
1648
|
+
const universe = styleMapTuples(normalized, norm);
|
|
1649
|
+
if (universe.length === 0) return { classes: [], exact: true, warnings: [] };
|
|
1650
|
+
const chosen = minStringCover(universe, this.#buildCoverVocab());
|
|
1651
|
+
if (chosen && chosen.length > 0) {
|
|
1652
|
+
const reTuples = new Set(styleMapTuples(this.resolve({ classes: chosen }).styles, norm));
|
|
1653
|
+
let ok = reTuples.size === universe.length;
|
|
1654
|
+
if (ok) {
|
|
1655
|
+
for (const t of universe) if (!reTuples.has(t)) {
|
|
1656
|
+
ok = false;
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
if (ok) return { classes: chosen, exact: true, warnings: [] };
|
|
1661
|
+
}
|
|
2463
1662
|
const remaining = /* @__PURE__ */ new Map();
|
|
2464
|
-
for (const [ck, block] of
|
|
1663
|
+
for (const [ck, block] of normalized.blocks) {
|
|
2465
1664
|
for (const [prop, decl] of block.decls) {
|
|
2466
1665
|
remaining.set(`${ck} ${prop}`, String(decl.value));
|
|
2467
1666
|
}
|
|
@@ -2671,7 +1870,23 @@ var CustomCSSResolver = class {
|
|
|
2671
1870
|
if (rawBlocks.size === 0) return emptyStyleMap();
|
|
2672
1871
|
return normalizer.normalizeStyleMap({ blocks: rawBlocks });
|
|
2673
1872
|
}
|
|
2674
|
-
/**
|
|
1873
|
+
/**
|
|
1874
|
+
* Build (once) the cover vocabulary for the exact-cover engine: every forward-resolvable class
|
|
1875
|
+
* mapped to the {@link styleMapTuples} of its full (condition-keyed, `!important`-aware) declaration
|
|
1876
|
+
* set. Unlike {@link #reverseIndex} this carries ALL style conditions and the important flag, so the
|
|
1877
|
+
* engine can pick a custom class covering hover/media declarations too.
|
|
1878
|
+
*/
|
|
1879
|
+
#buildCoverVocab() {
|
|
1880
|
+
if (this.#coverVocab) return this.#coverVocab;
|
|
1881
|
+
const out = [];
|
|
1882
|
+
for (const token of this.#classIndex.keys()) {
|
|
1883
|
+
const tuples = styleMapTuples(this.#resolveTokens([token], [token]), normalizer);
|
|
1884
|
+
if (tuples.length > 0) out.push({ token, tuples });
|
|
1885
|
+
}
|
|
1886
|
+
this.#coverVocab = out;
|
|
1887
|
+
return out;
|
|
1888
|
+
}
|
|
1889
|
+
/** Build (once) the reverse index used by the greedy {@link emit} fallback. */
|
|
2675
1890
|
#reverseIndex() {
|
|
2676
1891
|
if (this.#reverse) return this.#reverse;
|
|
2677
1892
|
const out = [];
|
|
@@ -2695,6 +1910,351 @@ function createCssResolver(cssFiles = [], options) {
|
|
|
2695
1910
|
// ../resolver-css/src/index.ts
|
|
2696
1911
|
init_esm_shims();
|
|
2697
1912
|
|
|
1913
|
+
// ../frontend-html/src/index.ts
|
|
1914
|
+
init_esm_shims();
|
|
1915
|
+
|
|
1916
|
+
// ../frontend-html/src/backend.ts
|
|
1917
|
+
init_esm_shims();
|
|
1918
|
+
import MagicString from "magic-string";
|
|
1919
|
+
function staticTokensOf(classes) {
|
|
1920
|
+
const out = [];
|
|
1921
|
+
for (const seg of classes.segments) {
|
|
1922
|
+
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
1923
|
+
}
|
|
1924
|
+
return out;
|
|
1925
|
+
}
|
|
1926
|
+
function sameTokens(a, b) {
|
|
1927
|
+
if (a.length !== b.length) return false;
|
|
1928
|
+
for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
|
|
1929
|
+
return true;
|
|
1930
|
+
}
|
|
1931
|
+
function primarySource(doc) {
|
|
1932
|
+
for (const sf of doc.sources.values()) {
|
|
1933
|
+
if (typeof sf.text === "string" && sf.text.length > 0) return sf;
|
|
1934
|
+
}
|
|
1935
|
+
return null;
|
|
1936
|
+
}
|
|
1937
|
+
function collectKept(doc) {
|
|
1938
|
+
const out = [];
|
|
1939
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1940
|
+
const visit = (id) => {
|
|
1941
|
+
if (seen.has(id)) return;
|
|
1942
|
+
seen.add(id);
|
|
1943
|
+
const n = doc.nodes.get(id);
|
|
1944
|
+
if (!n) return;
|
|
1945
|
+
out.push(n);
|
|
1946
|
+
if (n.kind === "element" || n.kind === "fragment") for (const c of n.children) visit(c);
|
|
1947
|
+
};
|
|
1948
|
+
visit(doc.root);
|
|
1949
|
+
return out;
|
|
1950
|
+
}
|
|
1951
|
+
function strictlyContains(a, b) {
|
|
1952
|
+
if (a.file !== b.file) return false;
|
|
1953
|
+
if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
|
|
1954
|
+
return false;
|
|
1955
|
+
}
|
|
1956
|
+
function backrefIds(doc) {
|
|
1957
|
+
const out = [];
|
|
1958
|
+
const max = doc.alloc.peek;
|
|
1959
|
+
for (let i = 1; i < max; i += 1) {
|
|
1960
|
+
const id = i;
|
|
1961
|
+
if (doc.backref.get(id)) out.push(id);
|
|
1962
|
+
}
|
|
1963
|
+
return out;
|
|
1964
|
+
}
|
|
1965
|
+
function currentTokens(sf, valueSpan) {
|
|
1966
|
+
const raw = sf.text.slice(valueSpan.start, valueSpan.end).trim();
|
|
1967
|
+
const unquoted = raw.replace(/^['"]/, "").replace(/['"]$/, "");
|
|
1968
|
+
return unquoted.split(/\s+/).filter((t) => t.length > 0);
|
|
1969
|
+
}
|
|
1970
|
+
function editClasses(ms, doc, sf, el) {
|
|
1971
|
+
const classes = el.classes;
|
|
1972
|
+
if (classes.hasDynamic || classes.opaque) return false;
|
|
1973
|
+
const tokens = staticTokensOf(classes);
|
|
1974
|
+
const valueSpan = classes.valueSpan;
|
|
1975
|
+
if (valueSpan && valueSpan.file === sf.id) {
|
|
1976
|
+
if (sameTokens(currentTokens(sf, valueSpan), tokens)) return false;
|
|
1977
|
+
const current = sf.text.slice(valueSpan.start, valueSpan.end).trim();
|
|
1978
|
+
const quote = current.startsWith("'") ? "'" : '"';
|
|
1979
|
+
ms.overwrite(valueSpan.start, valueSpan.end, `${quote}${tokens.join(" ")}${quote}`);
|
|
1980
|
+
return true;
|
|
1981
|
+
}
|
|
1982
|
+
if (tokens.length === 0) return false;
|
|
1983
|
+
const openTag = doc.backref.get(el.id)?.openTagSpan;
|
|
1984
|
+
if (!openTag || openTag.file !== sf.id) return false;
|
|
1985
|
+
ms.appendLeft(openTag.start + 1 + el.tag.length, ` class="${tokens.join(" ")}"`);
|
|
1986
|
+
return true;
|
|
1987
|
+
}
|
|
1988
|
+
function surgicalPrint(doc) {
|
|
1989
|
+
const sf = primarySource(doc);
|
|
1990
|
+
if (!sf) return null;
|
|
1991
|
+
const ms = new MagicString(sf.text);
|
|
1992
|
+
const kept = collectKept(doc);
|
|
1993
|
+
const keptSpans = [];
|
|
1994
|
+
for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
|
|
1995
|
+
const removed = [];
|
|
1996
|
+
for (const id of backrefIds(doc)) {
|
|
1997
|
+
if (doc.nodes.has(id)) continue;
|
|
1998
|
+
const back = doc.backref.get(id);
|
|
1999
|
+
if (!back || back.span.file !== sf.id) continue;
|
|
2000
|
+
const unwrapped = keptSpans.some((k) => strictlyContains(back.span, k));
|
|
2001
|
+
removed.push({ backref: back, unwrapped });
|
|
2002
|
+
}
|
|
2003
|
+
const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
|
|
2004
|
+
for (const r of removed) {
|
|
2005
|
+
const s = r.backref.span;
|
|
2006
|
+
if (fullRemovals.some((f) => f !== s && strictlyContains(f, s))) continue;
|
|
2007
|
+
if (r.unwrapped) {
|
|
2008
|
+
const open = r.backref.openTagSpan;
|
|
2009
|
+
const close = r.backref.closeTagSpan;
|
|
2010
|
+
if (open && open.file === sf.id && open.end > open.start) ms.remove(open.start, open.end);
|
|
2011
|
+
if (close && close.file === sf.id && close.end > close.start) ms.remove(close.start, close.end);
|
|
2012
|
+
} else {
|
|
2013
|
+
ms.remove(s.start, s.end);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
for (const n of kept) if (n.kind === "element") editClasses(ms, doc, sf, n);
|
|
2017
|
+
return ms.toString();
|
|
2018
|
+
}
|
|
2019
|
+
function doPrint(doc) {
|
|
2020
|
+
return surgicalPrint(doc) ?? "";
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
// ../frontend-html/src/parse.ts
|
|
2024
|
+
init_esm_shims();
|
|
2025
|
+
import { createRequire as createRequire3 } from "module";
|
|
2026
|
+
|
|
2027
|
+
// ../frontend-html/src/walk.ts
|
|
2028
|
+
init_esm_shims();
|
|
2029
|
+
var HTML_LANGS = ["html"];
|
|
2030
|
+
var FILE_ID = 1;
|
|
2031
|
+
function looksLikeHtml(id, code) {
|
|
2032
|
+
if (/\.html?$/i.test(id)) return true;
|
|
2033
|
+
const head = code.slice(0, 256).trimStart().toLowerCase();
|
|
2034
|
+
return head.startsWith("<!doctype html") || head.startsWith("<html") || head.startsWith("<");
|
|
2035
|
+
}
|
|
2036
|
+
var OPAQUE_SUBTREE_TAGS = /* @__PURE__ */ new Set([
|
|
2037
|
+
"script",
|
|
2038
|
+
"style",
|
|
2039
|
+
"template",
|
|
2040
|
+
"svg",
|
|
2041
|
+
"pre",
|
|
2042
|
+
"textarea"
|
|
2043
|
+
]);
|
|
2044
|
+
function isOpaqueSubtreeTag(tag) {
|
|
2045
|
+
return OPAQUE_SUBTREE_TAGS.has(tag);
|
|
2046
|
+
}
|
|
2047
|
+
function elementIsOpaque(attrs) {
|
|
2048
|
+
for (const a of attrs) {
|
|
2049
|
+
const n = a.name.toLowerCase();
|
|
2050
|
+
if (n === "id" || n === "contenteditable") return true;
|
|
2051
|
+
if (n.startsWith("on")) return true;
|
|
2052
|
+
}
|
|
2053
|
+
return false;
|
|
2054
|
+
}
|
|
2055
|
+
function hasEventHandler(attrs) {
|
|
2056
|
+
for (const a of attrs) if (/^on/i.test(a.name)) return true;
|
|
2057
|
+
return false;
|
|
2058
|
+
}
|
|
2059
|
+
function span(start, end) {
|
|
2060
|
+
return { file: FILE_ID, start, end };
|
|
2061
|
+
}
|
|
2062
|
+
function attrsLocOf(loc) {
|
|
2063
|
+
if (!loc) return void 0;
|
|
2064
|
+
return loc.startTag?.attrs ?? loc.attrs;
|
|
2065
|
+
}
|
|
2066
|
+
function classValueSpan(loc, source) {
|
|
2067
|
+
const attrsLoc = attrsLocOf(loc);
|
|
2068
|
+
const cl = attrsLoc?.["class"];
|
|
2069
|
+
if (!cl) return null;
|
|
2070
|
+
const text = source.slice(cl.startOffset, cl.endOffset);
|
|
2071
|
+
const eq = text.indexOf("=");
|
|
2072
|
+
if (eq === -1) return null;
|
|
2073
|
+
let i = eq + 1;
|
|
2074
|
+
while (i < text.length && /\s/.test(text[i])) i += 1;
|
|
2075
|
+
if (i >= text.length) return null;
|
|
2076
|
+
return span(cl.startOffset + i, cl.endOffset);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// ../frontend-html/src/parse.ts
|
|
2080
|
+
var cachedParse5 = null;
|
|
2081
|
+
function loadParse5() {
|
|
2082
|
+
if (cachedParse5) return cachedParse5;
|
|
2083
|
+
const req = createRequire3(import.meta.url);
|
|
2084
|
+
cachedParse5 = req("parse5");
|
|
2085
|
+
return cachedParse5;
|
|
2086
|
+
}
|
|
2087
|
+
function doParse(code, ctx) {
|
|
2088
|
+
const diagnostics = [];
|
|
2089
|
+
const doc = createDocument("html");
|
|
2090
|
+
const backref = doc.backref;
|
|
2091
|
+
const parse5 = loadParse5();
|
|
2092
|
+
const document = parse5.parse(code, { sourceCodeLocationInfo: true });
|
|
2093
|
+
const eol = code.includes("\r\n") ? "\r\n" : "\n";
|
|
2094
|
+
const sourceFile = {
|
|
2095
|
+
id: FILE_ID,
|
|
2096
|
+
path: ctx.id,
|
|
2097
|
+
text: code,
|
|
2098
|
+
frontend: "html",
|
|
2099
|
+
eol,
|
|
2100
|
+
indentUnit: " ",
|
|
2101
|
+
native: document
|
|
2102
|
+
};
|
|
2103
|
+
doc.sources.set(FILE_ID, sourceFile);
|
|
2104
|
+
const resolveComputed = (tokens, tag, nodeId, meta) => {
|
|
2105
|
+
if (tokens.length === 0) return emptyStyleMap();
|
|
2106
|
+
const res = ctx.resolver.resolve({ classes: tokens, element: { tagName: tag, namespace: "html" } });
|
|
2107
|
+
if (res.unknown.length > 0) meta.hasUnresolvedClasses = true;
|
|
2108
|
+
for (const w of res.warnings) {
|
|
2109
|
+
diagnostics.push({
|
|
2110
|
+
code: "DF_STYLE_CONFLICT_UNRESOLVED",
|
|
2111
|
+
severity: w.severity,
|
|
2112
|
+
message: w.message,
|
|
2113
|
+
nodeId
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
return ctx.normalizer.normalizeStyleMap(res.styles);
|
|
2117
|
+
};
|
|
2118
|
+
const splitTokens = (raw) => raw.split(/\s+/).filter((t) => t.length > 0);
|
|
2119
|
+
const appendChild = (node, parentId, out) => {
|
|
2120
|
+
const name = node.nodeName;
|
|
2121
|
+
if (name === "#text") {
|
|
2122
|
+
const value = node.value ?? "";
|
|
2123
|
+
const id = doc.alloc.next();
|
|
2124
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2125
|
+
doc.nodes.set(
|
|
2126
|
+
id,
|
|
2127
|
+
createText(id, value, {
|
|
2128
|
+
parent: parentId,
|
|
2129
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null,
|
|
2130
|
+
collapsible: /^\s*$/.test(value)
|
|
2131
|
+
})
|
|
2132
|
+
);
|
|
2133
|
+
out.push(id);
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
if (name === "#comment") {
|
|
2137
|
+
const id = doc.alloc.next();
|
|
2138
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2139
|
+
doc.nodes.set(
|
|
2140
|
+
id,
|
|
2141
|
+
createComment(id, node.data ?? "", {
|
|
2142
|
+
parent: parentId,
|
|
2143
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null
|
|
2144
|
+
})
|
|
2145
|
+
);
|
|
2146
|
+
out.push(id);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
if (name === "#documentType") return;
|
|
2150
|
+
if (name.startsWith("#")) {
|
|
2151
|
+
for (const c of node.childNodes ?? []) appendChild(c, parentId, out);
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
out.push(buildElement(node, parentId));
|
|
2155
|
+
};
|
|
2156
|
+
const buildElement = (node, parentId) => {
|
|
2157
|
+
const id = doc.alloc.next();
|
|
2158
|
+
const tag = (node.tagName ?? node.nodeName).toLowerCase();
|
|
2159
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2160
|
+
const attrsArr = node.attrs ?? [];
|
|
2161
|
+
const opaqueSubtree = isOpaqueSubtreeTag(tag);
|
|
2162
|
+
const synthetic = loc == null;
|
|
2163
|
+
const opaque = opaqueSubtree || synthetic || elementIsOpaque(attrsArr);
|
|
2164
|
+
const meta = defaultMeta();
|
|
2165
|
+
meta.hasEventHandlers = hasEventHandler(attrsArr);
|
|
2166
|
+
meta.safetyFloor = opaque ? 0 : 3;
|
|
2167
|
+
let classes = emptyClassList();
|
|
2168
|
+
let classTokens = [];
|
|
2169
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2170
|
+
const order = [];
|
|
2171
|
+
for (const a of attrsArr) {
|
|
2172
|
+
if (a.name.toLowerCase() === "class") {
|
|
2173
|
+
classTokens = splitTokens(a.value);
|
|
2174
|
+
const valueSpan = classValueSpan(loc, code);
|
|
2175
|
+
const clAttr = attrsLocOf(loc)?.["class"];
|
|
2176
|
+
const seg = {
|
|
2177
|
+
kind: "static",
|
|
2178
|
+
span: valueSpan ?? void 0,
|
|
2179
|
+
tokens: classTokens.map((value) => ({ value }))
|
|
2180
|
+
};
|
|
2181
|
+
classes = {
|
|
2182
|
+
form: "string-literal",
|
|
2183
|
+
segments: [seg],
|
|
2184
|
+
valueSpan,
|
|
2185
|
+
attrSpan: clAttr ? span(clAttr.startOffset, clAttr.endOffset) : void 0,
|
|
2186
|
+
hasDynamic: false,
|
|
2187
|
+
opaque: false,
|
|
2188
|
+
rewritable: valueSpan != null
|
|
2189
|
+
};
|
|
2190
|
+
continue;
|
|
2191
|
+
}
|
|
2192
|
+
const v = a.value;
|
|
2193
|
+
entries.set(a.name, { kind: "static", value: v === "" ? true : v });
|
|
2194
|
+
order.push(a.name);
|
|
2195
|
+
}
|
|
2196
|
+
const attrs = { entries, spreads: [], order };
|
|
2197
|
+
const computed = resolveComputed(classTokens, tag, id, meta);
|
|
2198
|
+
const children = [];
|
|
2199
|
+
if (!opaqueSubtree) {
|
|
2200
|
+
for (const c of node.childNodes ?? []) appendChild(c, id, children);
|
|
2201
|
+
}
|
|
2202
|
+
const el = createElement(id, {
|
|
2203
|
+
tag,
|
|
2204
|
+
namespace: "html",
|
|
2205
|
+
isComponent: false,
|
|
2206
|
+
selfClosing: loc ? loc.endTag == null : false,
|
|
2207
|
+
classes,
|
|
2208
|
+
computed,
|
|
2209
|
+
attrs,
|
|
2210
|
+
children,
|
|
2211
|
+
parent: parentId,
|
|
2212
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null,
|
|
2213
|
+
meta
|
|
2214
|
+
});
|
|
2215
|
+
doc.nodes.set(id, el);
|
|
2216
|
+
if (loc) {
|
|
2217
|
+
backref.set(id, {
|
|
2218
|
+
nodeId: id,
|
|
2219
|
+
span: span(loc.startOffset, loc.endOffset),
|
|
2220
|
+
openTagSpan: loc.startTag ? span(loc.startTag.startOffset, loc.startTag.endOffset) : null,
|
|
2221
|
+
closeTagSpan: loc.endTag ? span(loc.endTag.startOffset, loc.endTag.endOffset) : null,
|
|
2222
|
+
innerSpan: null,
|
|
2223
|
+
selfClosing: loc.endTag == null
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
return id;
|
|
2227
|
+
};
|
|
2228
|
+
const rootFrag = doc.nodes.get(doc.root);
|
|
2229
|
+
appendChild(document, doc.root, rootFrag.children);
|
|
2230
|
+
return { doc, diagnostics };
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// ../frontend-html/src/index.ts
|
|
2234
|
+
var htmlFrontend = {
|
|
2235
|
+
name: "html",
|
|
2236
|
+
langs: HTML_LANGS,
|
|
2237
|
+
canParse(id, code) {
|
|
2238
|
+
return looksLikeHtml(id, code);
|
|
2239
|
+
},
|
|
2240
|
+
parse(code, ctx) {
|
|
2241
|
+
return doParse(code, ctx);
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
function createHtmlFrontend() {
|
|
2245
|
+
return htmlFrontend;
|
|
2246
|
+
}
|
|
2247
|
+
var htmlBackend = {
|
|
2248
|
+
name: "html",
|
|
2249
|
+
langs: HTML_LANGS,
|
|
2250
|
+
print(doc, _plan, _ctx) {
|
|
2251
|
+
return { code: doPrint(doc), map: null, edits: [], diagnostics: [] };
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
function createHtmlBackend() {
|
|
2255
|
+
return htmlBackend;
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2698
2258
|
// ../frontend-jsx/src/frontend.ts
|
|
2699
2259
|
init_esm_shims();
|
|
2700
2260
|
|
|
@@ -2703,7 +2263,7 @@ init_esm_shims();
|
|
|
2703
2263
|
import babelTraverse from "@babel/traverse";
|
|
2704
2264
|
var traverse = typeof babelTraverse === "function" ? babelTraverse : babelTraverse.default;
|
|
2705
2265
|
var JSX_LANGS = ["jsx", "tsx"];
|
|
2706
|
-
var
|
|
2266
|
+
var FILE_ID2 = 1;
|
|
2707
2267
|
function jsxName(node) {
|
|
2708
2268
|
switch (node.type) {
|
|
2709
2269
|
case "JSXIdentifier":
|
|
@@ -2828,7 +2388,7 @@ function looksLikeJsx(id, code) {
|
|
|
2828
2388
|
// ../frontend-jsx/src/frontend-parse.ts
|
|
2829
2389
|
init_esm_shims();
|
|
2830
2390
|
import { parse as babelParse } from "@babel/parser";
|
|
2831
|
-
function
|
|
2391
|
+
function doParse2(code, ctx) {
|
|
2832
2392
|
const diagnostics = [];
|
|
2833
2393
|
const doc = createDocument("jsx");
|
|
2834
2394
|
const backref = doc.backref;
|
|
@@ -2838,7 +2398,7 @@ function doParse(code, ctx) {
|
|
|
2838
2398
|
});
|
|
2839
2399
|
const eol = code.includes("\r\n") ? "\r\n" : "\n";
|
|
2840
2400
|
const sourceFile = {
|
|
2841
|
-
id:
|
|
2401
|
+
id: FILE_ID2,
|
|
2842
2402
|
path: ctx.id,
|
|
2843
2403
|
text: code,
|
|
2844
2404
|
frontend: "jsx",
|
|
@@ -2846,23 +2406,23 @@ function doParse(code, ctx) {
|
|
|
2846
2406
|
indentUnit: " ",
|
|
2847
2407
|
native: ast
|
|
2848
2408
|
};
|
|
2849
|
-
doc.sources.set(
|
|
2409
|
+
doc.sources.set(FILE_ID2, sourceFile);
|
|
2850
2410
|
const spanOf = (node) => {
|
|
2851
2411
|
if (node.start == null || node.end == null) return null;
|
|
2852
|
-
const
|
|
2853
|
-
file:
|
|
2412
|
+
const span2 = {
|
|
2413
|
+
file: FILE_ID2,
|
|
2854
2414
|
start: node.start,
|
|
2855
2415
|
end: node.end,
|
|
2856
2416
|
startLoc: node.loc ? { line: node.loc.start.line, column: node.loc.start.column } : void 0,
|
|
2857
2417
|
endLoc: node.loc ? { line: node.loc.end.line, column: node.loc.end.column } : void 0
|
|
2858
2418
|
};
|
|
2859
|
-
return
|
|
2419
|
+
return span2;
|
|
2860
2420
|
};
|
|
2861
2421
|
const sliceOf = (node) => node.start == null || node.end == null ? "" : code.slice(node.start, node.end);
|
|
2862
2422
|
const internExpr = (node, spread) => {
|
|
2863
2423
|
const payload = { text: sliceOf(node), spread };
|
|
2864
2424
|
return doc.exprs.intern({
|
|
2865
|
-
span: spanOf(node) ?? { file:
|
|
2425
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
2866
2426
|
kind: exprKind(node),
|
|
2867
2427
|
payload
|
|
2868
2428
|
});
|
|
@@ -2908,7 +2468,7 @@ function doParse(code, ctx) {
|
|
|
2908
2468
|
}
|
|
2909
2469
|
return emptyClassList();
|
|
2910
2470
|
};
|
|
2911
|
-
const
|
|
2471
|
+
const staticTokensOf3 = (classes) => {
|
|
2912
2472
|
const out = [];
|
|
2913
2473
|
for (const seg of classes.segments) {
|
|
2914
2474
|
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
@@ -2986,7 +2546,7 @@ function doParse(code, ctx) {
|
|
|
2986
2546
|
doc.nodes.set(id, createFragment(id, { children, parent: parentId, span: spanOf(node) }));
|
|
2987
2547
|
backref.set(id, {
|
|
2988
2548
|
nodeId: id,
|
|
2989
|
-
span: spanOf(node) ?? { file:
|
|
2549
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
2990
2550
|
openTagSpan: spanOf(node.openingFragment),
|
|
2991
2551
|
closeTagSpan: spanOf(node.closingFragment),
|
|
2992
2552
|
innerSpan: null,
|
|
@@ -3033,15 +2593,16 @@ function doParse(code, ctx) {
|
|
|
3033
2593
|
break;
|
|
3034
2594
|
}
|
|
3035
2595
|
}
|
|
3036
|
-
let
|
|
2596
|
+
let computed = emptyStyleMap();
|
|
3037
2597
|
if (!classes.hasDynamic) {
|
|
3038
|
-
const tokens =
|
|
2598
|
+
const tokens = staticTokensOf3(classes);
|
|
3039
2599
|
if (tokens.length > 0) {
|
|
3040
2600
|
const res = ctx.resolver.resolve({
|
|
3041
2601
|
classes: tokens,
|
|
3042
2602
|
element: { tagName: tag, namespace: component ? void 0 : "html" }
|
|
3043
2603
|
});
|
|
3044
|
-
|
|
2604
|
+
computed = ctx.normalizer.normalizeStyleMap(res.styles);
|
|
2605
|
+
if (res.unknown.length > 0) meta.hasUnresolvedClasses = true;
|
|
3045
2606
|
for (const w of res.warnings) {
|
|
3046
2607
|
diagnostics.push({
|
|
3047
2608
|
code: "DF_STYLE_CONFLICT_UNRESOLVED",
|
|
@@ -3059,7 +2620,7 @@ function doParse(code, ctx) {
|
|
|
3059
2620
|
isComponent: component,
|
|
3060
2621
|
selfClosing: opening.selfClosing,
|
|
3061
2622
|
classes,
|
|
3062
|
-
computed
|
|
2623
|
+
computed,
|
|
3063
2624
|
attrs,
|
|
3064
2625
|
children,
|
|
3065
2626
|
parent: parentId,
|
|
@@ -3068,13 +2629,13 @@ function doParse(code, ctx) {
|
|
|
3068
2629
|
});
|
|
3069
2630
|
doc.nodes.set(id, el);
|
|
3070
2631
|
const inner = children.length > 0 ? spanOf(node.children[0]) && spanOf(node.children.at(-1)) ? {
|
|
3071
|
-
file:
|
|
2632
|
+
file: FILE_ID2,
|
|
3072
2633
|
start: spanOf(node.children[0]).start,
|
|
3073
2634
|
end: spanOf(node.children.at(-1)).end
|
|
3074
2635
|
} : null : null;
|
|
3075
2636
|
backref.set(id, {
|
|
3076
2637
|
nodeId: id,
|
|
3077
|
-
span: spanOf(node) ?? { file:
|
|
2638
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
3078
2639
|
openTagSpan: spanOf(opening),
|
|
3079
2640
|
closeTagSpan: node.closingElement ? spanOf(node.closingElement) : null,
|
|
3080
2641
|
innerSpan: inner,
|
|
@@ -3084,13 +2645,13 @@ function doParse(code, ctx) {
|
|
|
3084
2645
|
};
|
|
3085
2646
|
const roots = [];
|
|
3086
2647
|
traverse(ast, {
|
|
3087
|
-
JSXElement(
|
|
3088
|
-
roots.push(
|
|
3089
|
-
|
|
2648
|
+
JSXElement(path5) {
|
|
2649
|
+
roots.push(path5.node);
|
|
2650
|
+
path5.skip();
|
|
3090
2651
|
},
|
|
3091
|
-
JSXFragment(
|
|
3092
|
-
roots.push(
|
|
3093
|
-
|
|
2652
|
+
JSXFragment(path5) {
|
|
2653
|
+
roots.push(path5.node);
|
|
2654
|
+
path5.skip();
|
|
3094
2655
|
}
|
|
3095
2656
|
});
|
|
3096
2657
|
const rootFrag = doc.nodes.get(doc.root);
|
|
@@ -3109,7 +2670,7 @@ var jsxFrontend = {
|
|
|
3109
2670
|
return looksLikeJsx(id, code);
|
|
3110
2671
|
},
|
|
3111
2672
|
parse(code, ctx) {
|
|
3112
|
-
return
|
|
2673
|
+
return doParse2(code, ctx);
|
|
3113
2674
|
}
|
|
3114
2675
|
};
|
|
3115
2676
|
function createJsxFrontend() {
|
|
@@ -3118,7 +2679,7 @@ function createJsxFrontend() {
|
|
|
3118
2679
|
|
|
3119
2680
|
// ../frontend-jsx/src/backend.ts
|
|
3120
2681
|
init_esm_shims();
|
|
3121
|
-
import
|
|
2682
|
+
import MagicString2 from "magic-string";
|
|
3122
2683
|
var JSX_LANGS2 = ["jsx", "tsx"];
|
|
3123
2684
|
function exprText(doc, ref) {
|
|
3124
2685
|
const rec = doc.exprs.get(ref);
|
|
@@ -3132,20 +2693,20 @@ function exprText(doc, ref) {
|
|
|
3132
2693
|
}
|
|
3133
2694
|
return { text: "", spread: false };
|
|
3134
2695
|
}
|
|
3135
|
-
function
|
|
2696
|
+
function staticTokensOf2(classes) {
|
|
3136
2697
|
const out = [];
|
|
3137
2698
|
for (const seg of classes.segments) {
|
|
3138
2699
|
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
3139
2700
|
}
|
|
3140
2701
|
return out;
|
|
3141
2702
|
}
|
|
3142
|
-
function
|
|
2703
|
+
function primarySource2(doc) {
|
|
3143
2704
|
for (const sf of doc.sources.values()) {
|
|
3144
2705
|
if (typeof sf.text === "string" && sf.text.length > 0) return sf;
|
|
3145
2706
|
}
|
|
3146
2707
|
return null;
|
|
3147
2708
|
}
|
|
3148
|
-
function
|
|
2709
|
+
function collectKept2(doc) {
|
|
3149
2710
|
const out = [];
|
|
3150
2711
|
const seen = /* @__PURE__ */ new Set();
|
|
3151
2712
|
const visit = (id) => {
|
|
@@ -3159,15 +2720,15 @@ function collectKept(doc) {
|
|
|
3159
2720
|
visit(doc.root);
|
|
3160
2721
|
return out;
|
|
3161
2722
|
}
|
|
3162
|
-
function
|
|
2723
|
+
function strictlyContains2(a, b) {
|
|
3163
2724
|
if (a.file !== b.file) return false;
|
|
3164
2725
|
if (a.start <= b.start && b.end <= a.end) return !(a.start === b.start && a.end === b.end);
|
|
3165
2726
|
return false;
|
|
3166
2727
|
}
|
|
3167
|
-
function
|
|
2728
|
+
function editClasses2(ms, doc, sf, el) {
|
|
3168
2729
|
const classes = el.classes;
|
|
3169
2730
|
if (classes.hasDynamic || classes.opaque) return false;
|
|
3170
|
-
const tokens =
|
|
2731
|
+
const tokens = staticTokensOf2(classes);
|
|
3171
2732
|
const valueSpan = classes.valueSpan;
|
|
3172
2733
|
if (valueSpan && valueSpan.file === sf.id) {
|
|
3173
2734
|
const current = sf.text.slice(valueSpan.start, valueSpan.end);
|
|
@@ -3231,10 +2792,10 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
|
|
|
3231
2792
|
const inside = [];
|
|
3232
2793
|
for (const n of kept) {
|
|
3233
2794
|
if (n.kind !== "element" || !n.span || n.span.file !== sf.id) continue;
|
|
3234
|
-
if (
|
|
2795
|
+
if (strictlyContains2(region.span, n.span)) inside.push(n);
|
|
3235
2796
|
}
|
|
3236
2797
|
const maximal = inside.filter(
|
|
3237
|
-
(n) => !inside.some((o) => o !== n && o.span && n.span &&
|
|
2798
|
+
(n) => !inside.some((o) => o !== n && o.span && n.span && strictlyContains2(o.span, n.span))
|
|
3238
2799
|
);
|
|
3239
2800
|
if (maximal.length !== 1) return;
|
|
3240
2801
|
const child = maximal[0];
|
|
@@ -3243,25 +2804,25 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
|
|
|
3243
2804
|
if (extractKeyAttr(sf.text.slice(childOpen.start, childOpen.end))) return;
|
|
3244
2805
|
ms.appendLeft(childOpen.start + 1 + child.tag.length, ` ${keyAttr}`);
|
|
3245
2806
|
}
|
|
3246
|
-
function
|
|
3247
|
-
const sf =
|
|
2807
|
+
function surgicalPrint2(doc) {
|
|
2808
|
+
const sf = primarySource2(doc);
|
|
3248
2809
|
if (!sf) return null;
|
|
3249
|
-
const ms = new
|
|
3250
|
-
const kept =
|
|
2810
|
+
const ms = new MagicString2(sf.text);
|
|
2811
|
+
const kept = collectKept2(doc);
|
|
3251
2812
|
const keptSpans = [];
|
|
3252
2813
|
for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
|
|
3253
2814
|
const removed = [];
|
|
3254
|
-
for (const id of
|
|
2815
|
+
for (const id of backrefIds2(doc)) {
|
|
3255
2816
|
if (doc.nodes.has(id)) continue;
|
|
3256
2817
|
const back = doc.backref.get(id);
|
|
3257
2818
|
if (!back || back.span.file !== sf.id) continue;
|
|
3258
|
-
const unwrapped = keptSpans.some((k) =>
|
|
2819
|
+
const unwrapped = keptSpans.some((k) => strictlyContains2(back.span, k));
|
|
3259
2820
|
removed.push({ backref: back, unwrapped });
|
|
3260
2821
|
}
|
|
3261
2822
|
const fullRemovals = removed.filter((r) => !r.unwrapped).map((r) => r.backref.span);
|
|
3262
2823
|
for (const r of removed) {
|
|
3263
|
-
const
|
|
3264
|
-
const coveredByFull = fullRemovals.some((f) => f !==
|
|
2824
|
+
const span2 = r.backref.span;
|
|
2825
|
+
const coveredByFull = fullRemovals.some((f) => f !== span2 && strictlyContains2(f, span2));
|
|
3265
2826
|
if (coveredByFull) continue;
|
|
3266
2827
|
if (r.unwrapped) {
|
|
3267
2828
|
transferKeyOnUnwrap(ms, doc, sf, r.backref, kept);
|
|
@@ -3272,15 +2833,15 @@ function surgicalPrint(doc) {
|
|
|
3272
2833
|
ms.remove(close.start, close.end);
|
|
3273
2834
|
}
|
|
3274
2835
|
} else {
|
|
3275
|
-
ms.remove(
|
|
2836
|
+
ms.remove(span2.start, span2.end);
|
|
3276
2837
|
}
|
|
3277
2838
|
}
|
|
3278
2839
|
for (const n of kept) {
|
|
3279
|
-
if (n.kind === "element")
|
|
2840
|
+
if (n.kind === "element") editClasses2(ms, doc, sf, n);
|
|
3280
2841
|
}
|
|
3281
2842
|
return ms.toString();
|
|
3282
2843
|
}
|
|
3283
|
-
function
|
|
2844
|
+
function backrefIds2(doc) {
|
|
3284
2845
|
const out = [];
|
|
3285
2846
|
const max = doc.alloc.peek;
|
|
3286
2847
|
for (let i = 1; i < max; i += 1) {
|
|
@@ -3295,7 +2856,7 @@ function classText(doc, classes) {
|
|
|
3295
2856
|
if (dynamic && dynamic.kind === "dynamic") {
|
|
3296
2857
|
return `className={${exprText(doc, dynamic.expr).text}}`;
|
|
3297
2858
|
}
|
|
3298
|
-
const tokens =
|
|
2859
|
+
const tokens = staticTokensOf2(classes);
|
|
3299
2860
|
return `className="${tokens.join(" ")}"`;
|
|
3300
2861
|
}
|
|
3301
2862
|
function attrText(doc, name, value) {
|
|
@@ -3348,15 +2909,15 @@ function rePrint(doc) {
|
|
|
3348
2909
|
if (!root || root.kind !== "fragment") return printNode(doc, doc.root);
|
|
3349
2910
|
return root.children.map((c) => printNode(doc, c)).join("");
|
|
3350
2911
|
}
|
|
3351
|
-
function
|
|
3352
|
-
const surgical =
|
|
2912
|
+
function doPrint2(doc) {
|
|
2913
|
+
const surgical = surgicalPrint2(doc);
|
|
3353
2914
|
return surgical ?? rePrint(doc);
|
|
3354
2915
|
}
|
|
3355
2916
|
var jsxBackend = {
|
|
3356
2917
|
name: "babel-jsx",
|
|
3357
2918
|
langs: JSX_LANGS2,
|
|
3358
2919
|
print(doc, _plan, _ctx) {
|
|
3359
|
-
const code =
|
|
2920
|
+
const code = doPrint2(doc);
|
|
3360
2921
|
return { code, map: null, edits: [], diagnostics: [] };
|
|
3361
2922
|
}
|
|
3362
2923
|
};
|
|
@@ -3368,32 +2929,20 @@ function createJsxBackend() {
|
|
|
3368
2929
|
init_esm_shims();
|
|
3369
2930
|
|
|
3370
2931
|
export {
|
|
2932
|
+
flexCenterWrapper,
|
|
2933
|
+
redundantFragment,
|
|
2934
|
+
gridCenterWrapper,
|
|
3371
2935
|
displayContentsWrapper,
|
|
3372
2936
|
emptyStyleDiv,
|
|
3373
|
-
|
|
3374
|
-
inlineFlexCenterWrapper,
|
|
3375
|
-
nestedFlexMerge,
|
|
3376
|
-
nestedGridMerge,
|
|
2937
|
+
inheritedOnlyWrapper,
|
|
3377
2938
|
passthroughWrapper,
|
|
3378
|
-
redundantFragment,
|
|
3379
2939
|
redundantInlineWrapper,
|
|
3380
|
-
borderRadiusShorthand,
|
|
3381
|
-
borderShorthand,
|
|
3382
|
-
dedupeClasses,
|
|
3383
|
-
gapShorthand,
|
|
3384
|
-
insetShorthand,
|
|
3385
|
-
marginShorthand,
|
|
3386
|
-
overflowShorthand,
|
|
3387
|
-
overscrollBehaviorShorthand,
|
|
3388
|
-
paddingShorthand,
|
|
3389
|
-
placeShorthand,
|
|
3390
|
-
scrollMarginShorthand,
|
|
3391
|
-
scrollPaddingShorthand,
|
|
3392
|
-
sizeShorthand,
|
|
3393
2940
|
builtinPatterns,
|
|
3394
2941
|
createTailwindResolver,
|
|
3395
2942
|
createCssResolver,
|
|
2943
|
+
createHtmlFrontend,
|
|
2944
|
+
createHtmlBackend,
|
|
3396
2945
|
createJsxFrontend,
|
|
3397
2946
|
createJsxBackend
|
|
3398
2947
|
};
|
|
3399
|
-
//# sourceMappingURL=chunk-
|
|
2948
|
+
//# sourceMappingURL=chunk-FPT4EJ6Q.js.map
|