domflax 0.1.1 → 0.1.4
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 +25 -8
- package/dist/{chunk-DNHOGPYV.js → chunk-3Z5ZWLXX.js} +407 -51
- package/dist/chunk-3Z5ZWLXX.js.map +1 -0
- package/dist/{chunk-DOQEBGWB.js → chunk-5FWENSD2.js} +63 -8
- package/dist/chunk-5FWENSD2.js.map +1 -0
- package/dist/chunk-EVENAJYI.js +336 -0
- package/dist/chunk-EVENAJYI.js.map +1 -0
- package/dist/{chunk-DWLB7FRR.js → chunk-H5KTGI3A.js} +153 -7
- package/dist/chunk-H5KTGI3A.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 +1033 -178
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +285 -243
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +614 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -18
- package/dist/index.d.ts +34 -18
- package/dist/index.js +4 -4
- package/dist/{pattern-F5xBtIE-.d.cts → pattern-CP9_HpVK.d.cts} +1 -1
- package/dist/{pattern-CV607P87.d.ts → pattern-CYgsv-jO.d.ts} +1 -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/{resolve-ops-DIwEelH-.d.ts → resolve-ops-Ci7LgYHC.d.cts} +9 -0
- package/dist/{resolve-ops-DIwEelH-.d.cts → resolve-ops-Ci7LgYHC.d.ts} +9 -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 +614 -68
- package/dist/webpack-loader.cjs.map +1 -1
- package/dist/webpack-loader.d.cts +2 -2
- package/dist/webpack-loader.d.ts +2 -2
- package/dist/webpack-loader.js +4 -4
- package/dist/worker.cjs +5955 -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.map +0 -1
- package/dist/chunk-DWLB7FRR.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { e as IRDocument, d as RewriteOp, I as IRNodeId, h as StyleResolver, g as SelectorIndex, f as SafetyLevel, l as PassPhase, r as RewriteFactory, i as Diagnostic, c as StyleNormalizer, R as RewriteOpDraft, j as SyntheticSink } from './resolve-ops-
|
|
2
|
-
export { A as AttrMap, Q as AttrValue, y as Backref, B as BackrefTable, T as Brand, w as ClassList, U as ClassListForm, W as ClassSegment, X as ClassToken, Y as CommentSpec, u as ConditionKey, C as CssProperty, Z as CssValue, _ as DeclSignature, o as DeepReadonly, D as DiagnosticCode, $ as DistributiveOmit, E as ElementLike, a0 as ElementSpec, a1 as EmitContext, a2 as EmitResult, a3 as ExprKind, a4 as ExprRecord, H as ExprRef, K as ExprRegistry, a5 as ExprSpec, F as FileKind, a6 as FragmentSpec, G as FrontendKind, z as IRComment, p as IRElement, J as IRExpr, L as IRFragment, v as IRNamespace, q as IRNode, a7 as IRNodeBase, a8 as IRNodeKind, O as IRText, M as IdAllocator, a9 as InheritedPropertyTable, x as InlineStyle, N as NodeLike, n as NodeMeta, aa as NodeRefSpec, b as NodeSpec, ab as OpOrigin, ac as OpaqueReason, ad as OpaqueToken, m as PassCategory, ae as PassTraceEntry, P as PatternName, af as Position, s as Reporter, ag as ResolveInput, ah as ResolveResult, ai as ResolverDiagnostic, aj as SelectorUsage, ak as Severity, al as SourceFile, am as SourceFileId, k as SourceSpan, an as StyleBlock, t as StyleCondition, a as StyleConflictPolicy, ao as StyleDecl, S as StyleMap, ap as StyleOrigin, aq as SyntheticClass, ar as TextSpec, as as VisitContext, at as VisitSignal, V as Visitor } from './resolve-ops-
|
|
3
|
-
import { y as ApplyResult, z as RewriteGroup, B as ApplyContext, C as MatchContext, E as FixpointConfig, H as HaltReason, G as Pass, I as PassManager, J as Pattern, K as PhaseRunResult, L as Pipeline, A as AuthoredPattern, N as Captures, O as EncodedSourceMap } from './pattern-
|
|
4
|
-
export { Q as AppliedOp, S as BASE_CONDITION, U as BASE_CONDITION_KEY, V as Backend, W as BackendContext, X as CodegenResult, Y as EditPlan, Z as ElementInit, _ as FlattenGate, $ as Frontend, a0 as FrontendConfig, a1 as FrontendParseContext, a2 as MatchResult, a3 as MutableBackrefTable, a4 as OpValidationIssue, a5 as ParentLayoutContext, a6 as ParseResult, a7 as PatternDoc, a8 as PipelineConfig, a9 as PipelineInput, aa as PipelineOutput, ab as PipelineStats, ac as PreconditionSketch, ad as ReindentSpec, ae as RewriteContext, af as SkippedOpGroup, ag as StructuralInverse, ah as StylePredicate, ai as TextEdit, aj as TreeShapeSketch, ak as childIds, al as conditionKey, am as createBackrefTable, an as createComment, ao as createDocument, ap as createElement, aq as createExpr, ar as createExprRegistry, as as createFragment, at as createIdAllocator, au as createText, av as defaultMeta, aw as elementIds, ax as emptyAttrMap, ay as emptyClassList, az as emptyInlineStyle, l as emptyStyleMap, aA as getElement, aB as getNode, aC as walk } from './pattern-
|
|
1
|
+
import { e as IRDocument, d as RewriteOp, I as IRNodeId, h as StyleResolver, g as SelectorIndex, f as SafetyLevel, l as PassPhase, r as RewriteFactory, i as Diagnostic, c as StyleNormalizer, R as RewriteOpDraft, j as SyntheticSink } from './resolve-ops-Ci7LgYHC.cjs';
|
|
2
|
+
export { A as AttrMap, Q as AttrValue, y as Backref, B as BackrefTable, T as Brand, w as ClassList, U as ClassListForm, W as ClassSegment, X as ClassToken, Y as CommentSpec, u as ConditionKey, C as CssProperty, Z as CssValue, _ as DeclSignature, o as DeepReadonly, D as DiagnosticCode, $ as DistributiveOmit, E as ElementLike, a0 as ElementSpec, a1 as EmitContext, a2 as EmitResult, a3 as ExprKind, a4 as ExprRecord, H as ExprRef, K as ExprRegistry, a5 as ExprSpec, F as FileKind, a6 as FragmentSpec, G as FrontendKind, z as IRComment, p as IRElement, J as IRExpr, L as IRFragment, v as IRNamespace, q as IRNode, a7 as IRNodeBase, a8 as IRNodeKind, O as IRText, M as IdAllocator, a9 as InheritedPropertyTable, x as InlineStyle, N as NodeLike, n as NodeMeta, aa as NodeRefSpec, b as NodeSpec, ab as OpOrigin, ac as OpaqueReason, ad as OpaqueToken, m as PassCategory, ae as PassTraceEntry, P as PatternName, af as Position, s as Reporter, ag as ResolveInput, ah as ResolveResult, ai as ResolverDiagnostic, aj as SelectorUsage, ak as Severity, al as SourceFile, am as SourceFileId, k as SourceSpan, an as StyleBlock, t as StyleCondition, a as StyleConflictPolicy, ao as StyleDecl, S as StyleMap, ap as StyleOrigin, aq as SyntheticClass, ar as TextSpec, as as VisitContext, at as VisitSignal, V as Visitor } from './resolve-ops-Ci7LgYHC.cjs';
|
|
3
|
+
import { y as ApplyResult, z as RewriteGroup, B as ApplyContext, C as MatchContext, E as FixpointConfig, H as HaltReason, G as Pass, I as PassManager, J as Pattern, K as PhaseRunResult, L as Pipeline, A as AuthoredPattern, N as Captures, O as EncodedSourceMap } from './pattern-CP9_HpVK.cjs';
|
|
4
|
+
export { Q as AppliedOp, S as BASE_CONDITION, U as BASE_CONDITION_KEY, V as Backend, W as BackendContext, X as CodegenResult, Y as EditPlan, Z as ElementInit, _ as FlattenGate, $ as Frontend, a0 as FrontendConfig, a1 as FrontendParseContext, a2 as MatchResult, a3 as MutableBackrefTable, a4 as OpValidationIssue, a5 as ParentLayoutContext, a6 as ParseResult, a7 as PatternDoc, a8 as PipelineConfig, a9 as PipelineInput, aa as PipelineOutput, ab as PipelineStats, ac as PreconditionSketch, ad as ReindentSpec, ae as RewriteContext, af as SkippedOpGroup, ag as StructuralInverse, ah as StylePredicate, ai as TextEdit, aj as TreeShapeSketch, ak as childIds, al as conditionKey, am as createBackrefTable, an as createComment, ao as createDocument, ap as createElement, aq as createExpr, ar as createExprRegistry, as as createFragment, at as createIdAllocator, au as createText, av as defaultMeta, aw as elementIds, ax as emptyAttrMap, ay as emptyClassList, az as emptyInlineStyle, l as emptyStyleMap, aA as getElement, aB as getNode, aC as walk } from './pattern-CP9_HpVK.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @domflax/core — applier runtime helpers (shared by the per-op handlers in `./apply`).
|
|
@@ -201,13 +201,29 @@ declare function createPipeline(): Pipeline;
|
|
|
201
201
|
* orchestrator (the `domflax` meta package, `@domflax/cli`, and the pattern auto-test harness) so
|
|
202
202
|
* their pipelines cannot diverge.
|
|
203
203
|
*
|
|
204
|
-
* ##
|
|
204
|
+
* ## Only STYLE-DIRTY elements are re-emitted (never inflate a bystander)
|
|
205
205
|
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
206
|
+
* Reverse-emit runs ONLY on elements a pass actually rewrote the computed style of — `meta.styleDirty`
|
|
207
|
+
* (a `setClassList`, a `mergeStyle` onto it, or an inherited fold into it). An element that was merely
|
|
208
|
+
* `touched` as a STRUCTURAL BYSTANDER — a child was flattened/unwrapped, a sibling merged/moved, a
|
|
209
|
+
* node inserted next to it — never has its own computed changed, so its `class` attribute is left
|
|
210
|
+
* BYTE-FOR-BYTE IDENTICAL. This is what stops a real custom-CSS site from INFLATING: an unchanged
|
|
211
|
+
* `<div class="product-art">` can no longer gain a redundant `.bg-cream-deep` just because an inert
|
|
212
|
+
* child next to it was flattened.
|
|
213
|
+
*
|
|
214
|
+
* ## REPLACE, not append — with retained-class coverage SUBTRACTED
|
|
215
|
+
*
|
|
216
|
+
* For every style-dirty, rewritable (non-opaque, non-dynamic) element we ask the resolver for the
|
|
217
|
+
* MINIMAL class set reproducing the element's computed style, then REPLACE the element's droppable
|
|
218
|
+
* tokens with it — rather than appending. Replacing is what lets a compress pass actually shorten
|
|
219
|
+
* output: `px-4 py-4` collapses to `p-4`, equal `w/h` to `size-*`, the four insets to `inset-0`, and
|
|
220
|
+
* fully-overridden duplicates simply disappear.
|
|
221
|
+
*
|
|
222
|
+
* Crucially, before choosing what to emit we SUBTRACT the style already supplied by the element's
|
|
223
|
+
* RETAINED (kept, non-droppable) classes: we emit only for the RESIDUAL declarations those classes do
|
|
224
|
+
* not already reproduce. So reverse-emit can never materialize a utility for a property a semantic
|
|
225
|
+
* class the element keeps already sets (the `.product-art` background is never re-added as
|
|
226
|
+
* `.bg-cream-deep`). Output therefore never grows with a class whose contribution is already covered.
|
|
211
227
|
*
|
|
212
228
|
* ## Droppability gate (never lose a load-bearing class)
|
|
213
229
|
*
|
|
@@ -215,12 +231,13 @@ declare function createPipeline(): Pipeline;
|
|
|
215
231
|
* plain, resolver-owned utility whose entire contribution is reproducible from `computed`. Tokens
|
|
216
232
|
* that are unknown to the resolver, opaque (combinator/at-rule utilities whose effect never folds
|
|
217
233
|
* onto the element's own box), variant-bound, or referenced by a custom-CSS selector are NOT
|
|
218
|
-
* droppable and are preserved verbatim. As a safety net, if `emit` produces nothing at
|
|
219
|
-
* the element's tokens untouched (a resolver that failed to load must never erase
|
|
234
|
+
* droppable and are preserved verbatim. As a safety net, if the residual `emit` produces nothing at
|
|
235
|
+
* all we leave the element's tokens untouched (a resolver that failed to load must never erase
|
|
236
|
+
* classes).
|
|
220
237
|
*/
|
|
221
238
|
|
|
222
239
|
/**
|
|
223
|
-
* Fold every
|
|
240
|
+
* Fold every STYLE-DIRTY, rewritable element's optimized computed style back into the MINIMAL static
|
|
224
241
|
* class-token set (see module docs). Mutates `doc` in place.
|
|
225
242
|
*/
|
|
226
243
|
declare function syncClassesFromComputed(doc: IRDocument, resolver: StyleResolver, norm: StyleNormalizer): void;
|
|
@@ -814,13 +831,12 @@ declare const builtinPatterns: readonly Pattern[];
|
|
|
814
831
|
* `@domflax/patterns` library, then layers thin, framework-agnostic build adapters on top
|
|
815
832
|
* (`vite()` / `webpack()`) plus a programmatic `createDomflax()` factory.
|
|
816
833
|
*
|
|
817
|
-
* Each adapter runs the SAME single-file engine as {@link createDomflax} (JSX/TSX
|
|
818
|
-
* Tailwind/CSS resolver → core pass manager → reverse-emit →
|
|
834
|
+
* Each adapter runs the SAME single-file engine as {@link createDomflax} (JSX/TSX + HTML frontends +
|
|
835
|
+
* lazy Tailwind/CSS resolver → core pass manager → reverse-emit → surgical backend). The adapters are
|
|
819
836
|
* structurally typed against their bundlers — they never hard-depend on `vite` or `webpack`.
|
|
820
837
|
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
* - `@domflax/backend-*` — additional surgical codegen backends.
|
|
838
|
+
* `.jsx`/`.tsx` route to `@domflax/frontend-jsx` (Babel); `.html`/`.htm` route to
|
|
839
|
+
* `@domflax/frontend-html` (parse5). Both emit via SURGICAL span edits over the original source.
|
|
824
840
|
*/
|
|
825
841
|
|
|
826
842
|
/** How class names resolve to computed styles. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { e as IRDocument, d as RewriteOp, I as IRNodeId, h as StyleResolver, g as SelectorIndex, f as SafetyLevel, l as PassPhase, r as RewriteFactory, i as Diagnostic, c as StyleNormalizer, R as RewriteOpDraft, j as SyntheticSink } from './resolve-ops-
|
|
2
|
-
export { A as AttrMap, Q as AttrValue, y as Backref, B as BackrefTable, T as Brand, w as ClassList, U as ClassListForm, W as ClassSegment, X as ClassToken, Y as CommentSpec, u as ConditionKey, C as CssProperty, Z as CssValue, _ as DeclSignature, o as DeepReadonly, D as DiagnosticCode, $ as DistributiveOmit, E as ElementLike, a0 as ElementSpec, a1 as EmitContext, a2 as EmitResult, a3 as ExprKind, a4 as ExprRecord, H as ExprRef, K as ExprRegistry, a5 as ExprSpec, F as FileKind, a6 as FragmentSpec, G as FrontendKind, z as IRComment, p as IRElement, J as IRExpr, L as IRFragment, v as IRNamespace, q as IRNode, a7 as IRNodeBase, a8 as IRNodeKind, O as IRText, M as IdAllocator, a9 as InheritedPropertyTable, x as InlineStyle, N as NodeLike, n as NodeMeta, aa as NodeRefSpec, b as NodeSpec, ab as OpOrigin, ac as OpaqueReason, ad as OpaqueToken, m as PassCategory, ae as PassTraceEntry, P as PatternName, af as Position, s as Reporter, ag as ResolveInput, ah as ResolveResult, ai as ResolverDiagnostic, aj as SelectorUsage, ak as Severity, al as SourceFile, am as SourceFileId, k as SourceSpan, an as StyleBlock, t as StyleCondition, a as StyleConflictPolicy, ao as StyleDecl, S as StyleMap, ap as StyleOrigin, aq as SyntheticClass, ar as TextSpec, as as VisitContext, at as VisitSignal, V as Visitor } from './resolve-ops-
|
|
3
|
-
import { y as ApplyResult, z as RewriteGroup, B as ApplyContext, C as MatchContext, E as FixpointConfig, H as HaltReason, G as Pass, I as PassManager, J as Pattern, K as PhaseRunResult, L as Pipeline, A as AuthoredPattern, N as Captures, O as EncodedSourceMap } from './pattern-
|
|
4
|
-
export { Q as AppliedOp, S as BASE_CONDITION, U as BASE_CONDITION_KEY, V as Backend, W as BackendContext, X as CodegenResult, Y as EditPlan, Z as ElementInit, _ as FlattenGate, $ as Frontend, a0 as FrontendConfig, a1 as FrontendParseContext, a2 as MatchResult, a3 as MutableBackrefTable, a4 as OpValidationIssue, a5 as ParentLayoutContext, a6 as ParseResult, a7 as PatternDoc, a8 as PipelineConfig, a9 as PipelineInput, aa as PipelineOutput, ab as PipelineStats, ac as PreconditionSketch, ad as ReindentSpec, ae as RewriteContext, af as SkippedOpGroup, ag as StructuralInverse, ah as StylePredicate, ai as TextEdit, aj as TreeShapeSketch, ak as childIds, al as conditionKey, am as createBackrefTable, an as createComment, ao as createDocument, ap as createElement, aq as createExpr, ar as createExprRegistry, as as createFragment, at as createIdAllocator, au as createText, av as defaultMeta, aw as elementIds, ax as emptyAttrMap, ay as emptyClassList, az as emptyInlineStyle, l as emptyStyleMap, aA as getElement, aB as getNode, aC as walk } from './pattern-
|
|
1
|
+
import { e as IRDocument, d as RewriteOp, I as IRNodeId, h as StyleResolver, g as SelectorIndex, f as SafetyLevel, l as PassPhase, r as RewriteFactory, i as Diagnostic, c as StyleNormalizer, R as RewriteOpDraft, j as SyntheticSink } from './resolve-ops-Ci7LgYHC.js';
|
|
2
|
+
export { A as AttrMap, Q as AttrValue, y as Backref, B as BackrefTable, T as Brand, w as ClassList, U as ClassListForm, W as ClassSegment, X as ClassToken, Y as CommentSpec, u as ConditionKey, C as CssProperty, Z as CssValue, _ as DeclSignature, o as DeepReadonly, D as DiagnosticCode, $ as DistributiveOmit, E as ElementLike, a0 as ElementSpec, a1 as EmitContext, a2 as EmitResult, a3 as ExprKind, a4 as ExprRecord, H as ExprRef, K as ExprRegistry, a5 as ExprSpec, F as FileKind, a6 as FragmentSpec, G as FrontendKind, z as IRComment, p as IRElement, J as IRExpr, L as IRFragment, v as IRNamespace, q as IRNode, a7 as IRNodeBase, a8 as IRNodeKind, O as IRText, M as IdAllocator, a9 as InheritedPropertyTable, x as InlineStyle, N as NodeLike, n as NodeMeta, aa as NodeRefSpec, b as NodeSpec, ab as OpOrigin, ac as OpaqueReason, ad as OpaqueToken, m as PassCategory, ae as PassTraceEntry, P as PatternName, af as Position, s as Reporter, ag as ResolveInput, ah as ResolveResult, ai as ResolverDiagnostic, aj as SelectorUsage, ak as Severity, al as SourceFile, am as SourceFileId, k as SourceSpan, an as StyleBlock, t as StyleCondition, a as StyleConflictPolicy, ao as StyleDecl, S as StyleMap, ap as StyleOrigin, aq as SyntheticClass, ar as TextSpec, as as VisitContext, at as VisitSignal, V as Visitor } from './resolve-ops-Ci7LgYHC.js';
|
|
3
|
+
import { y as ApplyResult, z as RewriteGroup, B as ApplyContext, C as MatchContext, E as FixpointConfig, H as HaltReason, G as Pass, I as PassManager, J as Pattern, K as PhaseRunResult, L as Pipeline, A as AuthoredPattern, N as Captures, O as EncodedSourceMap } from './pattern-CYgsv-jO.js';
|
|
4
|
+
export { Q as AppliedOp, S as BASE_CONDITION, U as BASE_CONDITION_KEY, V as Backend, W as BackendContext, X as CodegenResult, Y as EditPlan, Z as ElementInit, _ as FlattenGate, $ as Frontend, a0 as FrontendConfig, a1 as FrontendParseContext, a2 as MatchResult, a3 as MutableBackrefTable, a4 as OpValidationIssue, a5 as ParentLayoutContext, a6 as ParseResult, a7 as PatternDoc, a8 as PipelineConfig, a9 as PipelineInput, aa as PipelineOutput, ab as PipelineStats, ac as PreconditionSketch, ad as ReindentSpec, ae as RewriteContext, af as SkippedOpGroup, ag as StructuralInverse, ah as StylePredicate, ai as TextEdit, aj as TreeShapeSketch, ak as childIds, al as conditionKey, am as createBackrefTable, an as createComment, ao as createDocument, ap as createElement, aq as createExpr, ar as createExprRegistry, as as createFragment, at as createIdAllocator, au as createText, av as defaultMeta, aw as elementIds, ax as emptyAttrMap, ay as emptyClassList, az as emptyInlineStyle, l as emptyStyleMap, aA as getElement, aB as getNode, aC as walk } from './pattern-CYgsv-jO.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @domflax/core — applier runtime helpers (shared by the per-op handlers in `./apply`).
|
|
@@ -201,13 +201,29 @@ declare function createPipeline(): Pipeline;
|
|
|
201
201
|
* orchestrator (the `domflax` meta package, `@domflax/cli`, and the pattern auto-test harness) so
|
|
202
202
|
* their pipelines cannot diverge.
|
|
203
203
|
*
|
|
204
|
-
* ##
|
|
204
|
+
* ## Only STYLE-DIRTY elements are re-emitted (never inflate a bystander)
|
|
205
205
|
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
206
|
+
* Reverse-emit runs ONLY on elements a pass actually rewrote the computed style of — `meta.styleDirty`
|
|
207
|
+
* (a `setClassList`, a `mergeStyle` onto it, or an inherited fold into it). An element that was merely
|
|
208
|
+
* `touched` as a STRUCTURAL BYSTANDER — a child was flattened/unwrapped, a sibling merged/moved, a
|
|
209
|
+
* node inserted next to it — never has its own computed changed, so its `class` attribute is left
|
|
210
|
+
* BYTE-FOR-BYTE IDENTICAL. This is what stops a real custom-CSS site from INFLATING: an unchanged
|
|
211
|
+
* `<div class="product-art">` can no longer gain a redundant `.bg-cream-deep` just because an inert
|
|
212
|
+
* child next to it was flattened.
|
|
213
|
+
*
|
|
214
|
+
* ## REPLACE, not append — with retained-class coverage SUBTRACTED
|
|
215
|
+
*
|
|
216
|
+
* For every style-dirty, rewritable (non-opaque, non-dynamic) element we ask the resolver for the
|
|
217
|
+
* MINIMAL class set reproducing the element's computed style, then REPLACE the element's droppable
|
|
218
|
+
* tokens with it — rather than appending. Replacing is what lets a compress pass actually shorten
|
|
219
|
+
* output: `px-4 py-4` collapses to `p-4`, equal `w/h` to `size-*`, the four insets to `inset-0`, and
|
|
220
|
+
* fully-overridden duplicates simply disappear.
|
|
221
|
+
*
|
|
222
|
+
* Crucially, before choosing what to emit we SUBTRACT the style already supplied by the element's
|
|
223
|
+
* RETAINED (kept, non-droppable) classes: we emit only for the RESIDUAL declarations those classes do
|
|
224
|
+
* not already reproduce. So reverse-emit can never materialize a utility for a property a semantic
|
|
225
|
+
* class the element keeps already sets (the `.product-art` background is never re-added as
|
|
226
|
+
* `.bg-cream-deep`). Output therefore never grows with a class whose contribution is already covered.
|
|
211
227
|
*
|
|
212
228
|
* ## Droppability gate (never lose a load-bearing class)
|
|
213
229
|
*
|
|
@@ -215,12 +231,13 @@ declare function createPipeline(): Pipeline;
|
|
|
215
231
|
* plain, resolver-owned utility whose entire contribution is reproducible from `computed`. Tokens
|
|
216
232
|
* that are unknown to the resolver, opaque (combinator/at-rule utilities whose effect never folds
|
|
217
233
|
* onto the element's own box), variant-bound, or referenced by a custom-CSS selector are NOT
|
|
218
|
-
* droppable and are preserved verbatim. As a safety net, if `emit` produces nothing at
|
|
219
|
-
* the element's tokens untouched (a resolver that failed to load must never erase
|
|
234
|
+
* droppable and are preserved verbatim. As a safety net, if the residual `emit` produces nothing at
|
|
235
|
+
* all we leave the element's tokens untouched (a resolver that failed to load must never erase
|
|
236
|
+
* classes).
|
|
220
237
|
*/
|
|
221
238
|
|
|
222
239
|
/**
|
|
223
|
-
* Fold every
|
|
240
|
+
* Fold every STYLE-DIRTY, rewritable element's optimized computed style back into the MINIMAL static
|
|
224
241
|
* class-token set (see module docs). Mutates `doc` in place.
|
|
225
242
|
*/
|
|
226
243
|
declare function syncClassesFromComputed(doc: IRDocument, resolver: StyleResolver, norm: StyleNormalizer): void;
|
|
@@ -814,13 +831,12 @@ declare const builtinPatterns: readonly Pattern[];
|
|
|
814
831
|
* `@domflax/patterns` library, then layers thin, framework-agnostic build adapters on top
|
|
815
832
|
* (`vite()` / `webpack()`) plus a programmatic `createDomflax()` factory.
|
|
816
833
|
*
|
|
817
|
-
* Each adapter runs the SAME single-file engine as {@link createDomflax} (JSX/TSX
|
|
818
|
-
* Tailwind/CSS resolver → core pass manager → reverse-emit →
|
|
834
|
+
* Each adapter runs the SAME single-file engine as {@link createDomflax} (JSX/TSX + HTML frontends +
|
|
835
|
+
* lazy Tailwind/CSS resolver → core pass manager → reverse-emit → surgical backend). The adapters are
|
|
819
836
|
* structurally typed against their bundlers — they never hard-depend on `vite` or `webpack`.
|
|
820
837
|
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
* - `@domflax/backend-*` — additional surgical codegen backends.
|
|
838
|
+
* `.jsx`/`.tsx` route to `@domflax/frontend-jsx` (Babel); `.html`/`.htm` route to
|
|
839
|
+
* `@domflax/frontend-html` (parse5). Both emit via SURGICAL span edits over the original source.
|
|
824
840
|
*/
|
|
825
841
|
|
|
826
842
|
/** How class names resolve to computed styles. */
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
src_default,
|
|
4
4
|
vite,
|
|
5
5
|
webpack
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5FWENSD2.js";
|
|
7
7
|
import {
|
|
8
8
|
borderRadiusShorthand,
|
|
9
9
|
borderShorthand,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
scrollMarginShorthand,
|
|
29
29
|
scrollPaddingShorthand,
|
|
30
30
|
sizeShorthand
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-3Z5ZWLXX.js";
|
|
32
32
|
import {
|
|
33
33
|
BASE_CONDITION,
|
|
34
34
|
BASE_CONDITION_KEY,
|
|
@@ -76,8 +76,8 @@ import {
|
|
|
76
76
|
stampOrigin,
|
|
77
77
|
syncClassesFromComputed,
|
|
78
78
|
walk
|
|
79
|
-
} from "./chunk-
|
|
80
|
-
import "./chunk-
|
|
79
|
+
} from "./chunk-H5KTGI3A.js";
|
|
80
|
+
import "./chunk-U5GOONKV.js";
|
|
81
81
|
export {
|
|
82
82
|
BASE_CONDITION,
|
|
83
83
|
BASE_CONDITION_KEY,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as RewriteOp, e as IRDocument, f as SafetyLevel, c as StyleNormalizer, g as SelectorIndex, h as StyleResolver, I as IRNodeId, P as PatternName, D as DiagnosticCode, i as Diagnostic, F as FileKind, j as SyntheticSink, k as SourceSpan, l as PassPhase, m as PassCategory, n as NodeMeta, o as DeepReadonly, p as IRElement, S as StyleMap, N as NodeLike, E as ElementLike, q as IRNode, r as RewriteFactory, R as RewriteOpDraft, s as Reporter, t as StyleCondition, u as ConditionKey, v as IRNamespace, w as ClassList, x as InlineStyle, A as AttrMap, B as BackrefTable, y as Backref, z as IRComment, G as FrontendKind, H as ExprRef, J as IRExpr, K as ExprRegistry, L as IRFragment, M as IdAllocator, O as IRText, V as Visitor, a as StyleConflictPolicy } from './resolve-ops-
|
|
1
|
+
import { d as RewriteOp, e as IRDocument, f as SafetyLevel, c as StyleNormalizer, g as SelectorIndex, h as StyleResolver, I as IRNodeId, P as PatternName, D as DiagnosticCode, i as Diagnostic, F as FileKind, j as SyntheticSink, k as SourceSpan, l as PassPhase, m as PassCategory, n as NodeMeta, o as DeepReadonly, p as IRElement, S as StyleMap, N as NodeLike, E as ElementLike, q as IRNode, r as RewriteFactory, R as RewriteOpDraft, s as Reporter, t as StyleCondition, u as ConditionKey, v as IRNamespace, w as ClassList, x as InlineStyle, A as AttrMap, B as BackrefTable, y as Backref, z as IRComment, G as FrontendKind, H as ExprRef, J as IRExpr, K as ExprRegistry, L as IRFragment, M as IdAllocator, O as IRText, V as Visitor, a as StyleConflictPolicy } from './resolve-ops-Ci7LgYHC.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @domflax/core — type contract, part 3/3: the pattern contract + match/rewrite contexts, the pass
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as RewriteOp, e as IRDocument, f as SafetyLevel, c as StyleNormalizer, g as SelectorIndex, h as StyleResolver, I as IRNodeId, P as PatternName, D as DiagnosticCode, i as Diagnostic, F as FileKind, j as SyntheticSink, k as SourceSpan, l as PassPhase, m as PassCategory, n as NodeMeta, o as DeepReadonly, p as IRElement, S as StyleMap, N as NodeLike, E as ElementLike, q as IRNode, r as RewriteFactory, R as RewriteOpDraft, s as Reporter, t as StyleCondition, u as ConditionKey, v as IRNamespace, w as ClassList, x as InlineStyle, A as AttrMap, B as BackrefTable, y as Backref, z as IRComment, G as FrontendKind, H as ExprRef, J as IRExpr, K as ExprRegistry, L as IRFragment, M as IdAllocator, O as IRText, V as Visitor, a as StyleConflictPolicy } from './resolve-ops-
|
|
1
|
+
import { d as RewriteOp, e as IRDocument, f as SafetyLevel, c as StyleNormalizer, g as SelectorIndex, h as StyleResolver, I as IRNodeId, P as PatternName, D as DiagnosticCode, i as Diagnostic, F as FileKind, j as SyntheticSink, k as SourceSpan, l as PassPhase, m as PassCategory, n as NodeMeta, o as DeepReadonly, p as IRElement, S as StyleMap, N as NodeLike, E as ElementLike, q as IRNode, r as RewriteFactory, R as RewriteOpDraft, s as Reporter, t as StyleCondition, u as ConditionKey, v as IRNamespace, w as ClassList, x as InlineStyle, A as AttrMap, B as BackrefTable, y as Backref, z as IRComment, G as FrontendKind, H as ExprRef, J as IRExpr, K as ExprRegistry, L as IRFragment, M as IdAllocator, O as IRText, V as Visitor, a as StyleConflictPolicy } from './resolve-ops-Ci7LgYHC.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @domflax/core — type contract, part 3/3: the pattern contract + match/rewrite contexts, the pass
|
package/dist/pattern-kit.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pattern-kit.ts","../../core/src/builders.ts","../../pattern-kit/src/normalize.ts","../../pattern-kit/src/combinators.ts","../../pattern-kit/src/ops.ts","../../pattern-kit/src/define.ts","../../pattern-kit/src/pattern.ts"],"sourcesContent":["/**\n * `domflax/pattern-kit` — author custom flatten/compress patterns.\n *\n * Subpath export of the bundled (private) `@domflax/pattern-kit`: `definePattern`, the combinator\n * vocabulary, rewrite-op factories, and the shared style normalizer. Power-user surface; the happy\n * path is `import domflax from 'domflax'`.\n */\nexport * from '@domflax/pattern-kit';\n","/**\n * @domflax/core — runtime builders + traversal.\n *\n * Pure, dependency-free helpers to construct IR nodes, assemble an {@link IRDocument},\n * and walk the tree honouring {@link VisitSignal}. No heavy third-party deps: only the\n * type contract in `./types`.\n */\n\nimport type {\n AttrMap,\n Backref,\n BackrefTable,\n ClassList,\n ConditionKey,\n CssProperty,\n ExprRecord,\n ExprRef,\n ExprRegistry,\n FrontendKind,\n IdAllocator,\n IRComment,\n IRDocument,\n IRElement,\n IRExpr,\n IRFragment,\n IRNamespace,\n IRNode,\n IRNodeId,\n IRText,\n InlineStyle,\n NodeMeta,\n SafetyLevel,\n SourceSpan,\n StyleBlock,\n StyleCondition,\n StyleMap,\n Visitor,\n VisitContext,\n VisitSignal,\n} from './types';\n\n/* ───────────────────────── id / registry primitives ───────────────────────── */\n\n/** Monotonic IRNodeId allocator. `peek` reports the id `next()` would return. */\nexport function createIdAllocator(start = 1): IdAllocator {\n let n = start;\n return {\n next(): IRNodeId {\n const id = n;\n n += 1;\n return id as IRNodeId;\n },\n get peek(): IRNodeId {\n return n as IRNodeId;\n },\n };\n}\n\n/** Minimal in-memory ExprRegistry. */\nexport function createExprRegistry(start = 1): ExprRegistry {\n const map = new Map<ExprRef, ExprRecord>();\n let n = start;\n return {\n get(r: ExprRef): ExprRecord | undefined {\n return map.get(r);\n },\n intern(rec: Omit<ExprRecord, 'ref'>): ExprRef {\n const ref = n as ExprRef;\n n += 1;\n map.set(ref, { ...rec, ref });\n return ref;\n },\n releasePayloads(): void {\n for (const [k, v] of map) map.set(k, { ...v, payload: undefined });\n },\n };\n}\n\n/** Mutable BackrefTable: frontends register backrefs as they parse. */\nexport interface MutableBackrefTable extends BackrefTable {\n set(id: IRNodeId, backref: Backref): void;\n}\n\nexport function createBackrefTable(): MutableBackrefTable {\n const map = new Map<IRNodeId, Backref>();\n return {\n get(id: IRNodeId): Backref | undefined {\n return map.get(id);\n },\n span(id: IRNodeId): SourceSpan | null {\n return map.get(id)?.span ?? null;\n },\n childrenSpan(id: IRNodeId): SourceSpan | null {\n return map.get(id)?.innerSpan ?? null;\n },\n set(id: IRNodeId, backref: Backref): void {\n map.set(id, backref);\n },\n };\n}\n\n/* ───────────────────────── default sub-structures ───────────────────────── */\n\n/** A NodeMeta with every barrier/flag cleared. */\nexport function defaultMeta(safetyFloor: SafetyLevel = 0): NodeMeta {\n return {\n hasRef: false,\n hasEventHandlers: false,\n hasKey: false,\n hasSpreadAttrs: false,\n hasDynamicChildren: false,\n isComponent: false,\n hasDangerousHtml: false,\n targetedByCombinator: false,\n targetedByStructuralPseudo: false,\n selectorDependents: 0,\n hasOwnVisualStyle: false,\n establishesBox: false,\n establishesStackingContext: false,\n isContainingBlock: false,\n establishesFormattingContext: false,\n declaresCustomProperties: false,\n whitespaceSensitive: false,\n touched: false,\n synthetic: false,\n safetyFloor,\n };\n}\n\n/** Canonical base style condition (`media:'' states:[] pseudoElement:''`). */\nexport const BASE_CONDITION: StyleCondition = { media: '', states: [], pseudoElement: '' };\n\n/** Stable serialization of a StyleCondition into a ConditionKey. */\nexport function conditionKey(c: StyleCondition): ConditionKey {\n const states = [...c.states].sort().join(',');\n return `${c.media}|${states}|${c.pseudoElement}` as ConditionKey;\n}\n\nexport const BASE_CONDITION_KEY: ConditionKey = conditionKey(BASE_CONDITION);\n\n/** An empty StyleMap (no blocks). */\nexport function emptyStyleMap(): StyleMap {\n return { blocks: new Map<ConditionKey, StyleBlock>() };\n}\n\n/** An empty (absent) ClassList. */\nexport function emptyClassList(): ClassList {\n return {\n form: 'absent',\n segments: [],\n valueSpan: null,\n hasDynamic: false,\n opaque: false,\n rewritable: false,\n };\n}\n\n/** An empty AttrMap. */\nexport function emptyAttrMap(): AttrMap {\n return { entries: new Map(), spreads: [], order: [] };\n}\n\n/** An empty InlineStyle. */\nexport function emptyInlineStyle(): InlineStyle {\n return { decls: new Map<CssProperty, never>() as InlineStyle['decls'], dynamic: null };\n}\n\n/* ───────────────────────── node factories ───────────────────────── */\n\nexport interface ElementInit {\n readonly tag: string;\n readonly namespace?: IRNamespace;\n readonly isComponent?: boolean;\n readonly selfClosing?: boolean;\n readonly classes?: ClassList;\n readonly inlineStyle?: InlineStyle;\n readonly computed?: StyleMap;\n readonly attrs?: AttrMap;\n readonly children?: IRNodeId[];\n readonly parent?: IRNodeId | null;\n readonly span?: SourceSpan | null;\n readonly meta?: NodeMeta;\n}\n\nexport function createElement(id: IRNodeId, init: ElementInit): IRElement {\n return {\n id,\n kind: 'element',\n parent: init.parent ?? null,\n span: init.span ?? null,\n meta: init.meta ?? defaultMeta(),\n tag: init.tag,\n namespace: init.namespace ?? 'html',\n isComponent: init.isComponent ?? false,\n selfClosing: init.selfClosing ?? false,\n classes: init.classes ?? emptyClassList(),\n inlineStyle: init.inlineStyle ?? emptyInlineStyle(),\n computed: init.computed ?? emptyStyleMap(),\n attrs: init.attrs ?? emptyAttrMap(),\n children: init.children ?? [],\n };\n}\n\nexport function createText(\n id: IRNodeId,\n value: string,\n opts?: { collapsible?: boolean; parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRText {\n return {\n id,\n kind: 'text',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n value,\n collapsible: opts?.collapsible ?? true,\n };\n}\n\nexport function createExpr(\n id: IRNodeId,\n expr: ExprRef,\n opts?: { parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRExpr {\n return {\n id,\n kind: 'expr',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n expr,\n };\n}\n\nexport function createFragment(\n id: IRNodeId,\n opts?: { children?: IRNodeId[]; parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRFragment {\n return {\n id,\n kind: 'fragment',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n children: opts?.children ?? [],\n };\n}\n\nexport function createComment(\n id: IRNodeId,\n value: string,\n opts?: { parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRComment {\n return {\n id,\n kind: 'comment',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n value,\n };\n}\n\n/** Build an empty document whose root is a fresh fragment. */\nexport function createDocument(frontend: FrontendKind): IRDocument {\n const alloc = createIdAllocator();\n const rootId = alloc.next();\n const root = createFragment(rootId);\n const nodes = new Map<IRNodeId, IRNode>([[rootId, root]]);\n return {\n root: rootId,\n nodes,\n exprs: createExprRegistry(),\n sources: new Map(),\n backref: createBackrefTable(),\n frontend,\n alloc,\n };\n}\n\n/* ───────────────────────── tree accessors ───────────────────────── */\n\n/** Returns the child id list for container nodes, or an empty array. */\nexport function childIds(node: IRNode): readonly IRNodeId[] {\n return node.kind === 'element' || node.kind === 'fragment' ? node.children : [];\n}\n\n/** Returns the node, or undefined. */\nexport function getNode(doc: IRDocument, id: IRNodeId): IRNode | undefined {\n return doc.nodes.get(id);\n}\n\n/** Returns the node iff it is an element. */\nexport function getElement(doc: IRDocument, id: IRNodeId): IRElement | undefined {\n const n = doc.nodes.get(id);\n return n && n.kind === 'element' ? n : undefined;\n}\n\n/** Pre-order list of every element id reachable from the root. */\nexport function elementIds(doc: IRDocument): IRNodeId[] {\n const out: IRNodeId[] = [];\n const visit = (id: IRNodeId): void => {\n const n = doc.nodes.get(id);\n if (!n) return;\n if (n.kind === 'element') out.push(id);\n for (const c of childIds(n)) visit(c);\n };\n visit(doc.root);\n return out;\n}\n\n/* ───────────────────────── traversal ───────────────────────── */\n\n/**\n * Depth-first pre/post-order walk. `enter` may return `'skip'` (don't descend) or `'stop'`\n * (abort the whole walk); `exit` may return `'stop'`. The visitor receives a live {@link IRNode}\n * plus a {@link VisitContext} exposing depth and the parent node.\n */\nexport function walk(doc: IRDocument, visitor: Visitor): void {\n const roDoc = doc as unknown as VisitContext['doc'];\n let stopped = false;\n\n const visit = (id: IRNodeId, depth: number): void => {\n if (stopped) return;\n const node = doc.nodes.get(id);\n if (!node) return;\n\n const ctx: VisitContext = {\n doc: roDoc,\n depth,\n parent(): IRNode | null {\n return node.parent == null ? null : doc.nodes.get(node.parent) ?? null;\n },\n };\n\n const entered: VisitSignal = visitor.enter ? visitor.enter(node, ctx) : undefined;\n if (entered === 'stop') {\n stopped = true;\n return;\n }\n if (entered !== 'skip') {\n for (const child of childIds(node)) {\n visit(child, depth + 1);\n if (stopped) return;\n }\n }\n\n const exited: VisitSignal = visitor.exit ? visitor.exit(node, ctx) : undefined;\n if (exited === 'stop') stopped = true;\n };\n\n visit(doc.root, 0);\n}\n","/**\n * @domflax/pattern-kit — the shared StyleMap normalizer.\n *\n * A single, syntactic-only {@link StyleNormalizer} implementation that core, the patterns, and the\n * verifier all reuse so they agree, byte-for-byte, on what two style declarations \"mean\". It NEVER\n * resolves initial/inherited/computed defaults (that is the verifier's job) — it only:\n *\n * • canonicalizes colors (`transparent` ⇒ `rgba(0, 0, 0, 0)`, hex lower-cased + 3→6 expanded,\n * `rgb()/rgba()/hsl()/hsla()` argument spacing normalized),\n * • canonicalizes units (whitespace collapsed, zero-lengths `0px`/`0%`/… ⇒ `0`),\n * • expands a fixed set of box shorthands to longhands (`padding`/`margin`/`inset`/`border-width`\n * into their four sides, `gap` into `row-gap`/`column-gap`),\n * • orders declarations by property for stable comparison.\n *\n * Dependency-free: only `@domflax/core` (types + the StyleMap builder helpers).\n */\n\nimport type {\n CssProperty,\n CssValue,\n ConditionKey,\n InheritedPropertyTable,\n StyleBlock,\n StyleDecl,\n StyleMap,\n StyleNormalizer,\n} from '@domflax/core';\n\nimport { conditionKey, emptyStyleMap } from '@domflax/core';\n\n/* ───────────────────────── inherited-property table ───────────────────────── */\n\n/**\n * Canonical, versioned set of inherited CSS longhands. Any author custom property (`--*`) is\n * also treated as inherited via the `isInherited` predicate.\n */\nconst INHERITED_PROPERTIES: readonly string[] = [\n 'azimuth',\n 'border-collapse',\n 'border-spacing',\n 'caption-side',\n 'color',\n 'cursor',\n 'direction',\n 'empty-cells',\n 'font-family',\n 'font-feature-settings',\n 'font-kerning',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-variant-caps',\n 'font-variant-numeric',\n 'font-weight',\n 'hyphens',\n 'letter-spacing',\n 'line-height',\n 'list-style-image',\n 'list-style-position',\n 'list-style-type',\n 'orphans',\n 'overflow-wrap',\n 'quotes',\n 'tab-size',\n 'text-align',\n 'text-align-last',\n 'text-decoration-color',\n 'text-indent',\n 'text-justify',\n 'text-rendering',\n 'text-shadow',\n 'text-transform',\n 'text-underline-position',\n 'visibility',\n 'white-space',\n 'widows',\n 'word-break',\n 'word-spacing',\n 'writing-mode',\n '-webkit-font-smoothing',\n];\n\nfunction createInheritedTable(): InheritedPropertyTable {\n const properties = new Set<CssProperty>(INHERITED_PROPERTIES as unknown as CssProperty[]);\n return {\n version: 'domflax-inherited@1',\n properties,\n isInherited(property: CssProperty): boolean {\n // Author custom properties (`--*`) inherit by definition.\n return String(property).startsWith('--') || properties.has(property);\n },\n };\n}\n\n/* ───────────────────────── value canonicalization ───────────────────────── */\n\nconst ZERO_LENGTH_RE =\n /\\b0(?:px|em|rem|ex|ch|vh|vw|vmin|vmax|vi|vb|pt|pc|cm|mm|in|q|lh|rlh|fr|deg|rad|turn|s|ms|%)\\b/g;\n\nconst FUNC_ARGS_RE = /\\b(rgba?|hsla?|hwb|lab|lch|oklab|oklch)\\(([^()]*)\\)/gi;\n\nconst RELATIVE_UNIT_RE = /(?:\\d*\\.?\\d+)(?:em|ex|ch|lh)\\b|%/i;\n\n/**\n * Pure, syntactic value canonicalization. Idempotent: `canon(canon(v)) === canon(v)`.\n */\nfunction canonValue(raw: string): string {\n let v = raw.trim().replace(/\\s+/g, ' ');\n\n // Lower-case hex colors (#abc / #aabbcc / #aabbccff).\n v = v.replace(/#([0-9a-fA-F]{3,8})\\b/g, (_m, hex: string) => '#' + hex.toLowerCase());\n\n // Expand 3-digit hex (#abc → #aabbcc) — only when exactly 3 hex digits.\n v = v.replace(\n /#([0-9a-f])([0-9a-f])([0-9a-f])(?![0-9a-f])/g,\n (_m, r: string, g: string, b: string) => `#${r}${r}${g}${g}${b}${b}`,\n );\n\n // Canonical fully-transparent color.\n v = v.replace(/\\btransparent\\b/gi, 'rgba(0, 0, 0, 0)');\n v = v.replace(/#00000000\\b/g, 'rgba(0, 0, 0, 0)');\n\n // Collapse zero lengths/angles/times to a bare `0`.\n v = v.replace(ZERO_LENGTH_RE, '0');\n\n // Normalize the argument spacing of color/space functions: single space after each comma.\n v = v.replace(FUNC_ARGS_RE, (_m, fn: string, args: string) => {\n const parts = args\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return `${fn.toLowerCase()}(${parts.join(', ')})`;\n });\n\n return v;\n}\n\n/** True when the (canonicalized) value uses a parent-relative unit (em/ex/ch/lh/%). */\nfunction isRelativeValue(value: string): boolean {\n return RELATIVE_UNIT_RE.test(value);\n}\n\n/* ───────────────────────── shorthand expansion ───────────────────────── */\n\n/** Box-model shorthands whose 1–4 value form expands to four explicit sides. */\nconst BOX_SIDES: Readonly<Record<string, readonly [string, string, string, string]>> = {\n padding: ['padding-top', 'padding-right', 'padding-bottom', 'padding-left'],\n margin: ['margin-top', 'margin-right', 'margin-bottom', 'margin-left'],\n inset: ['top', 'right', 'bottom', 'left'],\n 'border-width': [\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n ],\n 'border-style': [\n 'border-top-style',\n 'border-right-style',\n 'border-bottom-style',\n 'border-left-style',\n ],\n 'border-color': [\n 'border-top-color',\n 'border-right-color',\n 'border-bottom-color',\n 'border-left-color',\n ],\n};\n\n/** Split on top-level whitespace, keeping `fn(a, b)` groups intact. */\nfunction splitTopLevel(value: string): string[] {\n const out: string[] = [];\n let depth = 0;\n let cur = '';\n for (const ch of value) {\n if (ch === '(') depth += 1;\n else if (ch === ')') depth = Math.max(0, depth - 1);\n if (depth === 0 && /\\s/.test(ch)) {\n if (cur.length > 0) {\n out.push(cur);\n cur = '';\n }\n continue;\n }\n cur += ch;\n }\n if (cur.length > 0) out.push(cur);\n return out;\n}\n\n/** Map a 1–4 value box shorthand onto its [top, right, bottom, left] sides. */\nfunction boxFourSides(values: readonly string[]): [string, string, string, string] {\n const [a, b, c, d] = values;\n switch (values.length) {\n case 1:\n return [a!, a!, a!, a!];\n case 2:\n return [a!, b!, a!, b!];\n case 3:\n return [a!, b!, c!, b!];\n default:\n return [a!, b!, c!, d!];\n }\n}\n\n/** Expand one declaration into longhand `[property, value]` pairs (single pair if not shorthand). */\nfunction expandShorthand(prop: string, value: string): Array<[string, string]> {\n const box = BOX_SIDES[prop];\n if (box) {\n const parts = splitTopLevel(value);\n if (parts.length >= 1 && parts.length <= 4) {\n const sides = boxFourSides(parts);\n return box.map((p, i) => [p, sides[i]!] as [string, string]);\n }\n return [[prop, value]];\n }\n\n if (prop === 'gap' || prop === 'grid-gap') {\n const parts = splitTopLevel(value);\n if (parts.length === 1) {\n return [\n ['row-gap', parts[0]!],\n ['column-gap', parts[0]!],\n ];\n }\n if (parts.length === 2) {\n return [\n ['row-gap', parts[0]!],\n ['column-gap', parts[1]!],\n ];\n }\n return [[prop, value]];\n }\n\n return [[prop, value]];\n}\n\n/* ───────────────────────── the normalizer ───────────────────────── */\n\nfunction makeDecl(\n table: InheritedPropertyTable,\n prop: string,\n rawValue: string,\n important: boolean,\n): StyleDecl {\n const property = prop.trim().toLowerCase() as CssProperty;\n const value = canonValue(rawValue) as CssValue;\n return {\n property,\n value,\n important,\n relativeToParent: isRelativeValue(value),\n inherited: table.isInherited(property),\n };\n}\n\nexport function createNormalizer(): StyleNormalizer {\n const inherited = createInheritedTable();\n\n const normalizeDeclaration = (\n prop: string,\n value: string,\n important: boolean,\n ): readonly StyleDecl[] => {\n const p = prop.trim().toLowerCase();\n const expanded = expandShorthand(p, value.trim());\n return expanded.map(([lp, lv]) => makeDecl(inherited, lp, lv, important));\n };\n\n const normalizeValue = (prop: CssProperty, raw: string): CssValue => {\n void prop;\n return canonValue(raw) as CssValue;\n };\n\n const normalizeStyleMap = (sm: StyleMap): StyleMap => {\n const blocks = new Map<ConditionKey, StyleBlock>();\n for (const block of sm.blocks.values()) {\n const decls = new Map<CssProperty, StyleDecl>();\n // Re-canonicalize every value and re-key (the decls are already longhand).\n for (const decl of block.decls.values()) {\n const next: StyleDecl = {\n ...decl,\n value: canonValue(String(decl.value)) as CssValue,\n relativeToParent: isRelativeValue(String(decl.value)),\n inherited: inherited.isInherited(decl.property),\n };\n decls.set(next.property, next);\n }\n // Property-sorted for deterministic iteration/serialization.\n const sorted = new Map<CssProperty, StyleDecl>(\n [...decls.entries()].sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)),\n );\n const key = conditionKey(block.condition);\n blocks.set(key, { condition: block.condition, decls: sorted });\n }\n return { blocks };\n };\n\n const equals = (a: StyleMap, b: StyleMap): boolean => {\n const na = normalizeStyleMap(a);\n const nb = normalizeStyleMap(b);\n if (na.blocks.size !== nb.blocks.size) return false;\n for (const [key, blockA] of na.blocks) {\n const blockB = nb.blocks.get(key);\n if (!blockB) return false;\n if (blockA.decls.size !== blockB.decls.size) return false;\n for (const [prop, declA] of blockA.decls) {\n const declB = blockB.decls.get(prop);\n if (!declB) return false;\n if (declA.value !== declB.value || declA.important !== declB.important) return false;\n }\n }\n return true;\n };\n\n return {\n version: 'domflax-normalizer@1',\n normalizeDeclaration,\n normalizeValue,\n normalizeStyleMap,\n equals,\n inherited,\n };\n}\n\n/** The shared, process-wide normalizer instance reused by core / patterns / verify. */\nexport const normalizer: StyleNormalizer = createNormalizer();\n\n/* ───────────────────────── superset helper (used by `computed()` matcher) ───────────────────────── */\n\n/**\n * True when `full` contains every declaration of `partial` with an equal normalized value\n * (a per-condition, per-declaration superset test). Both maps are normalized first so the\n * comparison is meaning-based, not string-based. Empty `partial` ⇒ always `true`.\n */\nexport function isStyleSuperset(\n full: StyleMap,\n partial: StyleMap,\n norm: StyleNormalizer = normalizer,\n): boolean {\n const nf = norm.normalizeStyleMap(full);\n const np = norm.normalizeStyleMap(partial);\n for (const [key, want] of np.blocks) {\n const have = nf.blocks.get(key) ?? nf.blocks.get(conditionKey(want.condition));\n if (!have) return false;\n for (const [prop, decl] of want.decls) {\n const got = have.decls.get(prop);\n if (!got || got.value !== decl.value) return false;\n }\n }\n return true;\n}\n\n/** Re-exported for callers that want to (de)construct keys without importing core directly. */\nexport { emptyStyleMap };\n","/**\n * @domflax/pattern-kit — composable matcher vocabulary.\n *\n * A {@link Matcher} is a PURE predicate over a node + its {@link MatchContext}. Matchers never\n * mutate; they only read the (DeepReadonly) IR and the precomputed targeting/selector facts the\n * context exposes. Authors compose them with {@link and}/{@link or}/{@link not} and feed the\n * result into a pattern's `evaluate`.\n *\n * Style-aware matchers (`computed`, `hasOwnVisualStyle`) reason over the NORMALIZED StyleMap via\n * the shared normalizer in `./normalize`, so they query meaning, not raw CSS strings.\n */\n\nimport type {\n DeepReadonly,\n ElementLike,\n IRElement,\n IRNode,\n IRNodeId,\n MatchContext,\n NodeLike,\n StyleMap,\n} from '@domflax/core';\n\nimport { isStyleSuperset, normalizer } from './normalize';\n\n/** A pure predicate: does `node` satisfy this condition in the given match context? */\nexport type Matcher = (node: NodeLike, ctx: MatchContext) => boolean;\n\n/* ───────────────────────── internal helpers ───────────────────────── */\n\nfunction asElement(node: NodeLike): DeepReadonly<IRElement> | null {\n const n = node as DeepReadonly<IRNode>;\n return n.kind === 'element' ? (n as DeepReadonly<IRElement>) : null;\n}\n\nfunction elementChildrenOf(\n el: DeepReadonly<IRElement>,\n ctx: MatchContext,\n): DeepReadonly<IRElement>[] {\n const out: DeepReadonly<IRElement>[] = [];\n for (const childId of el.children) {\n const child = ctx.doc.nodes.get(childId);\n if (child && child.kind === 'element') out.push(child as DeepReadonly<IRElement>);\n }\n return out;\n}\n\n/* ───────────────────────── boolean combinators ───────────────────────── */\n\n/** Logical AND. Empty list ⇒ always matches. Short-circuits on the first failure. */\nexport function and(...matchers: readonly Matcher[]): Matcher {\n return (node, ctx) => matchers.every((m) => m(node, ctx));\n}\n\n/** Logical OR. Empty list ⇒ never matches. Short-circuits on the first success. */\nexport function or(...matchers: readonly Matcher[]): Matcher {\n return (node, ctx) => matchers.some((m) => m(node, ctx));\n}\n\n/** Logical NOT. */\nexport function not(matcher: Matcher): Matcher {\n return (node, ctx) => !matcher(node, ctx);\n}\n\n/* ───────────────────────── structural matchers ───────────────────────── */\n\n/** Matches any element; with `tag`, only elements whose (case-insensitive) tag equals it. */\nexport function isElement(tag?: string): Matcher {\n const want = tag?.toLowerCase();\n return (node) => {\n const el = asElement(node);\n if (!el) return false;\n return want === undefined || el.tag.toLowerCase() === want;\n };\n}\n\n/** Matches an element with exactly one ELEMENT child (text/expr/comment children ignored). */\nexport const hasSingleElementChild: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return elementChildrenOf(el, ctx).length === 1;\n};\n\n/* ───────────────────────── style matchers ───────────────────────── */\n\n/**\n * Matches when the node's computed StyleMap is a SUPERSET of `partial` — i.e. every declaration\n * in `partial` is present in `node.computed` with an equal normalized value. Comparison is\n * meaning-based (both sides normalized first). Empty `partial` always matches.\n */\nexport function computed(partial: StyleMap): Matcher {\n return (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n const full = ctx.computedOf(el as unknown as NodeLike) ?? (el.computed as StyleMap);\n return isStyleSuperset(full as StyleMap, partial, normalizer);\n };\n}\n\n/** Visual (paint-establishing) properties that count as \"own visual style\", beyond pure layout. */\nconst VISUAL_PROPERTIES: ReadonlySet<string> = new Set<string>([\n 'background',\n 'background-color',\n 'background-image',\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n 'border-top-style',\n 'border-right-style',\n 'border-bottom-style',\n 'border-left-style',\n 'border-top-color',\n 'border-right-color',\n 'border-bottom-color',\n 'border-left-color',\n 'border-radius',\n 'box-shadow',\n 'outline',\n 'outline-width',\n 'outline-style',\n 'outline-color',\n 'text-shadow',\n 'filter',\n 'backdrop-filter',\n 'mix-blend-mode',\n 'opacity',\n]);\n\n/** Values that mean \"no paint\" — a visual property set to one of these does NOT count. */\nconst EMPTY_VISUAL_VALUES: ReadonlySet<string> = new Set<string>([\n 'none',\n '0',\n 'normal',\n 'transparent',\n 'rgba(0, 0, 0, 0)',\n 'initial',\n 'unset',\n 'auto',\n]);\n\n/**\n * Matches when the element paints something of its own: a meaningful background, border, shadow,\n * outline, filter, etc. across ANY style condition. Honours the frontend-set `meta.hasOwnVisualStyle`\n * fast-path, then falls back to scanning the normalized computed StyleMap.\n */\nexport const hasOwnVisualStyle: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n if (el.meta.hasOwnVisualStyle) return true;\n\n const computedMap = ctx.computedOf(el as unknown as NodeLike) ?? (el.computed as StyleMap);\n const norm = normalizer.normalizeStyleMap(computedMap as StyleMap);\n for (const block of norm.blocks.values()) {\n for (const decl of block.decls.values()) {\n if (!VISUAL_PROPERTIES.has(String(decl.property))) continue;\n if (!EMPTY_VISUAL_VALUES.has(String(decl.value))) return true;\n }\n }\n return false;\n};\n\n/* ───────────────────────── opacity-barrier / meta matchers ───────────────────────── */\n\n/** Element carries a `ref` (hard opacity barrier). */\nexport const hasRef: Matcher = (node) => asElement(node)?.meta.hasRef ?? false;\n\n/** Element has event handlers (onClick, …). */\nexport const hasEventHandlers: Matcher = (node) => asElement(node)?.meta.hasEventHandlers ?? false;\n\n/** Element has dynamic children (mapped/conditional islands). */\nexport const hasDynamicChildren: Matcher = (node) =>\n asElement(node)?.meta.hasDynamicChildren ?? false;\n\n/** Element's class list contains a dynamic segment (template/expr) → not freely rewritable. */\nexport const hasDynamicClasses: Matcher = (node) => asElement(node)?.classes.hasDynamic ?? false;\n\n/**\n * Element's class list is wholly dynamic / spread-derived (`classes.opaque`, or spread attrs) — its\n * concrete tokens can't be seen or statically rewritten, so a class-rewriting (compress) pattern\n * must decline. Delegates to the context's authoritative {@link MatchContext.isOpaque}.\n */\nexport const opaque: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return ctx.isOpaque(el as unknown as ElementLike);\n};\n\n/**\n * Element is the subject of a combinator selector (`>`/`+`/`~`). Honours the frontend-set meta\n * flag and the precomputed {@link SelectorIndex} in the context.\n */\nexport const targetedByCombinator: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n if (el.meta.targetedByCombinator) return true;\n // `el.id` is a branded number; DeepReadonly widens the brand, so re-narrow for the index call.\n return ctx.selectors.targetedByCombinator(el.id as unknown as IRNodeId);\n};\n","/**\n * @domflax/pattern-kit — ergonomic op-draft constructors.\n *\n * Thin, pure helpers that build the core {@link RewriteOpDraft} objects so pattern authors can\n * assemble a `MatchResult.ops` array without hand-writing discriminant literals. Drafts carry NO\n * `origin` — the pass-manager stamps `{ pattern, category, safety }` when it schedules the op\n * (see core's `stampOrigin`). Each helper accepts a live node, a DeepReadonly view, or a bare\n * {@link IRNodeId}.\n *\n * Mirrors the four ops a rewrite typically reaches for: `mergeStyle`, `foldInheritedStyles`,\n * `replaceWith`, `removeNode`.\n */\n\nimport type {\n CssProperty,\n ElementLike,\n IRNode,\n IRNodeId,\n NodeLike,\n NodeSpec,\n RewriteOpDraft,\n StyleConflictPolicy,\n StyleMap,\n} from '@domflax/core';\n\n/** Accept a live/readonly node or a bare id. */\ntype Ref = NodeLike | ElementLike | IRNodeId;\n\nfunction idOf(ref: Ref): IRNodeId {\n return typeof ref === 'number' ? (ref as IRNodeId) : ((ref as IRNode).id as IRNodeId);\n}\n\n/* ───────────────────────── style ops ───────────────────────── */\n\n/**\n * Merge `style` onto `target`, optionally pulling from `source` (or `null` for a literal patch).\n * `onConflict` defaults to `'abort'` — the safest policy (the applier refuses rather than guess).\n */\nexport function mergeStyle(\n target: Ref,\n source: Ref | null,\n style: StyleMap,\n onConflict: StyleConflictPolicy = 'abort',\n): RewriteOpDraft {\n return {\n op: 'mergeStyle',\n target: idOf(target),\n source: source == null ? null : idOf(source),\n style,\n onConflict,\n };\n}\n\n/**\n * Fold inheritable declarations from `from` down into one or more descendants. `conditions:'all'`\n * folds across every StyleCondition (states/media/pseudo-elements); the default `'base'` folds only\n * the unconditional block. `only` restricts the property set (otherwise `'all-inherited'`).\n */\nexport function foldInheritedStyles(\n from: Ref,\n into: Ref | readonly Ref[],\n opts?: { only?: readonly CssProperty[]; conditions?: 'base' | 'all' },\n): RewriteOpDraft {\n const list: readonly Ref[] = Array.isArray(into) ? (into as readonly Ref[]) : [into as Ref];\n return {\n op: 'foldInheritedStyles',\n from: idOf(from),\n into: list.map(idOf),\n properties: opts?.only ?? 'all-inherited',\n conditions: opts?.conditions ?? 'base',\n };\n}\n\n/* ───────────────────────── structural ops ───────────────────────── */\n\n/** Replace `target` with a detached {@link NodeSpec} (the applier materializes ids on apply). */\nexport function replaceWith(target: Ref, replacement: NodeSpec): RewriteOpDraft {\n return { op: 'replaceWith', target: idOf(target), replacement };\n}\n\n/** Remove `target` (and its subtree) from the tree. */\nexport function removeNode(target: Ref): RewriteOpDraft {\n return { op: 'removeNode', target: idOf(target) };\n}\n","/**\n * @domflax/pattern-kit — `validatePattern` (INTERNAL).\n *\n * A small, eager validator + identity wrapper that turns a lowered {@link Pattern} spec into a\n * frozen, contract-checked Pattern. Catching shape errors here (bad category/phase, missing\n * `evaluate`, out-of-range safety) keeps the pass-manager's hot loop free of defensive checks and\n * gives authors an immediate, actionable error at module-load time.\n *\n * This is the PRIVATE lower-level core: it is consumed only by the declarative\n * {@link import('./pattern').definePattern} authoring surface (which compiles a high-level config\n * down to a {@link Pattern} and then runs it through this validator). It is intentionally NOT part\n * of the public package surface — authors use `definePattern` instead.\n */\n\nimport type { PassPhase, Pattern, SafetyLevel } from '@domflax/core';\n\nconst PHASES: ReadonlySet<PassPhase> = new Set<PassPhase>(['flatten', 'compress', 'extract']);\nconst SAFETY_LEVELS: ReadonlySet<SafetyLevel> = new Set<SafetyLevel>([0, 1, 2, 3]);\n\nfunction fail(name: string, why: string): never {\n throw new Error(`definePattern(${name || '<anonymous>'}): ${why}`);\n}\n\n/**\n * Validate and freeze a {@link Pattern}. Throws on any contract violation; otherwise returns the\n * (shallow-frozen) spec unchanged so it can be registered into a {@link Pass}. INTERNAL — see the\n * module header; authors call the declarative {@link import('./pattern').definePattern}.\n */\nexport function validatePattern(spec: Pattern): Pattern {\n if (spec == null || typeof spec !== 'object') {\n throw new Error('definePattern: spec must be an object');\n }\n\n const name = spec.name;\n if (typeof name !== 'string' || name.length === 0) {\n fail(String(name), 'name must be a non-empty string');\n }\n\n if (typeof spec.category !== 'string' || !spec.category.includes('/')) {\n fail(name, `category must be a \"<phase>/<slug>\" string (got ${JSON.stringify(spec.category)})`);\n }\n\n const phase = spec.category.split('/', 1)[0] as PassPhase;\n if (!PHASES.has(phase)) {\n fail(name, `category phase must be one of flatten|compress|extract (got \"${phase}\")`);\n }\n\n if (!SAFETY_LEVELS.has(spec.safety)) {\n fail(name, `safety must be 0|1|2|3 (got ${JSON.stringify(spec.safety)})`);\n }\n\n if (typeof spec.evaluate !== 'function') {\n fail(name, 'evaluate must be a function');\n }\n\n if (spec.priority !== undefined && !Number.isFinite(spec.priority)) {\n fail(name, 'priority must be a finite number when provided');\n }\n\n return Object.freeze({ ...spec });\n}\n","/**\n * @domflax/pattern-kit — `definePattern()`: THE declarative pattern-authoring surface.\n *\n * `definePattern(config)` is the single public way to author a rewrite pattern: definition AND its\n * tests are co-located in one call. It compiles down to the private lower-level\n * {@link import('./define').validatePattern}/{@link Pattern} contract (it never replaces the\n * engine). Authors describe the match as a plain DATA object and the rewrite as a named RECIPE; this\n * module maps each key to the existing matcher combinators and op-draft factories, auto-applies the\n * phase-appropriate safety guards (the full opacity-barrier + selector set for `flatten/*`; the\n * narrower class-rewrite-safety set for `compress/*`) so authors never hand-write them, and threads\n * `doc`/`test` through. Two escape hatches — a `match` predicate and a `rewrite` function — keep\n * exotic patterns (e.g. ones anchored on a parent fragment) expressible.\n *\n * The co-located {@link PatternTest} (`provider`/`cssFiles`/`cases`/`noMatch`/`custom`) is carried on\n * the compiled {@link AuthoredPattern} as `.test`, where the generic harness (`./testing`) reads it:\n * each `case` asserts `before → after`, each `noMatch` asserts the input is left unchanged, and the\n * optional `custom` hook runs arbitrary assertions against the built transform.\n *\n * `style` blocks in the declarative match (and in `childGains`/`mergeStyle` recipes) are PLAIN\n * objects (camelCase or kebab keys) auto-normalized into a superset StyleMap via the shared\n * normalizer — authors never import the normalizer or hand-build a StyleMap.\n *\n * `pattern` remains exported as a DEPRECATED alias of `definePattern` for backward compatibility.\n */\n\nimport type {\n Captures,\n ConditionKey,\n CssProperty,\n DeepReadonly,\n IRElement,\n IRNode,\n IRNodeId,\n MatchContext,\n MatchResult,\n NodeLike,\n NodeMeta,\n PassCategory,\n PassPhase,\n Pattern,\n PatternDoc,\n PreconditionSketch,\n RewriteFactory,\n RewriteOpDraft,\n SafetyLevel,\n StyleBlock,\n StyleDecl,\n StyleMap,\n StyleOrigin,\n StyleConflictPolicy,\n} from '@domflax/core';\nimport { BASE_CONDITION, conditionKey } from '@domflax/core';\n\nimport {\n and,\n computed,\n hasDynamicChildren,\n hasDynamicClasses,\n hasEventHandlers,\n hasOwnVisualStyle,\n hasRef,\n hasSingleElementChild,\n isElement,\n not,\n opaque,\n targetedByCombinator,\n type Matcher,\n} from './combinators';\nimport { validatePattern } from './define';\nimport { normalizer } from './normalize';\n\n/* ───────────────────────── public config shapes ───────────────────────── */\n\n/** A plain CSS style object: camelCase or kebab-case keys, string or number values. */\nexport type PlainStyle = Readonly<Record<string, string | number>>;\n\n/**\n * Declarative match as DATA. Every key maps to one of the existing matcher combinators; an empty\n * object matches any element. Use the `match` FUNCTION escape hatch for anything not expressible\n * here (relational/ancestor/sibling shapes, parent-anchored patterns, …).\n */\nexport interface DeclarativeMatch {\n /** Restrict to a tag (case-insensitive). Omit to match any element. */\n readonly tag?: string;\n /** Computed style the node must be a SUPERSET of (plain object, auto-normalized). */\n readonly style?: PlainStyle;\n /** Require exactly one ELEMENT child. */\n readonly onlyChild?: 'element';\n /** Require the element to paint nothing of its own (no own visual style). */\n readonly paintsNothing?: boolean;\n /** Extra, hand-written predicate AND-ed into the declarative match. */\n readonly where?: Matcher | readonly Matcher[];\n}\n\n/** Escape hatch: a raw match predicate (no auto-guards are added). */\nexport type MatchFn = (node: NodeLike, ctx: MatchContext) => boolean;\n\n/**\n * Flatten recipe: fold inherited styles onto the sole element child (default on), optionally merge\n * `childGains` onto it, then unwrap the node (id-preserving). Mirrors the flatten exemplars.\n */\nexport interface FlattenIntoRecipe {\n readonly flattenInto: 'child';\n /** Plain style merged onto the surviving child (source-wins) before unwrap. */\n readonly childGains?: PlainStyle;\n /** Fold inheritable declarations onto the child first. Default `true`. */\n readonly foldInherited?: boolean;\n}\n\n/** Compress recipe: rebuild the element's class StyleMap; return `null` to decline. */\nexport interface RewriteClassesRecipe {\n readonly rewriteClasses: (computed: StyleMap, ctx: MatchContext) => StyleMap | null;\n /** Keep opaque/selector-bound tokens verbatim. Default `true`. */\n readonly preserveOpaque?: boolean;\n}\n\n/** Compress recipe: drop fully-overridden class tokens (provenance is pruned automatically). */\nexport interface DropClassesRecipe {\n readonly dropClasses: (computed: StyleMap, ctx: MatchContext) => Iterable<string>;\n /** Keep opaque/selector-bound tokens verbatim. Default `true`. */\n readonly preserveOpaque?: boolean;\n}\n\n/** Merge a literal plain style onto the matched element. */\nexport interface MergeStyleRecipe {\n readonly mergeStyle: PlainStyle;\n readonly onConflict?: StyleConflictPolicy;\n}\n\nexport type RewriteRecipe =\n | FlattenIntoRecipe\n | RewriteClassesRecipe\n | DropClassesRecipe\n | MergeStyleRecipe;\n\n/** Escape hatch: a raw rewrite that returns op drafts (or `null`/`[]` for no-op). */\nexport type RewriteFn = (\n ctx: MatchContext,\n rw: RewriteFactory,\n) => readonly RewriteOpDraft[] | null;\n\n/** A single positive before→after assertion run through the pattern's built transform. */\nexport interface PatternTestCase {\n readonly name?: string;\n readonly before: string;\n readonly after: string;\n}\n\n/** Helpers handed to a {@link PatternTest.custom} hook (the built transform + expectation sugar). */\nexport interface TestHelpers {\n /** Run the pattern's transform on `code` (default filename `'X.tsx'`). */\n readonly transform: (code: string, filename?: string) => string;\n /** Assert `before` transforms to `after` (whitespace-normalized). */\n readonly expectTransforms: (before: string, after: string) => void;\n /** Assert `code` is left unchanged (whitespace-normalized). */\n readonly expectUnchanged: (code: string) => void;\n}\n\n/**\n * Co-located test spec for a pattern. The generic harness (`./testing`) builds a transform for the\n * declared `provider` (default `'tailwind'`; `'custom'` resolves the listed `cssFiles`), then runs\n * every `case` (`before → after`), every `noMatch` (left unchanged), and the optional `custom` hook.\n */\nexport interface PatternTest {\n /** Which style provider the harness builds the transform from. Default `'tailwind'`. */\n readonly provider?: 'tailwind' | 'custom';\n /** For `provider: 'custom'` — the project stylesheet paths backing the CSS resolver. */\n readonly cssFiles?: readonly string[];\n /** Positive before→after assertions. */\n readonly cases?: readonly PatternTestCase[];\n /** Inputs the pattern must leave UNCHANGED (barriers, non-matching shapes, safety reverts). */\n readonly noMatch?: readonly string[];\n /** Arbitrary extra assertions against the built transform. */\n readonly custom?: (h: TestHelpers) => void;\n}\n\nexport interface PatternConfig {\n readonly name: string;\n readonly category: PassCategory;\n readonly safety: SafetyLevel;\n readonly priority?: number;\n readonly precondition?: PreconditionSketch;\n readonly doc?: PatternDoc;\n /** Co-located tests consumed by the generic harness (`./testing`). */\n readonly test?: PatternTest;\n /** Declarative match DATA, or a raw predicate escape hatch. Defaults to \"any element\". */\n readonly match?: DeclarativeMatch | MatchFn;\n /** A named rewrite recipe, or a raw op-draft factory escape hatch. */\n readonly rewrite: RewriteRecipe | RewriteFn;\n}\n\n/** A {@link Pattern} that also carries its co-located {@link PatternTest} for the test harness. */\nexport interface AuthoredPattern<C extends Captures = Captures> extends Pattern {\n readonly test?: PatternTest;\n evaluate(ctx: MatchContext, rw: RewriteFactory): MatchResult<C> | null;\n}\n\n/* ───────────────────────── plain-style → StyleMap ───────────────────────── */\n\nfunction camelToKebab(key: string): string {\n if (key.startsWith('--')) return key; // custom property — leave verbatim\n return key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n}\n\n/** Build a single-(base-)condition StyleMap from a plain style object via the shared normalizer. */\nfunction plainToStyleMap(style: PlainStyle): StyleMap {\n const decls = new Map<CssProperty, StyleDecl>();\n for (const [rawKey, rawValue] of Object.entries(style)) {\n const prop = camelToKebab(rawKey);\n for (const decl of normalizer.normalizeDeclaration(prop, String(rawValue), false)) {\n decls.set(decl.property, decl);\n }\n }\n const block: StyleBlock = { condition: BASE_CONDITION, decls };\n return { blocks: new Map<ConditionKey, StyleBlock>([[conditionKey(BASE_CONDITION), block]]) };\n}\n\n/* ───────────────────────── local meta / selector matchers ───────────────────────── */\n\nfunction asElement(node: NodeLike): DeepReadonly<IRElement> | null {\n const n = node as DeepReadonly<IRNode>;\n return n.kind === 'element' ? (n as DeepReadonly<IRElement>) : null;\n}\n\nfunction metaFlag(flag: keyof NodeMeta): Matcher {\n return (node) => Boolean(asElement(node)?.meta[flag]);\n}\n\n/** Element renders raw/`dangerouslySetInnerHTML` markup — a hard opacity barrier. */\nconst hasRawHtml: Matcher = metaFlag('hasDangerousHtml');\n\n/**\n * Unwrapping/removing this node would change the combinator / structural-pseudo match-set of itself,\n * its child, or a former sibling. Empty `reparentImpact` ⇒ structurally safe to hoist.\n */\nconst affectsSelectorMatching: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return ctx.selectors.reparentImpact(el.id as unknown as IRNodeId).size > 0;\n};\n\n/**\n * The opacity-barrier + selector-safety guards every `flatten/*` pattern must carry. Auto-applied to\n * the declarative match so authors never hand-write them (the flatten exemplars spell them out).\n *\n * Flatten UNWRAPS the element (moving its children into a new parent and dropping its box), so every\n * opacity barrier matters: a ref, event handler, dynamic child, or raw HTML on the wrapper — or any\n * selector the reparent would disturb — makes the flatten unsafe.\n */\nconst FLATTEN_GUARDS: Matcher = and(\n not(hasRef),\n not(hasEventHandlers),\n not(hasDynamicChildren),\n not(hasRawHtml),\n not(targetedByCombinator),\n not(affectsSelectorMatching),\n);\n\n/**\n * The guards every `compress/*` pattern must carry. Compress ONLY ever rewrites the element's OWN\n * class tokens (e.g. `px-4 py-4 → p-4`) — it never touches the element's structure, children, or\n * identity. A dynamic `{expr}` child, a ref, an event handler, or `dangerouslySetInnerHTML` is\n * therefore wholly unaffected by a class-only change, so — unlike flatten — those opacity barriers\n * must NOT gate compress. Compress is gated ONLY on what actually makes a class rewrite unsafe:\n * • a className we can't statically rewrite — a dynamic segment ({@link hasDynamicClasses}) or a\n * wholly dynamic / spread-derived list ({@link opaque}); and\n * • the selector-safety guard — a class a CSS combinator selector structurally depends on\n * ({@link targetedByCombinator}) must not be dropped or rewritten.\n */\nconst COMPRESS_GUARDS: Matcher = and(\n not(hasDynamicClasses),\n not(opaque),\n not(targetedByCombinator),\n);\n\n/* ───────────────────────── match compilation ───────────────────────── */\n\n/** The auto-applied guard set for a pattern's phase (compress vs flatten get different barriers). */\nfunction autoGuardsFor(category: PassCategory): Matcher | null {\n switch (category.split('/', 1)[0] as PassPhase) {\n case 'flatten':\n return FLATTEN_GUARDS;\n case 'compress':\n return COMPRESS_GUARDS;\n default:\n return null;\n }\n}\n\nfunction compileDeclarativeMatch(m: DeclarativeMatch): Matcher {\n const parts: Matcher[] = [isElement(m.tag)];\n if (m.style) parts.push(computed(plainToStyleMap(m.style)));\n if (m.onlyChild === 'element') parts.push(hasSingleElementChild);\n if (m.paintsNothing) parts.push(not(hasOwnVisualStyle));\n if (m.where) {\n const extra = Array.isArray(m.where) ? (m.where as readonly Matcher[]) : [m.where as Matcher];\n for (const w of extra) parts.push(w);\n }\n return and(...parts);\n}\n\nfunction compileMatch(\n match: DeclarativeMatch | MatchFn | undefined,\n category: PassCategory,\n): MatchFn {\n // Escape hatch: a raw predicate takes full control (no auto-guards).\n if (typeof match === 'function') return match;\n\n const declarative = compileDeclarativeMatch(match ?? {});\n const guards = autoGuardsFor(category);\n const guarded = guards ? and(declarative, guards) : declarative;\n return (node, ctx) => guarded(node, ctx);\n}\n\n/* ───────────────────────── rewrite compilation ───────────────────────── */\n\n/** Clone `sm`, pruning every `shadowed` provenance entry that references a dropped class token. */\nfunction pruneShadowed(sm: StyleMap, drop: ReadonlySet<string>): StyleMap {\n const blocks = new Map<ConditionKey, StyleBlock>();\n for (const [key, block] of sm.blocks) {\n const decls = new Map<CssProperty, StyleDecl>();\n for (const [prop, decl] of block.decls) {\n const filtered = (decl.shadowed ?? []).filter(\n (o) => !(o.kind === 'class' && drop.has(o.className)),\n );\n const rest: StyleDecl = { ...decl };\n delete (rest as { shadowed?: readonly StyleOrigin[] }).shadowed;\n const next: StyleDecl = filtered.length > 0 ? { ...rest, shadowed: filtered } : rest;\n decls.set(prop, next);\n }\n blocks.set(key, { condition: block.condition, decls });\n }\n return { blocks };\n}\n\nfunction compileFlattenInto(recipe: FlattenIntoRecipe): RewriteFn {\n const childGains = recipe.childGains ? plainToStyleMap(recipe.childGains) : null;\n const fold = recipe.foldInherited !== false;\n return (ctx, rw) => {\n const wrapper = ctx.node;\n const child = ctx.onlyElementChild();\n if (!child) return null;\n const ops: RewriteOpDraft[] = [];\n if (fold) ops.push(rw.foldInheritedStyles(wrapper, child, { conditions: 'all' }));\n if (childGains) ops.push(rw.mergeStyle(child, null, childGains, 'source-wins'));\n ops.push(rw.unwrap(wrapper));\n return ops;\n };\n}\n\nfunction compileRewrite(rewrite: RewriteRecipe | RewriteFn): RewriteFn {\n if (typeof rewrite === 'function') return rewrite;\n\n if ('flattenInto' in rewrite) return compileFlattenInto(rewrite);\n\n if ('rewriteClasses' in rewrite) {\n const preserveOpaque = rewrite.preserveOpaque ?? true;\n return (ctx, rw) => {\n const next = rewrite.rewriteClasses(ctx.computed(), ctx);\n if (!next) return null;\n return [rw.setClassList(ctx.node, next, preserveOpaque)];\n };\n }\n\n if ('dropClasses' in rewrite) {\n const preserveOpaque = rewrite.preserveOpaque ?? true;\n return (ctx, rw) => {\n const drop = new Set<string>(rewrite.dropClasses(ctx.computed(), ctx));\n if (drop.size === 0) return null;\n return [rw.setClassList(ctx.node, pruneShadowed(ctx.computed(), drop), preserveOpaque)];\n };\n }\n\n // MergeStyleRecipe\n const style = plainToStyleMap(rewrite.mergeStyle);\n const onConflict = rewrite.onConflict ?? 'abort';\n return (ctx, rw) => [rw.mergeStyle(ctx.node, null, style, onConflict)];\n}\n\n/* ───────────────────────── the public factory ───────────────────────── */\n\n/**\n * THE declarative pattern-authoring function. Compile a {@link PatternConfig} (definition + co-located\n * {@link PatternTest}) into a validated {@link AuthoredPattern}: a normal {@link Pattern} (registerable\n * into any {@link import('@domflax/core').Pass}) that also exposes its `test` for the generic harness.\n */\nexport function definePattern(config: PatternConfig): AuthoredPattern {\n const matchFn = compileMatch(config.match, config.category);\n const rewriteFn = compileRewrite(config.rewrite);\n\n const spec: AuthoredPattern = {\n name: config.name,\n category: config.category,\n safety: config.safety,\n priority: config.priority,\n precondition: config.precondition,\n doc: config.doc,\n test: config.test,\n evaluate(ctx: MatchContext, rw: RewriteFactory): MatchResult | null {\n if (!matchFn(ctx.node as unknown as NodeLike, ctx)) return null;\n const ops = rewriteFn(ctx, rw);\n if (!ops || ops.length === 0) return null;\n return { ops };\n },\n };\n\n // `validatePattern` validates + freezes; the spread preserves `test` at runtime.\n return validatePattern(spec) as AuthoredPattern;\n}\n\n/**\n * @deprecated Use {@link definePattern}. Retained as a thin alias for backward compatibility.\n */\nexport const pattern = definePattern;\n"],"mappings":"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","names":["asElement"]}
|
|
1
|
+
{"version":3,"sources":["../src/pattern-kit.ts","../../core/src/builders.ts","../../pattern-kit/src/normalize.ts","../../pattern-kit/src/combinators.ts","../../pattern-kit/src/ops.ts","../../pattern-kit/src/define.ts","../../pattern-kit/src/pattern.ts"],"sourcesContent":["/**\n * `domflax/pattern-kit` — author custom flatten/compress patterns.\n *\n * Subpath export of the bundled (private) `@domflax/pattern-kit`: `definePattern`, the combinator\n * vocabulary, rewrite-op factories, and the shared style normalizer. Power-user surface; the happy\n * path is `import domflax from 'domflax'`.\n */\nexport * from '@domflax/pattern-kit';\n","/**\n * @domflax/core — runtime builders + traversal.\n *\n * Pure, dependency-free helpers to construct IR nodes, assemble an {@link IRDocument},\n * and walk the tree honouring {@link VisitSignal}. No heavy third-party deps: only the\n * type contract in `./types`.\n */\n\nimport type {\n AttrMap,\n Backref,\n BackrefTable,\n ClassList,\n ConditionKey,\n CssProperty,\n ExprRecord,\n ExprRef,\n ExprRegistry,\n FrontendKind,\n IdAllocator,\n IRComment,\n IRDocument,\n IRElement,\n IRExpr,\n IRFragment,\n IRNamespace,\n IRNode,\n IRNodeId,\n IRText,\n InlineStyle,\n NodeMeta,\n SafetyLevel,\n SourceSpan,\n StyleBlock,\n StyleCondition,\n StyleMap,\n Visitor,\n VisitContext,\n VisitSignal,\n} from './types';\n\n/* ───────────────────────── id / registry primitives ───────────────────────── */\n\n/** Monotonic IRNodeId allocator. `peek` reports the id `next()` would return. */\nexport function createIdAllocator(start = 1): IdAllocator {\n let n = start;\n return {\n next(): IRNodeId {\n const id = n;\n n += 1;\n return id as IRNodeId;\n },\n get peek(): IRNodeId {\n return n as IRNodeId;\n },\n };\n}\n\n/** Minimal in-memory ExprRegistry. */\nexport function createExprRegistry(start = 1): ExprRegistry {\n const map = new Map<ExprRef, ExprRecord>();\n let n = start;\n return {\n get(r: ExprRef): ExprRecord | undefined {\n return map.get(r);\n },\n intern(rec: Omit<ExprRecord, 'ref'>): ExprRef {\n const ref = n as ExprRef;\n n += 1;\n map.set(ref, { ...rec, ref });\n return ref;\n },\n releasePayloads(): void {\n for (const [k, v] of map) map.set(k, { ...v, payload: undefined });\n },\n };\n}\n\n/** Mutable BackrefTable: frontends register backrefs as they parse. */\nexport interface MutableBackrefTable extends BackrefTable {\n set(id: IRNodeId, backref: Backref): void;\n}\n\nexport function createBackrefTable(): MutableBackrefTable {\n const map = new Map<IRNodeId, Backref>();\n return {\n get(id: IRNodeId): Backref | undefined {\n return map.get(id);\n },\n span(id: IRNodeId): SourceSpan | null {\n return map.get(id)?.span ?? null;\n },\n childrenSpan(id: IRNodeId): SourceSpan | null {\n return map.get(id)?.innerSpan ?? null;\n },\n set(id: IRNodeId, backref: Backref): void {\n map.set(id, backref);\n },\n };\n}\n\n/* ───────────────────────── default sub-structures ───────────────────────── */\n\n/** A NodeMeta with every barrier/flag cleared. */\nexport function defaultMeta(safetyFloor: SafetyLevel = 0): NodeMeta {\n return {\n hasRef: false,\n hasEventHandlers: false,\n hasKey: false,\n hasSpreadAttrs: false,\n hasDynamicChildren: false,\n isComponent: false,\n hasDangerousHtml: false,\n targetedByCombinator: false,\n targetedByStructuralPseudo: false,\n selectorDependents: 0,\n hasOwnVisualStyle: false,\n establishesBox: false,\n establishesStackingContext: false,\n isContainingBlock: false,\n establishesFormattingContext: false,\n declaresCustomProperties: false,\n whitespaceSensitive: false,\n touched: false,\n styleDirty: false,\n synthetic: false,\n safetyFloor,\n };\n}\n\n/** Canonical base style condition (`media:'' states:[] pseudoElement:''`). */\nexport const BASE_CONDITION: StyleCondition = { media: '', states: [], pseudoElement: '' };\n\n/** Stable serialization of a StyleCondition into a ConditionKey. */\nexport function conditionKey(c: StyleCondition): ConditionKey {\n const states = [...c.states].sort().join(',');\n return `${c.media}|${states}|${c.pseudoElement}` as ConditionKey;\n}\n\nexport const BASE_CONDITION_KEY: ConditionKey = conditionKey(BASE_CONDITION);\n\n/** An empty StyleMap (no blocks). */\nexport function emptyStyleMap(): StyleMap {\n return { blocks: new Map<ConditionKey, StyleBlock>() };\n}\n\n/** An empty (absent) ClassList. */\nexport function emptyClassList(): ClassList {\n return {\n form: 'absent',\n segments: [],\n valueSpan: null,\n hasDynamic: false,\n opaque: false,\n rewritable: false,\n };\n}\n\n/** An empty AttrMap. */\nexport function emptyAttrMap(): AttrMap {\n return { entries: new Map(), spreads: [], order: [] };\n}\n\n/** An empty InlineStyle. */\nexport function emptyInlineStyle(): InlineStyle {\n return { decls: new Map<CssProperty, never>() as InlineStyle['decls'], dynamic: null };\n}\n\n/* ───────────────────────── node factories ───────────────────────── */\n\nexport interface ElementInit {\n readonly tag: string;\n readonly namespace?: IRNamespace;\n readonly isComponent?: boolean;\n readonly selfClosing?: boolean;\n readonly classes?: ClassList;\n readonly inlineStyle?: InlineStyle;\n readonly computed?: StyleMap;\n readonly attrs?: AttrMap;\n readonly children?: IRNodeId[];\n readonly parent?: IRNodeId | null;\n readonly span?: SourceSpan | null;\n readonly meta?: NodeMeta;\n}\n\nexport function createElement(id: IRNodeId, init: ElementInit): IRElement {\n return {\n id,\n kind: 'element',\n parent: init.parent ?? null,\n span: init.span ?? null,\n meta: init.meta ?? defaultMeta(),\n tag: init.tag,\n namespace: init.namespace ?? 'html',\n isComponent: init.isComponent ?? false,\n selfClosing: init.selfClosing ?? false,\n classes: init.classes ?? emptyClassList(),\n inlineStyle: init.inlineStyle ?? emptyInlineStyle(),\n computed: init.computed ?? emptyStyleMap(),\n attrs: init.attrs ?? emptyAttrMap(),\n children: init.children ?? [],\n };\n}\n\nexport function createText(\n id: IRNodeId,\n value: string,\n opts?: { collapsible?: boolean; parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRText {\n return {\n id,\n kind: 'text',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n value,\n collapsible: opts?.collapsible ?? true,\n };\n}\n\nexport function createExpr(\n id: IRNodeId,\n expr: ExprRef,\n opts?: { parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRExpr {\n return {\n id,\n kind: 'expr',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n expr,\n };\n}\n\nexport function createFragment(\n id: IRNodeId,\n opts?: { children?: IRNodeId[]; parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRFragment {\n return {\n id,\n kind: 'fragment',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n children: opts?.children ?? [],\n };\n}\n\nexport function createComment(\n id: IRNodeId,\n value: string,\n opts?: { parent?: IRNodeId | null; span?: SourceSpan | null },\n): IRComment {\n return {\n id,\n kind: 'comment',\n parent: opts?.parent ?? null,\n span: opts?.span ?? null,\n meta: defaultMeta(),\n value,\n };\n}\n\n/** Build an empty document whose root is a fresh fragment. */\nexport function createDocument(frontend: FrontendKind): IRDocument {\n const alloc = createIdAllocator();\n const rootId = alloc.next();\n const root = createFragment(rootId);\n const nodes = new Map<IRNodeId, IRNode>([[rootId, root]]);\n return {\n root: rootId,\n nodes,\n exprs: createExprRegistry(),\n sources: new Map(),\n backref: createBackrefTable(),\n frontend,\n alloc,\n };\n}\n\n/* ───────────────────────── tree accessors ───────────────────────── */\n\n/** Returns the child id list for container nodes, or an empty array. */\nexport function childIds(node: IRNode): readonly IRNodeId[] {\n return node.kind === 'element' || node.kind === 'fragment' ? node.children : [];\n}\n\n/** Returns the node, or undefined. */\nexport function getNode(doc: IRDocument, id: IRNodeId): IRNode | undefined {\n return doc.nodes.get(id);\n}\n\n/** Returns the node iff it is an element. */\nexport function getElement(doc: IRDocument, id: IRNodeId): IRElement | undefined {\n const n = doc.nodes.get(id);\n return n && n.kind === 'element' ? n : undefined;\n}\n\n/** Pre-order list of every element id reachable from the root. */\nexport function elementIds(doc: IRDocument): IRNodeId[] {\n const out: IRNodeId[] = [];\n const visit = (id: IRNodeId): void => {\n const n = doc.nodes.get(id);\n if (!n) return;\n if (n.kind === 'element') out.push(id);\n for (const c of childIds(n)) visit(c);\n };\n visit(doc.root);\n return out;\n}\n\n/* ───────────────────────── traversal ───────────────────────── */\n\n/**\n * Depth-first pre/post-order walk. `enter` may return `'skip'` (don't descend) or `'stop'`\n * (abort the whole walk); `exit` may return `'stop'`. The visitor receives a live {@link IRNode}\n * plus a {@link VisitContext} exposing depth and the parent node.\n */\nexport function walk(doc: IRDocument, visitor: Visitor): void {\n const roDoc = doc as unknown as VisitContext['doc'];\n let stopped = false;\n\n const visit = (id: IRNodeId, depth: number): void => {\n if (stopped) return;\n const node = doc.nodes.get(id);\n if (!node) return;\n\n const ctx: VisitContext = {\n doc: roDoc,\n depth,\n parent(): IRNode | null {\n return node.parent == null ? null : doc.nodes.get(node.parent) ?? null;\n },\n };\n\n const entered: VisitSignal = visitor.enter ? visitor.enter(node, ctx) : undefined;\n if (entered === 'stop') {\n stopped = true;\n return;\n }\n if (entered !== 'skip') {\n for (const child of childIds(node)) {\n visit(child, depth + 1);\n if (stopped) return;\n }\n }\n\n const exited: VisitSignal = visitor.exit ? visitor.exit(node, ctx) : undefined;\n if (exited === 'stop') stopped = true;\n };\n\n visit(doc.root, 0);\n}\n","/**\n * @domflax/pattern-kit — the shared StyleMap normalizer.\n *\n * A single, syntactic-only {@link StyleNormalizer} implementation that core, the patterns, and the\n * verifier all reuse so they agree, byte-for-byte, on what two style declarations \"mean\". It NEVER\n * resolves initial/inherited/computed defaults (that is the verifier's job) — it only:\n *\n * • canonicalizes colors (`transparent` ⇒ `rgba(0, 0, 0, 0)`, hex lower-cased + 3→6 expanded,\n * `rgb()/rgba()/hsl()/hsla()` argument spacing normalized),\n * • canonicalizes units (whitespace collapsed, zero-lengths `0px`/`0%`/… ⇒ `0`),\n * • expands a fixed set of box shorthands to longhands (`padding`/`margin`/`inset`/`border-width`\n * into their four sides, `gap` into `row-gap`/`column-gap`),\n * • orders declarations by property for stable comparison.\n *\n * Dependency-free: only `@domflax/core` (types + the StyleMap builder helpers).\n */\n\nimport type {\n CssProperty,\n CssValue,\n ConditionKey,\n InheritedPropertyTable,\n StyleBlock,\n StyleDecl,\n StyleMap,\n StyleNormalizer,\n} from '@domflax/core';\n\nimport { conditionKey, emptyStyleMap } from '@domflax/core';\n\n/* ───────────────────────── inherited-property table ───────────────────────── */\n\n/**\n * Canonical, versioned set of inherited CSS longhands. Any author custom property (`--*`) is\n * also treated as inherited via the `isInherited` predicate.\n */\nconst INHERITED_PROPERTIES: readonly string[] = [\n 'azimuth',\n 'border-collapse',\n 'border-spacing',\n 'caption-side',\n 'color',\n 'cursor',\n 'direction',\n 'empty-cells',\n 'font-family',\n 'font-feature-settings',\n 'font-kerning',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-variant-caps',\n 'font-variant-numeric',\n 'font-weight',\n 'hyphens',\n 'letter-spacing',\n 'line-height',\n 'list-style-image',\n 'list-style-position',\n 'list-style-type',\n 'orphans',\n 'overflow-wrap',\n 'quotes',\n 'tab-size',\n 'text-align',\n 'text-align-last',\n 'text-decoration-color',\n 'text-indent',\n 'text-justify',\n 'text-rendering',\n 'text-shadow',\n 'text-transform',\n 'text-underline-position',\n 'visibility',\n 'white-space',\n 'widows',\n 'word-break',\n 'word-spacing',\n 'writing-mode',\n '-webkit-font-smoothing',\n];\n\nfunction createInheritedTable(): InheritedPropertyTable {\n const properties = new Set<CssProperty>(INHERITED_PROPERTIES as unknown as CssProperty[]);\n return {\n version: 'domflax-inherited@1',\n properties,\n isInherited(property: CssProperty): boolean {\n // Author custom properties (`--*`) inherit by definition.\n return String(property).startsWith('--') || properties.has(property);\n },\n };\n}\n\n/* ───────────────────────── value canonicalization ───────────────────────── */\n\nconst ZERO_LENGTH_RE =\n /\\b0(?:px|em|rem|ex|ch|vh|vw|vmin|vmax|vi|vb|pt|pc|cm|mm|in|q|lh|rlh|fr|deg|rad|turn|s|ms|%)\\b/g;\n\nconst FUNC_ARGS_RE = /\\b(rgba?|hsla?|hwb|lab|lch|oklab|oklch)\\(([^()]*)\\)/gi;\n\nconst RELATIVE_UNIT_RE = /(?:\\d*\\.?\\d+)(?:em|ex|ch|lh)\\b|%/i;\n\n/**\n * Pure, syntactic value canonicalization. Idempotent: `canon(canon(v)) === canon(v)`.\n */\nfunction canonValue(raw: string): string {\n let v = raw.trim().replace(/\\s+/g, ' ');\n\n // Lower-case hex colors (#abc / #aabbcc / #aabbccff).\n v = v.replace(/#([0-9a-fA-F]{3,8})\\b/g, (_m, hex: string) => '#' + hex.toLowerCase());\n\n // Expand 3-digit hex (#abc → #aabbcc) — only when exactly 3 hex digits.\n v = v.replace(\n /#([0-9a-f])([0-9a-f])([0-9a-f])(?![0-9a-f])/g,\n (_m, r: string, g: string, b: string) => `#${r}${r}${g}${g}${b}${b}`,\n );\n\n // Canonical fully-transparent color.\n v = v.replace(/\\btransparent\\b/gi, 'rgba(0, 0, 0, 0)');\n v = v.replace(/#00000000\\b/g, 'rgba(0, 0, 0, 0)');\n\n // Collapse zero lengths/angles/times to a bare `0`.\n v = v.replace(ZERO_LENGTH_RE, '0');\n\n // Normalize the argument spacing of color/space functions: single space after each comma.\n v = v.replace(FUNC_ARGS_RE, (_m, fn: string, args: string) => {\n const parts = args\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return `${fn.toLowerCase()}(${parts.join(', ')})`;\n });\n\n return v;\n}\n\n/** True when the (canonicalized) value uses a parent-relative unit (em/ex/ch/lh/%). */\nfunction isRelativeValue(value: string): boolean {\n return RELATIVE_UNIT_RE.test(value);\n}\n\n/* ───────────────────────── shorthand expansion ───────────────────────── */\n\n/** Box-model shorthands whose 1–4 value form expands to four explicit sides. */\nconst BOX_SIDES: Readonly<Record<string, readonly [string, string, string, string]>> = {\n padding: ['padding-top', 'padding-right', 'padding-bottom', 'padding-left'],\n margin: ['margin-top', 'margin-right', 'margin-bottom', 'margin-left'],\n inset: ['top', 'right', 'bottom', 'left'],\n 'border-width': [\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n ],\n 'border-style': [\n 'border-top-style',\n 'border-right-style',\n 'border-bottom-style',\n 'border-left-style',\n ],\n 'border-color': [\n 'border-top-color',\n 'border-right-color',\n 'border-bottom-color',\n 'border-left-color',\n ],\n};\n\n/** Split on top-level whitespace, keeping `fn(a, b)` groups intact. */\nfunction splitTopLevel(value: string): string[] {\n const out: string[] = [];\n let depth = 0;\n let cur = '';\n for (const ch of value) {\n if (ch === '(') depth += 1;\n else if (ch === ')') depth = Math.max(0, depth - 1);\n if (depth === 0 && /\\s/.test(ch)) {\n if (cur.length > 0) {\n out.push(cur);\n cur = '';\n }\n continue;\n }\n cur += ch;\n }\n if (cur.length > 0) out.push(cur);\n return out;\n}\n\n/** Map a 1–4 value box shorthand onto its [top, right, bottom, left] sides. */\nfunction boxFourSides(values: readonly string[]): [string, string, string, string] {\n const [a, b, c, d] = values;\n switch (values.length) {\n case 1:\n return [a!, a!, a!, a!];\n case 2:\n return [a!, b!, a!, b!];\n case 3:\n return [a!, b!, c!, b!];\n default:\n return [a!, b!, c!, d!];\n }\n}\n\n/** Expand one declaration into longhand `[property, value]` pairs (single pair if not shorthand). */\nfunction expandShorthand(prop: string, value: string): Array<[string, string]> {\n const box = BOX_SIDES[prop];\n if (box) {\n const parts = splitTopLevel(value);\n if (parts.length >= 1 && parts.length <= 4) {\n const sides = boxFourSides(parts);\n return box.map((p, i) => [p, sides[i]!] as [string, string]);\n }\n return [[prop, value]];\n }\n\n if (prop === 'gap' || prop === 'grid-gap') {\n const parts = splitTopLevel(value);\n if (parts.length === 1) {\n return [\n ['row-gap', parts[0]!],\n ['column-gap', parts[0]!],\n ];\n }\n if (parts.length === 2) {\n return [\n ['row-gap', parts[0]!],\n ['column-gap', parts[1]!],\n ];\n }\n return [[prop, value]];\n }\n\n return [[prop, value]];\n}\n\n/* ───────────────────────── the normalizer ───────────────────────── */\n\nfunction makeDecl(\n table: InheritedPropertyTable,\n prop: string,\n rawValue: string,\n important: boolean,\n): StyleDecl {\n const property = prop.trim().toLowerCase() as CssProperty;\n const value = canonValue(rawValue) as CssValue;\n return {\n property,\n value,\n important,\n relativeToParent: isRelativeValue(value),\n inherited: table.isInherited(property),\n };\n}\n\nexport function createNormalizer(): StyleNormalizer {\n const inherited = createInheritedTable();\n\n const normalizeDeclaration = (\n prop: string,\n value: string,\n important: boolean,\n ): readonly StyleDecl[] => {\n const p = prop.trim().toLowerCase();\n const expanded = expandShorthand(p, value.trim());\n return expanded.map(([lp, lv]) => makeDecl(inherited, lp, lv, important));\n };\n\n const normalizeValue = (prop: CssProperty, raw: string): CssValue => {\n void prop;\n return canonValue(raw) as CssValue;\n };\n\n const normalizeStyleMap = (sm: StyleMap): StyleMap => {\n const blocks = new Map<ConditionKey, StyleBlock>();\n for (const block of sm.blocks.values()) {\n const decls = new Map<CssProperty, StyleDecl>();\n // Re-canonicalize every value and re-key (the decls are already longhand).\n for (const decl of block.decls.values()) {\n const next: StyleDecl = {\n ...decl,\n value: canonValue(String(decl.value)) as CssValue,\n relativeToParent: isRelativeValue(String(decl.value)),\n inherited: inherited.isInherited(decl.property),\n };\n decls.set(next.property, next);\n }\n // Property-sorted for deterministic iteration/serialization.\n const sorted = new Map<CssProperty, StyleDecl>(\n [...decls.entries()].sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)),\n );\n const key = conditionKey(block.condition);\n blocks.set(key, { condition: block.condition, decls: sorted });\n }\n return { blocks };\n };\n\n const equals = (a: StyleMap, b: StyleMap): boolean => {\n const na = normalizeStyleMap(a);\n const nb = normalizeStyleMap(b);\n if (na.blocks.size !== nb.blocks.size) return false;\n for (const [key, blockA] of na.blocks) {\n const blockB = nb.blocks.get(key);\n if (!blockB) return false;\n if (blockA.decls.size !== blockB.decls.size) return false;\n for (const [prop, declA] of blockA.decls) {\n const declB = blockB.decls.get(prop);\n if (!declB) return false;\n if (declA.value !== declB.value || declA.important !== declB.important) return false;\n }\n }\n return true;\n };\n\n return {\n version: 'domflax-normalizer@1',\n normalizeDeclaration,\n normalizeValue,\n normalizeStyleMap,\n equals,\n inherited,\n };\n}\n\n/** The shared, process-wide normalizer instance reused by core / patterns / verify. */\nexport const normalizer: StyleNormalizer = createNormalizer();\n\n/* ───────────────────────── superset helper (used by `computed()` matcher) ───────────────────────── */\n\n/**\n * True when `full` contains every declaration of `partial` with an equal normalized value\n * (a per-condition, per-declaration superset test). Both maps are normalized first so the\n * comparison is meaning-based, not string-based. Empty `partial` ⇒ always `true`.\n */\nexport function isStyleSuperset(\n full: StyleMap,\n partial: StyleMap,\n norm: StyleNormalizer = normalizer,\n): boolean {\n const nf = norm.normalizeStyleMap(full);\n const np = norm.normalizeStyleMap(partial);\n for (const [key, want] of np.blocks) {\n const have = nf.blocks.get(key) ?? nf.blocks.get(conditionKey(want.condition));\n if (!have) return false;\n for (const [prop, decl] of want.decls) {\n const got = have.decls.get(prop);\n if (!got || got.value !== decl.value) return false;\n }\n }\n return true;\n}\n\n/** Re-exported for callers that want to (de)construct keys without importing core directly. */\nexport { emptyStyleMap };\n","/**\n * @domflax/pattern-kit — composable matcher vocabulary.\n *\n * A {@link Matcher} is a PURE predicate over a node + its {@link MatchContext}. Matchers never\n * mutate; they only read the (DeepReadonly) IR and the precomputed targeting/selector facts the\n * context exposes. Authors compose them with {@link and}/{@link or}/{@link not} and feed the\n * result into a pattern's `evaluate`.\n *\n * Style-aware matchers (`computed`, `hasOwnVisualStyle`) reason over the NORMALIZED StyleMap via\n * the shared normalizer in `./normalize`, so they query meaning, not raw CSS strings.\n */\n\nimport type {\n DeepReadonly,\n ElementLike,\n IRElement,\n IRNode,\n IRNodeId,\n MatchContext,\n NodeLike,\n StyleMap,\n} from '@domflax/core';\n\nimport { isStyleSuperset, normalizer } from './normalize';\n\n/** A pure predicate: does `node` satisfy this condition in the given match context? */\nexport type Matcher = (node: NodeLike, ctx: MatchContext) => boolean;\n\n/* ───────────────────────── internal helpers ───────────────────────── */\n\nfunction asElement(node: NodeLike): DeepReadonly<IRElement> | null {\n const n = node as DeepReadonly<IRNode>;\n return n.kind === 'element' ? (n as DeepReadonly<IRElement>) : null;\n}\n\nfunction elementChildrenOf(\n el: DeepReadonly<IRElement>,\n ctx: MatchContext,\n): DeepReadonly<IRElement>[] {\n const out: DeepReadonly<IRElement>[] = [];\n for (const childId of el.children) {\n const child = ctx.doc.nodes.get(childId);\n if (child && child.kind === 'element') out.push(child as DeepReadonly<IRElement>);\n }\n return out;\n}\n\n/* ───────────────────────── boolean combinators ───────────────────────── */\n\n/** Logical AND. Empty list ⇒ always matches. Short-circuits on the first failure. */\nexport function and(...matchers: readonly Matcher[]): Matcher {\n return (node, ctx) => matchers.every((m) => m(node, ctx));\n}\n\n/** Logical OR. Empty list ⇒ never matches. Short-circuits on the first success. */\nexport function or(...matchers: readonly Matcher[]): Matcher {\n return (node, ctx) => matchers.some((m) => m(node, ctx));\n}\n\n/** Logical NOT. */\nexport function not(matcher: Matcher): Matcher {\n return (node, ctx) => !matcher(node, ctx);\n}\n\n/* ───────────────────────── structural matchers ───────────────────────── */\n\n/** Matches any element; with `tag`, only elements whose (case-insensitive) tag equals it. */\nexport function isElement(tag?: string): Matcher {\n const want = tag?.toLowerCase();\n return (node) => {\n const el = asElement(node);\n if (!el) return false;\n return want === undefined || el.tag.toLowerCase() === want;\n };\n}\n\n/** Matches an element with exactly one ELEMENT child (text/expr/comment children ignored). */\nexport const hasSingleElementChild: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return elementChildrenOf(el, ctx).length === 1;\n};\n\n/* ───────────────────────── style matchers ───────────────────────── */\n\n/**\n * Matches when the node's computed StyleMap is a SUPERSET of `partial` — i.e. every declaration\n * in `partial` is present in `node.computed` with an equal normalized value. Comparison is\n * meaning-based (both sides normalized first). Empty `partial` always matches.\n */\nexport function computed(partial: StyleMap): Matcher {\n return (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n const full = ctx.computedOf(el as unknown as NodeLike) ?? (el.computed as StyleMap);\n return isStyleSuperset(full as StyleMap, partial, normalizer);\n };\n}\n\n/** Visual (paint-establishing) properties that count as \"own visual style\", beyond pure layout. */\nconst VISUAL_PROPERTIES: ReadonlySet<string> = new Set<string>([\n 'background',\n 'background-color',\n 'background-image',\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n 'border-top-style',\n 'border-right-style',\n 'border-bottom-style',\n 'border-left-style',\n 'border-top-color',\n 'border-right-color',\n 'border-bottom-color',\n 'border-left-color',\n 'border-radius',\n 'box-shadow',\n 'outline',\n 'outline-width',\n 'outline-style',\n 'outline-color',\n 'text-shadow',\n 'filter',\n 'backdrop-filter',\n 'mix-blend-mode',\n 'opacity',\n]);\n\n/** Values that mean \"no paint\" — a visual property set to one of these does NOT count. */\nconst EMPTY_VISUAL_VALUES: ReadonlySet<string> = new Set<string>([\n 'none',\n '0',\n 'normal',\n 'transparent',\n 'rgba(0, 0, 0, 0)',\n 'initial',\n 'unset',\n 'auto',\n]);\n\n/**\n * Matches when the element paints something of its own: a meaningful background, border, shadow,\n * outline, filter, etc. across ANY style condition. Honours the frontend-set `meta.hasOwnVisualStyle`\n * fast-path, then falls back to scanning the normalized computed StyleMap.\n */\nexport const hasOwnVisualStyle: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n if (el.meta.hasOwnVisualStyle) return true;\n\n const computedMap = ctx.computedOf(el as unknown as NodeLike) ?? (el.computed as StyleMap);\n const norm = normalizer.normalizeStyleMap(computedMap as StyleMap);\n for (const block of norm.blocks.values()) {\n for (const decl of block.decls.values()) {\n if (!VISUAL_PROPERTIES.has(String(decl.property))) continue;\n if (!EMPTY_VISUAL_VALUES.has(String(decl.value))) return true;\n }\n }\n return false;\n};\n\n/* ───────────────────────── opacity-barrier / meta matchers ───────────────────────── */\n\n/** Element carries a `ref` (hard opacity barrier). */\nexport const hasRef: Matcher = (node) => asElement(node)?.meta.hasRef ?? false;\n\n/** Element has event handlers (onClick, …). */\nexport const hasEventHandlers: Matcher = (node) => asElement(node)?.meta.hasEventHandlers ?? false;\n\n/** Element has dynamic children (mapped/conditional islands). */\nexport const hasDynamicChildren: Matcher = (node) =>\n asElement(node)?.meta.hasDynamicChildren ?? false;\n\n/** Element's class list contains a dynamic segment (template/expr) → not freely rewritable. */\nexport const hasDynamicClasses: Matcher = (node) => asElement(node)?.classes.hasDynamic ?? false;\n\n/**\n * Element's class list is wholly dynamic / spread-derived (`classes.opaque`, or spread attrs) — its\n * concrete tokens can't be seen or statically rewritten, so a class-rewriting (compress) pattern\n * must decline. Delegates to the context's authoritative {@link MatchContext.isOpaque}.\n */\nexport const opaque: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return ctx.isOpaque(el as unknown as ElementLike);\n};\n\n/**\n * Element is the subject of a combinator selector (`>`/`+`/`~`). Honours the frontend-set meta\n * flag and the precomputed {@link SelectorIndex} in the context.\n */\nexport const targetedByCombinator: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n if (el.meta.targetedByCombinator) return true;\n // `el.id` is a branded number; DeepReadonly widens the brand, so re-narrow for the index call.\n return ctx.selectors.targetedByCombinator(el.id as unknown as IRNodeId);\n};\n","/**\n * @domflax/pattern-kit — ergonomic op-draft constructors.\n *\n * Thin, pure helpers that build the core {@link RewriteOpDraft} objects so pattern authors can\n * assemble a `MatchResult.ops` array without hand-writing discriminant literals. Drafts carry NO\n * `origin` — the pass-manager stamps `{ pattern, category, safety }` when it schedules the op\n * (see core's `stampOrigin`). Each helper accepts a live node, a DeepReadonly view, or a bare\n * {@link IRNodeId}.\n *\n * Mirrors the four ops a rewrite typically reaches for: `mergeStyle`, `foldInheritedStyles`,\n * `replaceWith`, `removeNode`.\n */\n\nimport type {\n CssProperty,\n ElementLike,\n IRNode,\n IRNodeId,\n NodeLike,\n NodeSpec,\n RewriteOpDraft,\n StyleConflictPolicy,\n StyleMap,\n} from '@domflax/core';\n\n/** Accept a live/readonly node or a bare id. */\ntype Ref = NodeLike | ElementLike | IRNodeId;\n\nfunction idOf(ref: Ref): IRNodeId {\n return typeof ref === 'number' ? (ref as IRNodeId) : ((ref as IRNode).id as IRNodeId);\n}\n\n/* ───────────────────────── style ops ───────────────────────── */\n\n/**\n * Merge `style` onto `target`, optionally pulling from `source` (or `null` for a literal patch).\n * `onConflict` defaults to `'abort'` — the safest policy (the applier refuses rather than guess).\n */\nexport function mergeStyle(\n target: Ref,\n source: Ref | null,\n style: StyleMap,\n onConflict: StyleConflictPolicy = 'abort',\n): RewriteOpDraft {\n return {\n op: 'mergeStyle',\n target: idOf(target),\n source: source == null ? null : idOf(source),\n style,\n onConflict,\n };\n}\n\n/**\n * Fold inheritable declarations from `from` down into one or more descendants. `conditions:'all'`\n * folds across every StyleCondition (states/media/pseudo-elements); the default `'base'` folds only\n * the unconditional block. `only` restricts the property set (otherwise `'all-inherited'`).\n */\nexport function foldInheritedStyles(\n from: Ref,\n into: Ref | readonly Ref[],\n opts?: { only?: readonly CssProperty[]; conditions?: 'base' | 'all' },\n): RewriteOpDraft {\n const list: readonly Ref[] = Array.isArray(into) ? (into as readonly Ref[]) : [into as Ref];\n return {\n op: 'foldInheritedStyles',\n from: idOf(from),\n into: list.map(idOf),\n properties: opts?.only ?? 'all-inherited',\n conditions: opts?.conditions ?? 'base',\n };\n}\n\n/* ───────────────────────── structural ops ───────────────────────── */\n\n/** Replace `target` with a detached {@link NodeSpec} (the applier materializes ids on apply). */\nexport function replaceWith(target: Ref, replacement: NodeSpec): RewriteOpDraft {\n return { op: 'replaceWith', target: idOf(target), replacement };\n}\n\n/** Remove `target` (and its subtree) from the tree. */\nexport function removeNode(target: Ref): RewriteOpDraft {\n return { op: 'removeNode', target: idOf(target) };\n}\n","/**\n * @domflax/pattern-kit — `validatePattern` (INTERNAL).\n *\n * A small, eager validator + identity wrapper that turns a lowered {@link Pattern} spec into a\n * frozen, contract-checked Pattern. Catching shape errors here (bad category/phase, missing\n * `evaluate`, out-of-range safety) keeps the pass-manager's hot loop free of defensive checks and\n * gives authors an immediate, actionable error at module-load time.\n *\n * This is the PRIVATE lower-level core: it is consumed only by the declarative\n * {@link import('./pattern').definePattern} authoring surface (which compiles a high-level config\n * down to a {@link Pattern} and then runs it through this validator). It is intentionally NOT part\n * of the public package surface — authors use `definePattern` instead.\n */\n\nimport type { PassPhase, Pattern, SafetyLevel } from '@domflax/core';\n\nconst PHASES: ReadonlySet<PassPhase> = new Set<PassPhase>(['flatten', 'compress', 'extract']);\nconst SAFETY_LEVELS: ReadonlySet<SafetyLevel> = new Set<SafetyLevel>([0, 1, 2, 3]);\n\nfunction fail(name: string, why: string): never {\n throw new Error(`definePattern(${name || '<anonymous>'}): ${why}`);\n}\n\n/**\n * Validate and freeze a {@link Pattern}. Throws on any contract violation; otherwise returns the\n * (shallow-frozen) spec unchanged so it can be registered into a {@link Pass}. INTERNAL — see the\n * module header; authors call the declarative {@link import('./pattern').definePattern}.\n */\nexport function validatePattern(spec: Pattern): Pattern {\n if (spec == null || typeof spec !== 'object') {\n throw new Error('definePattern: spec must be an object');\n }\n\n const name = spec.name;\n if (typeof name !== 'string' || name.length === 0) {\n fail(String(name), 'name must be a non-empty string');\n }\n\n if (typeof spec.category !== 'string' || !spec.category.includes('/')) {\n fail(name, `category must be a \"<phase>/<slug>\" string (got ${JSON.stringify(spec.category)})`);\n }\n\n const phase = spec.category.split('/', 1)[0] as PassPhase;\n if (!PHASES.has(phase)) {\n fail(name, `category phase must be one of flatten|compress|extract (got \"${phase}\")`);\n }\n\n if (!SAFETY_LEVELS.has(spec.safety)) {\n fail(name, `safety must be 0|1|2|3 (got ${JSON.stringify(spec.safety)})`);\n }\n\n if (typeof spec.evaluate !== 'function') {\n fail(name, 'evaluate must be a function');\n }\n\n if (spec.priority !== undefined && !Number.isFinite(spec.priority)) {\n fail(name, 'priority must be a finite number when provided');\n }\n\n return Object.freeze({ ...spec });\n}\n","/**\n * @domflax/pattern-kit — `definePattern()`: THE declarative pattern-authoring surface.\n *\n * `definePattern(config)` is the single public way to author a rewrite pattern: definition AND its\n * tests are co-located in one call. It compiles down to the private lower-level\n * {@link import('./define').validatePattern}/{@link Pattern} contract (it never replaces the\n * engine). Authors describe the match as a plain DATA object and the rewrite as a named RECIPE; this\n * module maps each key to the existing matcher combinators and op-draft factories, auto-applies the\n * phase-appropriate safety guards (the full opacity-barrier + selector set for `flatten/*`; the\n * narrower class-rewrite-safety set for `compress/*`) so authors never hand-write them, and threads\n * `doc`/`test` through. Two escape hatches — a `match` predicate and a `rewrite` function — keep\n * exotic patterns (e.g. ones anchored on a parent fragment) expressible.\n *\n * The co-located {@link PatternTest} (`provider`/`cssFiles`/`cases`/`noMatch`/`custom`) is carried on\n * the compiled {@link AuthoredPattern} as `.test`, where the generic harness (`./testing`) reads it:\n * each `case` asserts `before → after`, each `noMatch` asserts the input is left unchanged, and the\n * optional `custom` hook runs arbitrary assertions against the built transform.\n *\n * `style` blocks in the declarative match (and in `childGains`/`mergeStyle` recipes) are PLAIN\n * objects (camelCase or kebab keys) auto-normalized into a superset StyleMap via the shared\n * normalizer — authors never import the normalizer or hand-build a StyleMap.\n *\n * `pattern` remains exported as a DEPRECATED alias of `definePattern` for backward compatibility.\n */\n\nimport type {\n Captures,\n ConditionKey,\n CssProperty,\n DeepReadonly,\n IRElement,\n IRNode,\n IRNodeId,\n MatchContext,\n MatchResult,\n NodeLike,\n NodeMeta,\n PassCategory,\n PassPhase,\n Pattern,\n PatternDoc,\n PreconditionSketch,\n RewriteFactory,\n RewriteOpDraft,\n SafetyLevel,\n StyleBlock,\n StyleDecl,\n StyleMap,\n StyleOrigin,\n StyleConflictPolicy,\n} from '@domflax/core';\nimport { BASE_CONDITION, conditionKey } from '@domflax/core';\n\nimport {\n and,\n computed,\n hasDynamicChildren,\n hasDynamicClasses,\n hasEventHandlers,\n hasOwnVisualStyle,\n hasRef,\n hasSingleElementChild,\n isElement,\n not,\n opaque,\n targetedByCombinator,\n type Matcher,\n} from './combinators';\nimport { validatePattern } from './define';\nimport { normalizer } from './normalize';\n\n/* ───────────────────────── public config shapes ───────────────────────── */\n\n/** A plain CSS style object: camelCase or kebab-case keys, string or number values. */\nexport type PlainStyle = Readonly<Record<string, string | number>>;\n\n/**\n * Declarative match as DATA. Every key maps to one of the existing matcher combinators; an empty\n * object matches any element. Use the `match` FUNCTION escape hatch for anything not expressible\n * here (relational/ancestor/sibling shapes, parent-anchored patterns, …).\n */\nexport interface DeclarativeMatch {\n /** Restrict to a tag (case-insensitive). Omit to match any element. */\n readonly tag?: string;\n /** Computed style the node must be a SUPERSET of (plain object, auto-normalized). */\n readonly style?: PlainStyle;\n /** Require exactly one ELEMENT child. */\n readonly onlyChild?: 'element';\n /** Require the element to paint nothing of its own (no own visual style). */\n readonly paintsNothing?: boolean;\n /** Extra, hand-written predicate AND-ed into the declarative match. */\n readonly where?: Matcher | readonly Matcher[];\n}\n\n/** Escape hatch: a raw match predicate (no auto-guards are added). */\nexport type MatchFn = (node: NodeLike, ctx: MatchContext) => boolean;\n\n/**\n * Flatten recipe: fold inherited styles onto the sole element child (default on), optionally merge\n * `childGains` onto it, then unwrap the node (id-preserving). Mirrors the flatten exemplars.\n */\nexport interface FlattenIntoRecipe {\n readonly flattenInto: 'child';\n /** Plain style merged onto the surviving child (source-wins) before unwrap. */\n readonly childGains?: PlainStyle;\n /** Fold inheritable declarations onto the child first. Default `true`. */\n readonly foldInherited?: boolean;\n}\n\n/** Compress recipe: rebuild the element's class StyleMap; return `null` to decline. */\nexport interface RewriteClassesRecipe {\n readonly rewriteClasses: (computed: StyleMap, ctx: MatchContext) => StyleMap | null;\n /** Keep opaque/selector-bound tokens verbatim. Default `true`. */\n readonly preserveOpaque?: boolean;\n}\n\n/** Compress recipe: drop fully-overridden class tokens (provenance is pruned automatically). */\nexport interface DropClassesRecipe {\n readonly dropClasses: (computed: StyleMap, ctx: MatchContext) => Iterable<string>;\n /** Keep opaque/selector-bound tokens verbatim. Default `true`. */\n readonly preserveOpaque?: boolean;\n}\n\n/** Merge a literal plain style onto the matched element. */\nexport interface MergeStyleRecipe {\n readonly mergeStyle: PlainStyle;\n readonly onConflict?: StyleConflictPolicy;\n}\n\nexport type RewriteRecipe =\n | FlattenIntoRecipe\n | RewriteClassesRecipe\n | DropClassesRecipe\n | MergeStyleRecipe;\n\n/** Escape hatch: a raw rewrite that returns op drafts (or `null`/`[]` for no-op). */\nexport type RewriteFn = (\n ctx: MatchContext,\n rw: RewriteFactory,\n) => readonly RewriteOpDraft[] | null;\n\n/** A single positive before→after assertion run through the pattern's built transform. */\nexport interface PatternTestCase {\n readonly name?: string;\n readonly before: string;\n readonly after: string;\n}\n\n/** Helpers handed to a {@link PatternTest.custom} hook (the built transform + expectation sugar). */\nexport interface TestHelpers {\n /** Run the pattern's transform on `code` (default filename `'X.tsx'`). */\n readonly transform: (code: string, filename?: string) => string;\n /** Assert `before` transforms to `after` (whitespace-normalized). */\n readonly expectTransforms: (before: string, after: string) => void;\n /** Assert `code` is left unchanged (whitespace-normalized). */\n readonly expectUnchanged: (code: string) => void;\n}\n\n/**\n * Co-located test spec for a pattern. The generic harness (`./testing`) builds a transform for the\n * declared `provider` (default `'tailwind'`; `'custom'` resolves the listed `cssFiles`), then runs\n * every `case` (`before → after`), every `noMatch` (left unchanged), and the optional `custom` hook.\n */\nexport interface PatternTest {\n /** Which style provider the harness builds the transform from. Default `'tailwind'`. */\n readonly provider?: 'tailwind' | 'custom';\n /** For `provider: 'custom'` — the project stylesheet paths backing the CSS resolver. */\n readonly cssFiles?: readonly string[];\n /** Positive before→after assertions. */\n readonly cases?: readonly PatternTestCase[];\n /** Inputs the pattern must leave UNCHANGED (barriers, non-matching shapes, safety reverts). */\n readonly noMatch?: readonly string[];\n /** Arbitrary extra assertions against the built transform. */\n readonly custom?: (h: TestHelpers) => void;\n}\n\nexport interface PatternConfig {\n readonly name: string;\n readonly category: PassCategory;\n readonly safety: SafetyLevel;\n readonly priority?: number;\n readonly precondition?: PreconditionSketch;\n readonly doc?: PatternDoc;\n /** Co-located tests consumed by the generic harness (`./testing`). */\n readonly test?: PatternTest;\n /** Declarative match DATA, or a raw predicate escape hatch. Defaults to \"any element\". */\n readonly match?: DeclarativeMatch | MatchFn;\n /** A named rewrite recipe, or a raw op-draft factory escape hatch. */\n readonly rewrite: RewriteRecipe | RewriteFn;\n}\n\n/** A {@link Pattern} that also carries its co-located {@link PatternTest} for the test harness. */\nexport interface AuthoredPattern<C extends Captures = Captures> extends Pattern {\n readonly test?: PatternTest;\n evaluate(ctx: MatchContext, rw: RewriteFactory): MatchResult<C> | null;\n}\n\n/* ───────────────────────── plain-style → StyleMap ───────────────────────── */\n\nfunction camelToKebab(key: string): string {\n if (key.startsWith('--')) return key; // custom property — leave verbatim\n return key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n}\n\n/** Build a single-(base-)condition StyleMap from a plain style object via the shared normalizer. */\nfunction plainToStyleMap(style: PlainStyle): StyleMap {\n const decls = new Map<CssProperty, StyleDecl>();\n for (const [rawKey, rawValue] of Object.entries(style)) {\n const prop = camelToKebab(rawKey);\n for (const decl of normalizer.normalizeDeclaration(prop, String(rawValue), false)) {\n decls.set(decl.property, decl);\n }\n }\n const block: StyleBlock = { condition: BASE_CONDITION, decls };\n return { blocks: new Map<ConditionKey, StyleBlock>([[conditionKey(BASE_CONDITION), block]]) };\n}\n\n/* ───────────────────────── local meta / selector matchers ───────────────────────── */\n\nfunction asElement(node: NodeLike): DeepReadonly<IRElement> | null {\n const n = node as DeepReadonly<IRNode>;\n return n.kind === 'element' ? (n as DeepReadonly<IRElement>) : null;\n}\n\nfunction metaFlag(flag: keyof NodeMeta): Matcher {\n return (node) => Boolean(asElement(node)?.meta[flag]);\n}\n\n/** Element renders raw/`dangerouslySetInnerHTML` markup — a hard opacity barrier. */\nconst hasRawHtml: Matcher = metaFlag('hasDangerousHtml');\n\n/**\n * Unwrapping/removing this node would change the combinator / structural-pseudo match-set of itself,\n * its child, or a former sibling. Empty `reparentImpact` ⇒ structurally safe to hoist.\n */\nconst affectsSelectorMatching: Matcher = (node, ctx) => {\n const el = asElement(node);\n if (!el) return false;\n return ctx.selectors.reparentImpact(el.id as unknown as IRNodeId).size > 0;\n};\n\n/**\n * The opacity-barrier + selector-safety guards every `flatten/*` pattern must carry. Auto-applied to\n * the declarative match so authors never hand-write them (the flatten exemplars spell them out).\n *\n * Flatten UNWRAPS the element (moving its children into a new parent and dropping its box), so every\n * opacity barrier matters: a ref, event handler, dynamic child, or raw HTML on the wrapper — or any\n * selector the reparent would disturb — makes the flatten unsafe.\n */\nconst FLATTEN_GUARDS: Matcher = and(\n not(hasRef),\n not(hasEventHandlers),\n not(hasDynamicChildren),\n not(hasRawHtml),\n not(targetedByCombinator),\n not(affectsSelectorMatching),\n);\n\n/**\n * The guards every `compress/*` pattern must carry. Compress ONLY ever rewrites the element's OWN\n * class tokens (e.g. `px-4 py-4 → p-4`) — it never touches the element's structure, children, or\n * identity. A dynamic `{expr}` child, a ref, an event handler, or `dangerouslySetInnerHTML` is\n * therefore wholly unaffected by a class-only change, so — unlike flatten — those opacity barriers\n * must NOT gate compress. Compress is gated ONLY on what actually makes a class rewrite unsafe:\n * • a className we can't statically rewrite — a dynamic segment ({@link hasDynamicClasses}) or a\n * wholly dynamic / spread-derived list ({@link opaque}); and\n * • the selector-safety guard — a class a CSS combinator selector structurally depends on\n * ({@link targetedByCombinator}) must not be dropped or rewritten.\n */\nconst COMPRESS_GUARDS: Matcher = and(\n not(hasDynamicClasses),\n not(opaque),\n not(targetedByCombinator),\n);\n\n/* ───────────────────────── match compilation ───────────────────────── */\n\n/** The auto-applied guard set for a pattern's phase (compress vs flatten get different barriers). */\nfunction autoGuardsFor(category: PassCategory): Matcher | null {\n switch (category.split('/', 1)[0] as PassPhase) {\n case 'flatten':\n return FLATTEN_GUARDS;\n case 'compress':\n return COMPRESS_GUARDS;\n default:\n return null;\n }\n}\n\nfunction compileDeclarativeMatch(m: DeclarativeMatch): Matcher {\n const parts: Matcher[] = [isElement(m.tag)];\n if (m.style) parts.push(computed(plainToStyleMap(m.style)));\n if (m.onlyChild === 'element') parts.push(hasSingleElementChild);\n if (m.paintsNothing) parts.push(not(hasOwnVisualStyle));\n if (m.where) {\n const extra = Array.isArray(m.where) ? (m.where as readonly Matcher[]) : [m.where as Matcher];\n for (const w of extra) parts.push(w);\n }\n return and(...parts);\n}\n\nfunction compileMatch(\n match: DeclarativeMatch | MatchFn | undefined,\n category: PassCategory,\n): MatchFn {\n // Escape hatch: a raw predicate takes full control (no auto-guards).\n if (typeof match === 'function') return match;\n\n const declarative = compileDeclarativeMatch(match ?? {});\n const guards = autoGuardsFor(category);\n const guarded = guards ? and(declarative, guards) : declarative;\n return (node, ctx) => guarded(node, ctx);\n}\n\n/* ───────────────────────── rewrite compilation ───────────────────────── */\n\n/** Clone `sm`, pruning every `shadowed` provenance entry that references a dropped class token. */\nfunction pruneShadowed(sm: StyleMap, drop: ReadonlySet<string>): StyleMap {\n const blocks = new Map<ConditionKey, StyleBlock>();\n for (const [key, block] of sm.blocks) {\n const decls = new Map<CssProperty, StyleDecl>();\n for (const [prop, decl] of block.decls) {\n const filtered = (decl.shadowed ?? []).filter(\n (o) => !(o.kind === 'class' && drop.has(o.className)),\n );\n const rest: StyleDecl = { ...decl };\n delete (rest as { shadowed?: readonly StyleOrigin[] }).shadowed;\n const next: StyleDecl = filtered.length > 0 ? { ...rest, shadowed: filtered } : rest;\n decls.set(prop, next);\n }\n blocks.set(key, { condition: block.condition, decls });\n }\n return { blocks };\n}\n\nfunction compileFlattenInto(recipe: FlattenIntoRecipe): RewriteFn {\n const childGains = recipe.childGains ? plainToStyleMap(recipe.childGains) : null;\n const fold = recipe.foldInherited !== false;\n return (ctx, rw) => {\n const wrapper = ctx.node;\n const child = ctx.onlyElementChild();\n if (!child) return null;\n const ops: RewriteOpDraft[] = [];\n if (fold) ops.push(rw.foldInheritedStyles(wrapper, child, { conditions: 'all' }));\n if (childGains) ops.push(rw.mergeStyle(child, null, childGains, 'source-wins'));\n ops.push(rw.unwrap(wrapper));\n return ops;\n };\n}\n\nfunction compileRewrite(rewrite: RewriteRecipe | RewriteFn): RewriteFn {\n if (typeof rewrite === 'function') return rewrite;\n\n if ('flattenInto' in rewrite) return compileFlattenInto(rewrite);\n\n if ('rewriteClasses' in rewrite) {\n const preserveOpaque = rewrite.preserveOpaque ?? true;\n return (ctx, rw) => {\n const next = rewrite.rewriteClasses(ctx.computed(), ctx);\n if (!next) return null;\n return [rw.setClassList(ctx.node, next, preserveOpaque)];\n };\n }\n\n if ('dropClasses' in rewrite) {\n const preserveOpaque = rewrite.preserveOpaque ?? true;\n return (ctx, rw) => {\n const drop = new Set<string>(rewrite.dropClasses(ctx.computed(), ctx));\n if (drop.size === 0) return null;\n return [rw.setClassList(ctx.node, pruneShadowed(ctx.computed(), drop), preserveOpaque)];\n };\n }\n\n // MergeStyleRecipe\n const style = plainToStyleMap(rewrite.mergeStyle);\n const onConflict = rewrite.onConflict ?? 'abort';\n return (ctx, rw) => [rw.mergeStyle(ctx.node, null, style, onConflict)];\n}\n\n/* ───────────────────────── the public factory ───────────────────────── */\n\n/**\n * THE declarative pattern-authoring function. Compile a {@link PatternConfig} (definition + co-located\n * {@link PatternTest}) into a validated {@link AuthoredPattern}: a normal {@link Pattern} (registerable\n * into any {@link import('@domflax/core').Pass}) that also exposes its `test` for the generic harness.\n */\nexport function definePattern(config: PatternConfig): AuthoredPattern {\n const matchFn = compileMatch(config.match, config.category);\n const rewriteFn = compileRewrite(config.rewrite);\n\n const spec: AuthoredPattern = {\n name: config.name,\n category: config.category,\n safety: config.safety,\n priority: config.priority,\n precondition: config.precondition,\n doc: config.doc,\n test: config.test,\n evaluate(ctx: MatchContext, rw: RewriteFactory): MatchResult | null {\n if (!matchFn(ctx.node as unknown as NodeLike, ctx)) return null;\n const ops = rewriteFn(ctx, rw);\n if (!ops || ops.length === 0) return null;\n return { ops };\n },\n };\n\n // `validatePattern` validates + freezes; the spread preserves `test` at runtime.\n return validatePattern(spec) as AuthoredPattern;\n}\n\n/**\n * @deprecated Use {@link definePattern}. Retained as a thin alias for backward compatibility.\n */\nexport const pattern = definePattern;\n"],"mappings":"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","names":["asElement"]}
|
package/dist/pattern-kit.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { A as AuthoredPattern, D as DeclarativeMatch, a as DropClassesRecipe, F as FlattenIntoRecipe, M as MatchFn, b as Matcher, c as MergeStyleRecipe, P as PatternConfig, d as PatternTest, e as PatternTestCase, f as PlainStyle, R as RewriteClassesRecipe, g as RewriteFn, h as RewriteRecipe, T as TestHelpers, i as and, j as computed, k as definePattern, l as emptyStyleMap, m as hasDynamicChildren, n as hasDynamicClasses, o as hasEventHandlers, p as hasOwnVisualStyle, q as hasRef, r as hasSingleElementChild, s as isElement, t as not, u as opaque, v as or, w as pattern, x as targetedByCombinator } from './pattern-
|
|
2
|
-
import { N as NodeLike, E as ElementLike, I as IRNodeId, C as CssProperty, R as RewriteOpDraft, S as StyleMap, a as StyleConflictPolicy, b as NodeSpec, c as StyleNormalizer } from './resolve-ops-
|
|
1
|
+
export { A as AuthoredPattern, D as DeclarativeMatch, a as DropClassesRecipe, F as FlattenIntoRecipe, M as MatchFn, b as Matcher, c as MergeStyleRecipe, P as PatternConfig, d as PatternTest, e as PatternTestCase, f as PlainStyle, R as RewriteClassesRecipe, g as RewriteFn, h as RewriteRecipe, T as TestHelpers, i as and, j as computed, k as definePattern, l as emptyStyleMap, m as hasDynamicChildren, n as hasDynamicClasses, o as hasEventHandlers, p as hasOwnVisualStyle, q as hasRef, r as hasSingleElementChild, s as isElement, t as not, u as opaque, v as or, w as pattern, x as targetedByCombinator } from './pattern-CP9_HpVK.cjs';
|
|
2
|
+
import { N as NodeLike, E as ElementLike, I as IRNodeId, C as CssProperty, R as RewriteOpDraft, S as StyleMap, a as StyleConflictPolicy, b as NodeSpec, c as StyleNormalizer } from './resolve-ops-Ci7LgYHC.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @domflax/pattern-kit — ergonomic op-draft constructors.
|
package/dist/pattern-kit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { A as AuthoredPattern, D as DeclarativeMatch, a as DropClassesRecipe, F as FlattenIntoRecipe, M as MatchFn, b as Matcher, c as MergeStyleRecipe, P as PatternConfig, d as PatternTest, e as PatternTestCase, f as PlainStyle, R as RewriteClassesRecipe, g as RewriteFn, h as RewriteRecipe, T as TestHelpers, i as and, j as computed, k as definePattern, l as emptyStyleMap, m as hasDynamicChildren, n as hasDynamicClasses, o as hasEventHandlers, p as hasOwnVisualStyle, q as hasRef, r as hasSingleElementChild, s as isElement, t as not, u as opaque, v as or, w as pattern, x as targetedByCombinator } from './pattern-
|
|
2
|
-
import { N as NodeLike, E as ElementLike, I as IRNodeId, C as CssProperty, R as RewriteOpDraft, S as StyleMap, a as StyleConflictPolicy, b as NodeSpec, c as StyleNormalizer } from './resolve-ops-
|
|
1
|
+
export { A as AuthoredPattern, D as DeclarativeMatch, a as DropClassesRecipe, F as FlattenIntoRecipe, M as MatchFn, b as Matcher, c as MergeStyleRecipe, P as PatternConfig, d as PatternTest, e as PatternTestCase, f as PlainStyle, R as RewriteClassesRecipe, g as RewriteFn, h as RewriteRecipe, T as TestHelpers, i as and, j as computed, k as definePattern, l as emptyStyleMap, m as hasDynamicChildren, n as hasDynamicClasses, o as hasEventHandlers, p as hasOwnVisualStyle, q as hasRef, r as hasSingleElementChild, s as isElement, t as not, u as opaque, v as or, w as pattern, x as targetedByCombinator } from './pattern-CYgsv-jO.js';
|
|
2
|
+
import { N as NodeLike, E as ElementLike, I as IRNodeId, C as CssProperty, R as RewriteOpDraft, S as StyleMap, a as StyleConflictPolicy, b as NodeSpec, c as StyleNormalizer } from './resolve-ops-Ci7LgYHC.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @domflax/pattern-kit — ergonomic op-draft constructors.
|