@jesscss/core 2.0.0-alpha.4 → 2.0.0-alpha.6
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/lib/index.cjs +20159 -0
- package/lib/index.d.cts +5993 -0
- package/lib/index.d.cts.map +1 -0
- package/lib/index.d.ts +5992 -21
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +19926 -22
- package/lib/index.js.map +1 -1
- package/package.json +15 -14
- package/src/__tests__/define-function-record.test.ts +58 -0
- package/src/__tests__/define-function-simple.test.ts +55 -0
- package/src/__tests__/define-function-split-sequence.test.ts +547 -0
- package/src/__tests__/define-function-type-parity.test.ts +9 -0
- package/src/__tests__/define-function.test.ts +763 -0
- package/src/__tests__/num-operations.test.ts +91 -0
- package/src/__tests__/safe-parse.test.ts +374 -0
- package/src/context.ts +896 -0
- package/src/conversions.ts +282 -0
- package/src/debug-log.ts +29 -0
- package/src/define-function.ts +1006 -0
- package/src/deprecation.ts +67 -0
- package/src/globals.d.ts +26 -0
- package/src/index.ts +31 -0
- package/src/jess-error.ts +773 -0
- package/src/logger/deprecation-processing.ts +109 -0
- package/src/logger.ts +31 -0
- package/src/plugin.ts +292 -0
- package/src/tree/LOOKUP_CHAINS.md +35 -0
- package/src/tree/README.md +18 -0
- package/src/tree/__tests__/__snapshots__/extend-eval-integration.test.ts.snap +1455 -0
- package/src/tree/__tests__/ampersand.test.ts +382 -0
- package/src/tree/__tests__/at-rule.test.ts +2047 -0
- package/src/tree/__tests__/basic-render.test.ts +212 -0
- package/src/tree/__tests__/block.test.ts +40 -0
- package/src/tree/__tests__/call.test.ts +346 -0
- package/src/tree/__tests__/color.test.ts +537 -0
- package/src/tree/__tests__/condition.test.ts +186 -0
- package/src/tree/__tests__/control.test.ts +564 -0
- package/src/tree/__tests__/declaration.test.ts +253 -0
- package/src/tree/__tests__/dependency-graph.test.ts +177 -0
- package/src/tree/__tests__/detached-rulesets.test.ts +213 -0
- package/src/tree/__tests__/dimension.test.ts +236 -0
- package/src/tree/__tests__/expression.test.ts +73 -0
- package/src/tree/__tests__/ext-node.test.ts +31 -0
- package/src/tree/__tests__/extend-eval-integration.test.ts +1033 -0
- package/src/tree/__tests__/extend-import-style.test.ts +929 -0
- package/src/tree/__tests__/extend-less-fixtures.test.ts +851 -0
- package/src/tree/__tests__/extend-list.test.ts +31 -0
- package/src/tree/__tests__/extend-roots.test.ts +1045 -0
- package/src/tree/__tests__/extend-rules.test.ts +740 -0
- package/src/tree/__tests__/func.test.ts +171 -0
- package/src/tree/__tests__/import-js.test.ts +33 -0
- package/src/tree/__tests__/import-style-test-helpers.ts +56 -0
- package/src/tree/__tests__/import-style.test.ts +1967 -0
- package/src/tree/__tests__/interpolated-reference.test.ts +44 -0
- package/src/tree/__tests__/interpolated.test.ts +41 -0
- package/src/tree/__tests__/list.test.ts +177 -0
- package/src/tree/__tests__/log.test.ts +83 -0
- package/src/tree/__tests__/mixin-recursion.test.ts +639 -0
- package/src/tree/__tests__/mixin.test.ts +2171 -0
- package/src/tree/__tests__/negative.test.ts +45 -0
- package/src/tree/__tests__/nesting-collapse.test.ts +519 -0
- package/src/tree/__tests__/node-flags-perf.test.ts +195 -0
- package/src/tree/__tests__/node-flags.test.ts +410 -0
- package/src/tree/__tests__/node-graph.test.ts +598 -0
- package/src/tree/__tests__/node-mutation.test.ts +182 -0
- package/src/tree/__tests__/operation.test.ts +18 -0
- package/src/tree/__tests__/paren.test.ts +90 -0
- package/src/tree/__tests__/preserve-mode-output.test.ts +50 -0
- package/src/tree/__tests__/quoted.test.ts +72 -0
- package/src/tree/__tests__/range.test.ts +59 -0
- package/src/tree/__tests__/reference.test.ts +743 -0
- package/src/tree/__tests__/rest.test.ts +29 -0
- package/src/tree/__tests__/rules-raw.test.ts +14 -0
- package/src/tree/__tests__/rules.test.ts +1271 -0
- package/src/tree/__tests__/ruleset.test.ts +597 -0
- package/src/tree/__tests__/selector-attr.test.ts +50 -0
- package/src/tree/__tests__/selector-basic.test.ts +44 -0
- package/src/tree/__tests__/selector-capture.test.ts +22 -0
- package/src/tree/__tests__/selector-complex.test.ts +120 -0
- package/src/tree/__tests__/selector-compound.test.ts +74 -0
- package/src/tree/__tests__/selector-interpolated.test.ts +50 -0
- package/src/tree/__tests__/selector-list.test.ts +59 -0
- package/src/tree/__tests__/selector-pseudo.test.ts +23 -0
- package/src/tree/__tests__/selector.test.ts +182 -0
- package/src/tree/__tests__/sequence.test.ts +226 -0
- package/src/tree/__tests__/serialize-types.test.ts +529 -0
- package/src/tree/__tests__/spaced.test.ts +8 -0
- package/src/tree/__tests__/url.test.ts +72 -0
- package/src/tree/__tests__/var-declaration.test.ts +90 -0
- package/src/tree/ampersand.ts +538 -0
- package/src/tree/any.ts +169 -0
- package/src/tree/at-rule.ts +760 -0
- package/src/tree/block.ts +72 -0
- package/src/tree/bool.ts +46 -0
- package/src/tree/call.ts +593 -0
- package/src/tree/collection.ts +52 -0
- package/src/tree/color.ts +629 -0
- package/src/tree/combinator.ts +30 -0
- package/src/tree/comment.ts +36 -0
- package/src/tree/condition.ts +194 -0
- package/src/tree/control.ts +452 -0
- package/src/tree/declaration-custom.ts +56 -0
- package/src/tree/declaration-var.ts +87 -0
- package/src/tree/declaration.ts +742 -0
- package/src/tree/default-guard.ts +35 -0
- package/src/tree/dimension.ts +392 -0
- package/src/tree/expression.ts +97 -0
- package/src/tree/extend-list.ts +51 -0
- package/src/tree/extend.ts +391 -0
- package/src/tree/function.ts +254 -0
- package/src/tree/import-js.ts +130 -0
- package/src/tree/import-style.ts +875 -0
- package/{lib/tree/index.js → src/tree/index.ts} +49 -22
- package/src/tree/interpolated.ts +346 -0
- package/src/tree/js-array.ts +21 -0
- package/src/tree/js-expr.ts +50 -0
- package/src/tree/js-function.ts +31 -0
- package/src/tree/js-object.ts +22 -0
- package/src/tree/list.ts +415 -0
- package/src/tree/log.ts +89 -0
- package/src/tree/mixin.ts +331 -0
- package/src/tree/negative.ts +58 -0
- package/src/tree/nil.ts +57 -0
- package/src/tree/node-base.ts +1716 -0
- package/src/tree/node-type.ts +122 -0
- package/src/tree/node.ts +118 -0
- package/src/tree/number.ts +54 -0
- package/src/tree/operation.ts +187 -0
- package/src/tree/paren.ts +132 -0
- package/src/tree/query-condition.ts +47 -0
- package/src/tree/quoted.ts +119 -0
- package/src/tree/range.ts +101 -0
- package/src/tree/reference.ts +1099 -0
- package/src/tree/rest.ts +55 -0
- package/src/tree/rules-raw.ts +52 -0
- package/src/tree/rules.ts +2896 -0
- package/src/tree/ruleset.ts +1217 -0
- package/src/tree/selector-attr.ts +172 -0
- package/src/tree/selector-basic.ts +75 -0
- package/src/tree/selector-capture.ts +85 -0
- package/src/tree/selector-complex.ts +189 -0
- package/src/tree/selector-compound.ts +205 -0
- package/src/tree/selector-interpolated.ts +95 -0
- package/src/tree/selector-list.ts +245 -0
- package/src/tree/selector-pseudo.ts +173 -0
- package/src/tree/selector-simple.ts +10 -0
- package/src/tree/selector.ts +152 -0
- package/src/tree/sequence.ts +463 -0
- package/src/tree/tree.ts +130 -0
- package/src/tree/url.ts +95 -0
- package/src/tree/util/EXTEND_ARCHITECTURE_ANALYSIS.md +215 -0
- package/src/tree/util/EXTEND_AUDIT.md +233 -0
- package/src/tree/util/EXTEND_BASELINE.md +64 -0
- package/src/tree/util/EXTEND_CALL_GRAPH_ANALYSIS.md +244 -0
- package/src/tree/util/EXTEND_DOCS.md +24 -0
- package/src/tree/util/EXTEND_FINAL_SUMMARY.md +95 -0
- package/src/tree/util/EXTEND_FUNCTION_AUDIT.md +1433 -0
- package/src/tree/util/EXTEND_OPTIMIZATION_PLAN.md +114 -0
- package/src/tree/util/EXTEND_REFACTORING_SUMMARY.md +152 -0
- package/src/tree/util/EXTEND_RULES.md +74 -0
- package/src/tree/util/EXTEND_UNUSED_FUNCTIONS.md +127 -0
- package/src/tree/util/EXTEND_UNUSED_FUNCTIONS_ANALYSIS.md +227 -0
- package/src/tree/util/NODE_COPY_REDUCTION_PLAN.md +12 -0
- package/src/tree/util/__tests__/EXTEND_TEST_INDEX.md +59 -0
- package/src/tree/util/__tests__/OPTIMIZATION-ANALYSIS.md +130 -0
- package/src/tree/util/__tests__/WALK_AND_CONSUME_DESIGN.md +138 -0
- package/src/tree/util/__tests__/_archive/2026-02-09__OPTIMIZATION-ANALYSIS.md +9 -0
- package/src/tree/util/__tests__/_archive/README.md +4 -0
- package/src/tree/util/__tests__/bitset.test.ts +142 -0
- package/src/tree/util/__tests__/debug-log.ts +50 -0
- package/src/tree/util/__tests__/extend-comment-handling.test.ts +187 -0
- package/src/tree/util/__tests__/extend-core-unit.test.ts +941 -0
- package/src/tree/util/__tests__/extend-pipeline-bench.test.ts +154 -0
- package/src/tree/util/__tests__/extend-pipeline-bench.ts +190 -0
- package/src/tree/util/__tests__/fast-reject.test.ts +377 -0
- package/src/tree/util/__tests__/is-node.test.ts +63 -0
- package/src/tree/util/__tests__/list-like.test.ts +63 -0
- package/src/tree/util/__tests__/outputwriter.test.ts +523 -0
- package/src/tree/util/__tests__/print.test.ts +183 -0
- package/src/tree/util/__tests__/process-extends.test.ts +226 -0
- package/src/tree/util/__tests__/process-leading-is.test.ts +205 -0
- package/src/tree/util/__tests__/recursion-helper.test.ts +184 -0
- package/src/tree/util/__tests__/selector-match-unit.test.ts +1427 -0
- package/src/tree/util/__tests__/sourcemap.test.ts +117 -0
- package/src/tree/util/ampersand-template.ts +9 -0
- package/src/tree/util/bitset.ts +194 -0
- package/src/tree/util/calculate.ts +11 -0
- package/src/tree/util/cast.ts +89 -0
- package/src/tree/util/cloning.ts +8 -0
- package/src/tree/util/collections.ts +299 -0
- package/src/tree/util/compare.ts +90 -0
- package/src/tree/util/cursor.ts +171 -0
- package/src/tree/util/extend-core.ts +2139 -0
- package/src/tree/util/extend-roots.ts +1108 -0
- package/src/tree/util/field-helpers.ts +354 -0
- package/src/tree/util/is-node.ts +43 -0
- package/src/tree/util/list-like.ts +93 -0
- package/src/tree/util/mixin-instance-primitives.ts +2020 -0
- package/src/tree/util/print.ts +303 -0
- package/src/tree/util/process-leading-is.ts +421 -0
- package/src/tree/util/recursion-helper.ts +54 -0
- package/src/tree/util/regex.ts +2 -0
- package/src/tree/util/registry-utils.ts +1953 -0
- package/src/tree/util/ruleset-trace.ts +17 -0
- package/src/tree/util/scoped-body-eval.ts +320 -0
- package/src/tree/util/selector-match-core.ts +2005 -0
- package/src/tree/util/selector-utils.ts +757 -0
- package/src/tree/util/serialize-helper.ts +535 -0
- package/src/tree/util/serialize-types.ts +318 -0
- package/src/tree/util/should-operate.ts +78 -0
- package/src/tree/util/sourcemap.ts +37 -0
- package/src/types/config.ts +247 -0
- package/src/types/index.ts +12 -0
- package/{lib/types/modes.d.ts → src/types/modes.ts} +2 -1
- package/src/types.d.ts +9 -0
- package/src/types.ts +68 -0
- package/src/use-webpack-resolver.ts +56 -0
- package/src/visitor/__tests__/visitor.test.ts +136 -0
- package/src/visitor/index.ts +263 -0
- package/{lib/visitor/less-visitor.js → src/visitor/less-visitor.ts} +3 -2
- package/lib/context.d.ts +0 -352
- package/lib/context.d.ts.map +0 -1
- package/lib/context.js +0 -636
- package/lib/context.js.map +0 -1
- package/lib/conversions.d.ts +0 -73
- package/lib/conversions.d.ts.map +0 -1
- package/lib/conversions.js +0 -253
- package/lib/conversions.js.map +0 -1
- package/lib/debug-log.d.ts +0 -2
- package/lib/debug-log.d.ts.map +0 -1
- package/lib/debug-log.js +0 -27
- package/lib/debug-log.js.map +0 -1
- package/lib/define-function.d.ts +0 -587
- package/lib/define-function.d.ts.map +0 -1
- package/lib/define-function.js +0 -726
- package/lib/define-function.js.map +0 -1
- package/lib/deprecation.d.ts +0 -34
- package/lib/deprecation.d.ts.map +0 -1
- package/lib/deprecation.js +0 -57
- package/lib/deprecation.js.map +0 -1
- package/lib/jess-error.d.ts +0 -343
- package/lib/jess-error.d.ts.map +0 -1
- package/lib/jess-error.js +0 -508
- package/lib/jess-error.js.map +0 -1
- package/lib/logger/deprecation-processing.d.ts +0 -41
- package/lib/logger/deprecation-processing.d.ts.map +0 -1
- package/lib/logger/deprecation-processing.js +0 -81
- package/lib/logger/deprecation-processing.js.map +0 -1
- package/lib/logger.d.ts +0 -10
- package/lib/logger.d.ts.map +0 -1
- package/lib/logger.js +0 -20
- package/lib/logger.js.map +0 -1
- package/lib/plugin.d.ts +0 -94
- package/lib/plugin.d.ts.map +0 -1
- package/lib/plugin.js +0 -174
- package/lib/plugin.js.map +0 -1
- package/lib/tree/ampersand.d.ts +0 -94
- package/lib/tree/ampersand.d.ts.map +0 -1
- package/lib/tree/ampersand.js +0 -269
- package/lib/tree/ampersand.js.map +0 -1
- package/lib/tree/any.d.ts +0 -58
- package/lib/tree/any.d.ts.map +0 -1
- package/lib/tree/any.js +0 -104
- package/lib/tree/any.js.map +0 -1
- package/lib/tree/at-rule.d.ts +0 -53
- package/lib/tree/at-rule.d.ts.map +0 -1
- package/lib/tree/at-rule.js +0 -503
- package/lib/tree/at-rule.js.map +0 -1
- package/lib/tree/block.d.ts +0 -22
- package/lib/tree/block.d.ts.map +0 -1
- package/lib/tree/block.js +0 -24
- package/lib/tree/block.js.map +0 -1
- package/lib/tree/bool.d.ts +0 -18
- package/lib/tree/bool.d.ts.map +0 -1
- package/lib/tree/bool.js +0 -28
- package/lib/tree/bool.js.map +0 -1
- package/lib/tree/call.d.ts +0 -66
- package/lib/tree/call.d.ts.map +0 -1
- package/lib/tree/call.js +0 -306
- package/lib/tree/call.js.map +0 -1
- package/lib/tree/collection.d.ts +0 -30
- package/lib/tree/collection.d.ts.map +0 -1
- package/lib/tree/collection.js +0 -37
- package/lib/tree/collection.js.map +0 -1
- package/lib/tree/color.d.ts +0 -101
- package/lib/tree/color.d.ts.map +0 -1
- package/lib/tree/color.js +0 -513
- package/lib/tree/color.js.map +0 -1
- package/lib/tree/combinator.d.ts +0 -13
- package/lib/tree/combinator.d.ts.map +0 -1
- package/lib/tree/combinator.js +0 -12
- package/lib/tree/combinator.js.map +0 -1
- package/lib/tree/comment.d.ts +0 -20
- package/lib/tree/comment.d.ts.map +0 -1
- package/lib/tree/comment.js +0 -19
- package/lib/tree/comment.js.map +0 -1
- package/lib/tree/condition.d.ts +0 -31
- package/lib/tree/condition.d.ts.map +0 -1
- package/lib/tree/condition.js +0 -103
- package/lib/tree/condition.js.map +0 -1
- package/lib/tree/control.d.ts +0 -104
- package/lib/tree/control.d.ts.map +0 -1
- package/lib/tree/control.js +0 -430
- package/lib/tree/control.js.map +0 -1
- package/lib/tree/declaration-custom.d.ts +0 -18
- package/lib/tree/declaration-custom.d.ts.map +0 -1
- package/lib/tree/declaration-custom.js +0 -24
- package/lib/tree/declaration-custom.js.map +0 -1
- package/lib/tree/declaration-var.d.ts +0 -35
- package/lib/tree/declaration-var.d.ts.map +0 -1
- package/lib/tree/declaration-var.js +0 -63
- package/lib/tree/declaration-var.js.map +0 -1
- package/lib/tree/declaration.d.ts +0 -78
- package/lib/tree/declaration.d.ts.map +0 -1
- package/lib/tree/declaration.js +0 -286
- package/lib/tree/declaration.js.map +0 -1
- package/lib/tree/default-guard.d.ts +0 -15
- package/lib/tree/default-guard.d.ts.map +0 -1
- package/lib/tree/default-guard.js +0 -19
- package/lib/tree/default-guard.js.map +0 -1
- package/lib/tree/dimension.d.ts +0 -34
- package/lib/tree/dimension.d.ts.map +0 -1
- package/lib/tree/dimension.js +0 -294
- package/lib/tree/dimension.js.map +0 -1
- package/lib/tree/expression.d.ts +0 -25
- package/lib/tree/expression.d.ts.map +0 -1
- package/lib/tree/expression.js +0 -32
- package/lib/tree/expression.js.map +0 -1
- package/lib/tree/extend-list.d.ts +0 -23
- package/lib/tree/extend-list.d.ts.map +0 -1
- package/lib/tree/extend-list.js +0 -23
- package/lib/tree/extend-list.js.map +0 -1
- package/lib/tree/extend.d.ts +0 -47
- package/lib/tree/extend.d.ts.map +0 -1
- package/lib/tree/extend.js +0 -296
- package/lib/tree/extend.js.map +0 -1
- package/lib/tree/function.d.ts +0 -48
- package/lib/tree/function.d.ts.map +0 -1
- package/lib/tree/function.js +0 -74
- package/lib/tree/function.js.map +0 -1
- package/lib/tree/import-js.d.ts +0 -35
- package/lib/tree/import-js.d.ts.map +0 -1
- package/lib/tree/import-js.js +0 -45
- package/lib/tree/import-js.js.map +0 -1
- package/lib/tree/import-style.d.ts +0 -156
- package/lib/tree/import-style.d.ts.map +0 -1
- package/lib/tree/import-style.js +0 -566
- package/lib/tree/import-style.js.map +0 -1
- package/lib/tree/index.d.ts +0 -71
- package/lib/tree/index.d.ts.map +0 -1
- package/lib/tree/index.js.map +0 -1
- package/lib/tree/interpolated-reference.d.ts +0 -24
- package/lib/tree/interpolated-reference.d.ts.map +0 -1
- package/lib/tree/interpolated-reference.js +0 -37
- package/lib/tree/interpolated-reference.js.map +0 -1
- package/lib/tree/interpolated.d.ts +0 -62
- package/lib/tree/interpolated.d.ts.map +0 -1
- package/lib/tree/interpolated.js +0 -204
- package/lib/tree/interpolated.js.map +0 -1
- package/lib/tree/js-array.d.ts +0 -10
- package/lib/tree/js-array.d.ts.map +0 -1
- package/lib/tree/js-array.js +0 -10
- package/lib/tree/js-array.js.map +0 -1
- package/lib/tree/js-expr.d.ts +0 -23
- package/lib/tree/js-expr.d.ts.map +0 -1
- package/lib/tree/js-expr.js +0 -28
- package/lib/tree/js-expr.js.map +0 -1
- package/lib/tree/js-function.d.ts +0 -20
- package/lib/tree/js-function.d.ts.map +0 -1
- package/lib/tree/js-function.js +0 -16
- package/lib/tree/js-function.js.map +0 -1
- package/lib/tree/js-object.d.ts +0 -10
- package/lib/tree/js-object.d.ts.map +0 -1
- package/lib/tree/js-object.js +0 -10
- package/lib/tree/js-object.js.map +0 -1
- package/lib/tree/list.d.ts +0 -38
- package/lib/tree/list.d.ts.map +0 -1
- package/lib/tree/list.js +0 -83
- package/lib/tree/list.js.map +0 -1
- package/lib/tree/log.d.ts +0 -29
- package/lib/tree/log.d.ts.map +0 -1
- package/lib/tree/log.js +0 -56
- package/lib/tree/log.js.map +0 -1
- package/lib/tree/mixin.d.ts +0 -87
- package/lib/tree/mixin.d.ts.map +0 -1
- package/lib/tree/mixin.js +0 -112
- package/lib/tree/mixin.js.map +0 -1
- package/lib/tree/negative.d.ts +0 -17
- package/lib/tree/negative.d.ts.map +0 -1
- package/lib/tree/negative.js +0 -22
- package/lib/tree/negative.js.map +0 -1
- package/lib/tree/nil.d.ts +0 -30
- package/lib/tree/nil.d.ts.map +0 -1
- package/lib/tree/nil.js +0 -35
- package/lib/tree/nil.js.map +0 -1
- package/lib/tree/node-base.d.ts +0 -361
- package/lib/tree/node-base.d.ts.map +0 -1
- package/lib/tree/node-base.js +0 -930
- package/lib/tree/node-base.js.map +0 -1
- package/lib/tree/node.d.ts +0 -10
- package/lib/tree/node.d.ts.map +0 -1
- package/lib/tree/node.js +0 -45
- package/lib/tree/node.js.map +0 -1
- package/lib/tree/number.d.ts +0 -21
- package/lib/tree/number.d.ts.map +0 -1
- package/lib/tree/number.js +0 -27
- package/lib/tree/number.js.map +0 -1
- package/lib/tree/operation.d.ts +0 -26
- package/lib/tree/operation.d.ts.map +0 -1
- package/lib/tree/operation.js +0 -103
- package/lib/tree/operation.js.map +0 -1
- package/lib/tree/paren.d.ts +0 -19
- package/lib/tree/paren.d.ts.map +0 -1
- package/lib/tree/paren.js +0 -92
- package/lib/tree/paren.js.map +0 -1
- package/lib/tree/query-condition.d.ts +0 -17
- package/lib/tree/query-condition.d.ts.map +0 -1
- package/lib/tree/query-condition.js +0 -39
- package/lib/tree/query-condition.js.map +0 -1
- package/lib/tree/quoted.d.ts +0 -28
- package/lib/tree/quoted.d.ts.map +0 -1
- package/lib/tree/quoted.js +0 -75
- package/lib/tree/quoted.js.map +0 -1
- package/lib/tree/range.d.ts +0 -33
- package/lib/tree/range.d.ts.map +0 -1
- package/lib/tree/range.js +0 -47
- package/lib/tree/range.js.map +0 -1
- package/lib/tree/reference.d.ts +0 -76
- package/lib/tree/reference.d.ts.map +0 -1
- package/lib/tree/reference.js +0 -521
- package/lib/tree/reference.js.map +0 -1
- package/lib/tree/rest.d.ts +0 -15
- package/lib/tree/rest.d.ts.map +0 -1
- package/lib/tree/rest.js +0 -32
- package/lib/tree/rest.js.map +0 -1
- package/lib/tree/rules-raw.d.ts +0 -17
- package/lib/tree/rules-raw.d.ts.map +0 -1
- package/lib/tree/rules-raw.js +0 -37
- package/lib/tree/rules-raw.js.map +0 -1
- package/lib/tree/rules.d.ts +0 -262
- package/lib/tree/rules.d.ts.map +0 -1
- package/lib/tree/rules.js +0 -2359
- package/lib/tree/rules.js.map +0 -1
- package/lib/tree/ruleset.d.ts +0 -92
- package/lib/tree/ruleset.d.ts.map +0 -1
- package/lib/tree/ruleset.js +0 -528
- package/lib/tree/ruleset.js.map +0 -1
- package/lib/tree/selector-attr.d.ts +0 -31
- package/lib/tree/selector-attr.d.ts.map +0 -1
- package/lib/tree/selector-attr.js +0 -99
- package/lib/tree/selector-attr.js.map +0 -1
- package/lib/tree/selector-basic.d.ts +0 -24
- package/lib/tree/selector-basic.d.ts.map +0 -1
- package/lib/tree/selector-basic.js +0 -38
- package/lib/tree/selector-basic.js.map +0 -1
- package/lib/tree/selector-capture.d.ts +0 -23
- package/lib/tree/selector-capture.d.ts.map +0 -1
- package/lib/tree/selector-capture.js +0 -34
- package/lib/tree/selector-capture.js.map +0 -1
- package/lib/tree/selector-complex.d.ts +0 -40
- package/lib/tree/selector-complex.d.ts.map +0 -1
- package/lib/tree/selector-complex.js +0 -143
- package/lib/tree/selector-complex.js.map +0 -1
- package/lib/tree/selector-compound.d.ts +0 -16
- package/lib/tree/selector-compound.d.ts.map +0 -1
- package/lib/tree/selector-compound.js +0 -114
- package/lib/tree/selector-compound.js.map +0 -1
- package/lib/tree/selector-interpolated.d.ts +0 -23
- package/lib/tree/selector-interpolated.d.ts.map +0 -1
- package/lib/tree/selector-interpolated.js +0 -27
- package/lib/tree/selector-interpolated.js.map +0 -1
- package/lib/tree/selector-list.d.ts +0 -17
- package/lib/tree/selector-list.d.ts.map +0 -1
- package/lib/tree/selector-list.js +0 -174
- package/lib/tree/selector-list.js.map +0 -1
- package/lib/tree/selector-pseudo.d.ts +0 -42
- package/lib/tree/selector-pseudo.d.ts.map +0 -1
- package/lib/tree/selector-pseudo.js +0 -204
- package/lib/tree/selector-pseudo.js.map +0 -1
- package/lib/tree/selector-simple.d.ts +0 -5
- package/lib/tree/selector-simple.d.ts.map +0 -1
- package/lib/tree/selector-simple.js +0 -6
- package/lib/tree/selector-simple.js.map +0 -1
- package/lib/tree/selector.d.ts +0 -43
- package/lib/tree/selector.d.ts.map +0 -1
- package/lib/tree/selector.js +0 -56
- package/lib/tree/selector.js.map +0 -1
- package/lib/tree/sequence.d.ts +0 -43
- package/lib/tree/sequence.d.ts.map +0 -1
- package/lib/tree/sequence.js +0 -151
- package/lib/tree/sequence.js.map +0 -1
- package/lib/tree/tree.d.ts +0 -87
- package/lib/tree/tree.d.ts.map +0 -1
- package/lib/tree/tree.js +0 -2
- package/lib/tree/tree.js.map +0 -1
- package/lib/tree/url.d.ts +0 -18
- package/lib/tree/url.d.ts.map +0 -1
- package/lib/tree/url.js +0 -35
- package/lib/tree/url.js.map +0 -1
- package/lib/tree/util/__tests__/debug-log.d.ts +0 -1
- package/lib/tree/util/__tests__/debug-log.d.ts.map +0 -1
- package/lib/tree/util/__tests__/debug-log.js +0 -36
- package/lib/tree/util/__tests__/debug-log.js.map +0 -1
- package/lib/tree/util/calculate.d.ts +0 -3
- package/lib/tree/util/calculate.d.ts.map +0 -1
- package/lib/tree/util/calculate.js +0 -10
- package/lib/tree/util/calculate.js.map +0 -1
- package/lib/tree/util/cast.d.ts +0 -10
- package/lib/tree/util/cast.d.ts.map +0 -1
- package/lib/tree/util/cast.js +0 -87
- package/lib/tree/util/cast.js.map +0 -1
- package/lib/tree/util/cloning.d.ts +0 -4
- package/lib/tree/util/cloning.d.ts.map +0 -1
- package/lib/tree/util/cloning.js +0 -8
- package/lib/tree/util/cloning.js.map +0 -1
- package/lib/tree/util/collections.d.ts +0 -57
- package/lib/tree/util/collections.d.ts.map +0 -1
- package/lib/tree/util/collections.js +0 -136
- package/lib/tree/util/collections.js.map +0 -1
- package/lib/tree/util/compare.d.ts +0 -11
- package/lib/tree/util/compare.d.ts.map +0 -1
- package/lib/tree/util/compare.js +0 -89
- package/lib/tree/util/compare.js.map +0 -1
- package/lib/tree/util/extend-helpers.d.ts +0 -2
- package/lib/tree/util/extend-helpers.d.ts.map +0 -1
- package/lib/tree/util/extend-helpers.js +0 -2
- package/lib/tree/util/extend-helpers.js.map +0 -1
- package/lib/tree/util/extend-roots.d.ts +0 -37
- package/lib/tree/util/extend-roots.d.ts.map +0 -1
- package/lib/tree/util/extend-roots.js +0 -700
- package/lib/tree/util/extend-roots.js.map +0 -1
- package/lib/tree/util/extend-roots.old.d.ts +0 -132
- package/lib/tree/util/extend-roots.old.d.ts.map +0 -1
- package/lib/tree/util/extend-roots.old.js +0 -2272
- package/lib/tree/util/extend-roots.old.js.map +0 -1
- package/lib/tree/util/extend-trace-debug.d.ts +0 -13
- package/lib/tree/util/extend-trace-debug.d.ts.map +0 -1
- package/lib/tree/util/extend-trace-debug.js +0 -34
- package/lib/tree/util/extend-trace-debug.js.map +0 -1
- package/lib/tree/util/extend-walk.d.ts +0 -53
- package/lib/tree/util/extend-walk.d.ts.map +0 -1
- package/lib/tree/util/extend-walk.js +0 -881
- package/lib/tree/util/extend-walk.js.map +0 -1
- package/lib/tree/util/extend.d.ts +0 -218
- package/lib/tree/util/extend.d.ts.map +0 -1
- package/lib/tree/util/extend.js +0 -3182
- package/lib/tree/util/extend.js.map +0 -1
- package/lib/tree/util/find-extendable-locations.d.ts +0 -2
- package/lib/tree/util/find-extendable-locations.d.ts.map +0 -1
- package/lib/tree/util/find-extendable-locations.js +0 -2
- package/lib/tree/util/find-extendable-locations.js.map +0 -1
- package/lib/tree/util/format.d.ts +0 -20
- package/lib/tree/util/format.d.ts.map +0 -1
- package/lib/tree/util/format.js +0 -67
- package/lib/tree/util/format.js.map +0 -1
- package/lib/tree/util/is-node.d.ts +0 -13
- package/lib/tree/util/is-node.d.ts.map +0 -1
- package/lib/tree/util/is-node.js +0 -43
- package/lib/tree/util/is-node.js.map +0 -1
- package/lib/tree/util/print.d.ts +0 -80
- package/lib/tree/util/print.d.ts.map +0 -1
- package/lib/tree/util/print.js +0 -205
- package/lib/tree/util/print.js.map +0 -1
- package/lib/tree/util/process-leading-is.d.ts +0 -25
- package/lib/tree/util/process-leading-is.d.ts.map +0 -1
- package/lib/tree/util/process-leading-is.js +0 -364
- package/lib/tree/util/process-leading-is.js.map +0 -1
- package/lib/tree/util/recursion-helper.d.ts +0 -15
- package/lib/tree/util/recursion-helper.d.ts.map +0 -1
- package/lib/tree/util/recursion-helper.js +0 -43
- package/lib/tree/util/recursion-helper.js.map +0 -1
- package/lib/tree/util/regex.d.ts +0 -4
- package/lib/tree/util/regex.d.ts.map +0 -1
- package/lib/tree/util/regex.js +0 -4
- package/lib/tree/util/regex.js.map +0 -1
- package/lib/tree/util/registry-utils.d.ts +0 -192
- package/lib/tree/util/registry-utils.d.ts.map +0 -1
- package/lib/tree/util/registry-utils.js +0 -1214
- package/lib/tree/util/registry-utils.js.map +0 -1
- package/lib/tree/util/ruleset-trace.d.ts +0 -4
- package/lib/tree/util/ruleset-trace.d.ts.map +0 -1
- package/lib/tree/util/ruleset-trace.js +0 -14
- package/lib/tree/util/ruleset-trace.js.map +0 -1
- package/lib/tree/util/selector-compare.d.ts +0 -2
- package/lib/tree/util/selector-compare.d.ts.map +0 -1
- package/lib/tree/util/selector-compare.js +0 -2
- package/lib/tree/util/selector-compare.js.map +0 -1
- package/lib/tree/util/selector-match-core.d.ts +0 -184
- package/lib/tree/util/selector-match-core.d.ts.map +0 -1
- package/lib/tree/util/selector-match-core.js +0 -1603
- package/lib/tree/util/selector-match-core.js.map +0 -1
- package/lib/tree/util/selector-utils.d.ts +0 -30
- package/lib/tree/util/selector-utils.d.ts.map +0 -1
- package/lib/tree/util/selector-utils.js +0 -100
- package/lib/tree/util/selector-utils.js.map +0 -1
- package/lib/tree/util/serialize-helper.d.ts +0 -13
- package/lib/tree/util/serialize-helper.d.ts.map +0 -1
- package/lib/tree/util/serialize-helper.js +0 -387
- package/lib/tree/util/serialize-helper.js.map +0 -1
- package/lib/tree/util/serialize-types.d.ts +0 -9
- package/lib/tree/util/serialize-types.d.ts.map +0 -1
- package/lib/tree/util/serialize-types.js +0 -216
- package/lib/tree/util/serialize-types.js.map +0 -1
- package/lib/tree/util/should-operate.d.ts +0 -23
- package/lib/tree/util/should-operate.d.ts.map +0 -1
- package/lib/tree/util/should-operate.js +0 -46
- package/lib/tree/util/should-operate.js.map +0 -1
- package/lib/tree/util/sourcemap.d.ts +0 -7
- package/lib/tree/util/sourcemap.d.ts.map +0 -1
- package/lib/tree/util/sourcemap.js +0 -25
- package/lib/tree/util/sourcemap.js.map +0 -1
- package/lib/types/config.d.ts +0 -205
- package/lib/types/config.d.ts.map +0 -1
- package/lib/types/config.js +0 -2
- package/lib/types/config.js.map +0 -1
- package/lib/types/index.d.ts +0 -15
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/index.js +0 -3
- package/lib/types/index.js.map +0 -1
- package/lib/types/modes.d.ts.map +0 -1
- package/lib/types/modes.js +0 -2
- package/lib/types/modes.js.map +0 -1
- package/lib/types.d.ts +0 -61
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/lib/use-webpack-resolver.d.ts +0 -9
- package/lib/use-webpack-resolver.d.ts.map +0 -1
- package/lib/use-webpack-resolver.js +0 -41
- package/lib/use-webpack-resolver.js.map +0 -1
- package/lib/visitor/index.d.ts +0 -136
- package/lib/visitor/index.d.ts.map +0 -1
- package/lib/visitor/index.js +0 -135
- package/lib/visitor/index.js.map +0 -1
- package/lib/visitor/less-visitor.d.ts +0 -7
- package/lib/visitor/less-visitor.d.ts.map +0 -1
- package/lib/visitor/less-visitor.js.map +0 -1
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CALLER,
|
|
3
|
+
CANONICAL,
|
|
4
|
+
Node,
|
|
5
|
+
F_VISIBLE,
|
|
6
|
+
F_EXTENDED,
|
|
7
|
+
F_EXTEND_TARGET,
|
|
8
|
+
F_IMPLICIT_AMPERSAND,
|
|
9
|
+
F_NON_STATIC,
|
|
10
|
+
defineType,
|
|
11
|
+
type NodeOptions,
|
|
12
|
+
type OptionalLocation,
|
|
13
|
+
type RenderKey,
|
|
14
|
+
type NodeEdge
|
|
15
|
+
} from './node.js';
|
|
16
|
+
import { Rules } from './rules.js';
|
|
17
|
+
import type { Context, TreeContext } from '../context.js';
|
|
18
|
+
import { Nil } from './nil.js';
|
|
19
|
+
import { Bool } from './bool.js';
|
|
20
|
+
import type { Condition } from './condition.js';
|
|
21
|
+
import type { Selector } from './selector.js';
|
|
22
|
+
import { atIndex } from './util/collections.js';
|
|
23
|
+
import { isNode } from './util/is-node.js';
|
|
24
|
+
import { N } from './node-type.js';
|
|
25
|
+
import { Ampersand } from './ampersand.js';
|
|
26
|
+
import { ComplexSelector, type ComplexSelectorComponent } from './selector-complex.js';
|
|
27
|
+
import { SelectorList } from './selector-list.js';
|
|
28
|
+
import { type PrintOptions, type FinalPrintOptions, getPrintOptions } from './util/print.js';
|
|
29
|
+
import { type MaybePromise, pipe, isThenable } from '@jesscss/awaitable-pipe';
|
|
30
|
+
import type { AtRule } from './at-rule.js';
|
|
31
|
+
import { serializeRulesContainer, normalizeIndent, indent } from './util/serialize-helper.js';
|
|
32
|
+
import { getCurrentParentNode, getImplicitSelector as getImplicitSelectorUtil, getParentRuleset, hasExtendedSelector, hasSourceExtendWrapperParent, selectorHasAuthoredAmpersand } from './util/selector-utils.js';
|
|
33
|
+
import { addEdge } from './util/cursor.js';
|
|
34
|
+
import { processLeadingIs } from './util/process-leading-is.js';
|
|
35
|
+
|
|
36
|
+
export type RulesetValue = {
|
|
37
|
+
selector: Selector | Nil;
|
|
38
|
+
/**
|
|
39
|
+
* It's important that any Node that defines a Rules
|
|
40
|
+
* sets it to the `rules` property. This allows us to
|
|
41
|
+
* generalize nodes for the `frames` property in Context
|
|
42
|
+
*/
|
|
43
|
+
rules: Rules;
|
|
44
|
+
guard?: Condition | Nil;
|
|
45
|
+
/**
|
|
46
|
+
* When this ruleset is extended, we store its selector before the first extend.
|
|
47
|
+
* Nested rulesets' implicit & (selectorContainer → parent value) use this when set, so they
|
|
48
|
+
* do not "see" the extended form (EXTEND_RULES §5: do not materialize ampersands
|
|
49
|
+
* that were not matched and extended).
|
|
50
|
+
*/
|
|
51
|
+
selectorBeforeExtend?: Selector | Nil;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type RulesetOptions = NodeOptions & {
|
|
55
|
+
parentSelector?: Selector | Nil;
|
|
56
|
+
/** Own selector before parent resolution (getImplicitSelector); used by extend so nested rulesets extend .replace,.c not the resolved form. */
|
|
57
|
+
ownSelector?: Selector | Nil;
|
|
58
|
+
/** Hoisted at-rule wrapper already carries the caller selector; do not prepend the parent again in preEval. */
|
|
59
|
+
resolvedHoistWrapper?: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** @todo - Fix typing */
|
|
63
|
+
type NarrowRulesetValue<T> = T extends RulesetValue ? T : RulesetValue;
|
|
64
|
+
|
|
65
|
+
export type RulesetChildData = {
|
|
66
|
+
selector: Selector | Nil;
|
|
67
|
+
rules: Rules;
|
|
68
|
+
guard: Condition | Nil | undefined;
|
|
69
|
+
selectorBeforeExtend: Selector | Nil | undefined;
|
|
70
|
+
/** Patched selector from extend — used by serialization instead of canonical selector. */
|
|
71
|
+
_extendedSelector: Selector | Nil | undefined;
|
|
72
|
+
frames: (Ruleset | AtRule)[] | undefined;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A qualified rule. This is historically called a "Ruleset"
|
|
77
|
+
* by older CSS documentation and by Less.
|
|
78
|
+
*
|
|
79
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax#css_rulesets
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* .box {
|
|
83
|
+
* color: black;
|
|
84
|
+
* }
|
|
85
|
+
*/
|
|
86
|
+
export interface Ruleset {
|
|
87
|
+
type: 'Ruleset';
|
|
88
|
+
shortType: 'ruleset';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class Ruleset<T = RulesetValue> extends Node<NarrowRulesetValue<T>, RulesetOptions, RulesetChildData> {
|
|
92
|
+
static override childKeys = ['selector', 'rules', 'guard', 'selectorBeforeExtend'] as const;
|
|
93
|
+
|
|
94
|
+
// Ruleset has preEval method but doesn't need to set flags - preEvaluated is tracked as boolean
|
|
95
|
+
private frames: (Ruleset | AtRule)[] | undefined;
|
|
96
|
+
|
|
97
|
+
selector!: Selector | Nil;
|
|
98
|
+
declare selectorEdge: NodeEdge<Selector | Nil> | undefined;
|
|
99
|
+
rules!: Rules;
|
|
100
|
+
declare rulesEdge: NodeEdge<Rules> | undefined;
|
|
101
|
+
guard: Condition | Nil | undefined;
|
|
102
|
+
declare guardEdge: NodeEdge<Condition | Nil | undefined> | undefined;
|
|
103
|
+
selectorBeforeExtend: Selector | Nil | undefined;
|
|
104
|
+
declare selectorBeforeExtendEdge: NodeEdge<Selector | Nil | undefined> | undefined;
|
|
105
|
+
/** Patched selector from extend — used by serialization instead of canonical selector. */
|
|
106
|
+
private _extendedSelector: Selector | Nil | undefined;
|
|
107
|
+
declare _extendedSelectorEdge: NodeEdge<Selector | Nil | undefined> | undefined;
|
|
108
|
+
|
|
109
|
+
constructor(value: NarrowRulesetValue<T>, options?: RulesetOptions, location?: OptionalLocation, treeContext?: TreeContext) {
|
|
110
|
+
super(value, options, location, treeContext);
|
|
111
|
+
this.selector = value.selector;
|
|
112
|
+
this.rules = value.rules;
|
|
113
|
+
this.guard = value.guard;
|
|
114
|
+
this.selectorBeforeExtend = value.selectorBeforeExtend;
|
|
115
|
+
if (this.selector instanceof Node) {
|
|
116
|
+
this.adopt(this.selector);
|
|
117
|
+
}
|
|
118
|
+
if (this.rules instanceof Node) {
|
|
119
|
+
this.adopt(this.rules);
|
|
120
|
+
}
|
|
121
|
+
if (this.guard instanceof Node) {
|
|
122
|
+
this.adopt(this.guard);
|
|
123
|
+
}
|
|
124
|
+
if (this.selectorBeforeExtend instanceof Node) {
|
|
125
|
+
this.adopt(this.selectorBeforeExtend);
|
|
126
|
+
}
|
|
127
|
+
this.allowRoot = true;
|
|
128
|
+
this.allowRuleRoot = true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* If this ruleset shares its value object with a descendant ruleset, give those
|
|
133
|
+
* descendants their own value so mutating this ruleset's value.selector does not
|
|
134
|
+
* overwrite the descendant's selector (e.g. .rep_ace nested ruleset case).
|
|
135
|
+
*/
|
|
136
|
+
static ensureDescendantRulesetsHaveOwnValue(
|
|
137
|
+
ruleset: Ruleset,
|
|
138
|
+
sharedValue: RulesetValue
|
|
139
|
+
): void {
|
|
140
|
+
const rules = ruleset.rules;
|
|
141
|
+
if (!rules || !isNode(rules, N.Rules)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const children = (rules as Rules).value;
|
|
145
|
+
if (!Array.isArray(children)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
for (const child of children) {
|
|
149
|
+
if (!isNode(child, N.Ruleset)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const rs = child as Ruleset;
|
|
153
|
+
// With instance fields (no shared data object), shallow clones already
|
|
154
|
+
// have independent fields, so this identity check is always false.
|
|
155
|
+
// Kept for structural safety until full clone audit.
|
|
156
|
+
Ruleset.ensureDescendantRulesetsHaveOwnValue(rs, sharedValue);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static collapseRedundantGeneratedChildren(ruleset: Ruleset): void {
|
|
161
|
+
const rules = ruleset.rules;
|
|
162
|
+
if (!rules || !isNode(rules, N.Rules)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const children = [...rules.value];
|
|
166
|
+
const normalized: Node[] = [];
|
|
167
|
+
for (const child of children) {
|
|
168
|
+
if (!isNode(child, N.Ruleset)) {
|
|
169
|
+
normalized.push(child);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const childRuleset = child as Ruleset;
|
|
173
|
+
Ruleset.collapseRedundantGeneratedChildren(childRuleset);
|
|
174
|
+
const shouldInline =
|
|
175
|
+
Boolean(ruleset.options?.generated)
|
|
176
|
+
&& Boolean(childRuleset.options?.generated)
|
|
177
|
+
&& String(ruleset.selector?.valueOf?.() ?? '') === String(childRuleset.selector?.valueOf?.() ?? '');
|
|
178
|
+
if (shouldInline) {
|
|
179
|
+
normalized.push(...childRuleset.rules.value);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
normalized.push(childRuleset);
|
|
183
|
+
}
|
|
184
|
+
if (normalized.length !== rules.value.length || normalized.some((node, index) => node !== rules.value[index])) {
|
|
185
|
+
rules._setValueArray(normalized);
|
|
186
|
+
for (const child of normalized) {
|
|
187
|
+
rules.adopt(child);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
isHoisted(options: PrintOptions) {
|
|
193
|
+
return this.hoistToRoot ?? options.collapseNesting ?? false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
protected _valueOf: string | undefined;
|
|
197
|
+
|
|
198
|
+
private _resolveRenderKey(context?: Context): RenderKey {
|
|
199
|
+
return context?.renderKey ?? context?.rulesContext?.renderKey ?? this.renderKey;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getOwnSelector(): Selector | Nil | undefined {
|
|
203
|
+
return this.options.ownSelector;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
setOwnSelector(selector: Selector | Nil | undefined): void {
|
|
207
|
+
this.options = {
|
|
208
|
+
...this.options,
|
|
209
|
+
ownSelector: selector
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getSelector(renderKey?: RenderKey): Selector | Nil {
|
|
214
|
+
return renderKey !== undefined
|
|
215
|
+
? this.selectorEdge?.get(renderKey) ?? this.selector
|
|
216
|
+
: this.selector;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private _getSelectorSourceNode(selector: Selector | Nil | undefined): Node | undefined {
|
|
220
|
+
if (!(selector instanceof Node)) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
return selector.sourceNode;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Transitional edge/cursor seam: enter the render-owned Rules container for
|
|
228
|
+
* this ruleset. This is intentionally explicit because it may wrap/adopt.
|
|
229
|
+
*/
|
|
230
|
+
enterRules(context?: Context): Rules {
|
|
231
|
+
const renderKey = this._resolveRenderKey(context);
|
|
232
|
+
const rules = this.getRules(renderKey);
|
|
233
|
+
if (
|
|
234
|
+
renderKey !== undefined
|
|
235
|
+
&& renderKey !== CANONICAL
|
|
236
|
+
&& rules === this.rules
|
|
237
|
+
&& this.rules.renderKey !== CANONICAL
|
|
238
|
+
&& this.rules.renderKey !== renderKey
|
|
239
|
+
) {
|
|
240
|
+
const wrappedRules = this.rules.createShallowBodyWrapper(undefined, renderKey);
|
|
241
|
+
addEdge(this, 'rules', renderKey, wrappedRules);
|
|
242
|
+
if (context && getCurrentParentNode(wrappedRules, { ...context, renderKey }) !== this) {
|
|
243
|
+
this.adopt(wrappedRules, { ...context, renderKey });
|
|
244
|
+
}
|
|
245
|
+
return wrappedRules;
|
|
246
|
+
}
|
|
247
|
+
if (rules !== this.rules) {
|
|
248
|
+
if (context && getCurrentParentNode(rules, context) !== this) {
|
|
249
|
+
this.adopt(rules, context);
|
|
250
|
+
}
|
|
251
|
+
return rules;
|
|
252
|
+
}
|
|
253
|
+
return rules.withRenderOwner(this, renderKey, context);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
getRules(renderKey?: RenderKey): Rules {
|
|
257
|
+
return renderKey !== undefined
|
|
258
|
+
? this.rulesEdge?.get(renderKey) ?? this.rules
|
|
259
|
+
: this.rules;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private _assignRules(rules: Rules, context: Context): void {
|
|
263
|
+
const renderKey = this._resolveRenderKey(context);
|
|
264
|
+
if (renderKey !== undefined && renderKey !== CANONICAL) {
|
|
265
|
+
this.rulesEdge?.delete(renderKey);
|
|
266
|
+
if (this.rulesEdge?.size === 0) {
|
|
267
|
+
this.rulesEdge = undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this.rules = rules;
|
|
271
|
+
this.adopt(rules, context);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
getGuard(renderKey?: RenderKey): Condition | Nil | undefined {
|
|
275
|
+
return renderKey !== undefined
|
|
276
|
+
? this.guardEdge?.get(renderKey) ?? this.guard
|
|
277
|
+
: this.guard;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
getSelectorBeforeExtend(renderKey?: RenderKey): Selector | Nil | undefined {
|
|
281
|
+
return renderKey !== undefined
|
|
282
|
+
? this.selectorBeforeExtendEdge?.get(renderKey) ?? this.selectorBeforeExtend
|
|
283
|
+
: this.selectorBeforeExtend;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
setSelectorBeforeExtend(selector: Selector | Nil | undefined, context: Context): void {
|
|
287
|
+
const renderKey = this._resolveRenderKey(context);
|
|
288
|
+
if (renderKey === undefined || renderKey === CANONICAL) {
|
|
289
|
+
this.selectorBeforeExtend = selector;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (selector instanceof Node) {
|
|
293
|
+
this.adopt(selector, { ...context, renderKey });
|
|
294
|
+
}
|
|
295
|
+
addEdge(this, 'selectorBeforeExtend', renderKey, selector as Selector | Nil);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
getExtendedSelector(renderKey?: RenderKey): Selector | Nil | undefined {
|
|
299
|
+
return renderKey !== undefined
|
|
300
|
+
? this._extendedSelectorEdge?.get(renderKey) ?? this._extendedSelector
|
|
301
|
+
: this._extendedSelector;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
setExtendedSelector(selector: Selector | Nil | undefined, context?: Context): void {
|
|
305
|
+
const renderKey = context ? this._resolveRenderKey(context) : undefined;
|
|
306
|
+
if (renderKey === undefined || renderKey === CANONICAL) {
|
|
307
|
+
this._extendedSelector = selector;
|
|
308
|
+
this.invalidateSelectorValueCache();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (selector instanceof Node) {
|
|
312
|
+
this.adopt(selector, { ...context, renderKey });
|
|
313
|
+
}
|
|
314
|
+
addEdge(this, '_extendedSelector', renderKey, selector as Selector | Nil);
|
|
315
|
+
this.invalidateSelectorValueCache();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Returns the selector shape that should be printed for this ruleset.
|
|
320
|
+
*
|
|
321
|
+
* Nested rulesets keep rendering their local selector shape unless they are
|
|
322
|
+
* being serialized from root (`hoistToRoot`) or collapse nesting is enabled.
|
|
323
|
+
* In those cases, the selector must be recomposed against its parent.
|
|
324
|
+
*/
|
|
325
|
+
getRenderableSelector(collapseNesting = this.treeContext?.opts?.collapseNesting ?? false, context?: Context): Selector | Nil {
|
|
326
|
+
const ownSelector = this.getOwnSelector();
|
|
327
|
+
if (
|
|
328
|
+
!hasSourceExtendWrapperParent(this)
|
|
329
|
+
&& !this.hoistToRoot
|
|
330
|
+
&& !collapseNesting
|
|
331
|
+
&& ownSelector
|
|
332
|
+
&& !(ownSelector instanceof Nil)
|
|
333
|
+
&& this._hasAncestorRuleset(context)
|
|
334
|
+
) {
|
|
335
|
+
return ownSelector as Selector;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return this.getEffectiveSelector(collapseNesting, context);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private _hasAncestorRuleset(context?: Context): boolean {
|
|
342
|
+
const seen = new Set<Node>();
|
|
343
|
+
const pending: Node[] = [];
|
|
344
|
+
const enqueue = (node: Node | undefined) => {
|
|
345
|
+
if (!node || seen.has(node)) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
seen.add(node);
|
|
349
|
+
pending.push(node);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
enqueue(getCurrentParentNode(this, context));
|
|
353
|
+
enqueue(this.parent);
|
|
354
|
+
for (const parent of this.parentEdges?.values?.() ?? []) {
|
|
355
|
+
enqueue(parent);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
while (pending.length > 0) {
|
|
359
|
+
const current = pending.shift()!;
|
|
360
|
+
if (isNode(current, N.Ruleset)) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
enqueue(getCurrentParentNode(current, context));
|
|
364
|
+
enqueue(current.parent);
|
|
365
|
+
for (const parent of current.parentEdges?.values?.() ?? []) {
|
|
366
|
+
enqueue(parent);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Returns the selector that should be used for matching/rendering right now.
|
|
374
|
+
*
|
|
375
|
+
* For nested rulesets that keep a local `ownSelector`, this recomposes the
|
|
376
|
+
* selector against the current parent selector on demand instead of requiring
|
|
377
|
+
* eager mutation of `data.selector` after extends. Hoisted rulesets keep their
|
|
378
|
+
* concrete selector unchanged because they already serialize from root.
|
|
379
|
+
*/
|
|
380
|
+
getEffectiveSelector(collapseNesting = this.treeContext?.opts?.collapseNesting ?? false, context?: Context): Selector | Nil {
|
|
381
|
+
// Use extend-patched selector if available, else canonical
|
|
382
|
+
const renderKey = this._resolveRenderKey(context);
|
|
383
|
+
const extendedSelector = this.getExtendedSelector(renderKey);
|
|
384
|
+
const selector = (extendedSelector ?? this.getSelector(renderKey)) as Selector | Nil;
|
|
385
|
+
if (!selector || selector instanceof Nil) {
|
|
386
|
+
return selector;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const ownSelector = this.getOwnSelector();
|
|
390
|
+
const parentRs = getParentRuleset(this, context);
|
|
391
|
+
if (
|
|
392
|
+
collapseNesting
|
|
393
|
+
&& this.hoistToRoot
|
|
394
|
+
&& ownSelector
|
|
395
|
+
&& !(ownSelector instanceof Nil)
|
|
396
|
+
&& isNode(ownSelector as Selector, N.SelectorList)
|
|
397
|
+
&& isNode(selector as Selector, N.SelectorList)
|
|
398
|
+
&& ownSelector.valueOf() !== selector.valueOf()
|
|
399
|
+
) {
|
|
400
|
+
return selector;
|
|
401
|
+
}
|
|
402
|
+
if (
|
|
403
|
+
collapseNesting
|
|
404
|
+
&& this.hoistToRoot
|
|
405
|
+
&& ownSelector
|
|
406
|
+
&& !(ownSelector instanceof Nil)
|
|
407
|
+
&& Ruleset.isBareAmpersandSelector(ownSelector)
|
|
408
|
+
) {
|
|
409
|
+
return selector;
|
|
410
|
+
}
|
|
411
|
+
const normalizeParentSelector = (parentSelector: Selector | Nil | undefined): Selector | Nil | undefined => {
|
|
412
|
+
if (
|
|
413
|
+
parentRs
|
|
414
|
+
&& parentSelector
|
|
415
|
+
&& !(parentSelector instanceof Nil)
|
|
416
|
+
&& Ruleset.isBareAmpersandSelector(parentSelector)
|
|
417
|
+
) {
|
|
418
|
+
const parentOwn = parentRs.getOwnSelector();
|
|
419
|
+
if (
|
|
420
|
+
parentOwn
|
|
421
|
+
&& !(parentOwn instanceof Nil)
|
|
422
|
+
&& Ruleset.isBareAmpersandSelector(parentOwn)
|
|
423
|
+
&& parentRs.getSelector(parentRs._resolveRenderKey(context))
|
|
424
|
+
&& !(parentRs.getSelector(parentRs._resolveRenderKey(context)) instanceof Nil)
|
|
425
|
+
&& !Ruleset.isBareAmpersandSelector(parentRs.getSelector(parentRs._resolveRenderKey(context)))
|
|
426
|
+
) {
|
|
427
|
+
return parentRs.getSelector(parentRs._resolveRenderKey(context));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return parentSelector;
|
|
431
|
+
};
|
|
432
|
+
const getComposedParentSelector = (): Selector | Nil | undefined => {
|
|
433
|
+
let parentSelector = normalizeParentSelector(parentRs?.getEffectiveSelector(collapseNesting, context));
|
|
434
|
+
if (
|
|
435
|
+
parentSelector
|
|
436
|
+
&& !(parentSelector instanceof Nil)
|
|
437
|
+
&& parentRs?.getSelectorBeforeExtend(parentRs._resolveRenderKey(context))
|
|
438
|
+
&& Ruleset.hasReferenceBoundaryParent(parentRs, context)
|
|
439
|
+
) {
|
|
440
|
+
parentSelector = Ruleset.filterReferenceVisibleSelectorItems(
|
|
441
|
+
parentSelector as Selector,
|
|
442
|
+
parentRs.getSelectorBeforeExtend(parentRs._resolveRenderKey(context))
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
return parentSelector;
|
|
446
|
+
};
|
|
447
|
+
const parentSelector = getComposedParentSelector();
|
|
448
|
+
if (
|
|
449
|
+
this.hoistToRoot
|
|
450
|
+
&& extendedSelector
|
|
451
|
+
&& !(extendedSelector instanceof Nil)
|
|
452
|
+
&& ownSelector
|
|
453
|
+
&& !(ownSelector instanceof Nil)
|
|
454
|
+
&& selectorHasAuthoredAmpersand(ownSelector as Selector)
|
|
455
|
+
) {
|
|
456
|
+
return selector;
|
|
457
|
+
}
|
|
458
|
+
if (
|
|
459
|
+
ownSelector
|
|
460
|
+
&& !(ownSelector instanceof Nil)
|
|
461
|
+
&& parentSelector
|
|
462
|
+
&& !(parentSelector instanceof Nil)
|
|
463
|
+
&& ownSelector.valueOf() !== selector.valueOf()
|
|
464
|
+
) {
|
|
465
|
+
return getImplicitSelectorUtil(ownSelector as Selector, parentSelector as Selector, collapseNesting);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (this.hoistToRoot) {
|
|
469
|
+
return selector;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return selector;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Used for equality comparison with other rulesets */
|
|
476
|
+
override valueOf(context?: Context) {
|
|
477
|
+
if (context) {
|
|
478
|
+
const collapseNesting = context.opts.collapseNesting ?? this.treeContext?.opts?.collapseNesting ?? false;
|
|
479
|
+
const renderKey = this._resolveRenderKey(context);
|
|
480
|
+
const selector = (
|
|
481
|
+
this.getExtendedSelector(renderKey)
|
|
482
|
+
|| this.hoistToRoot
|
|
483
|
+
|| collapseNesting === true
|
|
484
|
+
)
|
|
485
|
+
? this.getEffectiveSelector(collapseNesting, context)
|
|
486
|
+
: this.getSelector(renderKey);
|
|
487
|
+
return selector instanceof Nil ? '' : (selector as Selector).valueOf();
|
|
488
|
+
}
|
|
489
|
+
if (this._valueOf !== undefined) {
|
|
490
|
+
return this._valueOf;
|
|
491
|
+
}
|
|
492
|
+
const selector = (
|
|
493
|
+
this._extendedSelector
|
|
494
|
+
|| this.hoistToRoot
|
|
495
|
+
|| this.treeContext?.opts?.collapseNesting === true
|
|
496
|
+
)
|
|
497
|
+
? this.getEffectiveSelector()
|
|
498
|
+
: this.selector;
|
|
499
|
+
if (selector instanceof Nil) {
|
|
500
|
+
this._valueOf = '';
|
|
501
|
+
return this._valueOf;
|
|
502
|
+
}
|
|
503
|
+
this._valueOf = selector instanceof Nil ? '' : (selector as Selector).valueOf();
|
|
504
|
+
return this._valueOf;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Invalidate cached selector-based string value.
|
|
509
|
+
*
|
|
510
|
+
* `Ruleset.valueOf()` is used by serialization frame tracking; when an extend
|
|
511
|
+
* mutates `value.selector`, we must clear this cache so frame/header caching
|
|
512
|
+
* reflects the updated selector.
|
|
513
|
+
*/
|
|
514
|
+
invalidateSelectorValueCache(): void {
|
|
515
|
+
this._valueOf = undefined;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
override toTrimmedString(options?: PrintOptions): string {
|
|
519
|
+
options = getPrintOptions(options);
|
|
520
|
+
const opts = options as FinalPrintOptions;
|
|
521
|
+
if (
|
|
522
|
+
opts.referenceMode === true
|
|
523
|
+
&& opts.referenceRenderEnabled !== false
|
|
524
|
+
&& this.hoistToRoot
|
|
525
|
+
) {
|
|
526
|
+
const ownSelector = this.getOwnSelector();
|
|
527
|
+
if (ownSelector && Ruleset.isBareAmpersandSelector(ownSelector)) {
|
|
528
|
+
return '';
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return serializeRulesContainer(this, opts);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Render the opening of this ruleset (selector)
|
|
536
|
+
* @todo - Efficiently serialize the selector with and without comments?
|
|
537
|
+
*/
|
|
538
|
+
/** Ensure every node in the selector has F_VISIBLE so toString() does not skip them (rep_ace bug).
|
|
539
|
+
* Do NOT add F_VISIBLE to implicit ampersands: they must stay invisible so nested output stays short. */
|
|
540
|
+
private static ensureSelectorVisible(sel: Selector | Nil): void {
|
|
541
|
+
if (!sel || sel instanceof Nil || typeof (sel as Node).addFlag !== 'function') {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const n = sel as Node;
|
|
545
|
+
if (isNode(sel, N.Ampersand) && n.hasFlag(F_IMPLICIT_AMPERSAND)) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
if (!n.hasFlag(F_VISIBLE)) {
|
|
549
|
+
n.addFlag(F_VISIBLE);
|
|
550
|
+
}
|
|
551
|
+
if (isNode(sel, N.SelectorList)) {
|
|
552
|
+
const list = sel as SelectorList;
|
|
553
|
+
for (const item of list.get('value')) {
|
|
554
|
+
Ruleset.ensureSelectorVisible(item);
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (isNode(sel, N.ComplexSelector)) {
|
|
559
|
+
const comps = (sel as ComplexSelector).get('value');
|
|
560
|
+
for (const c of comps) {
|
|
561
|
+
Ruleset.ensureSelectorVisible(c as Selector);
|
|
562
|
+
}
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const v = 'value' in sel ? sel.value : undefined;
|
|
566
|
+
if (Array.isArray(v)) {
|
|
567
|
+
for (const c of v) {
|
|
568
|
+
Ruleset.ensureSelectorVisible(c);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private static materializeHoistedImplicitAmpersands(sel: Selector | Nil): Selector | Nil {
|
|
574
|
+
if (!sel || sel instanceof Nil) {
|
|
575
|
+
return sel;
|
|
576
|
+
}
|
|
577
|
+
const materialize = (node: Selector): Selector => {
|
|
578
|
+
if (isNode(node, N.Ampersand)) {
|
|
579
|
+
const amp = node as Ampersand;
|
|
580
|
+
const n = amp as unknown as Node;
|
|
581
|
+
if (n.hasFlag(F_IMPLICIT_AMPERSAND)) {
|
|
582
|
+
const resolved = amp.getResolvedSelector();
|
|
583
|
+
if (resolved && !(resolved instanceof Nil)) {
|
|
584
|
+
return resolved as Selector;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return node;
|
|
588
|
+
}
|
|
589
|
+
if (isNode(node, N.SelectorList)) {
|
|
590
|
+
const list = node as SelectorList;
|
|
591
|
+
return SelectorList.create(list.get('value').map(item => materialize(item as Selector))).inherit(node) as Selector;
|
|
592
|
+
}
|
|
593
|
+
if (isNode(node, N.ComplexSelector)) {
|
|
594
|
+
const complex = node as ComplexSelector;
|
|
595
|
+
const parts: ComplexSelectorComponent[] = [];
|
|
596
|
+
for (const part of complex.get('value')) {
|
|
597
|
+
if (isNode(part, N.Ampersand)) {
|
|
598
|
+
const amp = part as Ampersand;
|
|
599
|
+
const n = amp as unknown as Node;
|
|
600
|
+
if (n.hasFlag(F_IMPLICIT_AMPERSAND)) {
|
|
601
|
+
const resolved = amp.getResolvedSelector();
|
|
602
|
+
if (resolved && !(resolved instanceof Nil)) {
|
|
603
|
+
const repl = materialize(resolved as Selector);
|
|
604
|
+
if (isNode(repl, N.ComplexSelector)) {
|
|
605
|
+
parts.push(...(repl as ComplexSelector).get('value') as ComplexSelectorComponent[]);
|
|
606
|
+
} else {
|
|
607
|
+
parts.push(repl as ComplexSelectorComponent);
|
|
608
|
+
}
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
parts.push(materialize(part as Selector) as ComplexSelectorComponent);
|
|
614
|
+
}
|
|
615
|
+
return ComplexSelector.create(parts).inherit(node) as Selector;
|
|
616
|
+
}
|
|
617
|
+
const arr = 'value' in node ? node.value : undefined;
|
|
618
|
+
if (Array.isArray(arr)) {
|
|
619
|
+
const cloned = node.copy(true) as Selector & { value?: Selector[] };
|
|
620
|
+
cloned.value = arr.map(item => materialize(item as Selector));
|
|
621
|
+
return cloned as Selector;
|
|
622
|
+
}
|
|
623
|
+
return node;
|
|
624
|
+
};
|
|
625
|
+
const materialized = materialize(sel as Selector);
|
|
626
|
+
return processLeadingIs(materialized) as Selector;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
static isBareAmpersandSelector(sel: Selector | Nil): boolean {
|
|
630
|
+
if (!sel || sel instanceof Nil) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
if (isNode(sel, N.Ampersand)) {
|
|
634
|
+
return (sel as Ampersand).isPlainAmpersand();
|
|
635
|
+
}
|
|
636
|
+
if (isNode(sel, N.CompoundSelector | N.ComplexSelector)) {
|
|
637
|
+
const items = (sel as unknown as { value?: unknown[] }).value;
|
|
638
|
+
if (!Array.isArray(items)) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
return items.length === 1
|
|
642
|
+
&& isNode(items[0] as Node, N.Ampersand)
|
|
643
|
+
&& (items[0] as Ampersand).isPlainAmpersand();
|
|
644
|
+
}
|
|
645
|
+
if (isNode(sel, N.SelectorList)) {
|
|
646
|
+
return (sel as SelectorList).get('value').every(
|
|
647
|
+
item => isNode(item, N.Ampersand) && (item as Ampersand).isPlainAmpersand()
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
private static hasReferenceBoundaryParent(node: Node, context?: Context): boolean {
|
|
654
|
+
const parent = getCurrentParentNode(node, context);
|
|
655
|
+
return Boolean(
|
|
656
|
+
parent
|
|
657
|
+
&& isNode(parent, N.Rules)
|
|
658
|
+
&& (parent as Rules).options?.referenceMode === true
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
static hasExtendedTopLevelSelector(sel: Selector | Nil): boolean {
|
|
663
|
+
return hasExtendedSelector(sel);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private static filterSelectorItems(
|
|
667
|
+
sel: Selector,
|
|
668
|
+
shouldKeep: (item: Selector) => boolean
|
|
669
|
+
): Selector | Nil {
|
|
670
|
+
if (!isNode(sel, N.SelectorList)) {
|
|
671
|
+
return shouldKeep(sel) ? sel : new Nil();
|
|
672
|
+
}
|
|
673
|
+
const seen = new Set<string>();
|
|
674
|
+
const kept: Selector[] = [];
|
|
675
|
+
for (const item of (sel as SelectorList).get('value')) {
|
|
676
|
+
if (!shouldKeep(item)) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
const key = item.valueOf();
|
|
680
|
+
if (seen.has(key)) {
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
seen.add(key);
|
|
684
|
+
kept.push(item as Selector);
|
|
685
|
+
}
|
|
686
|
+
if (kept.length === 0) {
|
|
687
|
+
return new Nil();
|
|
688
|
+
}
|
|
689
|
+
if (kept.length === 1) {
|
|
690
|
+
return kept[0]!;
|
|
691
|
+
}
|
|
692
|
+
return SelectorList.create(kept).inherit(sel);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
private static filterExtendedTopLevelSelectorItems(sel: Selector, context?: Context): Selector | Nil {
|
|
696
|
+
return Ruleset.filterSelectorItems(sel, item =>
|
|
697
|
+
(context ? item._hasFlag(F_EXTENDED, context) : item.hasFlag(F_EXTENDED))
|
|
698
|
+
&& !(context ? item._hasFlag(F_EXTEND_TARGET, context) : item.hasFlag(F_EXTEND_TARGET))
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private static filterReferenceVisibleSelectorItems(
|
|
703
|
+
current: Selector,
|
|
704
|
+
original?: Selector | Nil,
|
|
705
|
+
context?: Context
|
|
706
|
+
): Selector | Nil {
|
|
707
|
+
if (!original || original instanceof Nil) {
|
|
708
|
+
return Ruleset.filterExtendedTopLevelSelectorItems(current, context);
|
|
709
|
+
}
|
|
710
|
+
const originalValues = new Set<string>();
|
|
711
|
+
if (isNode(original, N.SelectorList)) {
|
|
712
|
+
for (const item of (original as SelectorList).get('value')) {
|
|
713
|
+
originalValues.add(item.valueOf());
|
|
714
|
+
}
|
|
715
|
+
} else {
|
|
716
|
+
originalValues.add(original.valueOf());
|
|
717
|
+
}
|
|
718
|
+
const changedItems = Ruleset.filterSelectorItems(current, item =>
|
|
719
|
+
!originalValues.has(item.valueOf())
|
|
720
|
+
);
|
|
721
|
+
if (!(changedItems instanceof Nil)) {
|
|
722
|
+
return changedItems;
|
|
723
|
+
}
|
|
724
|
+
return Ruleset.filterSelectorItems(current, item =>
|
|
725
|
+
(context ? item._hasFlag(F_EXTENDED, context) : item.hasFlag(F_EXTENDED))
|
|
726
|
+
&& !(context ? item._hasFlag(F_EXTEND_TARGET, context) : item.hasFlag(F_EXTEND_TARGET))
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
getHeaderString(options: FinalPrintOptions, withoutComments?: boolean): string {
|
|
731
|
+
const w = options.writer;
|
|
732
|
+
const renderKey = this.renderKey !== CANONICAL
|
|
733
|
+
? this.renderKey
|
|
734
|
+
: this._resolveRenderKey(options.context);
|
|
735
|
+
const selector = this.getRenderableSelector(
|
|
736
|
+
options.collapseNesting,
|
|
737
|
+
options.context ? { ...options.context, renderKey } : options.context
|
|
738
|
+
);
|
|
739
|
+
const idt = indent(options.depth);
|
|
740
|
+
|
|
741
|
+
// Should never be called for Nil selectors (serializeRulesContainer guards this),
|
|
742
|
+
// but keep it safe for TypeScript and invariants.
|
|
743
|
+
if (selector instanceof Nil) {
|
|
744
|
+
return '';
|
|
745
|
+
}
|
|
746
|
+
if (withoutComments) {
|
|
747
|
+
options = { ...options, suppressComments: true };
|
|
748
|
+
}
|
|
749
|
+
let renderSelector: Selector | Nil = selector;
|
|
750
|
+
const ownSelector = this.getOwnSelector();
|
|
751
|
+
const currentSelector = this.getSelector(renderKey);
|
|
752
|
+
if (
|
|
753
|
+
this.hoistToRoot
|
|
754
|
+
&& Ruleset.isBareAmpersandSelector(renderSelector)
|
|
755
|
+
&& ownSelector
|
|
756
|
+
&& !(ownSelector instanceof Nil)
|
|
757
|
+
&& Ruleset.isBareAmpersandSelector(ownSelector)
|
|
758
|
+
&& !Ruleset.isBareAmpersandSelector(currentSelector)
|
|
759
|
+
) {
|
|
760
|
+
renderSelector = currentSelector;
|
|
761
|
+
}
|
|
762
|
+
if (this.hoistToRoot && options.depth === 0 && !(renderSelector instanceof Nil)) {
|
|
763
|
+
renderSelector = Ruleset.materializeHoistedImplicitAmpersands(renderSelector as Selector) as typeof selector;
|
|
764
|
+
}
|
|
765
|
+
if (
|
|
766
|
+
options.referenceMode === true
|
|
767
|
+
&& options.referenceRenderEnabled === true
|
|
768
|
+
&& !(renderSelector instanceof Nil)
|
|
769
|
+
) {
|
|
770
|
+
const filteredReferenceSelector = Ruleset.filterReferenceVisibleSelectorItems(
|
|
771
|
+
renderSelector as Selector,
|
|
772
|
+
this.getSelectorBeforeExtend(renderKey),
|
|
773
|
+
options.context
|
|
774
|
+
) as typeof renderSelector;
|
|
775
|
+
const rulesetExtended = options.context
|
|
776
|
+
? this._hasFlag(F_EXTENDED, options.context)
|
|
777
|
+
: this.hasFlag(F_EXTENDED);
|
|
778
|
+
if (!(filteredReferenceSelector instanceof Nil)) {
|
|
779
|
+
renderSelector = filteredReferenceSelector;
|
|
780
|
+
} else if (!rulesetExtended) {
|
|
781
|
+
return '';
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const prevReferenceFilterTargets = options.referenceFilterTargets === true;
|
|
785
|
+
const disableTargetFilteringForTopLevelList = (
|
|
786
|
+
(options.context ? this._hasFlag(F_EXTENDED, options.context) : this.hasFlag(F_EXTENDED))
|
|
787
|
+
&& !(renderSelector instanceof Nil)
|
|
788
|
+
&& isNode(renderSelector as Selector, N.SelectorList)
|
|
789
|
+
);
|
|
790
|
+
options.referenceFilterTargets = (
|
|
791
|
+
options.referenceMode === true
|
|
792
|
+
&& options.referenceRenderEnabled === true
|
|
793
|
+
&& !disableTargetFilteringForTopLevelList
|
|
794
|
+
);
|
|
795
|
+
Ruleset.ensureSelectorVisible(renderSelector);
|
|
796
|
+
const ctx = options.context;
|
|
797
|
+
const previousRenderKey = ctx?.renderKey;
|
|
798
|
+
if (ctx && renderKey !== undefined) {
|
|
799
|
+
ctx.renderKey = renderKey;
|
|
800
|
+
}
|
|
801
|
+
const selOut = w.capture(() => renderSelector.toString(options));
|
|
802
|
+
if (ctx) {
|
|
803
|
+
ctx.renderKey = previousRenderKey;
|
|
804
|
+
}
|
|
805
|
+
options.referenceFilterTargets = prevReferenceFilterTargets;
|
|
806
|
+
return normalizeIndent(selOut.replace(/\s+$/, '') + ' {', idt) + '\n';
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
override preEval(context: Context): MaybePromise<this> {
|
|
810
|
+
if (!this.preEvaluated) {
|
|
811
|
+
const node = this.clone(false, undefined, context);
|
|
812
|
+
node.preEvaluated = true;
|
|
813
|
+
const renderKey = node._resolveRenderKey(context);
|
|
814
|
+
const selectorText = String(this.getSelector(renderKey)?.valueOf?.() ?? '');
|
|
815
|
+
if (process.env.JESS_DEBUG_LOCK === 'throw-pre-ruleset' && selectorText.includes('.call-inner-lock-mixin')) {
|
|
816
|
+
throw new Error(`[lock-pre-ruleset] ${JSON.stringify({
|
|
817
|
+
selectorText,
|
|
818
|
+
parent: this.parent?.type,
|
|
819
|
+
sourceParent: this.sourceParent?.type,
|
|
820
|
+
renderKey: String(renderKey)
|
|
821
|
+
})}`);
|
|
822
|
+
}
|
|
823
|
+
// Index should already be assigned by parent Rules
|
|
824
|
+
node.sourceNode ??= this;
|
|
825
|
+
const rulesetOptions = node.options;
|
|
826
|
+
let rules = node.enterRules(context);
|
|
827
|
+
// On re-eval (e.g. mixin clone), use the pre-composition ownSelector so we
|
|
828
|
+
// compose from the authored selector, not the already-composed one.
|
|
829
|
+
let selector: Selector | Nil = rulesetOptions.ownSelector ?? node.getSelector(renderKey);
|
|
830
|
+
// Generated wrapper rulesets (e.g. implicit `& { ... }` created by AtRule hoisting)
|
|
831
|
+
// should not force var visibility to `private`, otherwise sibling vars inside the wrapper
|
|
832
|
+
// (like Less `@base`) become inaccessible.
|
|
833
|
+
if (!rulesetOptions.generated) {
|
|
834
|
+
if (rules.renderKey === CANONICAL) {
|
|
835
|
+
const wrappedRules = rules.createShallowBodyWrapper(context);
|
|
836
|
+
node.rules = wrappedRules;
|
|
837
|
+
node.adopt(wrappedRules, context);
|
|
838
|
+
rules = wrappedRules;
|
|
839
|
+
}
|
|
840
|
+
const nextRulesOptions = {
|
|
841
|
+
...rules.options,
|
|
842
|
+
rulesVisibility: {
|
|
843
|
+
...rules.options.rulesVisibility
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
if (context.leakyRules) {
|
|
847
|
+
nextRulesOptions.rulesVisibility.Mixin = 'public';
|
|
848
|
+
nextRulesOptions.rulesVisibility.VarDeclaration = 'optional';
|
|
849
|
+
} else {
|
|
850
|
+
nextRulesOptions.rulesVisibility.Mixin = 'private';
|
|
851
|
+
nextRulesOptions.rulesVisibility.VarDeclaration = 'private';
|
|
852
|
+
}
|
|
853
|
+
rules.options = nextRulesOptions;
|
|
854
|
+
}
|
|
855
|
+
const parentRuleset = context.rulesetFrames.at(-1);
|
|
856
|
+
const parentSelector = parentRuleset?.getSelector(parentRuleset._resolveRenderKey(context));
|
|
857
|
+
// Store own selector before parent resolution so extend can extend .replace,.c not the resolved form.
|
|
858
|
+
node.setOwnSelector(selector);
|
|
859
|
+
if (
|
|
860
|
+
!node.options.resolvedHoistWrapper
|
|
861
|
+
&& parentSelector
|
|
862
|
+
&& !(parentSelector instanceof Nil)
|
|
863
|
+
&& !(selector instanceof Nil)
|
|
864
|
+
&& parentRuleset
|
|
865
|
+
) {
|
|
866
|
+
const collapseForComposition = Boolean(
|
|
867
|
+
context.opts.collapseNesting
|
|
868
|
+
&& !selectorHasAuthoredAmpersand(selector as Selector)
|
|
869
|
+
);
|
|
870
|
+
selector = getImplicitSelectorUtil(
|
|
871
|
+
selector as Selector,
|
|
872
|
+
parentSelector as Selector,
|
|
873
|
+
collapseForComposition
|
|
874
|
+
);
|
|
875
|
+
{
|
|
876
|
+
const selectorSourceNode = node === this
|
|
877
|
+
? selector.clone(false, undefined, context)
|
|
878
|
+
: selector;
|
|
879
|
+
if (selector instanceof Node) {
|
|
880
|
+
selector.sourceNode = selectorSourceNode;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
// DO NOT evaluate guard here - guards are evaluated at call time in getFunctionFromMixins
|
|
885
|
+
// Just evaluate the selector
|
|
886
|
+
const ownSelector = node.getOwnSelector();
|
|
887
|
+
return pipe(
|
|
888
|
+
() => selector.eval(context),
|
|
889
|
+
(sel) => {
|
|
890
|
+
// If ownSelector has non-static children (e.g. interpolated attr values),
|
|
891
|
+
// evaluate it so extend matching uses the resolved form.
|
|
892
|
+
// Evaluate with collapseNesting=false so Ampersand nodes stay lazy
|
|
893
|
+
// (pointing at their parent container) rather than expanding into
|
|
894
|
+
// :is(parent). The combined selector was already correctly composed
|
|
895
|
+
// by getImplicitSelectorUtil; expanding & here corrupts the relative
|
|
896
|
+
// form and causes getEffectiveSelector to prepend the parent twice.
|
|
897
|
+
if (
|
|
898
|
+
ownSelector
|
|
899
|
+
&& !isNode(ownSelector, N.Nil)
|
|
900
|
+
&& ownSelector !== selector
|
|
901
|
+
) {
|
|
902
|
+
const savedCollapseNesting = context.opts.collapseNesting;
|
|
903
|
+
context.opts.collapseNesting = false;
|
|
904
|
+
return pipe(
|
|
905
|
+
() => ownSelector.eval(context),
|
|
906
|
+
(evaledOwn) => {
|
|
907
|
+
context.opts.collapseNesting = savedCollapseNesting;
|
|
908
|
+
node.setOwnSelector(evaledOwn as Selector);
|
|
909
|
+
return sel;
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
return sel;
|
|
914
|
+
},
|
|
915
|
+
(sel) => {
|
|
916
|
+
if (isNode(sel as Node, N.Selector)) {
|
|
917
|
+
sel = processLeadingIs(sel as Selector) as Selector | Nil;
|
|
918
|
+
}
|
|
919
|
+
// If this ruleset shares its value with a descendant ruleset, give descendants
|
|
920
|
+
// their own value before we overwrite value.selector so they keep their selector.
|
|
921
|
+
Ruleset.ensureDescendantRulesetsHaveOwnValue(node as Ruleset, {} as RulesetValue);
|
|
922
|
+
// Store the evaluated selector - this is what will be in the frame
|
|
923
|
+
node.selector = sel as Selector | Nil;
|
|
924
|
+
if (sel instanceof Node) {
|
|
925
|
+
node.adopt(sel, context);
|
|
926
|
+
}
|
|
927
|
+
if (sel.hoistToRoot) {
|
|
928
|
+
node.hoistToRoot = true;
|
|
929
|
+
}
|
|
930
|
+
// Register to extend root's registry for extend lookups
|
|
931
|
+
const extendRoot = context.extendRoots.getCurrentExtendRoot();
|
|
932
|
+
if (extendRoot) {
|
|
933
|
+
extendRoot.register('ruleset', node as Ruleset);
|
|
934
|
+
// Keep a per-root registry list for visibility processing
|
|
935
|
+
context.extendRoots.registerRuleset(extendRoot, node as Ruleset);
|
|
936
|
+
}
|
|
937
|
+
// Depth-first: preEval child rules immediately so all nested rulesets/extends
|
|
938
|
+
// are registered in source order before we process extends.
|
|
939
|
+
// Push this ruleset to the frame so nested rulesets get the correct parent selector
|
|
940
|
+
// when building implicit selectors (e.g. .header-nav inside .header → .header .header-nav).
|
|
941
|
+
const childRules = node.enterRules(context);
|
|
942
|
+
if (childRules && !(childRules as unknown as Ruleset).preEvaluated) {
|
|
943
|
+
context.rulesetFrames.push(node as Ruleset);
|
|
944
|
+
if (extendRoot) {
|
|
945
|
+
context.extendRoots.registerRoot(childRules, extendRoot);
|
|
946
|
+
}
|
|
947
|
+
const preEvaldRules = childRules.preEval(context);
|
|
948
|
+
if (isThenable(preEvaldRules)) {
|
|
949
|
+
return (preEvaldRules as Promise<Rules>).then((rules) => {
|
|
950
|
+
context.rulesetFrames.pop();
|
|
951
|
+
node.rules = rules;
|
|
952
|
+
node.adopt(rules, context);
|
|
953
|
+
if (extendRoot && rules !== childRules) {
|
|
954
|
+
context.extendRoots.registerRoot(rules, extendRoot);
|
|
955
|
+
}
|
|
956
|
+
return node;
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
context.rulesetFrames.pop();
|
|
960
|
+
node._assignRules(preEvaldRules as Rules, context);
|
|
961
|
+
if (extendRoot && preEvaldRules !== childRules) {
|
|
962
|
+
context.extendRoots.registerRoot(preEvaldRules as Rules, extendRoot);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return node;
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
return this;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/** Attach an (invisible) ampersand to the selector(s) if it's not already there */
|
|
973
|
+
getImplicitSelector(parentSelector: Selector, collapseNesting = false) {
|
|
974
|
+
const selector = this.get('selector');
|
|
975
|
+
if (selector instanceof Nil) {
|
|
976
|
+
return selector;
|
|
977
|
+
}
|
|
978
|
+
return getImplicitSelectorUtil(selector, parentSelector, collapseNesting);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
override clone(deep?: boolean, cloneFn?: (n: Node) => Node, ctx?: Context): this {
|
|
982
|
+
const priorSelectorParent = !deep && this.selector instanceof Node
|
|
983
|
+
? this.selector.parent
|
|
984
|
+
: undefined;
|
|
985
|
+
const priorRulesParent = !deep && this.rules instanceof Node
|
|
986
|
+
? this.rules.parent
|
|
987
|
+
: undefined;
|
|
988
|
+
const cloned = super.clone(deep, cloneFn, ctx) as this;
|
|
989
|
+
if (!deep) {
|
|
990
|
+
if (this.selector instanceof Node) {
|
|
991
|
+
(this.selector as unknown as { parent?: Node }).parent = priorSelectorParent;
|
|
992
|
+
}
|
|
993
|
+
if (this.rules instanceof Node) {
|
|
994
|
+
(this.rules as unknown as { parent?: Node }).parent = priorRulesParent;
|
|
995
|
+
}
|
|
996
|
+
const renderKey = ctx ? cloned._resolveRenderKey(ctx) : this.renderKey;
|
|
997
|
+
const selector = cloned.getSelector(renderKey);
|
|
998
|
+
if (selector instanceof Node) {
|
|
999
|
+
if (ctx || this !== this.sourceNode) {
|
|
1000
|
+
cloned.selector = selector.clone(false, undefined, ctx) as Selector | Nil;
|
|
1001
|
+
cloned.adopt(cloned.selector, ctx);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
const currentRules = this.getRules(renderKey);
|
|
1005
|
+
if (ctx && currentRules !== this.rules) {
|
|
1006
|
+
cloned.rules = currentRules;
|
|
1007
|
+
cloned.adopt(currentRules, ctx);
|
|
1008
|
+
}
|
|
1009
|
+
if (this !== this.sourceNode && cloned.rules === this.rules) {
|
|
1010
|
+
const rules = ctx ? cloned.enterRules(ctx) : cloned.rules;
|
|
1011
|
+
cloned.rules = rules.createShallowBodyWrapper(ctx);
|
|
1012
|
+
cloned.adopt(cloned.rules, ctx);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
if (!deep && ctx && this !== this.sourceNode && cloned.rules !== this.rules && cloned.rules.parent !== cloned) {
|
|
1016
|
+
cloned.adopt(cloned.rules, ctx);
|
|
1017
|
+
}
|
|
1018
|
+
return cloned;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
override copy(deep?: boolean): this {
|
|
1022
|
+
const node = super.copy(deep);
|
|
1023
|
+
const selectorSource = this.getOwnSelector() ?? this.selector;
|
|
1024
|
+
node.selector = selectorSource.sourceNode.copy(true) as Selector | Nil;
|
|
1025
|
+
node.adopt(node.selector);
|
|
1026
|
+
return node;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
override evalNode(context: Context): MaybePromise<Ruleset | Rules | Nil> {
|
|
1030
|
+
if (this.evaluated) {
|
|
1031
|
+
return this;
|
|
1032
|
+
}
|
|
1033
|
+
let pushedFrames = false;
|
|
1034
|
+
const renderKey = this._resolveRenderKey(context);
|
|
1035
|
+
const previousRenderKey = context.renderKey;
|
|
1036
|
+
if (renderKey !== undefined && renderKey !== CANONICAL) {
|
|
1037
|
+
context.renderKey = renderKey;
|
|
1038
|
+
}
|
|
1039
|
+
/** Should have been maybe cloned in preEval */
|
|
1040
|
+
this.evaluated = true;
|
|
1041
|
+
const collapseNesting = context.opts.collapseNesting;
|
|
1042
|
+
|
|
1043
|
+
// Store frames snapshot for collapseNesting serialization
|
|
1044
|
+
if (collapseNesting) {
|
|
1045
|
+
this.frames = [...context.frames];
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const out = pipe(
|
|
1049
|
+
() => {
|
|
1050
|
+
const selectorText = String(this.getSelector(renderKey)?.valueOf?.() ?? '');
|
|
1051
|
+
if (process.env.JESS_DEBUG_LOCK === 'throw-ruleset' && selectorText.includes('.call-inner-lock-mixin')) {
|
|
1052
|
+
throw new Error(`[lock-ruleset] ${JSON.stringify({
|
|
1053
|
+
selectorText,
|
|
1054
|
+
parent: this.parent?.type,
|
|
1055
|
+
sourceParent: this.sourceParent?.type,
|
|
1056
|
+
renderKey: String(renderKey),
|
|
1057
|
+
childCount: this.enterRules(context).get('value', context).length
|
|
1058
|
+
})}`);
|
|
1059
|
+
}
|
|
1060
|
+
if (
|
|
1061
|
+
selectorText.includes('.call-lock-mixin')
|
|
1062
|
+
|| selectorText.includes('#guarded-caller')
|
|
1063
|
+
|| selectorText.includes('#guarded-deeper')
|
|
1064
|
+
) {
|
|
1065
|
+
}
|
|
1066
|
+
let guard = this.getGuard(renderKey);
|
|
1067
|
+
// Guard was already set to Nil (failed in a previous eval)
|
|
1068
|
+
if (guard instanceof Nil) {
|
|
1069
|
+
return guard;
|
|
1070
|
+
}
|
|
1071
|
+
// Evaluate guard at definition time (not call time like mixins)
|
|
1072
|
+
// This is different from mixins because rulesets can't use caller scope for guards
|
|
1073
|
+
if (guard) {
|
|
1074
|
+
return pipe(
|
|
1075
|
+
() => guard.eval(context),
|
|
1076
|
+
(guardResult) => {
|
|
1077
|
+
const selectorText = String(this.getSelector(renderKey)?.valueOf?.() ?? '');
|
|
1078
|
+
const guardPasses = Boolean(guardResult instanceof Bool && guardResult.value === true);
|
|
1079
|
+
if (selectorText.includes('#guarded') || selectorText.includes('#top') || selectorText.includes('#deeper')) {
|
|
1080
|
+
}
|
|
1081
|
+
if (!guardPasses) {
|
|
1082
|
+
// Guard failed - mark as Nil and return it
|
|
1083
|
+
this.guard = new Nil() as Condition | Nil;
|
|
1084
|
+
return new Nil();
|
|
1085
|
+
}
|
|
1086
|
+
// Guard passed - clear it and continue with selector evaluation
|
|
1087
|
+
this.guard = undefined as Condition | Nil | undefined;
|
|
1088
|
+
return undefined;
|
|
1089
|
+
}
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
return undefined;
|
|
1093
|
+
},
|
|
1094
|
+
(guardResult) => {
|
|
1095
|
+
// If guard failed, return Nil (ruleset produces no output)
|
|
1096
|
+
if (guardResult instanceof Nil) {
|
|
1097
|
+
return guardResult;
|
|
1098
|
+
}
|
|
1099
|
+
let selector = this.getSelector(renderKey);
|
|
1100
|
+
const frame = atIndex(context.rulesetFrames, -1);
|
|
1101
|
+
if (frame && (this.hoistToRoot ?? context.opts.collapseNesting)) {
|
|
1102
|
+
this.hoistToRoot = true;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (selector instanceof Nil) {
|
|
1106
|
+
// If selector evaluates to Nil, return the rules body directly instead of the ruleset
|
|
1107
|
+
// This allows rules to be output even when there's no selector context
|
|
1108
|
+
// We don't push frames because there's no selector context
|
|
1109
|
+
// Store Nil in selector so next step can detect this case
|
|
1110
|
+
this.selector = selector as Selector | Nil;
|
|
1111
|
+
const evaluatedRules = this.enterRules(context).eval(context);
|
|
1112
|
+
// Update this.rules to point to evaluated Rules to prevent circular reference
|
|
1113
|
+
// when debug code traverses the AST
|
|
1114
|
+
if (isThenable(evaluatedRules)) {
|
|
1115
|
+
return (evaluatedRules as Promise<Rules>).then((rules) => {
|
|
1116
|
+
this._assignRules(rules, context);
|
|
1117
|
+
return rules;
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
this._assignRules(evaluatedRules as Rules, context);
|
|
1121
|
+
return evaluatedRules;
|
|
1122
|
+
}
|
|
1123
|
+
// Preserve the sourceNode from the current selector before replacing it
|
|
1124
|
+
const preservedSourceNode = this._getSelectorSourceNode(this.getSelector(renderKey));
|
|
1125
|
+
this.selector = selector as Selector | Nil;
|
|
1126
|
+
this.adopt(this.selector, context);
|
|
1127
|
+
// Restore the sourceNode on the new selector so it's available when copying
|
|
1128
|
+
const currentSelector = this.getSelector(renderKey);
|
|
1129
|
+
if (preservedSourceNode && currentSelector) {
|
|
1130
|
+
{
|
|
1131
|
+
const selectorForSourceNode = currentSelector;
|
|
1132
|
+
if (selectorForSourceNode instanceof Node && preservedSourceNode) {
|
|
1133
|
+
selectorForSourceNode.sourceNode = preservedSourceNode;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (context.opts.collapseNesting) {
|
|
1138
|
+
this.hoistToRoot = true;
|
|
1139
|
+
}
|
|
1140
|
+
context.rulesetFrames.push(this as Ruleset);
|
|
1141
|
+
context.frames.push(this);
|
|
1142
|
+
pushedFrames = true;
|
|
1143
|
+
return this.enterRules(context).eval(context);
|
|
1144
|
+
},
|
|
1145
|
+
(evaluatedRules: Rules | Nil) => {
|
|
1146
|
+
if (pushedFrames) {
|
|
1147
|
+
context.rulesetFrames.pop();
|
|
1148
|
+
context.frames.pop();
|
|
1149
|
+
}
|
|
1150
|
+
if (evaluatedRules instanceof Nil) {
|
|
1151
|
+
return evaluatedRules;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// If selector was Nil, evaluatedRules is already Rules (not wrapped in Ruleset)
|
|
1155
|
+
// In that case, return it directly without wrapping back in Ruleset
|
|
1156
|
+
if (this.getSelector(renderKey) instanceof Nil) {
|
|
1157
|
+
// Selector was Nil, so we already returned Rules directly - just return it
|
|
1158
|
+
return evaluatedRules;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
this._assignRules(evaluatedRules as Rules, context);
|
|
1162
|
+
const rules = this.enterRules(context);
|
|
1163
|
+
if (rules.visibleRules(context).length === 0) {
|
|
1164
|
+
this._removeFlag(F_VISIBLE, context);
|
|
1165
|
+
}
|
|
1166
|
+
return this;
|
|
1167
|
+
}
|
|
1168
|
+
);
|
|
1169
|
+
|
|
1170
|
+
if (isThenable(out)) {
|
|
1171
|
+
return (out as Promise<Ruleset | Rules | Nil>).then(
|
|
1172
|
+
(result) => {
|
|
1173
|
+
context.renderKey = previousRenderKey;
|
|
1174
|
+
return result;
|
|
1175
|
+
},
|
|
1176
|
+
(error) => {
|
|
1177
|
+
context.renderKey = previousRenderKey;
|
|
1178
|
+
throw error;
|
|
1179
|
+
}
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
context.renderKey = previousRenderKey;
|
|
1183
|
+
return out;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/** @todo move to ToCssVisitor */
|
|
1187
|
+
// toCSS(context: Context, out: OutputCollector) {
|
|
1188
|
+
// const { sels, value } = this
|
|
1189
|
+
// context.inSelector = true
|
|
1190
|
+
// sels.toCSS(context, out)
|
|
1191
|
+
// context.inSelector = false
|
|
1192
|
+
// out.add(' ')
|
|
1193
|
+
// value.toCSS(context, out)
|
|
1194
|
+
// }
|
|
1195
|
+
|
|
1196
|
+
/** @todo Move to ToModuleVisitor */
|
|
1197
|
+
// toModule(context: Context, out: OutputCollector) {
|
|
1198
|
+
// out.add('$J.rule({\n', this.location)
|
|
1199
|
+
// context.indent++
|
|
1200
|
+
// const pre = context.pre
|
|
1201
|
+
// out.add(`${pre}sels: `)
|
|
1202
|
+
// this.sels.toModule(context, out)
|
|
1203
|
+
// out.add(`,\n${pre}value: `)
|
|
1204
|
+
// this.data.toModule(context, out)
|
|
1205
|
+
// context.indent--
|
|
1206
|
+
// out.add(`},${JSON.stringify(this.location)})`)
|
|
1207
|
+
// }
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
type RulesetParams = ConstructorParameters<typeof Ruleset>;
|
|
1211
|
+
|
|
1212
|
+
export const ruleset = defineType<RulesetValue>(Ruleset, 'Ruleset') as (
|
|
1213
|
+
value: RulesetValue | RulesetParams[0],
|
|
1214
|
+
options?: RulesetParams[1],
|
|
1215
|
+
location?: RulesetParams[2],
|
|
1216
|
+
treeContext?: RulesetParams[3]
|
|
1217
|
+
) => Ruleset;
|