@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,1006 @@
|
|
|
1
|
+
import { isPlainObject } from './tree/util/collections.js';
|
|
2
|
+
import { AbstractClass, Class, OmitIndexSignature } from 'type-fest';
|
|
3
|
+
import { isNode } from './tree/util/is-node.js';
|
|
4
|
+
import { N } from './tree/node-type.js';
|
|
5
|
+
import type { Context } from './context.js';
|
|
6
|
+
import { isThenable } from '@jesscss/awaitable-pipe';
|
|
7
|
+
import type { MaybePromise } from '@jesscss/awaitable-pipe';
|
|
8
|
+
import { List, Sequence, Operation, Num, Dimension } from './tree/index.js';
|
|
9
|
+
import type { ConversionPlugin, PreprocessParams } from './conversions.js';
|
|
10
|
+
import { isEvaluated } from './tree/util/field-helpers.js';
|
|
11
|
+
import { F_STATIC } from './tree/node.js';
|
|
12
|
+
export type PrimitiveType = 'string' | 'number' | 'boolean' | 'null' | 'undefined';
|
|
13
|
+
export type ArgType = PrimitiveType | Class<any> | AbstractClass<any>;
|
|
14
|
+
export type Lazy<T> = () => MaybePromise<T>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* FunctionThis provides a proxy-based interface for function execution context.
|
|
18
|
+
*
|
|
19
|
+
* The `args` property is always a function that returns a `MaybePromise<List>`,
|
|
20
|
+
* providing a consistent API regardless of lazy parameter configuration.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const func = defineFunction('test', async function(this: FunctionThis) {
|
|
25
|
+
* // this.args is always a function that returns the arguments
|
|
26
|
+
* const evaluatedArgs = await this.args();
|
|
27
|
+
* return evaluatedArgs;
|
|
28
|
+
* }, {
|
|
29
|
+
* params: [
|
|
30
|
+
* { name: 'value', type: 'string', lazy: true }
|
|
31
|
+
* ]
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export type FunctionThis = {
|
|
36
|
+
/** The evaluation context */
|
|
37
|
+
context: Context;
|
|
38
|
+
/** The current call node that invoked this function, when available. */
|
|
39
|
+
caller?: Context['caller'];
|
|
40
|
+
/**
|
|
41
|
+
* The function arguments. Always returns a function that evaluates to MaybePromise<List>.
|
|
42
|
+
* This provides a consistent API regardless of lazy parameter configuration.
|
|
43
|
+
*/
|
|
44
|
+
args: () => MaybePromise<List>;
|
|
45
|
+
/** The original arguments, not evaluated */
|
|
46
|
+
rawArgs: List;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type ParamDefinition = {
|
|
50
|
+
name: string;
|
|
51
|
+
type: ArgType | readonly ArgType[];
|
|
52
|
+
optional?: boolean;
|
|
53
|
+
default?: any;
|
|
54
|
+
/** Marks this parameter as a variadic rest parameter. Must be the last param. */
|
|
55
|
+
rest?: boolean;
|
|
56
|
+
/** If true, provide a thunk (() => Promise<T>) to the internal positional function */
|
|
57
|
+
lazy?: boolean;
|
|
58
|
+
/** Conversion plugins to apply to the argument before passing to the function */
|
|
59
|
+
convert?: ConversionPlugin[];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type DefineFunctionOptions = {
|
|
63
|
+
/**
|
|
64
|
+
* Parameter definitions. Can be a single array for one signature,
|
|
65
|
+
* or an array of arrays for function overloading (multiple signatures).
|
|
66
|
+
* The system will try each signature until one matches.
|
|
67
|
+
*/
|
|
68
|
+
params: readonly ParamDefinition[] | readonly ParamDefinition[][];
|
|
69
|
+
/**
|
|
70
|
+
* Preprocesses the raw arguments array before parsing into a record.
|
|
71
|
+
* This allows transformations like splitting sequences, normalizing arguments, etc.
|
|
72
|
+
* Applied in order, with each preprocessor receiving the output of the previous one.
|
|
73
|
+
*
|
|
74
|
+
* @param args - The raw arguments array
|
|
75
|
+
* @param context - The evaluation context
|
|
76
|
+
* @returns The processed arguments array (can be async)
|
|
77
|
+
*/
|
|
78
|
+
preprocessParams?: PreprocessParams[];
|
|
79
|
+
// Future options can be added here
|
|
80
|
+
// example?: boolean;
|
|
81
|
+
// validate?: boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Helper type to get the inferred type from ArgType
|
|
85
|
+
type GetArgType<T extends ArgType> =
|
|
86
|
+
T extends 'string'
|
|
87
|
+
? string
|
|
88
|
+
: T extends 'number'
|
|
89
|
+
? number
|
|
90
|
+
: T extends 'boolean'
|
|
91
|
+
? boolean
|
|
92
|
+
: T extends 'null'
|
|
93
|
+
? null
|
|
94
|
+
: T extends 'undefined'
|
|
95
|
+
? undefined
|
|
96
|
+
: T extends Class<any> | AbstractClass<any>
|
|
97
|
+
? InstanceType<T>
|
|
98
|
+
: never;
|
|
99
|
+
|
|
100
|
+
// Helper type to get the inferred type from a parameter definition, accounting for lazy
|
|
101
|
+
type GetParamType<T extends DefineFunctionOptions['params'][number]> =
|
|
102
|
+
T extends { lazy: true; type: infer A extends ArgType }
|
|
103
|
+
? Lazy<GetArgType<A>>
|
|
104
|
+
: T extends { lazy: true; type: readonly ArgType[] }
|
|
105
|
+
? Lazy<GetArgType<T['type'][number]>>
|
|
106
|
+
: T extends { type: infer A extends ArgType }
|
|
107
|
+
? GetArgType<A>
|
|
108
|
+
: T extends { type: readonly ArgType[] }
|
|
109
|
+
? GetArgType<T['type'][number]>
|
|
110
|
+
: never;
|
|
111
|
+
|
|
112
|
+
/** This should be getting only required types but it doesn't? */
|
|
113
|
+
type GetBaseRecordType<T extends DefineFunctionOptions['params']> = (
|
|
114
|
+
OmitIndexSignature<{
|
|
115
|
+
[K in keyof T as T[K] extends { optional: true } | { default: any }
|
|
116
|
+
? never
|
|
117
|
+
: T[K] extends { name: infer N extends string }
|
|
118
|
+
? N
|
|
119
|
+
: never]:
|
|
120
|
+
T[K] extends DefineFunctionOptions['params'][number]
|
|
121
|
+
? GetParamType<T[K]>
|
|
122
|
+
: never;
|
|
123
|
+
}>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
type GetOptionalRecordType<T extends DefineFunctionOptions['params']> = {
|
|
127
|
+
[K in keyof T as T[K] extends { optional: true } | { default: any }
|
|
128
|
+
? T[K] extends { name: infer N extends string }
|
|
129
|
+
? N
|
|
130
|
+
: never
|
|
131
|
+
: never]?:
|
|
132
|
+
T[K] extends { rest: true }
|
|
133
|
+
? (
|
|
134
|
+
T[K] extends DefineFunctionOptions['params'][number]
|
|
135
|
+
? GetParamType<T[K]>[]
|
|
136
|
+
: never
|
|
137
|
+
)
|
|
138
|
+
: (
|
|
139
|
+
T[K] extends DefineFunctionOptions['params'][number]
|
|
140
|
+
? GetParamType<T[K]>
|
|
141
|
+
: never
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Get record types for named parameters
|
|
146
|
+
type GetRecordType<T extends DefineFunctionOptions['params']> = (
|
|
147
|
+
GetOptionalRecordType<T> & Omit<GetBaseRecordType<T>, keyof GetOptionalRecordType<T>>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
type GetPositionalTypes<
|
|
151
|
+
T extends DefineFunctionOptions['params'],
|
|
152
|
+
P extends Partial<GetRecordType<DefineFunctionOptions['params']>> = Partial<GetRecordType<T>>
|
|
153
|
+
> = T extends readonly [infer First, ...infer Rest]
|
|
154
|
+
? Rest extends DefineFunctionOptions['params']
|
|
155
|
+
? First extends { optional: true } | { default: any }
|
|
156
|
+
? First extends DefineFunctionOptions['params'][number]
|
|
157
|
+
? [(GetParamType<First> | (P & GetRecordType<T>))?, ...GetPositionalTypes<Rest, P>]
|
|
158
|
+
: never
|
|
159
|
+
: First extends DefineFunctionOptions['params'][number]
|
|
160
|
+
? [GetParamType<First> | (P & GetRecordType<T>), ...GetPositionalTypes<Rest, P>]
|
|
161
|
+
: never
|
|
162
|
+
: []
|
|
163
|
+
: [];
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Validates that the internal function signature matches the params definition
|
|
167
|
+
*/
|
|
168
|
+
type ValidateFunctionSignature<
|
|
169
|
+
T extends DefineFunctionOptions,
|
|
170
|
+
F extends (...args: any[]) => any
|
|
171
|
+
> = F;
|
|
172
|
+
|
|
173
|
+
export function defineFunction<
|
|
174
|
+
const T extends DefineFunctionOptions,
|
|
175
|
+
F extends (...args: any[]) => any
|
|
176
|
+
>(
|
|
177
|
+
name: string,
|
|
178
|
+
fn: ValidateFunctionSignature<T, F>,
|
|
179
|
+
options?: T
|
|
180
|
+
): DefinedFunction<T, F>;
|
|
181
|
+
|
|
182
|
+
export type DefinedFunction<
|
|
183
|
+
T extends DefineFunctionOptions,
|
|
184
|
+
F extends (...args: any[]) => any
|
|
185
|
+
> = {
|
|
186
|
+
(...args: any[]): ReturnType<F>;
|
|
187
|
+
name: string;
|
|
188
|
+
params: DefineFunctionOptions['params'];
|
|
189
|
+
} & {
|
|
190
|
+
call(thisArg: any, ...args: any[]): ReturnType<F>;
|
|
191
|
+
apply(thisArg: any, args: any[]): ReturnType<F>;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export function defineFunction<
|
|
195
|
+
const T extends DefineFunctionOptions,
|
|
196
|
+
F extends (...args: any[]) => any
|
|
197
|
+
>(
|
|
198
|
+
name: string,
|
|
199
|
+
fn: ValidateFunctionSignature<T, F>,
|
|
200
|
+
options?: T
|
|
201
|
+
) {
|
|
202
|
+
// The external API types remain exactly the same, but internal function accepts positional parameters only
|
|
203
|
+
|
|
204
|
+
type NamedFunction = DefinedFunction<T, F>;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Function that accepts either positional arguments or a record object.
|
|
208
|
+
* Parameter names are inferred from the params array: name, value, etc.
|
|
209
|
+
* All calls are converted to positional format before calling the internal function.
|
|
210
|
+
*/
|
|
211
|
+
const result = function(...args: any[]): ReturnType<F> {
|
|
212
|
+
const rawParams = options?.params;
|
|
213
|
+
if (!rawParams) {
|
|
214
|
+
return (fn as any)(...args);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Normalize params - handle overloaded signatures
|
|
218
|
+
const paramSignatures: ParamDefinition[][] = Array.isArray(rawParams) && rawParams.length > 0 && Array.isArray(rawParams[0])
|
|
219
|
+
? rawParams.map(sig => [...sig]) as ParamDefinition[][]
|
|
220
|
+
: [[...(rawParams as readonly ParamDefinition[])]];
|
|
221
|
+
|
|
222
|
+
// For direct calls, use the first signature (overloading handled in callWithContext)
|
|
223
|
+
const params = paramSignatures[0]!;
|
|
224
|
+
|
|
225
|
+
// Validate rest parameter position
|
|
226
|
+
validateRestParameterPosition(params);
|
|
227
|
+
|
|
228
|
+
// Parse arguments into a record
|
|
229
|
+
const record = parseArgumentsToRecord(args, params);
|
|
230
|
+
|
|
231
|
+
// Apply defaults and validate
|
|
232
|
+
applyDefaultsAndValidate(record, params);
|
|
233
|
+
|
|
234
|
+
// Convert to positional arguments and call internal function
|
|
235
|
+
const positionalArgs = buildPositionalArgs(record, params);
|
|
236
|
+
return (fn as any)(...positionalArgs);
|
|
237
|
+
} as NamedFunction;
|
|
238
|
+
|
|
239
|
+
/** Allow runtime reflection on the function */
|
|
240
|
+
return new Proxy(result, {
|
|
241
|
+
has(target, prop) {
|
|
242
|
+
if (prop === 'name' || prop === 'options') {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
return prop in target;
|
|
246
|
+
},
|
|
247
|
+
get(target, prop) {
|
|
248
|
+
if (prop === 'name') {
|
|
249
|
+
return name;
|
|
250
|
+
} else if (prop === 'options') {
|
|
251
|
+
return options;
|
|
252
|
+
} else if (prop === '_internal') {
|
|
253
|
+
return fn;
|
|
254
|
+
}
|
|
255
|
+
return (target as any)[prop];
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** This will be called internally by Jess to functions created with defineFunction */
|
|
261
|
+
export async function callWithContext(context: Context, fn: (...args: any[]) => any, ...args: any[]): Promise<any> {
|
|
262
|
+
const listArg = args.length === 1 && isNode(args[0], N.List)
|
|
263
|
+
? args[0] as List
|
|
264
|
+
: undefined;
|
|
265
|
+
args = listArg ? [...listArg.get('value')] : args;
|
|
266
|
+
// Only reject record-based calls (plain objects) when there's no params metadata
|
|
267
|
+
// Collections are allowed as positional arguments even without params metadata
|
|
268
|
+
// (e.g., detached rulesets passed to mixins)
|
|
269
|
+
if (!(fn as any)?.options?.params && args.some(arg => isPlainObject(arg) && !isNode(arg))) {
|
|
270
|
+
throw new Error('Record-based call without params is not supported');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Normalize positional args into a List node for tracking original arguments */
|
|
274
|
+
const originalArgsList: List = listArg
|
|
275
|
+
? listArg.clone(false)
|
|
276
|
+
: new List(args.map(arg => isNode(arg) ? arg.clone() : arg));
|
|
277
|
+
|
|
278
|
+
const hasParams = !!(fn as any)?.options?.params;
|
|
279
|
+
|
|
280
|
+
if (!hasParams) {
|
|
281
|
+
// No metadata; treat as normal positional function call (sync or async)
|
|
282
|
+
return (fn as any).call(context, ...args);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const params = (fn as any)?.options?.params as DefineFunctionOptions['params'] | undefined;
|
|
286
|
+
const options = (fn as any)?.options as DefineFunctionOptions | undefined;
|
|
287
|
+
|
|
288
|
+
// Apply preprocessParams if provided (e.g., for splitting sequences)
|
|
289
|
+
if (options?.preprocessParams && options.preprocessParams.length > 0) {
|
|
290
|
+
for (const preprocessor of options.preprocessParams) {
|
|
291
|
+
const processed = preprocessor(args, context);
|
|
292
|
+
if (isThenable(processed)) {
|
|
293
|
+
args = await processed;
|
|
294
|
+
} else {
|
|
295
|
+
args = processed;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Handle function overloading: params can be an array of param arrays
|
|
301
|
+
// Normalize to always be an array of signatures
|
|
302
|
+
const paramSignatures: ParamDefinition[][] = (() => {
|
|
303
|
+
if (!params) {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
// Check if params is an array of arrays (overloaded signatures)
|
|
307
|
+
if (Array.isArray(params) && params.length > 0 && Array.isArray(params[0])) {
|
|
308
|
+
return params.map(sig => [...sig]) as ParamDefinition[][];
|
|
309
|
+
}
|
|
310
|
+
// Single signature - wrap in array
|
|
311
|
+
return [[...(params as readonly ParamDefinition[])]];
|
|
312
|
+
})();
|
|
313
|
+
|
|
314
|
+
let matchedParams: readonly ParamDefinition[] | undefined;
|
|
315
|
+
let record: any;
|
|
316
|
+
let lastError: Error | undefined;
|
|
317
|
+
|
|
318
|
+
// Try each signature until one matches
|
|
319
|
+
for (const signature of paramSignatures) {
|
|
320
|
+
try {
|
|
321
|
+
record = parseCallWithContextArgs(args, signature);
|
|
322
|
+
// Try to build positional args to validate the signature matches
|
|
323
|
+
// We'll do a dry-run validation
|
|
324
|
+
const tempRecord = { ...record };
|
|
325
|
+
let isValid = true;
|
|
326
|
+
|
|
327
|
+
// Check if we have a record object (plain object) in args
|
|
328
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
329
|
+
const hasRecordArg = args.some(arg => isPlainObject(arg));
|
|
330
|
+
|
|
331
|
+
for (let i = 0; i < signature.length; i++) {
|
|
332
|
+
const def = signature[i]!;
|
|
333
|
+
const value = tempRecord[def.name];
|
|
334
|
+
|
|
335
|
+
// Check required parameters
|
|
336
|
+
if (!def.optional && !def.rest && value === undefined) {
|
|
337
|
+
isValid = false;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Check if we have enough arguments (skip this check if we have a record arg)
|
|
342
|
+
if (!hasRecordArg && !def.rest && i >= args.length && !def.optional) {
|
|
343
|
+
isValid = false;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Check if we have too many arguments (not counting rest params or record args)
|
|
349
|
+
const hasRest = signature.some(p => p.rest);
|
|
350
|
+
if (!hasRest && !hasRecordArg && args.length > signature.length) {
|
|
351
|
+
isValid = false;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (isValid) {
|
|
355
|
+
matchedParams = signature;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
lastError = error as Error;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// If no signature matched, throw an error
|
|
365
|
+
if (!matchedParams) {
|
|
366
|
+
if (lastError) {
|
|
367
|
+
throw lastError;
|
|
368
|
+
}
|
|
369
|
+
throw new Error(`No matching function signature for ${args.length} argument(s)`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Re-parse with the matched signature to ensure correct record structure
|
|
373
|
+
record = parseCallWithContextArgs(args, matchedParams);
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Create FunctionThis proxy for function execution context.
|
|
377
|
+
* The args property is always a function that returns the arguments.
|
|
378
|
+
*/
|
|
379
|
+
context.callStack.at(-1)?.adopt(originalArgsList);
|
|
380
|
+
const functionThis: FunctionThis = {
|
|
381
|
+
context,
|
|
382
|
+
args: () => originalArgsList.eval(context),
|
|
383
|
+
rawArgs: originalArgsList,
|
|
384
|
+
caller: context.caller
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// Build positional arguments with evaluation, validation, and conversion
|
|
388
|
+
const positionalArgs = await buildCallWithContextPositionalArgs(record, matchedParams, context);
|
|
389
|
+
|
|
390
|
+
// Call the function with the evaluated arguments
|
|
391
|
+
// Mixin functions expect Context as 'this', not FunctionThis
|
|
392
|
+
if ((fn as any)._internal) {
|
|
393
|
+
return ((fn as any)._internal).call(functionThis, ...positionalArgs);
|
|
394
|
+
} else {
|
|
395
|
+
// For mixin functions and other functions that expect Context as 'this'
|
|
396
|
+
return (fn as any).call(context, ...positionalArgs);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// ============================================================================
|
|
401
|
+
// HELPER FUNCTIONS
|
|
402
|
+
// ============================================================================
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Validates that rest parameters are in the correct position (last)
|
|
406
|
+
*/
|
|
407
|
+
function validateRestParameterPosition(params: readonly ParamDefinition[]): void {
|
|
408
|
+
const restIndex = params.findIndex(p => p.rest);
|
|
409
|
+
if (restIndex >= 0 && restIndex !== params.length - 1) {
|
|
410
|
+
throw new Error('Rest parameter must be the last parameter');
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Applies conversion plugins to a value
|
|
416
|
+
*/
|
|
417
|
+
function applyConversionPlugins(value: unknown, plugins: ConversionPlugin[]): unknown {
|
|
418
|
+
let result: unknown = value;
|
|
419
|
+
|
|
420
|
+
// Apply conversion plugins in sequence
|
|
421
|
+
for (const plugin of plugins) {
|
|
422
|
+
result = plugin(result);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Parses function arguments into a record object
|
|
430
|
+
*/
|
|
431
|
+
function parseArgumentsToRecord(args: any[], params: readonly ParamDefinition[]): any {
|
|
432
|
+
const record: any = {};
|
|
433
|
+
const restIndex = params.findIndex(p => (p as any).rest);
|
|
434
|
+
const hasRest = restIndex >= 0;
|
|
435
|
+
|
|
436
|
+
// Handle pure record call (single object argument)
|
|
437
|
+
if (args.length === 1 && isPlainObject(args[0])) {
|
|
438
|
+
const isClassInstance = params?.some((opt) => {
|
|
439
|
+
const types = Array.isArray(opt.type) ? opt.type : [opt.type];
|
|
440
|
+
return types.some(type =>
|
|
441
|
+
typeof type === 'function' && args[0] instanceof type
|
|
442
|
+
);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
if (!isClassInstance) {
|
|
446
|
+
const input = args[0] as any;
|
|
447
|
+
const isLateProxy = !!input && typeof input === 'object' && '_raw' in input;
|
|
448
|
+
return isLateProxy ? input._raw : { ...input };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Handle hybrid call (positional + record)
|
|
453
|
+
if (args.length > 1 && isPlainObject(args[args.length - 1])) {
|
|
454
|
+
const positionalArgs = args.slice(0, -1);
|
|
455
|
+
const recordArg = args[args.length - 1];
|
|
456
|
+
|
|
457
|
+
// Set values from positional arguments
|
|
458
|
+
if (!hasRest) {
|
|
459
|
+
for (let i = 0; i < positionalArgs.length && i < (params?.length ?? 0); i++) {
|
|
460
|
+
const paramName = params?.[i]?.name;
|
|
461
|
+
if (paramName) {
|
|
462
|
+
record[paramName] = positionalArgs[i];
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
467
|
+
const def = params[i]!;
|
|
468
|
+
const paramName = def.name;
|
|
469
|
+
if ((def as any).rest) {
|
|
470
|
+
record[paramName] = positionalArgs.slice(i);
|
|
471
|
+
break;
|
|
472
|
+
} else if (i < positionalArgs.length) {
|
|
473
|
+
record[paramName] = positionalArgs[i];
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Override with values from record (record takes precedence)
|
|
479
|
+
Object.assign(record, recordArg);
|
|
480
|
+
return record;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Handle pure positional call
|
|
484
|
+
if (!hasRest) {
|
|
485
|
+
for (let i = 0; i < Math.max(args.length, params?.length ?? 0); i++) {
|
|
486
|
+
const paramName = params?.[i]?.name;
|
|
487
|
+
if (paramName) {
|
|
488
|
+
if (i < args.length) {
|
|
489
|
+
record[paramName] = args[i];
|
|
490
|
+
} else if (params?.[i]?.default !== undefined) {
|
|
491
|
+
record[paramName] = params![i]?.default;
|
|
492
|
+
} else if (params?.[i]?.optional) {
|
|
493
|
+
record[paramName] = undefined;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
498
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
499
|
+
const def = params[i]!;
|
|
500
|
+
const paramName = def.name;
|
|
501
|
+
if ((def as any).rest) {
|
|
502
|
+
record[paramName] = args.slice(i);
|
|
503
|
+
break;
|
|
504
|
+
} else if (i < args.length) {
|
|
505
|
+
record[paramName] = args[i];
|
|
506
|
+
} else if (def.default !== undefined) {
|
|
507
|
+
record[paramName] = def.default;
|
|
508
|
+
} else if (def.optional) {
|
|
509
|
+
record[paramName] = undefined;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return record;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Applies defaults and validates arguments
|
|
519
|
+
*/
|
|
520
|
+
function applyDefaultsAndValidate(record: any, params: readonly ParamDefinition[]): void {
|
|
521
|
+
// Apply defaults for missing parameters
|
|
522
|
+
for (const paramDef of params ?? []) {
|
|
523
|
+
const paramName = paramDef.name;
|
|
524
|
+
if (record[paramName] === undefined && paramDef.default !== undefined) {
|
|
525
|
+
record[paramName] = paramDef.default;
|
|
526
|
+
}
|
|
527
|
+
// Normalize rest param to array
|
|
528
|
+
if ((paramDef as any).rest) {
|
|
529
|
+
const current = record[paramName];
|
|
530
|
+
if (current === undefined) {
|
|
531
|
+
record[paramName] = [];
|
|
532
|
+
} else if (!Array.isArray(current)) {
|
|
533
|
+
record[paramName] = [current];
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
validateArguments(record, params);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Builds positional arguments from record
|
|
543
|
+
*/
|
|
544
|
+
function buildPositionalArgs(record: any, params: readonly ParamDefinition[]): any[] {
|
|
545
|
+
const positionalArgs: any[] = [];
|
|
546
|
+
|
|
547
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
548
|
+
const def = params![i]!;
|
|
549
|
+
const name = def.name;
|
|
550
|
+
|
|
551
|
+
if ((def as any).rest) {
|
|
552
|
+
const v = record[name];
|
|
553
|
+
const arr: any[] = Array.isArray(v) ? v : (v === undefined ? [] : [v]);
|
|
554
|
+
if ((def as any).lazy) {
|
|
555
|
+
positionalArgs.push(...arr.map(item => createThunk(item, def)));
|
|
556
|
+
} else {
|
|
557
|
+
positionalArgs.push(...arr.map((item) => {
|
|
558
|
+
// Apply conversion plugins if defined
|
|
559
|
+
if (def.convert && item instanceof Dimension) {
|
|
560
|
+
return applyConversionPlugins(item, def.convert);
|
|
561
|
+
}
|
|
562
|
+
return item;
|
|
563
|
+
}));
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
const v = record[name];
|
|
567
|
+
if ((def as any).lazy) {
|
|
568
|
+
// For optional lazy parameters, if value is undefined, pass undefined directly
|
|
569
|
+
// instead of creating a thunk (which would try to call undefined())
|
|
570
|
+
if (v === undefined && (def.optional || def.default !== undefined)) {
|
|
571
|
+
positionalArgs.push(undefined);
|
|
572
|
+
} else {
|
|
573
|
+
positionalArgs.push(createThunk(v, def));
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
// Apply conversion plugins if defined
|
|
577
|
+
if (def.convert && v instanceof Dimension) {
|
|
578
|
+
positionalArgs.push(applyConversionPlugins(v, def.convert));
|
|
579
|
+
} else {
|
|
580
|
+
positionalArgs.push(v);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return positionalArgs;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Parses callWithContext arguments into a record
|
|
591
|
+
*/
|
|
592
|
+
function parseCallWithContextArgs(args: any[], params: readonly ParamDefinition[] | undefined): any {
|
|
593
|
+
const record: any = {};
|
|
594
|
+
const restIndex = params ? params.findIndex(p => (p as any).rest) : -1;
|
|
595
|
+
const hasRest = (restIndex ?? -1) >= 0;
|
|
596
|
+
|
|
597
|
+
if (!hasRest) {
|
|
598
|
+
for (let i = 0; i < Math.min(args.length, params?.length ?? 0); i++) {
|
|
599
|
+
let arg = args[i];
|
|
600
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
601
|
+
if (isPlainObject(arg) && !isNode(arg)) {
|
|
602
|
+
Object.assign(record, arg);
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
const paramName = params?.[i]?.name as string;
|
|
606
|
+
if (!paramName) {
|
|
607
|
+
throw new Error('Function does not support this number of arguments');
|
|
608
|
+
}
|
|
609
|
+
record[paramName] = args[i];
|
|
610
|
+
}
|
|
611
|
+
} else {
|
|
612
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
613
|
+
const def = params![i]!;
|
|
614
|
+
const paramName = def.name;
|
|
615
|
+
const arg = args[i];
|
|
616
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
617
|
+
if (isPlainObject(arg) && !isNode(arg)) {
|
|
618
|
+
Object.assign(record, arg);
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if ((def as any).rest) {
|
|
622
|
+
record[paramName] = args.slice(i);
|
|
623
|
+
break;
|
|
624
|
+
} else {
|
|
625
|
+
record[paramName] = arg;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return record;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Builds positional arguments for callWithContext with evaluation
|
|
635
|
+
*/
|
|
636
|
+
async function buildCallWithContextPositionalArgs(
|
|
637
|
+
record: any,
|
|
638
|
+
params: readonly ParamDefinition[] | undefined,
|
|
639
|
+
context: Context
|
|
640
|
+
): Promise<any[]> {
|
|
641
|
+
const positionalArgs: any[] = [];
|
|
642
|
+
|
|
643
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
644
|
+
const def = params![i]!;
|
|
645
|
+
const name = def.name;
|
|
646
|
+
|
|
647
|
+
if ((def as any).rest) {
|
|
648
|
+
const v = record[name];
|
|
649
|
+
const arr: any[] = Array.isArray(v) ? v : (v === undefined ? [] : [v]);
|
|
650
|
+
if ((def as any).lazy) {
|
|
651
|
+
positionalArgs.push(...arr.map(item => createThunk(item, def, context)));
|
|
652
|
+
} else {
|
|
653
|
+
for (const item of arr) {
|
|
654
|
+
let processedItem: any = (isNode(item) && !isEvaluated(item, context)) ? (item as any).eval(context) : item;
|
|
655
|
+
if (isThenable(processedItem)) {
|
|
656
|
+
processedItem = await processedItem;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Validate AFTER evaluation but BEFORE conversion
|
|
660
|
+
validateArgumentIfNeeded(processedItem, def, 'Argument');
|
|
661
|
+
|
|
662
|
+
// Apply conversion plugins if defined
|
|
663
|
+
if (def.convert && processedItem instanceof Dimension) {
|
|
664
|
+
processedItem = applyConversionPlugins(processedItem, def.convert);
|
|
665
|
+
}
|
|
666
|
+
positionalArgs.push(processedItem);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
} else {
|
|
670
|
+
const v = record[name];
|
|
671
|
+
if ((def as any).lazy) {
|
|
672
|
+
// For optional lazy parameters, if value is undefined, pass undefined directly
|
|
673
|
+
// instead of creating a thunk (which would try to call undefined())
|
|
674
|
+
if (v === undefined && (def.optional || def.default !== undefined)) {
|
|
675
|
+
positionalArgs.push(undefined);
|
|
676
|
+
} else {
|
|
677
|
+
positionalArgs.push(createThunk(v, def, context));
|
|
678
|
+
}
|
|
679
|
+
} else {
|
|
680
|
+
let processedValue: any = (isNode(v) && !isEvaluated(v, context)) ? (v as any).eval(context) : v;
|
|
681
|
+
|
|
682
|
+
// Handle async evaluation without truncating remaining parameters.
|
|
683
|
+
if (isThenable(processedValue)) {
|
|
684
|
+
processedValue = await processedValue;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Validate AFTER evaluation but BEFORE conversion
|
|
688
|
+
validateArgumentIfNeeded(processedValue, def, 'Argument');
|
|
689
|
+
|
|
690
|
+
const callerName = context.caller && isNode(context.caller, N.Call)
|
|
691
|
+
? (() => {
|
|
692
|
+
const n = context.caller!.get('name');
|
|
693
|
+
return typeof n === 'string'
|
|
694
|
+
? n
|
|
695
|
+
: (isNode(n, N.Reference) ? String(n.get('key')?.valueOf?.() ?? '') : '');
|
|
696
|
+
})()
|
|
697
|
+
: '';
|
|
698
|
+
// Apply conversion plugins if defined
|
|
699
|
+
if (def.convert && processedValue instanceof Dimension) {
|
|
700
|
+
processedValue = applyConversionPlugins(processedValue, def.convert);
|
|
701
|
+
}
|
|
702
|
+
positionalArgs.push(processedValue);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return positionalArgs;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Validates callWithContext arguments from record (before conversion)
|
|
712
|
+
*/
|
|
713
|
+
function validateCallWithContextArgs(record: any, params: readonly ParamDefinition[] | undefined): void {
|
|
714
|
+
if (!params) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
for (let i = 0; i < params.length; i++) {
|
|
719
|
+
const def = params[i]!;
|
|
720
|
+
const value = record[def.name];
|
|
721
|
+
|
|
722
|
+
// Skip validation for lazy parameters since they're passed as thunks
|
|
723
|
+
if ((def as any).lazy) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Skip validation for rest parameters as they're validated as arrays
|
|
728
|
+
if ((def as any).rest) {
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Skip validation for optional parameters that are undefined
|
|
733
|
+
if ((def as any).optional && value === undefined) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
validateArgument(value, def, 'Argument');
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Creates a thunk function that evaluates a value and validates the result
|
|
743
|
+
*/
|
|
744
|
+
function createThunk(val: any, paramDef: any, context?: Context): () => MaybePromise<any> {
|
|
745
|
+
// For direct calls without context, val should be the user's lazy function (e.g., () => new Dimension(...))
|
|
746
|
+
// NOT a thunk. We create a thunk that calls val() and validates the resolved result.
|
|
747
|
+
if (typeof val === 'function' && !context) {
|
|
748
|
+
// Create a thunk that calls val() and validates the resolved result
|
|
749
|
+
// Note: We validate the RESOLVED result when the thunk is called, not the function itself
|
|
750
|
+
return async (): Promise<any> => {
|
|
751
|
+
const result = await val();
|
|
752
|
+
// A thunk should never return a function - if it does, that's an error
|
|
753
|
+
// Check both typeof and instanceof Function to catch all function types
|
|
754
|
+
if (typeof result === 'function' || result instanceof Function) {
|
|
755
|
+
throw new Error(`Thunk for parameter '${paramDef?.name}' returned a function. This indicates val was already a thunk, which should never happen. Original val type: ${typeof val}, result type: ${typeof result}, result constructor: ${result?.constructor?.name}`);
|
|
756
|
+
}
|
|
757
|
+
// Validate the RESOLVED result (not the function itself)
|
|
758
|
+
// This is where lazy parameter validation happens - when the thunk is called and the value is resolved
|
|
759
|
+
// Skip validation for optional parameters that are undefined
|
|
760
|
+
if (paramDef && !(paramDef as any).rest && !(result === undefined && (paramDef.optional || paramDef.default !== undefined))) {
|
|
761
|
+
const validation = validateValue(result, paramDef.type, paramDef.name);
|
|
762
|
+
if (!validation.isValid) {
|
|
763
|
+
throw new TypeError(validation.errorMessage);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
return result;
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// For callWithContext path or non-function values
|
|
771
|
+
// If val is undefined and parameter is optional, return a thunk that returns undefined
|
|
772
|
+
if (val === undefined && (paramDef?.optional || paramDef?.default !== undefined)) {
|
|
773
|
+
return async (): Promise<any> => {
|
|
774
|
+
return undefined;
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
return async (): Promise<any> => {
|
|
778
|
+
let result;
|
|
779
|
+
if (context && isNode(val) && !isEvaluated(val, context)) {
|
|
780
|
+
result = await (val as any).eval(context);
|
|
781
|
+
if (val.hasFlag(F_STATIC) && isNode(result) && result.sourceNode === val) {
|
|
782
|
+
result = val;
|
|
783
|
+
}
|
|
784
|
+
} else if (typeof val === 'function') {
|
|
785
|
+
// If val is a function (lazy parameter), call it
|
|
786
|
+
result = await val();
|
|
787
|
+
} else {
|
|
788
|
+
result = val;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Validate the evaluated result if we have param definition
|
|
792
|
+
// Note: For lazy parameters, we validate the result of calling the function, not the function itself
|
|
793
|
+
// Skip validation for optional parameters that are undefined
|
|
794
|
+
if (paramDef && !(paramDef as any).rest && !(result === undefined && (paramDef.optional || paramDef.default !== undefined))) {
|
|
795
|
+
const validation = validateValue(result, paramDef.type, paramDef.name);
|
|
796
|
+
if (!validation.isValid) {
|
|
797
|
+
throw new TypeError(validation.errorMessage);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return result;
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Runtime validation function to check argument types and required parameters for record-based calls
|
|
807
|
+
*/
|
|
808
|
+
function validateArguments(record: any, params?: readonly ParamDefinition[]) {
|
|
809
|
+
if (!params) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Check that all required parameters are provided
|
|
814
|
+
for (const paramDef of params) {
|
|
815
|
+
const paramName = paramDef.name;
|
|
816
|
+
const expectedType = paramDef.type;
|
|
817
|
+
const isOptional = paramDef.optional || paramDef.default !== undefined;
|
|
818
|
+
const value = record[paramName];
|
|
819
|
+
|
|
820
|
+
// Check if required parameter is missing
|
|
821
|
+
if (!isOptional && value === undefined) {
|
|
822
|
+
throw new TypeError(`Required argument '${paramName}' is missing`);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Skip validation for undefined optional arguments
|
|
826
|
+
if (value === undefined) {
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// For lazy parameters, validate that it's a function (validation of result happens in thunk)
|
|
831
|
+
if ((paramDef as any).lazy) {
|
|
832
|
+
if (typeof value !== 'function') {
|
|
833
|
+
throw new TypeError(`Argument '${paramName}' must be a function (lazy parameter). Got: ${typeof value}`);
|
|
834
|
+
}
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const isRest = (paramDef as any).rest === true;
|
|
839
|
+
if (isRest) {
|
|
840
|
+
if (!Array.isArray(value)) {
|
|
841
|
+
throw new TypeError(`Argument '${paramName}' must be an array (rest parameter)`);
|
|
842
|
+
}
|
|
843
|
+
const elementTypes = Array.isArray(expectedType) ? expectedType : [expectedType];
|
|
844
|
+
for (let idx = 0; idx < (value as any[]).length; idx++) {
|
|
845
|
+
const el = (value as any[])[idx];
|
|
846
|
+
const isValid = (Array.isArray(elementTypes) ? elementTypes : [elementTypes]).some(type => isValidType(el, type));
|
|
847
|
+
if (!isValid) {
|
|
848
|
+
const types = Array.isArray(elementTypes) ? elementTypes : [elementTypes];
|
|
849
|
+
const typeList = types.map((t: any) => typeof t === 'function' ? t.name : t).join(', ');
|
|
850
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
851
|
+
throw new TypeError(`Element ${idx} of '${paramName}' must be of type '${typeList}'. Got: ${actualType}`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
} else {
|
|
855
|
+
const validation = validateValue(value, expectedType, paramName, 'Argument');
|
|
856
|
+
if (!validation.isValid) {
|
|
857
|
+
throw new TypeError(validation.errorMessage);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Centralized validation result
|
|
865
|
+
*/
|
|
866
|
+
interface ValidationResult {
|
|
867
|
+
isValid: boolean;
|
|
868
|
+
errorMessage?: string;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* Validate argument if needed (checks for lazy and undefined values)
|
|
873
|
+
*/
|
|
874
|
+
function validateArgumentIfNeeded(
|
|
875
|
+
value: any,
|
|
876
|
+
def: any,
|
|
877
|
+
prefix: string = 'Parameter'
|
|
878
|
+
): void {
|
|
879
|
+
if (!(def as any).lazy && value !== undefined) {
|
|
880
|
+
const validation = validateValue(value, def.type, def.name, prefix);
|
|
881
|
+
if (!validation.isValid) {
|
|
882
|
+
throw new TypeError(validation.errorMessage);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Centralized validation function
|
|
889
|
+
*/
|
|
890
|
+
function validateValue(value: any, expectedType: ArgType | readonly ArgType[], paramName: string, context: string = 'Argument'): ValidationResult {
|
|
891
|
+
// Handle array of types (union types)
|
|
892
|
+
if (Array.isArray(expectedType)) {
|
|
893
|
+
const isValid = expectedType.some(type => isValidType(value, type));
|
|
894
|
+
if (!isValid) {
|
|
895
|
+
const typeList = expectedType.map((t: any) => typeof t === 'function' ? t.name : t).join(', ');
|
|
896
|
+
const actualType = typeof value === 'object' && value !== null ? value.constructor?.name || typeof value : typeof value;
|
|
897
|
+
return {
|
|
898
|
+
isValid: false,
|
|
899
|
+
errorMessage: `${context} '${paramName}' must be one of: ${typeList}. Got: ${actualType}`
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
return { isValid: true };
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Handle single type
|
|
906
|
+
if (!isValidType(value, expectedType as ArgType)) {
|
|
907
|
+
const typeName = typeof expectedType === 'function' ? expectedType.name : expectedType;
|
|
908
|
+
const actualType = typeof value === 'object' && value !== null ? value.constructor?.name || typeof value : typeof value;
|
|
909
|
+
return {
|
|
910
|
+
isValid: false,
|
|
911
|
+
errorMessage: `${context} '${paramName}' must be of type '${typeName}'. Got: ${actualType}`
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
return { isValid: true };
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Validate array elements (for rest parameters)
|
|
920
|
+
*/
|
|
921
|
+
function validateArrayElements(value: any[], elementTypes: ArgType | readonly ArgType[], paramName: string, context: string = 'Argument'): ValidationResult {
|
|
922
|
+
const types = Array.isArray(elementTypes) ? elementTypes : [elementTypes];
|
|
923
|
+
|
|
924
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
925
|
+
const el = value[idx];
|
|
926
|
+
const isValid = types.some(type => isValidType(el, type));
|
|
927
|
+
if (!isValid) {
|
|
928
|
+
const typeList = types.map((t: any) => typeof t === 'function' ? t.name : t).join(', ');
|
|
929
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
930
|
+
return {
|
|
931
|
+
isValid: false,
|
|
932
|
+
errorMessage: `Element ${idx} of '${paramName}' must be of type '${typeList}'. Got: ${actualType}`
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
return { isValid: true };
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Check if a value matches the expected type
|
|
942
|
+
*/
|
|
943
|
+
function isValidType(value: any, expectedType: ArgType): boolean {
|
|
944
|
+
switch (expectedType) {
|
|
945
|
+
case 'string':
|
|
946
|
+
return typeof value === 'string';
|
|
947
|
+
case 'number':
|
|
948
|
+
return typeof value === 'number';
|
|
949
|
+
case 'boolean':
|
|
950
|
+
return typeof value === 'boolean';
|
|
951
|
+
case 'null':
|
|
952
|
+
return value === null;
|
|
953
|
+
case 'undefined':
|
|
954
|
+
return value === undefined;
|
|
955
|
+
default:
|
|
956
|
+
// Check if it's a class constructor
|
|
957
|
+
if (typeof expectedType === 'function') {
|
|
958
|
+
return value instanceof expectedType;
|
|
959
|
+
}
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Validates a single argument against its parameter definition
|
|
966
|
+
*/
|
|
967
|
+
function validateArgument(value: any, def: any, context: string = 'argument'): void {
|
|
968
|
+
// Skip validation for optional parameters that are undefined
|
|
969
|
+
if ((def as any).optional && value === undefined) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// For lazy parameters, validate that it's a function
|
|
974
|
+
if ((def as any).lazy) {
|
|
975
|
+
if (typeof value !== 'function') {
|
|
976
|
+
throw new TypeError(
|
|
977
|
+
`${context} '${def.name}' must be a function (lazy parameter). Got: ${typeof value}`
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Validate rest parameters as arrays
|
|
984
|
+
if ((def as any).rest) {
|
|
985
|
+
if (!Array.isArray(value)) {
|
|
986
|
+
throw new TypeError(`${context} '${def.name}' must be an array (rest parameter)`);
|
|
987
|
+
}
|
|
988
|
+
const expectedType = def.type;
|
|
989
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
990
|
+
const el = value[idx];
|
|
991
|
+
if (!isValidType(el, expectedType as ArgType)) {
|
|
992
|
+
const typeName = typeof expectedType === 'function' ? expectedType.name : expectedType;
|
|
993
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
994
|
+
throw new TypeError(`Element ${idx} of '${def.name}' must be of type '${typeName}'. Got: ${actualType}`);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Validate regular parameters
|
|
1001
|
+
const expectedType = def.type;
|
|
1002
|
+
const validation = validateValue(value, expectedType, def.name, context);
|
|
1003
|
+
if (!validation.isValid) {
|
|
1004
|
+
throw new TypeError(validation.errorMessage);
|
|
1005
|
+
}
|
|
1006
|
+
}
|