@jesscss/core 2.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +9 -0
- package/lib/context.d.ts +352 -0
- package/lib/context.d.ts.map +1 -0
- package/lib/context.js +636 -0
- package/lib/context.js.map +1 -0
- package/lib/conversions.d.ts +73 -0
- package/lib/conversions.d.ts.map +1 -0
- package/lib/conversions.js +253 -0
- package/lib/conversions.js.map +1 -0
- package/lib/debug-log.d.ts +2 -0
- package/lib/debug-log.d.ts.map +1 -0
- package/lib/debug-log.js +27 -0
- package/lib/debug-log.js.map +1 -0
- package/lib/define-function.d.ts +587 -0
- package/lib/define-function.d.ts.map +1 -0
- package/lib/define-function.js +726 -0
- package/lib/define-function.js.map +1 -0
- package/lib/deprecation.d.ts +34 -0
- package/lib/deprecation.d.ts.map +1 -0
- package/lib/deprecation.js +57 -0
- package/lib/deprecation.js.map +1 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +23 -0
- package/lib/index.js.map +1 -0
- package/lib/jess-error.d.ts +343 -0
- package/lib/jess-error.d.ts.map +1 -0
- package/lib/jess-error.js +508 -0
- package/lib/jess-error.js.map +1 -0
- package/lib/logger/deprecation-processing.d.ts +41 -0
- package/lib/logger/deprecation-processing.d.ts.map +1 -0
- package/lib/logger/deprecation-processing.js +81 -0
- package/lib/logger/deprecation-processing.js.map +1 -0
- package/lib/logger.d.ts +10 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +20 -0
- package/lib/logger.js.map +1 -0
- package/lib/plugin.d.ts +94 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +174 -0
- package/lib/plugin.js.map +1 -0
- package/lib/tree/ampersand.d.ts +94 -0
- package/lib/tree/ampersand.d.ts.map +1 -0
- package/lib/tree/ampersand.js +269 -0
- package/lib/tree/ampersand.js.map +1 -0
- package/lib/tree/any.d.ts +58 -0
- package/lib/tree/any.d.ts.map +1 -0
- package/lib/tree/any.js +101 -0
- package/lib/tree/any.js.map +1 -0
- package/lib/tree/at-rule.d.ts +53 -0
- package/lib/tree/at-rule.d.ts.map +1 -0
- package/lib/tree/at-rule.js +503 -0
- package/lib/tree/at-rule.js.map +1 -0
- package/lib/tree/block.d.ts +22 -0
- package/lib/tree/block.d.ts.map +1 -0
- package/lib/tree/block.js +24 -0
- package/lib/tree/block.js.map +1 -0
- package/lib/tree/bool.d.ts +17 -0
- package/lib/tree/bool.d.ts.map +1 -0
- package/lib/tree/bool.js +24 -0
- package/lib/tree/bool.js.map +1 -0
- package/lib/tree/call.d.ts +66 -0
- package/lib/tree/call.d.ts.map +1 -0
- package/lib/tree/call.js +306 -0
- package/lib/tree/call.js.map +1 -0
- package/lib/tree/collection.d.ts +30 -0
- package/lib/tree/collection.d.ts.map +1 -0
- package/lib/tree/collection.js +37 -0
- package/lib/tree/collection.js.map +1 -0
- package/lib/tree/color.d.ts +101 -0
- package/lib/tree/color.d.ts.map +1 -0
- package/lib/tree/color.js +513 -0
- package/lib/tree/color.js.map +1 -0
- package/lib/tree/combinator.d.ts +12 -0
- package/lib/tree/combinator.d.ts.map +1 -0
- package/lib/tree/combinator.js +8 -0
- package/lib/tree/combinator.js.map +1 -0
- package/lib/tree/comment.d.ts +20 -0
- package/lib/tree/comment.d.ts.map +1 -0
- package/lib/tree/comment.js +18 -0
- package/lib/tree/comment.js.map +1 -0
- package/lib/tree/condition.d.ts +31 -0
- package/lib/tree/condition.d.ts.map +1 -0
- package/lib/tree/condition.js +103 -0
- package/lib/tree/condition.js.map +1 -0
- package/lib/tree/control.d.ts +104 -0
- package/lib/tree/control.d.ts.map +1 -0
- package/lib/tree/control.js +430 -0
- package/lib/tree/control.js.map +1 -0
- package/lib/tree/declaration-custom.d.ts +18 -0
- package/lib/tree/declaration-custom.d.ts.map +1 -0
- package/lib/tree/declaration-custom.js +24 -0
- package/lib/tree/declaration-custom.js.map +1 -0
- package/lib/tree/declaration-var.d.ts +36 -0
- package/lib/tree/declaration-var.d.ts.map +1 -0
- package/lib/tree/declaration-var.js +63 -0
- package/lib/tree/declaration-var.js.map +1 -0
- package/lib/tree/declaration.d.ts +78 -0
- package/lib/tree/declaration.d.ts.map +1 -0
- package/lib/tree/declaration.js +289 -0
- package/lib/tree/declaration.js.map +1 -0
- package/lib/tree/default-guard.d.ts +15 -0
- package/lib/tree/default-guard.d.ts.map +1 -0
- package/lib/tree/default-guard.js +19 -0
- package/lib/tree/default-guard.js.map +1 -0
- package/lib/tree/dimension.d.ts +33 -0
- package/lib/tree/dimension.d.ts.map +1 -0
- package/lib/tree/dimension.js +291 -0
- package/lib/tree/dimension.js.map +1 -0
- package/lib/tree/expression.d.ts +24 -0
- package/lib/tree/expression.d.ts.map +1 -0
- package/lib/tree/expression.js +28 -0
- package/lib/tree/expression.js.map +1 -0
- package/lib/tree/extend-list.d.ts +23 -0
- package/lib/tree/extend-list.d.ts.map +1 -0
- package/lib/tree/extend-list.js +20 -0
- package/lib/tree/extend-list.js.map +1 -0
- package/lib/tree/extend.d.ts +47 -0
- package/lib/tree/extend.d.ts.map +1 -0
- package/lib/tree/extend.js +292 -0
- package/lib/tree/extend.js.map +1 -0
- package/lib/tree/function.d.ts +48 -0
- package/lib/tree/function.d.ts.map +1 -0
- package/lib/tree/function.js +74 -0
- package/lib/tree/function.js.map +1 -0
- package/lib/tree/import-js.d.ts +35 -0
- package/lib/tree/import-js.d.ts.map +1 -0
- package/lib/tree/import-js.js +45 -0
- package/lib/tree/import-js.js.map +1 -0
- package/lib/tree/import-style.d.ts +156 -0
- package/lib/tree/import-style.d.ts.map +1 -0
- package/lib/tree/import-style.js +556 -0
- package/lib/tree/import-style.js.map +1 -0
- package/lib/tree/index.d.ts +71 -0
- package/lib/tree/index.d.ts.map +1 -0
- package/lib/tree/index.js +95 -0
- package/lib/tree/index.js.map +1 -0
- package/lib/tree/interpolated-reference.d.ts +24 -0
- package/lib/tree/interpolated-reference.d.ts.map +1 -0
- package/lib/tree/interpolated-reference.js +37 -0
- package/lib/tree/interpolated-reference.js.map +1 -0
- package/lib/tree/interpolated.d.ts +62 -0
- package/lib/tree/interpolated.d.ts.map +1 -0
- package/lib/tree/interpolated.js +204 -0
- package/lib/tree/interpolated.js.map +1 -0
- package/lib/tree/js-array.d.ts +10 -0
- package/lib/tree/js-array.d.ts.map +1 -0
- package/lib/tree/js-array.js +10 -0
- package/lib/tree/js-array.js.map +1 -0
- package/lib/tree/js-expr.d.ts +23 -0
- package/lib/tree/js-expr.d.ts.map +1 -0
- package/lib/tree/js-expr.js +28 -0
- package/lib/tree/js-expr.js.map +1 -0
- package/lib/tree/js-function.d.ts +20 -0
- package/lib/tree/js-function.d.ts.map +1 -0
- package/lib/tree/js-function.js +16 -0
- package/lib/tree/js-function.js.map +1 -0
- package/lib/tree/js-object.d.ts +10 -0
- package/lib/tree/js-object.d.ts.map +1 -0
- package/lib/tree/js-object.js +10 -0
- package/lib/tree/js-object.js.map +1 -0
- package/lib/tree/list.d.ts +38 -0
- package/lib/tree/list.d.ts.map +1 -0
- package/lib/tree/list.js +83 -0
- package/lib/tree/list.js.map +1 -0
- package/lib/tree/log.d.ts +29 -0
- package/lib/tree/log.d.ts.map +1 -0
- package/lib/tree/log.js +56 -0
- package/lib/tree/log.js.map +1 -0
- package/lib/tree/mixin.d.ts +87 -0
- package/lib/tree/mixin.d.ts.map +1 -0
- package/lib/tree/mixin.js +112 -0
- package/lib/tree/mixin.js.map +1 -0
- package/lib/tree/negative.d.ts +17 -0
- package/lib/tree/negative.d.ts.map +1 -0
- package/lib/tree/negative.js +22 -0
- package/lib/tree/negative.js.map +1 -0
- package/lib/tree/nil.d.ts +31 -0
- package/lib/tree/nil.d.ts.map +1 -0
- package/lib/tree/nil.js +36 -0
- package/lib/tree/nil.js.map +1 -0
- package/lib/tree/node-base.d.ts +359 -0
- package/lib/tree/node-base.d.ts.map +1 -0
- package/lib/tree/node-base.js +884 -0
- package/lib/tree/node-base.js.map +1 -0
- package/lib/tree/node.d.ts +10 -0
- package/lib/tree/node.d.ts.map +1 -0
- package/lib/tree/node.js +45 -0
- package/lib/tree/node.js.map +1 -0
- package/lib/tree/number.d.ts +21 -0
- package/lib/tree/number.d.ts.map +1 -0
- package/lib/tree/number.js +27 -0
- package/lib/tree/number.js.map +1 -0
- package/lib/tree/operation.d.ts +26 -0
- package/lib/tree/operation.d.ts.map +1 -0
- package/lib/tree/operation.js +103 -0
- package/lib/tree/operation.js.map +1 -0
- package/lib/tree/paren.d.ts +18 -0
- package/lib/tree/paren.d.ts.map +1 -0
- package/lib/tree/paren.js +86 -0
- package/lib/tree/paren.js.map +1 -0
- package/lib/tree/query-condition.d.ts +17 -0
- package/lib/tree/query-condition.d.ts.map +1 -0
- package/lib/tree/query-condition.js +39 -0
- package/lib/tree/query-condition.js.map +1 -0
- package/lib/tree/quoted.d.ts +27 -0
- package/lib/tree/quoted.d.ts.map +1 -0
- package/lib/tree/quoted.js +66 -0
- package/lib/tree/quoted.js.map +1 -0
- package/lib/tree/range.d.ts +33 -0
- package/lib/tree/range.d.ts.map +1 -0
- package/lib/tree/range.js +47 -0
- package/lib/tree/range.js.map +1 -0
- package/lib/tree/reference.d.ts +76 -0
- package/lib/tree/reference.d.ts.map +1 -0
- package/lib/tree/reference.js +521 -0
- package/lib/tree/reference.js.map +1 -0
- package/lib/tree/rest.d.ts +15 -0
- package/lib/tree/rest.d.ts.map +1 -0
- package/lib/tree/rest.js +32 -0
- package/lib/tree/rest.js.map +1 -0
- package/lib/tree/rules-raw.d.ts +17 -0
- package/lib/tree/rules-raw.d.ts.map +1 -0
- package/lib/tree/rules-raw.js +37 -0
- package/lib/tree/rules-raw.js.map +1 -0
- package/lib/tree/rules.d.ts +255 -0
- package/lib/tree/rules.d.ts.map +1 -0
- package/lib/tree/rules.js +2293 -0
- package/lib/tree/rules.js.map +1 -0
- package/lib/tree/ruleset.d.ts +91 -0
- package/lib/tree/ruleset.d.ts.map +1 -0
- package/lib/tree/ruleset.js +506 -0
- package/lib/tree/ruleset.js.map +1 -0
- package/lib/tree/selector-attr.d.ts +31 -0
- package/lib/tree/selector-attr.d.ts.map +1 -0
- package/lib/tree/selector-attr.js +99 -0
- package/lib/tree/selector-attr.js.map +1 -0
- package/lib/tree/selector-basic.d.ts +23 -0
- package/lib/tree/selector-basic.d.ts.map +1 -0
- package/lib/tree/selector-basic.js +34 -0
- package/lib/tree/selector-basic.js.map +1 -0
- package/lib/tree/selector-capture.d.ts +23 -0
- package/lib/tree/selector-capture.d.ts.map +1 -0
- package/lib/tree/selector-capture.js +34 -0
- package/lib/tree/selector-capture.js.map +1 -0
- package/lib/tree/selector-complex.d.ts +40 -0
- package/lib/tree/selector-complex.d.ts.map +1 -0
- package/lib/tree/selector-complex.js +143 -0
- package/lib/tree/selector-complex.js.map +1 -0
- package/lib/tree/selector-compound.d.ts +16 -0
- package/lib/tree/selector-compound.d.ts.map +1 -0
- package/lib/tree/selector-compound.js +114 -0
- package/lib/tree/selector-compound.js.map +1 -0
- package/lib/tree/selector-interpolated.d.ts +23 -0
- package/lib/tree/selector-interpolated.d.ts.map +1 -0
- package/lib/tree/selector-interpolated.js +27 -0
- package/lib/tree/selector-interpolated.js.map +1 -0
- package/lib/tree/selector-list.d.ts +17 -0
- package/lib/tree/selector-list.d.ts.map +1 -0
- package/lib/tree/selector-list.js +184 -0
- package/lib/tree/selector-list.js.map +1 -0
- package/lib/tree/selector-pseudo.d.ts +42 -0
- package/lib/tree/selector-pseudo.d.ts.map +1 -0
- package/lib/tree/selector-pseudo.js +191 -0
- package/lib/tree/selector-pseudo.js.map +1 -0
- package/lib/tree/selector-simple.d.ts +5 -0
- package/lib/tree/selector-simple.d.ts.map +1 -0
- package/lib/tree/selector-simple.js +6 -0
- package/lib/tree/selector-simple.js.map +1 -0
- package/lib/tree/selector.d.ts +43 -0
- package/lib/tree/selector.d.ts.map +1 -0
- package/lib/tree/selector.js +56 -0
- package/lib/tree/selector.js.map +1 -0
- package/lib/tree/sequence.d.ts +43 -0
- package/lib/tree/sequence.d.ts.map +1 -0
- package/lib/tree/sequence.js +148 -0
- package/lib/tree/sequence.js.map +1 -0
- package/lib/tree/tree.d.ts +87 -0
- package/lib/tree/tree.d.ts.map +1 -0
- package/lib/tree/tree.js +2 -0
- package/lib/tree/tree.js.map +1 -0
- package/lib/tree/url.d.ts +18 -0
- package/lib/tree/url.d.ts.map +1 -0
- package/lib/tree/url.js +35 -0
- package/lib/tree/url.js.map +1 -0
- package/lib/tree/util/__tests__/debug-log.d.ts +1 -0
- package/lib/tree/util/__tests__/debug-log.d.ts.map +1 -0
- package/lib/tree/util/__tests__/debug-log.js +36 -0
- package/lib/tree/util/__tests__/debug-log.js.map +1 -0
- package/lib/tree/util/calculate.d.ts +3 -0
- package/lib/tree/util/calculate.d.ts.map +1 -0
- package/lib/tree/util/calculate.js +10 -0
- package/lib/tree/util/calculate.js.map +1 -0
- package/lib/tree/util/cast.d.ts +10 -0
- package/lib/tree/util/cast.d.ts.map +1 -0
- package/lib/tree/util/cast.js +87 -0
- package/lib/tree/util/cast.js.map +1 -0
- package/lib/tree/util/cloning.d.ts +4 -0
- package/lib/tree/util/cloning.d.ts.map +1 -0
- package/lib/tree/util/cloning.js +8 -0
- package/lib/tree/util/cloning.js.map +1 -0
- package/lib/tree/util/collections.d.ts +57 -0
- package/lib/tree/util/collections.d.ts.map +1 -0
- package/lib/tree/util/collections.js +136 -0
- package/lib/tree/util/collections.js.map +1 -0
- package/lib/tree/util/compare.d.ts +11 -0
- package/lib/tree/util/compare.d.ts.map +1 -0
- package/lib/tree/util/compare.js +89 -0
- package/lib/tree/util/compare.js.map +1 -0
- package/lib/tree/util/extend-helpers.d.ts +2 -0
- package/lib/tree/util/extend-helpers.d.ts.map +1 -0
- package/lib/tree/util/extend-helpers.js +2 -0
- package/lib/tree/util/extend-helpers.js.map +1 -0
- package/lib/tree/util/extend-roots.d.ts +37 -0
- package/lib/tree/util/extend-roots.d.ts.map +1 -0
- package/lib/tree/util/extend-roots.js +682 -0
- package/lib/tree/util/extend-roots.js.map +1 -0
- package/lib/tree/util/extend-roots.old.d.ts +132 -0
- package/lib/tree/util/extend-roots.old.d.ts.map +1 -0
- package/lib/tree/util/extend-roots.old.js +2272 -0
- package/lib/tree/util/extend-roots.old.js.map +1 -0
- package/lib/tree/util/extend-trace-debug.d.ts +13 -0
- package/lib/tree/util/extend-trace-debug.d.ts.map +1 -0
- package/lib/tree/util/extend-trace-debug.js +34 -0
- package/lib/tree/util/extend-trace-debug.js.map +1 -0
- package/lib/tree/util/extend.d.ts +218 -0
- package/lib/tree/util/extend.d.ts.map +1 -0
- package/lib/tree/util/extend.js +3033 -0
- package/lib/tree/util/extend.js.map +1 -0
- package/lib/tree/util/find-extendable-locations.d.ts +2 -0
- package/lib/tree/util/find-extendable-locations.d.ts.map +1 -0
- package/lib/tree/util/find-extendable-locations.js +2 -0
- package/lib/tree/util/find-extendable-locations.js.map +1 -0
- package/lib/tree/util/format.d.ts +20 -0
- package/lib/tree/util/format.d.ts.map +1 -0
- package/lib/tree/util/format.js +67 -0
- package/lib/tree/util/format.js.map +1 -0
- package/lib/tree/util/is-node.d.ts +13 -0
- package/lib/tree/util/is-node.d.ts.map +1 -0
- package/lib/tree/util/is-node.js +43 -0
- package/lib/tree/util/is-node.js.map +1 -0
- package/lib/tree/util/print.d.ts +80 -0
- package/lib/tree/util/print.d.ts.map +1 -0
- package/lib/tree/util/print.js +205 -0
- package/lib/tree/util/print.js.map +1 -0
- package/lib/tree/util/process-leading-is.d.ts +25 -0
- package/lib/tree/util/process-leading-is.d.ts.map +1 -0
- package/lib/tree/util/process-leading-is.js +364 -0
- package/lib/tree/util/process-leading-is.js.map +1 -0
- package/lib/tree/util/recursion-helper.d.ts +15 -0
- package/lib/tree/util/recursion-helper.d.ts.map +1 -0
- package/lib/tree/util/recursion-helper.js +43 -0
- package/lib/tree/util/recursion-helper.js.map +1 -0
- package/lib/tree/util/regex.d.ts +4 -0
- package/lib/tree/util/regex.d.ts.map +1 -0
- package/lib/tree/util/regex.js +4 -0
- package/lib/tree/util/regex.js.map +1 -0
- package/lib/tree/util/registry-utils.d.ts +192 -0
- package/lib/tree/util/registry-utils.d.ts.map +1 -0
- package/lib/tree/util/registry-utils.js +1242 -0
- package/lib/tree/util/registry-utils.js.map +1 -0
- package/lib/tree/util/ruleset-trace.d.ts +4 -0
- package/lib/tree/util/ruleset-trace.d.ts.map +1 -0
- package/lib/tree/util/ruleset-trace.js +14 -0
- package/lib/tree/util/ruleset-trace.js.map +1 -0
- package/lib/tree/util/selector-compare.d.ts +2 -0
- package/lib/tree/util/selector-compare.d.ts.map +1 -0
- package/lib/tree/util/selector-compare.js +2 -0
- package/lib/tree/util/selector-compare.js.map +1 -0
- package/lib/tree/util/selector-match-core.d.ts +171 -0
- package/lib/tree/util/selector-match-core.d.ts.map +1 -0
- package/lib/tree/util/selector-match-core.js +1578 -0
- package/lib/tree/util/selector-match-core.js.map +1 -0
- package/lib/tree/util/selector-utils.d.ts +30 -0
- package/lib/tree/util/selector-utils.d.ts.map +1 -0
- package/lib/tree/util/selector-utils.js +100 -0
- package/lib/tree/util/selector-utils.js.map +1 -0
- package/lib/tree/util/serialize-helper.d.ts +13 -0
- package/lib/tree/util/serialize-helper.d.ts.map +1 -0
- package/lib/tree/util/serialize-helper.js +387 -0
- package/lib/tree/util/serialize-helper.js.map +1 -0
- package/lib/tree/util/serialize-types.d.ts +9 -0
- package/lib/tree/util/serialize-types.d.ts.map +1 -0
- package/lib/tree/util/serialize-types.js +216 -0
- package/lib/tree/util/serialize-types.js.map +1 -0
- package/lib/tree/util/should-operate.d.ts +23 -0
- package/lib/tree/util/should-operate.d.ts.map +1 -0
- package/lib/tree/util/should-operate.js +46 -0
- package/lib/tree/util/should-operate.js.map +1 -0
- package/lib/tree/util/sourcemap.d.ts +7 -0
- package/lib/tree/util/sourcemap.d.ts.map +1 -0
- package/lib/tree/util/sourcemap.js +25 -0
- package/lib/tree/util/sourcemap.js.map +1 -0
- package/lib/types/config.d.ts +205 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +2 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/index.d.ts +15 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +3 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/modes.d.ts +24 -0
- package/lib/types/modes.d.ts.map +1 -0
- package/lib/types/modes.js +2 -0
- package/lib/types/modes.js.map +1 -0
- package/lib/types.d.ts +61 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/lib/use-webpack-resolver.d.ts +9 -0
- package/lib/use-webpack-resolver.d.ts.map +1 -0
- package/lib/use-webpack-resolver.js +41 -0
- package/lib/use-webpack-resolver.js.map +1 -0
- package/lib/visitor/index.d.ts +136 -0
- package/lib/visitor/index.d.ts.map +1 -0
- package/lib/visitor/index.js +135 -0
- package/lib/visitor/index.js.map +1 -0
- package/lib/visitor/less-visitor.d.ts +7 -0
- package/lib/visitor/less-visitor.d.ts.map +1 -0
- package/lib/visitor/less-visitor.js +7 -0
- package/lib/visitor/less-visitor.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
import isPlainObject from 'lodash-es/isPlainObject.js';
|
|
2
|
+
import { isNode } from './tree/util/is-node.js';
|
|
3
|
+
import { isThenable } from '@jesscss/awaitable-pipe';
|
|
4
|
+
import { List, Dimension } from './tree/index.js';
|
|
5
|
+
export function defineFunction(name, fn, options) {
|
|
6
|
+
// The external API types remain exactly the same, but internal function accepts positional parameters only
|
|
7
|
+
/**
|
|
8
|
+
* Function that accepts either positional arguments or a record object.
|
|
9
|
+
* Parameter names are inferred from the params array: name, value, etc.
|
|
10
|
+
* All calls are converted to positional format before calling the internal function.
|
|
11
|
+
*/
|
|
12
|
+
const result = function (...args) {
|
|
13
|
+
const rawParams = options?.params;
|
|
14
|
+
if (!rawParams) {
|
|
15
|
+
return fn(...args);
|
|
16
|
+
}
|
|
17
|
+
// Normalize params - handle overloaded signatures
|
|
18
|
+
const paramSignatures = Array.isArray(rawParams) && rawParams.length > 0 && Array.isArray(rawParams[0])
|
|
19
|
+
? rawParams.map(sig => [...sig])
|
|
20
|
+
: [[...rawParams]];
|
|
21
|
+
// For direct calls, use the first signature (overloading handled in callWithContext)
|
|
22
|
+
const params = paramSignatures[0];
|
|
23
|
+
// Validate rest parameter position
|
|
24
|
+
validateRestParameterPosition(params);
|
|
25
|
+
// Parse arguments into a record
|
|
26
|
+
const record = parseArgumentsToRecord(args, params);
|
|
27
|
+
// Apply defaults and validate
|
|
28
|
+
applyDefaultsAndValidate(record, params);
|
|
29
|
+
// Convert to positional arguments and call internal function
|
|
30
|
+
const positionalArgs = buildPositionalArgs(record, params);
|
|
31
|
+
return fn(...positionalArgs);
|
|
32
|
+
};
|
|
33
|
+
/** Allow runtime reflection on the function */
|
|
34
|
+
return new Proxy(result, {
|
|
35
|
+
has(target, prop) {
|
|
36
|
+
if (prop === 'name' || prop === 'options') {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return prop in target;
|
|
40
|
+
},
|
|
41
|
+
get(target, prop) {
|
|
42
|
+
if (prop === 'name') {
|
|
43
|
+
return name;
|
|
44
|
+
}
|
|
45
|
+
else if (prop === 'options') {
|
|
46
|
+
return options;
|
|
47
|
+
}
|
|
48
|
+
else if (prop === '_internal') {
|
|
49
|
+
return fn;
|
|
50
|
+
}
|
|
51
|
+
return target[prop];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** This will be called internally by Jess to functions created with defineFunction */
|
|
56
|
+
export async function callWithContext(context, fn, ...args) {
|
|
57
|
+
const listArg = args.length === 1 && isNode(args[0], 'List')
|
|
58
|
+
? args[0]
|
|
59
|
+
: undefined;
|
|
60
|
+
args = listArg ? [...listArg.value] : args;
|
|
61
|
+
// Only reject record-based calls (plain objects) when there's no params metadata
|
|
62
|
+
// Collections are allowed as positional arguments even without params metadata
|
|
63
|
+
// (e.g., detached rulesets passed to mixins)
|
|
64
|
+
if (!fn?.options?.params && args.some(arg => isPlainObject(arg) && !isNode(arg))) {
|
|
65
|
+
throw new Error('Record-based call without params is not supported');
|
|
66
|
+
}
|
|
67
|
+
/** Normalize positional args into a List node for tracking original arguments */
|
|
68
|
+
const originalArgsList = listArg
|
|
69
|
+
? listArg.copy(true)
|
|
70
|
+
: new List(args.map(arg => isNode(arg) ? arg.clone() : arg));
|
|
71
|
+
const hasParams = !!fn?.options?.params;
|
|
72
|
+
if (!hasParams) {
|
|
73
|
+
// No metadata; treat as normal positional function call (sync or async)
|
|
74
|
+
return fn.call(context, ...args);
|
|
75
|
+
}
|
|
76
|
+
const params = fn?.options?.params;
|
|
77
|
+
const options = fn?.options;
|
|
78
|
+
// Apply preprocessParams if provided (e.g., for splitting sequences)
|
|
79
|
+
if (options?.preprocessParams && options.preprocessParams.length > 0) {
|
|
80
|
+
for (const preprocessor of options.preprocessParams) {
|
|
81
|
+
const processed = preprocessor(args, context);
|
|
82
|
+
if (isThenable(processed)) {
|
|
83
|
+
args = await processed;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
args = processed;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Handle function overloading: params can be an array of param arrays
|
|
91
|
+
// Normalize to always be an array of signatures
|
|
92
|
+
const paramSignatures = (() => {
|
|
93
|
+
if (!params) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
// Check if params is an array of arrays (overloaded signatures)
|
|
97
|
+
if (Array.isArray(params) && params.length > 0 && Array.isArray(params[0])) {
|
|
98
|
+
return params.map(sig => [...sig]);
|
|
99
|
+
}
|
|
100
|
+
// Single signature - wrap in array
|
|
101
|
+
return [[...params]];
|
|
102
|
+
})();
|
|
103
|
+
let matchedParams;
|
|
104
|
+
let record;
|
|
105
|
+
let lastError;
|
|
106
|
+
// Try each signature until one matches
|
|
107
|
+
for (const signature of paramSignatures) {
|
|
108
|
+
try {
|
|
109
|
+
record = parseCallWithContextArgs(args, signature);
|
|
110
|
+
// Try to build positional args to validate the signature matches
|
|
111
|
+
// We'll do a dry-run validation
|
|
112
|
+
const tempRecord = { ...record };
|
|
113
|
+
let isValid = true;
|
|
114
|
+
// Check if we have a record object (plain object) in args
|
|
115
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
116
|
+
const hasRecordArg = args.some(arg => isPlainObject(arg));
|
|
117
|
+
for (let i = 0; i < signature.length; i++) {
|
|
118
|
+
const def = signature[i];
|
|
119
|
+
const value = tempRecord[def.name];
|
|
120
|
+
// Check required parameters
|
|
121
|
+
if (!def.optional && !def.rest && value === undefined) {
|
|
122
|
+
isValid = false;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
// Check if we have enough arguments (skip this check if we have a record arg)
|
|
126
|
+
if (!hasRecordArg && !def.rest && i >= args.length && !def.optional) {
|
|
127
|
+
isValid = false;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Check if we have too many arguments (not counting rest params or record args)
|
|
132
|
+
const hasRest = signature.some(p => p.rest);
|
|
133
|
+
if (!hasRest && !hasRecordArg && args.length > signature.length) {
|
|
134
|
+
isValid = false;
|
|
135
|
+
}
|
|
136
|
+
if (isValid) {
|
|
137
|
+
matchedParams = signature;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
lastError = error;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// If no signature matched, throw an error
|
|
147
|
+
if (!matchedParams) {
|
|
148
|
+
if (lastError) {
|
|
149
|
+
throw lastError;
|
|
150
|
+
}
|
|
151
|
+
throw new Error(`No matching function signature for ${args.length} argument(s)`);
|
|
152
|
+
}
|
|
153
|
+
// Re-parse with the matched signature to ensure correct record structure
|
|
154
|
+
record = parseCallWithContextArgs(args, matchedParams);
|
|
155
|
+
/**
|
|
156
|
+
* Create FunctionThis proxy for function execution context.
|
|
157
|
+
* The args property is always a function that returns the arguments.
|
|
158
|
+
*/
|
|
159
|
+
context.callStack.at(-1)?.adopt(originalArgsList);
|
|
160
|
+
const functionThis = {
|
|
161
|
+
context,
|
|
162
|
+
args: () => originalArgsList.eval(context),
|
|
163
|
+
rawArgs: originalArgsList,
|
|
164
|
+
caller: context.caller
|
|
165
|
+
};
|
|
166
|
+
// Build positional arguments with evaluation, validation, and conversion
|
|
167
|
+
const positionalArgs = await buildCallWithContextPositionalArgs(record, matchedParams, context);
|
|
168
|
+
// Call the function with the evaluated arguments
|
|
169
|
+
// Mixin functions expect Context as 'this', not FunctionThis
|
|
170
|
+
if (fn._internal) {
|
|
171
|
+
return (fn._internal).call(functionThis, ...positionalArgs);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// For mixin functions and other functions that expect Context as 'this'
|
|
175
|
+
return fn.call(context, ...positionalArgs);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// HELPER FUNCTIONS
|
|
180
|
+
// ============================================================================
|
|
181
|
+
/**
|
|
182
|
+
* Validates that rest parameters are in the correct position (last)
|
|
183
|
+
*/
|
|
184
|
+
function validateRestParameterPosition(params) {
|
|
185
|
+
const restIndex = params.findIndex(p => p.rest);
|
|
186
|
+
if (restIndex >= 0 && restIndex !== params.length - 1) {
|
|
187
|
+
throw new Error('Rest parameter must be the last parameter');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Applies conversion plugins to a value
|
|
192
|
+
*/
|
|
193
|
+
function applyConversionPlugins(value, plugins) {
|
|
194
|
+
let result = value;
|
|
195
|
+
// Apply conversion plugins in sequence
|
|
196
|
+
for (const plugin of plugins) {
|
|
197
|
+
result = plugin(result);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Parses function arguments into a record object
|
|
203
|
+
*/
|
|
204
|
+
function parseArgumentsToRecord(args, params) {
|
|
205
|
+
const record = {};
|
|
206
|
+
const restIndex = params.findIndex(p => p.rest);
|
|
207
|
+
const hasRest = restIndex >= 0;
|
|
208
|
+
// Handle pure record call (single object argument)
|
|
209
|
+
if (args.length === 1 && isPlainObject(args[0])) {
|
|
210
|
+
const isClassInstance = params?.some((opt) => {
|
|
211
|
+
const types = Array.isArray(opt.type) ? opt.type : [opt.type];
|
|
212
|
+
return types.some(type => typeof type === 'function' && args[0] instanceof type);
|
|
213
|
+
});
|
|
214
|
+
if (!isClassInstance) {
|
|
215
|
+
const input = args[0];
|
|
216
|
+
const isLateProxy = !!input && typeof input === 'object' && '_raw' in input;
|
|
217
|
+
return isLateProxy ? input._raw : { ...input };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Handle hybrid call (positional + record)
|
|
221
|
+
if (args.length > 1 && isPlainObject(args[args.length - 1])) {
|
|
222
|
+
const positionalArgs = args.slice(0, -1);
|
|
223
|
+
const recordArg = args[args.length - 1];
|
|
224
|
+
// Set values from positional arguments
|
|
225
|
+
if (!hasRest) {
|
|
226
|
+
for (let i = 0; i < positionalArgs.length && i < (params?.length ?? 0); i++) {
|
|
227
|
+
const paramName = params?.[i]?.name;
|
|
228
|
+
if (paramName) {
|
|
229
|
+
record[paramName] = positionalArgs[i];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
235
|
+
const def = params[i];
|
|
236
|
+
const paramName = def.name;
|
|
237
|
+
if (def.rest) {
|
|
238
|
+
record[paramName] = positionalArgs.slice(i);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
else if (i < positionalArgs.length) {
|
|
242
|
+
record[paramName] = positionalArgs[i];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Override with values from record (record takes precedence)
|
|
247
|
+
Object.assign(record, recordArg);
|
|
248
|
+
return record;
|
|
249
|
+
}
|
|
250
|
+
// Handle pure positional call
|
|
251
|
+
if (!hasRest) {
|
|
252
|
+
for (let i = 0; i < Math.max(args.length, params?.length ?? 0); i++) {
|
|
253
|
+
const paramName = params?.[i]?.name;
|
|
254
|
+
if (paramName) {
|
|
255
|
+
if (i < args.length) {
|
|
256
|
+
record[paramName] = args[i];
|
|
257
|
+
}
|
|
258
|
+
else if (params?.[i]?.default !== undefined) {
|
|
259
|
+
record[paramName] = params[i]?.default;
|
|
260
|
+
}
|
|
261
|
+
else if (params?.[i]?.optional) {
|
|
262
|
+
record[paramName] = undefined;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
269
|
+
const def = params[i];
|
|
270
|
+
const paramName = def.name;
|
|
271
|
+
if (def.rest) {
|
|
272
|
+
record[paramName] = args.slice(i);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
else if (i < args.length) {
|
|
276
|
+
record[paramName] = args[i];
|
|
277
|
+
}
|
|
278
|
+
else if (def.default !== undefined) {
|
|
279
|
+
record[paramName] = def.default;
|
|
280
|
+
}
|
|
281
|
+
else if (def.optional) {
|
|
282
|
+
record[paramName] = undefined;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return record;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Applies defaults and validates arguments
|
|
290
|
+
*/
|
|
291
|
+
function applyDefaultsAndValidate(record, params) {
|
|
292
|
+
// Apply defaults for missing parameters
|
|
293
|
+
for (const paramDef of params ?? []) {
|
|
294
|
+
const paramName = paramDef.name;
|
|
295
|
+
if (record[paramName] === undefined && paramDef.default !== undefined) {
|
|
296
|
+
record[paramName] = paramDef.default;
|
|
297
|
+
}
|
|
298
|
+
// Normalize rest param to array
|
|
299
|
+
if (paramDef.rest) {
|
|
300
|
+
const current = record[paramName];
|
|
301
|
+
if (current === undefined) {
|
|
302
|
+
record[paramName] = [];
|
|
303
|
+
}
|
|
304
|
+
else if (!Array.isArray(current)) {
|
|
305
|
+
record[paramName] = [current];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
validateArguments(record, params);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Builds positional arguments from record
|
|
313
|
+
*/
|
|
314
|
+
function buildPositionalArgs(record, params) {
|
|
315
|
+
const positionalArgs = [];
|
|
316
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
317
|
+
const def = params[i];
|
|
318
|
+
const name = def.name;
|
|
319
|
+
if (def.rest) {
|
|
320
|
+
const v = record[name];
|
|
321
|
+
const arr = Array.isArray(v) ? v : (v === undefined ? [] : [v]);
|
|
322
|
+
if (def.lazy) {
|
|
323
|
+
positionalArgs.push(...arr.map(item => createThunk(item, def)));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
positionalArgs.push(...arr.map((item) => {
|
|
327
|
+
// Apply conversion plugins if defined
|
|
328
|
+
if (def.convert && item instanceof Dimension) {
|
|
329
|
+
return applyConversionPlugins(item, def.convert);
|
|
330
|
+
}
|
|
331
|
+
return item;
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const v = record[name];
|
|
337
|
+
if (def.lazy) {
|
|
338
|
+
// For optional lazy parameters, if value is undefined, pass undefined directly
|
|
339
|
+
// instead of creating a thunk (which would try to call undefined())
|
|
340
|
+
if (v === undefined && (def.optional || def.default !== undefined)) {
|
|
341
|
+
positionalArgs.push(undefined);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
positionalArgs.push(createThunk(v, def));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// Apply conversion plugins if defined
|
|
349
|
+
if (def.convert && v instanceof Dimension) {
|
|
350
|
+
positionalArgs.push(applyConversionPlugins(v, def.convert));
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
positionalArgs.push(v);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return positionalArgs;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Parses callWithContext arguments into a record
|
|
362
|
+
*/
|
|
363
|
+
function parseCallWithContextArgs(args, params) {
|
|
364
|
+
const record = {};
|
|
365
|
+
const restIndex = params ? params.findIndex(p => p.rest) : -1;
|
|
366
|
+
const hasRest = (restIndex ?? -1) >= 0;
|
|
367
|
+
if (!hasRest) {
|
|
368
|
+
for (let i = 0; i < Math.min(args.length, params?.length ?? 0); i++) {
|
|
369
|
+
let arg = args[i];
|
|
370
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
371
|
+
if (isPlainObject(arg) && !isNode(arg)) {
|
|
372
|
+
Object.assign(record, arg);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
const paramName = params?.[i]?.name;
|
|
376
|
+
if (!paramName) {
|
|
377
|
+
throw new Error('Function does not support this number of arguments');
|
|
378
|
+
}
|
|
379
|
+
record[paramName] = args[i];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
384
|
+
const def = params[i];
|
|
385
|
+
const paramName = def.name;
|
|
386
|
+
const arg = args[i];
|
|
387
|
+
// Collections are treated as positional arguments, not record-based calls
|
|
388
|
+
if (isPlainObject(arg) && !isNode(arg)) {
|
|
389
|
+
Object.assign(record, arg);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
if (def.rest) {
|
|
393
|
+
record[paramName] = args.slice(i);
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
record[paramName] = arg;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return record;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Builds positional arguments for callWithContext with evaluation
|
|
405
|
+
*/
|
|
406
|
+
async function buildCallWithContextPositionalArgs(record, params, context) {
|
|
407
|
+
const positionalArgs = [];
|
|
408
|
+
for (let i = 0; i < (params?.length ?? 0); i++) {
|
|
409
|
+
const def = params[i];
|
|
410
|
+
const name = def.name;
|
|
411
|
+
if (def.rest) {
|
|
412
|
+
const v = record[name];
|
|
413
|
+
const arr = Array.isArray(v) ? v : (v === undefined ? [] : [v]);
|
|
414
|
+
if (def.lazy) {
|
|
415
|
+
positionalArgs.push(...arr.map(item => createThunk(item, def, context)));
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
for (const item of arr) {
|
|
419
|
+
let processedItem = (isNode(item) && !item.evaluated) ? item.eval(context) : item;
|
|
420
|
+
if (isThenable(processedItem)) {
|
|
421
|
+
processedItem = await processedItem;
|
|
422
|
+
}
|
|
423
|
+
// Validate AFTER evaluation but BEFORE conversion
|
|
424
|
+
validateArgumentIfNeeded(processedItem, def, 'Argument');
|
|
425
|
+
// Apply conversion plugins if defined
|
|
426
|
+
if (def.convert && processedItem instanceof Dimension) {
|
|
427
|
+
processedItem = applyConversionPlugins(processedItem, def.convert);
|
|
428
|
+
}
|
|
429
|
+
positionalArgs.push(processedItem);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
const v = record[name];
|
|
435
|
+
if (def.lazy) {
|
|
436
|
+
// For optional lazy parameters, if value is undefined, pass undefined directly
|
|
437
|
+
// instead of creating a thunk (which would try to call undefined())
|
|
438
|
+
if (v === undefined && (def.optional || def.default !== undefined)) {
|
|
439
|
+
positionalArgs.push(undefined);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
positionalArgs.push(createThunk(v, def, context));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
let processedValue = (isNode(v) && !v.evaluated) ? v.eval(context) : v;
|
|
447
|
+
// Handle async evaluation without truncating remaining parameters.
|
|
448
|
+
if (isThenable(processedValue)) {
|
|
449
|
+
processedValue = await processedValue;
|
|
450
|
+
}
|
|
451
|
+
// Validate AFTER evaluation but BEFORE conversion
|
|
452
|
+
validateArgumentIfNeeded(processedValue, def, 'Argument');
|
|
453
|
+
const callerName = context.caller && isNode(context.caller, 'Call')
|
|
454
|
+
? (typeof context.caller.value.name === 'string'
|
|
455
|
+
? context.caller.value.name
|
|
456
|
+
: (isNode(context.caller.value.name, 'Reference')
|
|
457
|
+
? String(context.caller.value.name.value.key?.valueOf?.() ?? '')
|
|
458
|
+
: ''))
|
|
459
|
+
: '';
|
|
460
|
+
// Apply conversion plugins if defined
|
|
461
|
+
if (def.convert && processedValue instanceof Dimension) {
|
|
462
|
+
processedValue = applyConversionPlugins(processedValue, def.convert);
|
|
463
|
+
}
|
|
464
|
+
positionalArgs.push(processedValue);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return positionalArgs;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Validates callWithContext arguments from record (before conversion)
|
|
472
|
+
*/
|
|
473
|
+
function validateCallWithContextArgs(record, params) {
|
|
474
|
+
if (!params) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
for (let i = 0; i < params.length; i++) {
|
|
478
|
+
const def = params[i];
|
|
479
|
+
const value = record[def.name];
|
|
480
|
+
// Skip validation for lazy parameters since they're passed as thunks
|
|
481
|
+
if (def.lazy) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
// Skip validation for rest parameters as they're validated as arrays
|
|
485
|
+
if (def.rest) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
// Skip validation for optional parameters that are undefined
|
|
489
|
+
if (def.optional && value === undefined) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
validateArgument(value, def, 'Argument');
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Creates a thunk function that evaluates a value and validates the result
|
|
497
|
+
*/
|
|
498
|
+
function createThunk(val, paramDef, context) {
|
|
499
|
+
// For direct calls without context, val should be the user's lazy function (e.g., () => new Dimension(...))
|
|
500
|
+
// NOT a thunk. We create a thunk that calls val() and validates the resolved result.
|
|
501
|
+
if (typeof val === 'function' && !context) {
|
|
502
|
+
// Create a thunk that calls val() and validates the resolved result
|
|
503
|
+
// Note: We validate the RESOLVED result when the thunk is called, not the function itself
|
|
504
|
+
return async () => {
|
|
505
|
+
const result = await val();
|
|
506
|
+
// A thunk should never return a function - if it does, that's an error
|
|
507
|
+
// Check both typeof and instanceof Function to catch all function types
|
|
508
|
+
if (typeof result === 'function' || result instanceof Function) {
|
|
509
|
+
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}`);
|
|
510
|
+
}
|
|
511
|
+
// Validate the RESOLVED result (not the function itself)
|
|
512
|
+
// This is where lazy parameter validation happens - when the thunk is called and the value is resolved
|
|
513
|
+
// Skip validation for optional parameters that are undefined
|
|
514
|
+
if (paramDef && !paramDef.rest && !(result === undefined && (paramDef.optional || paramDef.default !== undefined))) {
|
|
515
|
+
const validation = validateValue(result, paramDef.type, paramDef.name);
|
|
516
|
+
if (!validation.isValid) {
|
|
517
|
+
throw new TypeError(validation.errorMessage);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return result;
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
// For callWithContext path or non-function values
|
|
524
|
+
// If val is undefined and parameter is optional, return a thunk that returns undefined
|
|
525
|
+
if (val === undefined && (paramDef?.optional || paramDef?.default !== undefined)) {
|
|
526
|
+
return async () => {
|
|
527
|
+
return undefined;
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
return async () => {
|
|
531
|
+
let result;
|
|
532
|
+
if (context && isNode(val) && !val.evaluated) {
|
|
533
|
+
result = await val.eval(context);
|
|
534
|
+
}
|
|
535
|
+
else if (typeof val === 'function') {
|
|
536
|
+
// If val is a function (lazy parameter), call it
|
|
537
|
+
result = await val();
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
result = val;
|
|
541
|
+
}
|
|
542
|
+
// Validate the evaluated result if we have param definition
|
|
543
|
+
// Note: For lazy parameters, we validate the result of calling the function, not the function itself
|
|
544
|
+
// Skip validation for optional parameters that are undefined
|
|
545
|
+
if (paramDef && !paramDef.rest && !(result === undefined && (paramDef.optional || paramDef.default !== undefined))) {
|
|
546
|
+
const validation = validateValue(result, paramDef.type, paramDef.name);
|
|
547
|
+
if (!validation.isValid) {
|
|
548
|
+
throw new TypeError(validation.errorMessage);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return result;
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Runtime validation function to check argument types and required parameters for record-based calls
|
|
556
|
+
*/
|
|
557
|
+
function validateArguments(record, params) {
|
|
558
|
+
if (!params) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
// Check that all required parameters are provided
|
|
562
|
+
for (const paramDef of params) {
|
|
563
|
+
const paramName = paramDef.name;
|
|
564
|
+
const expectedType = paramDef.type;
|
|
565
|
+
const isOptional = paramDef.optional || paramDef.default !== undefined;
|
|
566
|
+
const value = record[paramName];
|
|
567
|
+
// Check if required parameter is missing
|
|
568
|
+
if (!isOptional && value === undefined) {
|
|
569
|
+
throw new TypeError(`Required argument '${paramName}' is missing`);
|
|
570
|
+
}
|
|
571
|
+
// Skip validation for undefined optional arguments
|
|
572
|
+
if (value === undefined) {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
// For lazy parameters, validate that it's a function (validation of result happens in thunk)
|
|
576
|
+
if (paramDef.lazy) {
|
|
577
|
+
if (typeof value !== 'function') {
|
|
578
|
+
throw new TypeError(`Argument '${paramName}' must be a function (lazy parameter). Got: ${typeof value}`);
|
|
579
|
+
}
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const isRest = paramDef.rest === true;
|
|
583
|
+
if (isRest) {
|
|
584
|
+
if (!Array.isArray(value)) {
|
|
585
|
+
throw new TypeError(`Argument '${paramName}' must be an array (rest parameter)`);
|
|
586
|
+
}
|
|
587
|
+
const elementTypes = Array.isArray(expectedType) ? expectedType : [expectedType];
|
|
588
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
589
|
+
const el = value[idx];
|
|
590
|
+
const isValid = (Array.isArray(elementTypes) ? elementTypes : [elementTypes]).some(type => isValidType(el, type));
|
|
591
|
+
if (!isValid) {
|
|
592
|
+
const types = Array.isArray(elementTypes) ? elementTypes : [elementTypes];
|
|
593
|
+
const typeList = types.map((t) => typeof t === 'function' ? t.name : t).join(', ');
|
|
594
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
595
|
+
throw new TypeError(`Element ${idx} of '${paramName}' must be of type '${typeList}'. Got: ${actualType}`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
const validation = validateValue(value, expectedType, paramName, 'Argument');
|
|
601
|
+
if (!validation.isValid) {
|
|
602
|
+
throw new TypeError(validation.errorMessage);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Validate argument if needed (checks for lazy and undefined values)
|
|
609
|
+
*/
|
|
610
|
+
function validateArgumentIfNeeded(value, def, prefix = 'Parameter') {
|
|
611
|
+
if (!def.lazy && value !== undefined) {
|
|
612
|
+
const validation = validateValue(value, def.type, def.name, prefix);
|
|
613
|
+
if (!validation.isValid) {
|
|
614
|
+
throw new TypeError(validation.errorMessage);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Centralized validation function
|
|
620
|
+
*/
|
|
621
|
+
function validateValue(value, expectedType, paramName, context = 'Argument') {
|
|
622
|
+
// Handle array of types (union types)
|
|
623
|
+
if (Array.isArray(expectedType)) {
|
|
624
|
+
const isValid = expectedType.some(type => isValidType(value, type));
|
|
625
|
+
if (!isValid) {
|
|
626
|
+
const typeList = expectedType.map((t) => typeof t === 'function' ? t.name : t).join(', ');
|
|
627
|
+
const actualType = typeof value === 'object' && value !== null ? value.constructor?.name || typeof value : typeof value;
|
|
628
|
+
return {
|
|
629
|
+
isValid: false,
|
|
630
|
+
errorMessage: `${context} '${paramName}' must be one of: ${typeList}. Got: ${actualType}`
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return { isValid: true };
|
|
634
|
+
}
|
|
635
|
+
// Handle single type
|
|
636
|
+
if (!isValidType(value, expectedType)) {
|
|
637
|
+
const typeName = typeof expectedType === 'function' ? expectedType.name : expectedType;
|
|
638
|
+
const actualType = typeof value === 'object' && value !== null ? value.constructor?.name || typeof value : typeof value;
|
|
639
|
+
return {
|
|
640
|
+
isValid: false,
|
|
641
|
+
errorMessage: `${context} '${paramName}' must be of type '${typeName}'. Got: ${actualType}`
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
return { isValid: true };
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Validate array elements (for rest parameters)
|
|
648
|
+
*/
|
|
649
|
+
function validateArrayElements(value, elementTypes, paramName, context = 'Argument') {
|
|
650
|
+
const types = Array.isArray(elementTypes) ? elementTypes : [elementTypes];
|
|
651
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
652
|
+
const el = value[idx];
|
|
653
|
+
const isValid = types.some(type => isValidType(el, type));
|
|
654
|
+
if (!isValid) {
|
|
655
|
+
const typeList = types.map((t) => typeof t === 'function' ? t.name : t).join(', ');
|
|
656
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
657
|
+
return {
|
|
658
|
+
isValid: false,
|
|
659
|
+
errorMessage: `Element ${idx} of '${paramName}' must be of type '${typeList}'. Got: ${actualType}`
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return { isValid: true };
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Check if a value matches the expected type
|
|
667
|
+
*/
|
|
668
|
+
function isValidType(value, expectedType) {
|
|
669
|
+
switch (expectedType) {
|
|
670
|
+
case 'string':
|
|
671
|
+
return typeof value === 'string';
|
|
672
|
+
case 'number':
|
|
673
|
+
return typeof value === 'number';
|
|
674
|
+
case 'boolean':
|
|
675
|
+
return typeof value === 'boolean';
|
|
676
|
+
case 'null':
|
|
677
|
+
return value === null;
|
|
678
|
+
case 'undefined':
|
|
679
|
+
return value === undefined;
|
|
680
|
+
default:
|
|
681
|
+
// Check if it's a class constructor
|
|
682
|
+
if (typeof expectedType === 'function') {
|
|
683
|
+
return value instanceof expectedType;
|
|
684
|
+
}
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Validates a single argument against its parameter definition
|
|
690
|
+
*/
|
|
691
|
+
function validateArgument(value, def, context = 'argument') {
|
|
692
|
+
// Skip validation for optional parameters that are undefined
|
|
693
|
+
if (def.optional && value === undefined) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
// For lazy parameters, validate that it's a function
|
|
697
|
+
if (def.lazy) {
|
|
698
|
+
if (typeof value !== 'function') {
|
|
699
|
+
throw new TypeError(`${context} '${def.name}' must be a function (lazy parameter). Got: ${typeof value}`);
|
|
700
|
+
}
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
// Validate rest parameters as arrays
|
|
704
|
+
if (def.rest) {
|
|
705
|
+
if (!Array.isArray(value)) {
|
|
706
|
+
throw new TypeError(`${context} '${def.name}' must be an array (rest parameter)`);
|
|
707
|
+
}
|
|
708
|
+
const expectedType = def.type;
|
|
709
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
710
|
+
const el = value[idx];
|
|
711
|
+
if (!isValidType(el, expectedType)) {
|
|
712
|
+
const typeName = typeof expectedType === 'function' ? expectedType.name : expectedType;
|
|
713
|
+
const actualType = typeof el === 'object' && el !== null ? el.constructor?.name || typeof el : typeof el;
|
|
714
|
+
throw new TypeError(`Element ${idx} of '${def.name}' must be of type '${typeName}'. Got: ${actualType}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
// Validate regular parameters
|
|
720
|
+
const expectedType = def.type;
|
|
721
|
+
const validation = validateValue(value, expectedType, def.name, context);
|
|
722
|
+
if (!validation.isValid) {
|
|
723
|
+
throw new TypeError(validation.errorMessage);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
//# sourceMappingURL=define-function.js.map
|