@versionzero/schema 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/README.md +246 -0
- package/package.json +84 -0
- package/src/compilation/handler-compilation.js +28 -0
- package/src/compilation/metadata-compilation.js +35 -0
- package/src/compilation/schema-compilation.js +142 -0
- package/src/compilation/selection-compilation.js +84 -0
- package/src/compilation/union-compilation.js +510 -0
- package/src/compilation/values-compilation.js +35 -0
- package/src/compiled-schema.js +1709 -0
- package/src/constants.js +1 -0
- package/src/core-library/index.js +32 -0
- package/src/core-library/processors/aggregation-operators.js +75 -0
- package/src/core-library/processors/alpha-constraint.js +20 -0
- package/src/core-library/processors/alphanum-constraint.js +20 -0
- package/src/core-library/processors/array-operator.js +51 -0
- package/src/core-library/processors/assert-constraint.js +75 -0
- package/src/core-library/processors/base64-constraint.js +26 -0
- package/src/core-library/processors/camel-case-operator.js +24 -0
- package/src/core-library/processors/capitalize-operator.js +16 -0
- package/src/core-library/processors/cardnum-constraint.js +193 -0
- package/src/core-library/processors/ceil-operator.js +44 -0
- package/src/core-library/processors/collapse-operator.js +29 -0
- package/src/core-library/processors/compact-operator.js +34 -0
- package/src/core-library/processors/compile-operator.js +65 -0
- package/src/core-library/processors/concat-operator.js +51 -0
- package/src/core-library/processors/conditional-operators.js +301 -0
- package/src/core-library/processors/constant-case-operator.js +16 -0
- package/src/core-library/processors/data-size-operator.js +86 -0
- package/src/core-library/processors/date-object-operator.js +54 -0
- package/src/core-library/processors/date-operator.js +67 -0
- package/src/core-library/processors/date-range-constraint.js +76 -0
- package/src/core-library/processors/defined-constraint.js +30 -0
- package/src/core-library/processors/each-operator.js +57 -0
- package/src/core-library/processors/email-constraint.js +112 -0
- package/src/core-library/processors/entries-operator.js +25 -0
- package/src/core-library/processors/eq-constraint.js +37 -0
- package/src/core-library/processors/filter-operator.js +74 -0
- package/src/core-library/processors/find-schema-operator.js +45 -0
- package/src/core-library/processors/flatten-operator.js +40 -0
- package/src/core-library/processors/floor-operator.js +47 -0
- package/src/core-library/processors/get-operator.js +44 -0
- package/src/core-library/processors/group-by-operator.js +84 -0
- package/src/core-library/processors/has-prefix-constraint.js +37 -0
- package/src/core-library/processors/has-suffix-constraint.js +35 -0
- package/src/core-library/processors/hex-constraint.js +20 -0
- package/src/core-library/processors/hostname-constraint.js +22 -0
- package/src/core-library/processors/http-url-constraint.js +27 -0
- package/src/core-library/processors/in-constraint.js +66 -0
- package/src/core-library/processors/index-by-operator.js +98 -0
- package/src/core-library/processors/index.js +131 -0
- package/src/core-library/processors/input-operator.js +23 -0
- package/src/core-library/processors/instanceof-constraint.js +38 -0
- package/src/core-library/processors/integer-constraint.js +22 -0
- package/src/core-library/processors/invoke-operator.js +33 -0
- package/src/core-library/processors/ipv4-constraint.js +188 -0
- package/src/core-library/processors/ipv6-constraint.js +205 -0
- package/src/core-library/processors/is-array-constraint.js +21 -0
- package/src/core-library/processors/is-date-constraint.js +22 -0
- package/src/core-library/processors/is-number-constraint.js +21 -0
- package/src/core-library/processors/is-object-constraint.js +21 -0
- package/src/core-library/processors/is-string-constraint.js +21 -0
- package/src/core-library/processors/join-operator.js +41 -0
- package/src/core-library/processors/json-constraint.js +22 -0
- package/src/core-library/processors/json-decode-operator.js +25 -0
- package/src/core-library/processors/json-encode-operator.js +35 -0
- package/src/core-library/processors/kebab-case-operator.js +23 -0
- package/src/core-library/processors/keys-operator.js +20 -0
- package/src/core-library/processors/length-constraint.js +85 -0
- package/src/core-library/processors/lookup-operator.js +84 -0
- package/src/core-library/processors/lowercase-operator.js +14 -0
- package/src/core-library/processors/map-operator.js +84 -0
- package/src/core-library/processors/match-operator.js +64 -0
- package/src/core-library/processors/matches-constraint.js +54 -0
- package/src/core-library/processors/math-operators.js +151 -0
- package/src/core-library/processors/merge-deep-operator.js +61 -0
- package/src/core-library/processors/merge-operator.js +54 -0
- package/src/core-library/processors/metadata-operator.js +100 -0
- package/src/core-library/processors/negative-constraint.js +23 -0
- package/src/core-library/processors/never-constraint.js +69 -0
- package/src/core-library/processors/non-empty-constraint.js +59 -0
- package/src/core-library/processors/not-constraint.js +71 -0
- package/src/core-library/processors/number-operator.js +24 -0
- package/src/core-library/processors/numeric-constraint.js +22 -0
- package/src/core-library/processors/object-operator.js +38 -0
- package/src/core-library/processors/omit-operator.js +57 -0
- package/src/core-library/processors/parallel-operator.js +64 -0
- package/src/core-library/processors/pascal-case-operator.js +16 -0
- package/src/core-library/processors/phone-constraint.js +235 -0
- package/src/core-library/processors/pick-operator.js +62 -0
- package/src/core-library/processors/pipeline-operator.js +63 -0
- package/src/core-library/processors/port-constraint.js +22 -0
- package/src/core-library/processors/positive-constraint.js +23 -0
- package/src/core-library/processors/process-operator.js +55 -0
- package/src/core-library/processors/property-operator.js +49 -0
- package/src/core-library/processors/range-constraint.js +72 -0
- package/src/core-library/processors/reference-operator.js +79 -0
- package/src/core-library/processors/require-constraint.js +74 -0
- package/src/core-library/processors/reverse-operator.js +20 -0
- package/src/core-library/processors/round-operator.js +53 -0
- package/src/core-library/processors/schema-handler-operators.js +54 -0
- package/src/core-library/processors/semver-constraint.js +282 -0
- package/src/core-library/processors/sequence-processors.js +406 -0
- package/src/core-library/processors/sort-operator.js +52 -0
- package/src/core-library/processors/split-operator.js +43 -0
- package/src/core-library/processors/string-extra-operators.js +141 -0
- package/src/core-library/processors/string-operator.js +34 -0
- package/src/core-library/processors/target-operator.js +30 -0
- package/src/core-library/processors/template-operator.js +60 -0
- package/src/core-library/processors/title-case-operator.js +17 -0
- package/src/core-library/processors/trim-operator.js +14 -0
- package/src/core-library/processors/truthy-constraint.js +35 -0
- package/src/core-library/processors/type-operator.js +24 -0
- package/src/core-library/processors/unique-operator.js +21 -0
- package/src/core-library/processors/uppercase-operator.js +14 -0
- package/src/core-library/processors/url-constraint.js +31 -0
- package/src/core-library/processors/url-decode-operator.js +50 -0
- package/src/core-library/processors/url-encode-operator.js +44 -0
- package/src/core-library/processors/uuid-constraint.js +31 -0
- package/src/core-library/processors/values-operator.js +20 -0
- package/src/core-library/schemas/any-schema.js +23 -0
- package/src/core-library/schemas/array-schema.js +8 -0
- package/src/core-library/schemas/boolean-schema.js +10 -0
- package/src/core-library/schemas/date-schema.js +12 -0
- package/src/core-library/schemas/function-schema.js +40 -0
- package/src/core-library/schemas/number-schema.js +9 -0
- package/src/core-library/schemas/object-schema.js +10 -0
- package/src/core-library/schemas/root-schema.js +21 -0
- package/src/core-library/schemas/string-schema.js +9 -0
- package/src/core-library-node/index.js +47 -0
- package/src/core-library-node/processors/base64-decode-operator.js +20 -0
- package/src/core-library-node/processors/base64-encode-operator.js +20 -0
- package/src/core-library-node/processors/buffer-operator.js +39 -0
- package/src/core-library-node/processors/directory-constraint.js +35 -0
- package/src/core-library-node/processors/executable-constraint.js +34 -0
- package/src/core-library-node/processors/file-constraint.js +34 -0
- package/src/core-library-node/processors/file-size-constraint.js +94 -0
- package/src/core-library-node/processors/is-buffer-constraint.js +21 -0
- package/src/core-library-node/processors/reachable-constraint.js +28 -0
- package/src/core-library-node/processors/readable-constraint.js +34 -0
- package/src/core-library-node/processors/writable-constraint.js +59 -0
- package/src/core-library-node/schemas/buffer-schema.js +10 -0
- package/src/errors.js +209 -0
- package/src/executor/array-executor.js +78 -0
- package/src/executor/conditional-executor.js +134 -0
- package/src/executor/each-executor.js +68 -0
- package/src/executor/executor.js +123 -0
- package/src/executor/object-executor.js +98 -0
- package/src/executor/parallel-executor.js +43 -0
- package/src/executor/pipeline-executor.js +65 -0
- package/src/executor/sequence-executor.js +206 -0
- package/src/executor/serial-executor.js +24 -0
- package/src/executor/step-executor.js +68 -0
- package/src/helpers/case.js +124 -0
- package/src/helpers/data-size.js +144 -0
- package/src/helpers/debug-sink.js +15 -0
- package/src/helpers/deep.js +280 -0
- package/src/helpers/format.js +121 -0
- package/src/helpers/has-string-properties.js +30 -0
- package/src/helpers/index.js +16 -0
- package/src/helpers/object.js +115 -0
- package/src/helpers/parse-date.js +75 -0
- package/src/helpers/path.js +28 -0
- package/src/helpers/regex.js +18 -0
- package/src/helpers/stringify.js +309 -0
- package/src/helpers/to-data.js +64 -0
- package/src/helpers/truthy.js +55 -0
- package/src/index.js +29 -0
- package/src/schema-compiler.js +531 -0
- package/src/schema-location.js +200 -0
- package/src/schema-resolver.js +546 -0
- package/src/schema.js +1182 -0
- package/src/traversal/executors/check-condition.js +42 -0
- package/src/traversal/executors/check-input.js +27 -0
- package/src/traversal/executors/check-required.js +19 -0
- package/src/traversal/executors/check-schema.js +45 -0
- package/src/traversal/executors/defaults.js +21 -0
- package/src/traversal/executors/enter-existing.js +25 -0
- package/src/traversal/executors/enter-input.js +25 -0
- package/src/traversal/executors/enter.js +37 -0
- package/src/traversal/executors/exit.js +74 -0
- package/src/traversal/executors/finalize.js +64 -0
- package/src/traversal/executors/index.js +42 -0
- package/src/traversal/executors/normalize.js +38 -0
- package/src/traversal/executors/prepare-existing.js +27 -0
- package/src/traversal/executors/prepare-pending.js +54 -0
- package/src/traversal/executors/resolve-union.js +50 -0
- package/src/traversal/executors/serialize.js +48 -0
- package/src/traversal/executors/transform-early.js +51 -0
- package/src/traversal/executors/transform.js +68 -0
- package/src/traversal/executors/traversal-state-executor.js +46 -0
- package/src/traversal/executors/validate.js +63 -0
- package/src/traversal/traversal-context.js +231 -0
- package/src/traversal/traversal-state.js +809 -0
- package/src/types.js +102 -0
- package/src/value-processor/composed-value-processor.js +43 -0
- package/src/value-processor/defined-value-processor.js +72 -0
- package/src/value-processor/function-value-processor.js +68 -0
- package/src/value-processor/parameterized-value-processor.js +45 -0
- package/src/value-processor/parameters-value-processor.js +178 -0
- package/src/value-processor/spec.js +89 -0
- package/src/value-processor/value-processor.js +105 -0
- package/types/compilation/handler-compilation.d.ts +13 -0
- package/types/compilation/metadata-compilation.d.ts +6 -0
- package/types/compilation/schema-compilation.d.ts +32 -0
- package/types/compilation/selection-compilation.d.ts +9 -0
- package/types/compilation/union-compilation.d.ts +42 -0
- package/types/compilation/values-compilation.d.ts +12 -0
- package/types/compiled-schema.d.ts +883 -0
- package/types/constants.d.ts +1 -0
- package/types/core-library/index.d.ts +7 -0
- package/types/core-library/processors/aggregation-operators.d.ts +24 -0
- package/types/core-library/processors/alpha-constraint.d.ts +9 -0
- package/types/core-library/processors/alphanum-constraint.d.ts +9 -0
- package/types/core-library/processors/array-operator.d.ts +12 -0
- package/types/core-library/processors/assert-constraint.d.ts +30 -0
- package/types/core-library/processors/base64-constraint.d.ts +11 -0
- package/types/core-library/processors/camel-case-operator.d.ts +17 -0
- package/types/core-library/processors/capitalize-operator.d.ts +11 -0
- package/types/core-library/processors/cardnum-constraint.d.ts +51 -0
- package/types/core-library/processors/ceil-operator.d.ts +30 -0
- package/types/core-library/processors/collapse-operator.d.ts +24 -0
- package/types/core-library/processors/compact-operator.d.ts +29 -0
- package/types/core-library/processors/compile-operator.d.ts +34 -0
- package/types/core-library/processors/concat-operator.d.ts +23 -0
- package/types/core-library/processors/conditional-operators.d.ts +219 -0
- package/types/core-library/processors/constant-case-operator.d.ts +9 -0
- package/types/core-library/processors/data-size-operator.d.ts +31 -0
- package/types/core-library/processors/date-object-operator.d.ts +16 -0
- package/types/core-library/processors/date-operator.d.ts +21 -0
- package/types/core-library/processors/date-range-constraint.d.ts +26 -0
- package/types/core-library/processors/defined-constraint.d.ts +20 -0
- package/types/core-library/processors/each-operator.d.ts +34 -0
- package/types/core-library/processors/email-constraint.d.ts +54 -0
- package/types/core-library/processors/entries-operator.d.ts +13 -0
- package/types/core-library/processors/eq-constraint.d.ts +20 -0
- package/types/core-library/processors/filter-operator.d.ts +35 -0
- package/types/core-library/processors/find-schema-operator.d.ts +28 -0
- package/types/core-library/processors/flatten-operator.d.ts +26 -0
- package/types/core-library/processors/floor-operator.d.ts +33 -0
- package/types/core-library/processors/get-operator.d.ts +31 -0
- package/types/core-library/processors/group-by-operator.d.ts +36 -0
- package/types/core-library/processors/has-prefix-constraint.d.ts +22 -0
- package/types/core-library/processors/has-suffix-constraint.d.ts +20 -0
- package/types/core-library/processors/hex-constraint.d.ts +9 -0
- package/types/core-library/processors/hostname-constraint.d.ts +11 -0
- package/types/core-library/processors/http-url-constraint.d.ts +9 -0
- package/types/core-library/processors/in-constraint.d.ts +27 -0
- package/types/core-library/processors/index-by-operator.d.ts +26 -0
- package/types/core-library/processors/index.d.ts +8 -0
- package/types/core-library/processors/input-operator.d.ts +20 -0
- package/types/core-library/processors/instanceof-constraint.d.ts +23 -0
- package/types/core-library/processors/integer-constraint.d.ts +9 -0
- package/types/core-library/processors/invoke-operator.d.ts +12 -0
- package/types/core-library/processors/ipv4-constraint.d.ts +37 -0
- package/types/core-library/processors/ipv6-constraint.d.ts +34 -0
- package/types/core-library/processors/is-array-constraint.d.ts +10 -0
- package/types/core-library/processors/is-date-constraint.d.ts +10 -0
- package/types/core-library/processors/is-number-constraint.d.ts +10 -0
- package/types/core-library/processors/is-object-constraint.d.ts +10 -0
- package/types/core-library/processors/is-string-constraint.d.ts +10 -0
- package/types/core-library/processors/join-operator.d.ts +29 -0
- package/types/core-library/processors/json-constraint.d.ts +10 -0
- package/types/core-library/processors/json-decode-operator.d.ts +9 -0
- package/types/core-library/processors/json-encode-operator.d.ts +27 -0
- package/types/core-library/processors/kebab-case-operator.d.ts +16 -0
- package/types/core-library/processors/keys-operator.d.ts +9 -0
- package/types/core-library/processors/length-constraint.d.ts +34 -0
- package/types/core-library/processors/lookup-operator.d.ts +36 -0
- package/types/core-library/processors/lowercase-operator.d.ts +9 -0
- package/types/core-library/processors/map-operator.d.ts +38 -0
- package/types/core-library/processors/match-operator.d.ts +34 -0
- package/types/core-library/processors/matches-constraint.d.ts +29 -0
- package/types/core-library/processors/math-operators.d.ts +91 -0
- package/types/core-library/processors/merge-deep-operator.d.ts +32 -0
- package/types/core-library/processors/merge-operator.d.ts +26 -0
- package/types/core-library/processors/metadata-operator.d.ts +56 -0
- package/types/core-library/processors/negative-constraint.d.ts +13 -0
- package/types/core-library/processors/never-constraint.d.ts +26 -0
- package/types/core-library/processors/non-empty-constraint.d.ts +28 -0
- package/types/core-library/processors/not-constraint.d.ts +28 -0
- package/types/core-library/processors/number-operator.d.ts +9 -0
- package/types/core-library/processors/numeric-constraint.d.ts +10 -0
- package/types/core-library/processors/object-operator.d.ts +10 -0
- package/types/core-library/processors/omit-operator.d.ts +24 -0
- package/types/core-library/processors/parallel-operator.d.ts +41 -0
- package/types/core-library/processors/pascal-case-operator.d.ts +9 -0
- package/types/core-library/processors/phone-constraint.d.ts +65 -0
- package/types/core-library/processors/pick-operator.d.ts +27 -0
- package/types/core-library/processors/pipeline-operator.d.ts +40 -0
- package/types/core-library/processors/port-constraint.d.ts +11 -0
- package/types/core-library/processors/positive-constraint.d.ts +13 -0
- package/types/core-library/processors/process-operator.d.ts +37 -0
- package/types/core-library/processors/property-operator.d.ts +34 -0
- package/types/core-library/processors/range-constraint.d.ts +30 -0
- package/types/core-library/processors/reference-operator.d.ts +38 -0
- package/types/core-library/processors/require-constraint.d.ts +29 -0
- package/types/core-library/processors/reverse-operator.d.ts +9 -0
- package/types/core-library/processors/round-operator.d.ts +34 -0
- package/types/core-library/processors/schema-handler-operators.d.ts +28 -0
- package/types/core-library/processors/semver-constraint.d.ts +43 -0
- package/types/core-library/processors/sequence-processors.d.ts +213 -0
- package/types/core-library/processors/sort-operator.d.ts +31 -0
- package/types/core-library/processors/split-operator.d.ts +33 -0
- package/types/core-library/processors/string-extra-operators.d.ts +83 -0
- package/types/core-library/processors/string-operator.d.ts +10 -0
- package/types/core-library/processors/target-operator.d.ts +27 -0
- package/types/core-library/processors/template-operator.d.ts +31 -0
- package/types/core-library/processors/title-case-operator.d.ts +12 -0
- package/types/core-library/processors/trim-operator.d.ts +9 -0
- package/types/core-library/processors/truthy-constraint.d.ts +23 -0
- package/types/core-library/processors/type-operator.d.ts +11 -0
- package/types/core-library/processors/unique-operator.d.ts +10 -0
- package/types/core-library/processors/uppercase-operator.d.ts +9 -0
- package/types/core-library/processors/url-constraint.d.ts +20 -0
- package/types/core-library/processors/url-decode-operator.d.ts +31 -0
- package/types/core-library/processors/url-encode-operator.d.ts +36 -0
- package/types/core-library/processors/uuid-constraint.d.ts +20 -0
- package/types/core-library/processors/values-operator.d.ts +9 -0
- package/types/core-library/schemas/any-schema.d.ts +2 -0
- package/types/core-library/schemas/array-schema.d.ts +2 -0
- package/types/core-library/schemas/boolean-schema.d.ts +2 -0
- package/types/core-library/schemas/date-schema.d.ts +2 -0
- package/types/core-library/schemas/function-schema.d.ts +2 -0
- package/types/core-library/schemas/number-schema.d.ts +2 -0
- package/types/core-library/schemas/object-schema.d.ts +2 -0
- package/types/core-library/schemas/root-schema.d.ts +2 -0
- package/types/core-library/schemas/string-schema.d.ts +2 -0
- package/types/core-library-node/index.d.ts +12 -0
- package/types/core-library-node/processors/base64-decode-operator.d.ts +9 -0
- package/types/core-library-node/processors/base64-encode-operator.d.ts +9 -0
- package/types/core-library-node/processors/buffer-operator.d.ts +15 -0
- package/types/core-library-node/processors/directory-constraint.d.ts +14 -0
- package/types/core-library-node/processors/executable-constraint.d.ts +17 -0
- package/types/core-library-node/processors/file-constraint.d.ts +13 -0
- package/types/core-library-node/processors/file-size-constraint.d.ts +43 -0
- package/types/core-library-node/processors/is-buffer-constraint.d.ts +10 -0
- package/types/core-library-node/processors/reachable-constraint.d.ts +13 -0
- package/types/core-library-node/processors/readable-constraint.d.ts +17 -0
- package/types/core-library-node/processors/writable-constraint.d.ts +18 -0
- package/types/core-library-node/schemas/buffer-schema.d.ts +2 -0
- package/types/errors.d.ts +58 -0
- package/types/executor/array-executor.d.ts +17 -0
- package/types/executor/conditional-executor.d.ts +45 -0
- package/types/executor/each-executor.d.ts +15 -0
- package/types/executor/executor.d.ts +84 -0
- package/types/executor/object-executor.d.ts +14 -0
- package/types/executor/parallel-executor.d.ts +27 -0
- package/types/executor/pipeline-executor.d.ts +11 -0
- package/types/executor/sequence-executor.d.ts +32 -0
- package/types/executor/serial-executor.d.ts +16 -0
- package/types/executor/step-executor.d.ts +14 -0
- package/types/helpers/case.d.ts +30 -0
- package/types/helpers/data-size.d.ts +25 -0
- package/types/helpers/debug-sink.d.ts +9 -0
- package/types/helpers/deep.d.ts +33 -0
- package/types/helpers/format.d.ts +14 -0
- package/types/helpers/has-string-properties.d.ts +5 -0
- package/types/helpers/index.d.ts +13 -0
- package/types/helpers/object.d.ts +46 -0
- package/types/helpers/parse-date.d.ts +6 -0
- package/types/helpers/path.d.ts +13 -0
- package/types/helpers/regex.d.ts +7 -0
- package/types/helpers/stringify.d.ts +33 -0
- package/types/helpers/to-data.d.ts +13 -0
- package/types/helpers/truthy.d.ts +26 -0
- package/types/index.d.ts +6 -0
- package/types/schema-compiler.d.ts +49 -0
- package/types/schema-location.d.ts +64 -0
- package/types/schema-resolver.d.ts +145 -0
- package/types/schema.d.ts +586 -0
- package/types/traversal/executors/check-condition.d.ts +8 -0
- package/types/traversal/executors/check-input.d.ts +6 -0
- package/types/traversal/executors/check-required.d.ts +6 -0
- package/types/traversal/executors/check-schema.d.ts +7 -0
- package/types/traversal/executors/defaults.d.ts +8 -0
- package/types/traversal/executors/enter-existing.d.ts +6 -0
- package/types/traversal/executors/enter-input.d.ts +8 -0
- package/types/traversal/executors/enter.d.ts +7 -0
- package/types/traversal/executors/exit.d.ts +6 -0
- package/types/traversal/executors/finalize.d.ts +6 -0
- package/types/traversal/executors/index.d.ts +15 -0
- package/types/traversal/executors/normalize.d.ts +7 -0
- package/types/traversal/executors/prepare-existing.d.ts +6 -0
- package/types/traversal/executors/prepare-pending.d.ts +6 -0
- package/types/traversal/executors/resolve-union.d.ts +6 -0
- package/types/traversal/executors/serialize.d.ts +11 -0
- package/types/traversal/executors/transform-early.d.ts +6 -0
- package/types/traversal/executors/transform.d.ts +6 -0
- package/types/traversal/executors/traversal-state-executor.d.ts +19 -0
- package/types/traversal/executors/validate.d.ts +6 -0
- package/types/traversal/traversal-context.d.ts +67 -0
- package/types/traversal/traversal-state.d.ts +97 -0
- package/types/types.d.ts +218 -0
- package/types/value-processor/composed-value-processor.d.ts +17 -0
- package/types/value-processor/defined-value-processor.d.ts +16 -0
- package/types/value-processor/function-value-processor.d.ts +15 -0
- package/types/value-processor/parameterized-value-processor.d.ts +14 -0
- package/types/value-processor/parameters-value-processor.d.ts +28 -0
- package/types/value-processor/spec.d.ts +22 -0
- package/types/value-processor/value-processor.d.ts +92 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
|
|
2
|
+
import { ConstraintError } from '../../errors.js';
|
|
3
|
+
import { parseDate } from '../../helpers/parse-date.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ## $date-range
|
|
7
|
+
*
|
|
8
|
+
* Validates that a date value falls within the specified range (inclusive).
|
|
9
|
+
* Can specify minimum, maximum, or both bounds. Bounds are parsed using
|
|
10
|
+
* the same rules as the `date` schema normalizer, so strings, numbers,
|
|
11
|
+
* and Date objects are all accepted.
|
|
12
|
+
*
|
|
13
|
+
* ### Parameters
|
|
14
|
+
* - `min` (optional): Minimum date (inclusive). If omitted, no lower bound.
|
|
15
|
+
* - `max` (optional): Maximum date (inclusive). If omitted, no upper bound.
|
|
16
|
+
*
|
|
17
|
+
* ### Example
|
|
18
|
+
* ```js
|
|
19
|
+
* // Object form with named parameters
|
|
20
|
+
* new Schema('date').validator({'$date-range': {min: '2024-01-01', max: '2024-12-31'}})
|
|
21
|
+
*
|
|
22
|
+
* // Cross-reference: end date must be >= start date
|
|
23
|
+
* new Schema('object')
|
|
24
|
+
* .property('start', new Schema('date'))
|
|
25
|
+
* .property('end', new Schema('date').validator({'$date-range': {min: {$reference: '^start'}}}))
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
29
|
+
*/
|
|
30
|
+
export const DATE_RANGE_CONSTRAINT = {
|
|
31
|
+
keyword: 'date-range',
|
|
32
|
+
parameters: [
|
|
33
|
+
{ parameter: 'min', default: undefined },
|
|
34
|
+
{ parameter: 'max', default: undefined },
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
process: (value, _target, _location, options) => {
|
|
38
|
+
const { min, max } = options.args;
|
|
39
|
+
|
|
40
|
+
const dateMs = (value instanceof Date ? value : parseDate(value)).getTime();
|
|
41
|
+
|
|
42
|
+
if (min !== undefined) {
|
|
43
|
+
const minMs = (min instanceof Date ? min : parseDate(min)).getTime();
|
|
44
|
+
if (dateMs < minMs) {
|
|
45
|
+
throw new ConstraintError(`Date must not be before ${new Date(minMs).toISOString()}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (max !== undefined) {
|
|
49
|
+
const maxMs = (max instanceof Date ? max : parseDate(max)).getTime();
|
|
50
|
+
if (dateMs > maxMs) {
|
|
51
|
+
throw new ConstraintError(`Date must not be after ${new Date(maxMs).toISOString()}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
describe: (args) => {
|
|
58
|
+
if (!args) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const minProcessor = (Array.isArray(args) ? args[0] : args.min);
|
|
63
|
+
const maxProcessor = (Array.isArray(args) ? args[1] : args.max);
|
|
64
|
+
|
|
65
|
+
const min = minProcessor?.description;
|
|
66
|
+
const max = maxProcessor?.description;
|
|
67
|
+
|
|
68
|
+
return min !== undefined && max !== undefined
|
|
69
|
+
? `${min}..${max}`
|
|
70
|
+
: min !== undefined
|
|
71
|
+
? `>=${min}`
|
|
72
|
+
: max !== undefined
|
|
73
|
+
? `<=${max}`
|
|
74
|
+
: undefined;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## $defined
|
|
5
|
+
*
|
|
6
|
+
* Allow any value, as long as it's defined.
|
|
7
|
+
*
|
|
8
|
+
* ### Example
|
|
9
|
+
* ```js
|
|
10
|
+
* // Ensure an optional field, when supplied, is not undefined
|
|
11
|
+
* new Schema('any').validator('$defined')
|
|
12
|
+
*
|
|
13
|
+
* // Gate a sub-pipeline: only run if the value is defined
|
|
14
|
+
* new Schema('any').normalizer({$gate: ['$defined', '$trim']})
|
|
15
|
+
*
|
|
16
|
+
* // Require a computed result to be defined
|
|
17
|
+
* new Schema('string').validator({$require: {$get: {path: 'nested.key'}}})
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
21
|
+
*/
|
|
22
|
+
export const DEFINED_CONSTRAINT = {
|
|
23
|
+
keyword: 'defined',
|
|
24
|
+
process: (value) => {
|
|
25
|
+
if (value === undefined) {
|
|
26
|
+
throw new ConstraintError('Must be defined');
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { EachExecutor } from "../../executor/each-executor.js";
|
|
2
|
+
import { ComposedValueProcessor } from '../../value-processor/composed-value-processor.js';
|
|
3
|
+
import { Executor } from '../../executor/executor.js';
|
|
4
|
+
import { PipelineExecutor } from '../../executor/pipeline-executor.js';
|
|
5
|
+
import { ConstraintError } from '../../errors.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ## $each
|
|
9
|
+
*
|
|
10
|
+
* Applies a processor to each element of an array. The processor can be any valid
|
|
11
|
+
* processor specification (RegExp, function, keyword, or parameterized processor).
|
|
12
|
+
* If any element fails validation, the entire array is rejected.
|
|
13
|
+
*
|
|
14
|
+
* This operator is useful for applying consistent validation or transformation rules
|
|
15
|
+
* across all array elements without requiring explicit array element schemas.
|
|
16
|
+
*
|
|
17
|
+
* ### Parameters
|
|
18
|
+
* - `processor` (any valid processor spec, required): The processor to apply to each element.
|
|
19
|
+
* Can be a RegExp, function, string keyword (e.g., `'$numeric'`), or parameterized processor object.
|
|
20
|
+
*
|
|
21
|
+
* ### Example
|
|
22
|
+
* ```js
|
|
23
|
+
* // Trim whitespace from every string in an array
|
|
24
|
+
* new Schema('array').transformer({$each: '$trim'})
|
|
25
|
+
*
|
|
26
|
+
* // Validate that every element is numeric
|
|
27
|
+
* new Schema('array').validator({$each: '$numeric'})
|
|
28
|
+
*
|
|
29
|
+
* // Validate that each element is within a range
|
|
30
|
+
* new Schema('array').validator({$each: {$range: {min: 0, max: 100}}})
|
|
31
|
+
*
|
|
32
|
+
* // Normalize every tag: trim and lowercase
|
|
33
|
+
* new Schema('object', {
|
|
34
|
+
* tags: new Schema('array').transformer({$each: ['$trim', '$lowercase']}),
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
39
|
+
*/
|
|
40
|
+
export const EACH_OPERATOR = {
|
|
41
|
+
keyword: 'each',
|
|
42
|
+
parameters: [{parameter: 'processor', required: true}],
|
|
43
|
+
build: (args) => {
|
|
44
|
+
const processor = (Array.isArray(args)? args[0] : args.processor) ?? new Executor();
|
|
45
|
+
// TODO - wrap the processor in a function that passes the original collection in the options
|
|
46
|
+
|
|
47
|
+
const values = (Array.isArray(args)? args[1] : args.values) ?? new Executor();
|
|
48
|
+
|
|
49
|
+
const spec = {$each: processor.spec};
|
|
50
|
+
const description = processor.description ? `[${processor.description}]...` : 'values...';
|
|
51
|
+
|
|
52
|
+
return new ComposedValueProcessor(new PipelineExecutor([values, new EachExecutor(processor)]), spec, description);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
import { isFalsey } from '../../helpers/truthy.js';
|
|
3
|
+
|
|
4
|
+
// Username: letters, digits, and limited special chars (._%+-)
|
|
5
|
+
// No leading/trailing dot, no consecutive dots
|
|
6
|
+
// Domain: 2+ dot-separated labels of letters/digits/hyphens, ending with 2+ letter TLD
|
|
7
|
+
// No consecutive dots, no leading/trailing hyphens in labels
|
|
8
|
+
const EMAIL_REGEX =
|
|
9
|
+
/^[a-zA-Z0-9_%+-](?:[a-zA-Z0-9_%+.-]*[a-zA-Z0-9_%+-])?@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
10
|
+
|
|
11
|
+
// Additional check: no consecutive dots in local part
|
|
12
|
+
const CONSECUTIVE_DOTS = /\.\./;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* ## $email
|
|
16
|
+
*
|
|
17
|
+
* Validates that a string matches a practical email address format (local-part@domain.tld).
|
|
18
|
+
*
|
|
19
|
+
* **Username (local part):**
|
|
20
|
+
* - Allowed characters: letters, digits, `.`, `_`, `%`, `+`, `-`
|
|
21
|
+
* - Must not start or end with a dot
|
|
22
|
+
* - Must not contain consecutive dots
|
|
23
|
+
*
|
|
24
|
+
* **Domain:**
|
|
25
|
+
* - Must consist of at least two dot-separated labels (e.g. `example.com`)
|
|
26
|
+
* - Labels may contain letters, digits, and hyphens (no leading/trailing hyphens)
|
|
27
|
+
* - Must not contain consecutive dots
|
|
28
|
+
* - Must end in a TLD of 2+ letters
|
|
29
|
+
*
|
|
30
|
+
* **Not supported (by design):** quoted local parts, comments, IP address literals, emoji,
|
|
31
|
+
* non-ASCII characters. This processor is intended to handle addresses as they are typically
|
|
32
|
+
* used. If you need to support all the madness that the official RFC allows, you'll need to
|
|
33
|
+
* write your own version.
|
|
34
|
+
*
|
|
35
|
+
* The default behavior is to convert the address to lower case for consistency, but this
|
|
36
|
+
* can be overridden.
|
|
37
|
+
*
|
|
38
|
+
* ### Parameters
|
|
39
|
+
* - `case` (string, default `'lower'`): Case conversion applied to the domain portion,
|
|
40
|
+
* and (unless overridden by `case-sensitive`) to the username portion as well.
|
|
41
|
+
* Accepts `'lower'` or `'upper'`, or if falsey, doesn't do any conversion.
|
|
42
|
+
* - `case-sensitive` (boolean, default `false`): When `true`, preserve the original case of
|
|
43
|
+
* the username portion. When `false`, the username is converted using the `case` parameter.
|
|
44
|
+
* (Rationale: RFC 5321 technically allows case-sensitive local parts, but virtually all
|
|
45
|
+
* providers treat them as case-insensitive.)
|
|
46
|
+
* - `filter` (boolean, default `false`): When `true`, strip plus-addressing
|
|
47
|
+
* (e.g. `user+tag@` becomes `user@`), and for `gmail.com` domains, additionally remove
|
|
48
|
+
* all dots from the username (since Gmail ignores them).
|
|
49
|
+
*
|
|
50
|
+
* ### Example
|
|
51
|
+
* ```js
|
|
52
|
+
* // Basic validation only
|
|
53
|
+
* new Schema('string').validator('$email')
|
|
54
|
+
*
|
|
55
|
+
* // Normalize to lowercase, strip plus-addressing
|
|
56
|
+
* new Schema('string').validator({'$email': {filter: true}})
|
|
57
|
+
*
|
|
58
|
+
* // Preserve username case
|
|
59
|
+
* new Schema('string').validator({'$email': {'case-sensitive': true}})
|
|
60
|
+
*
|
|
61
|
+
* // Work for the government and like to shout at people?
|
|
62
|
+
* new Schema('string').validator({'$email': {'case': 'upper'}}
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
66
|
+
*/
|
|
67
|
+
export const EMAIL_CONSTRAINT = {
|
|
68
|
+
keyword: 'email',
|
|
69
|
+
parameters: [
|
|
70
|
+
{ parameter: 'case', default: 'lower' },
|
|
71
|
+
{ parameter: 'case-sensitive', type: 'boolean', default: false },
|
|
72
|
+
{ parameter: 'filter', type: 'boolean', default: false },
|
|
73
|
+
],
|
|
74
|
+
|
|
75
|
+
process: (value, _target, _location, options) => {
|
|
76
|
+
const { 'case': caseParam, 'case-sensitive': caseSensitive, filter } = options.args;
|
|
77
|
+
|
|
78
|
+
if (!EMAIL_REGEX.test(value)) {
|
|
79
|
+
throw new ConstraintError('Invalid email format');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const atIndex = value.lastIndexOf('@');
|
|
83
|
+
let username = value.slice(0, atIndex);
|
|
84
|
+
let domain = value.slice(atIndex + 1);
|
|
85
|
+
|
|
86
|
+
// Reject consecutive dots in local part (regex alone can't catch all combos cleanly)
|
|
87
|
+
if (CONSECUTIVE_DOTS.test(username)) {
|
|
88
|
+
throw new ConstraintError('Invalid email format');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Apply filter: strip plus-addressing and gmail dot normalization
|
|
92
|
+
if (filter) {
|
|
93
|
+
const plusIndex = username.indexOf('+');
|
|
94
|
+
if (plusIndex !== -1) {
|
|
95
|
+
username = username.slice(0, plusIndex);
|
|
96
|
+
}
|
|
97
|
+
if (domain.toLowerCase() === 'gmail.com') {
|
|
98
|
+
username = username.replace(/\./g, '');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Apply case conversion
|
|
103
|
+
|
|
104
|
+
const applyCase = isFalsey(caseParam)? (s) => s : (caseParam === 'upper' ? (s) => s.toUpperCase() : (s) => s.toLowerCase());
|
|
105
|
+
domain = applyCase(domain);
|
|
106
|
+
if (!caseSensitive) {
|
|
107
|
+
username = applyCase(username);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return `${username}@${domain}`;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isPlainObject } from '../../helpers/object.js';
|
|
2
|
+
import { ConstraintError } from '../../errors.js';
|
|
3
|
+
import { formatValue } from '../../helpers/format.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ## $entries
|
|
7
|
+
*
|
|
8
|
+
* Returns the enumerable own properties of an object as an array of `[key, value]` pairs,
|
|
9
|
+
* matching the output of `Object.entries()`.
|
|
10
|
+
*
|
|
11
|
+
* The resulting array can be reconstructed back into an object with `$object`.
|
|
12
|
+
*
|
|
13
|
+
* Throws if the input is not a plain object.
|
|
14
|
+
*
|
|
15
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
16
|
+
*/
|
|
17
|
+
export const ENTRIES_OPERATOR = {
|
|
18
|
+
keyword: 'entries',
|
|
19
|
+
process: (value, _target, location) => {
|
|
20
|
+
if (!isPlainObject(value)) {
|
|
21
|
+
throw new ConstraintError(`$entries requires a plain object, got ${formatValue(value)}`, {location});
|
|
22
|
+
}
|
|
23
|
+
return Object.entries(value);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { deepEquals } from "../../helpers/deep.js";
|
|
2
|
+
import { ConstraintError } from '../../errors.js';
|
|
3
|
+
import { formatValue } from '../../helpers/format.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ## $eq
|
|
7
|
+
*
|
|
8
|
+
* Do a deep equality check between the value and the provided constraint value.
|
|
9
|
+
*
|
|
10
|
+
* ### Parameters
|
|
11
|
+
* - `value` (any, required): The value to compare against using deep equality.
|
|
12
|
+
*
|
|
13
|
+
* ### Example
|
|
14
|
+
* ```js
|
|
15
|
+
* // Ensure a status field can only be 'active'
|
|
16
|
+
* new Schema('string').validator({$eq: 'active'})
|
|
17
|
+
*
|
|
18
|
+
* // Ensure an object matches an exact structure
|
|
19
|
+
* new Schema('object').validator({$eq: {type: 'config', version: 1}})
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}*
|
|
23
|
+
*/
|
|
24
|
+
export const EQ_CONSTRAINT = {
|
|
25
|
+
keyword: 'eq',
|
|
26
|
+
parameters: [ { parameter: 'value', required: true }, { parameter: 'compare' } ],
|
|
27
|
+
|
|
28
|
+
process: (value, _target, location, options) => {
|
|
29
|
+
const eqValue = options.args['value'];
|
|
30
|
+
const compare = options.args['compare'] ?? value;
|
|
31
|
+
|
|
32
|
+
if (!deepEquals(eqValue, compare)) {
|
|
33
|
+
throw new ConstraintError(`Value ${formatValue(value)} was not equal to constraint`, {value, location});
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ComposedValueProcessor } from '../../value-processor/composed-value-processor.js';
|
|
2
|
+
import { ConditionalExecutor } from '../../executor/conditional-executor.js';
|
|
3
|
+
import { FunctionValueProcessor } from '../../value-processor/function-value-processor.js';
|
|
4
|
+
import { EachExecutor } from '../../executor/each-executor.js';
|
|
5
|
+
|
|
6
|
+
import { SchemaError } from '../../errors.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ## $filter
|
|
10
|
+
*
|
|
11
|
+
* Runs a processor on each element of the input array, keeping elements for which the processor
|
|
12
|
+
* succeeds and returning the processor's output value (consistent with standard processor semantics).
|
|
13
|
+
* Elements are filtered out if the processor throws or returns undefined.
|
|
14
|
+
* (Note that processor results are not checked for truthiness — only for definedness.)
|
|
15
|
+
*
|
|
16
|
+
* Non-arrays are "filtered" as an empty array.
|
|
17
|
+
*
|
|
18
|
+
* ### Parameters
|
|
19
|
+
* - `processor` (any valid processor spec, optional): The processor to apply to each element.
|
|
20
|
+
* Elements where the processor returns undefined or throws are excluded from the result.
|
|
21
|
+
* If omitted, null/undefined elements are removed.
|
|
22
|
+
*
|
|
23
|
+
* ### Example
|
|
24
|
+
* ```js
|
|
25
|
+
* // Remove null and undefined values from an array
|
|
26
|
+
* new Schema('array').transformer('$filter')
|
|
27
|
+
*
|
|
28
|
+
* // Keep only numeric strings
|
|
29
|
+
* new Schema('array').transformer({$filter: '$numeric'})
|
|
30
|
+
*
|
|
31
|
+
* // Keep only values within range
|
|
32
|
+
* new Schema('array').transformer({$filter: {$range: {min: 0, max: 100}}})
|
|
33
|
+
*
|
|
34
|
+
* // Filter out non-email strings from a list
|
|
35
|
+
* new Schema('object', {
|
|
36
|
+
* recipients: new Schema('array').transformer({$filter: '$email'}),
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
41
|
+
*/
|
|
42
|
+
export const FILTER_OPERATOR = {
|
|
43
|
+
keyword: 'filter',
|
|
44
|
+
parameters: [{parameter: 'processor', required: false}],
|
|
45
|
+
build: (args) => {
|
|
46
|
+
let processor;
|
|
47
|
+
if (Array.isArray(args)) {
|
|
48
|
+
if (args.length > 1) {
|
|
49
|
+
throw new SchemaError('Expected exactly one argument for $filter operator');
|
|
50
|
+
}
|
|
51
|
+
processor = args[0];
|
|
52
|
+
}
|
|
53
|
+
else if (typeof args === 'object') {
|
|
54
|
+
if (Object.keys(args).length !== 1) {
|
|
55
|
+
throw new SchemaError('Expected only "processor" argument for $filter operator');
|
|
56
|
+
}
|
|
57
|
+
processor = args.processor;
|
|
58
|
+
}
|
|
59
|
+
processor ??= new FunctionValueProcessor(v => (v === undefined || v === null)? undefined : v);
|
|
60
|
+
|
|
61
|
+
return new ComposedValueProcessor(
|
|
62
|
+
new EachExecutor(
|
|
63
|
+
new ConditionalExecutor(processor, {}, [ConditionalExecutor.CHECK_DEFINED, ConditionalExecutor.PASS_RESULT]),
|
|
64
|
+
(inputs) => {
|
|
65
|
+
if (!Array.isArray(inputs)) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
return inputs;
|
|
69
|
+
},
|
|
70
|
+
(results) => (Array.isArray(results)? results.filter(r => r !== undefined) : [])
|
|
71
|
+
),
|
|
72
|
+
{$filter: processor.spec});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SchemaError } from '../../errors.js';
|
|
2
|
+
import { formatValue } from '../../helpers/format.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ## $find-schema
|
|
6
|
+
*
|
|
7
|
+
* Find a schema in the schema hierarchy based on a dotted path. Returns the current schema by default.
|
|
8
|
+
* The provided path is interpreted relative to the currently active schema but supports navigation
|
|
9
|
+
* to the root schema using '/' and parent schema using '^'.
|
|
10
|
+
*
|
|
11
|
+
* ### Parameters
|
|
12
|
+
* - `path` (string | number, required): Dot-separated property path or array index.
|
|
13
|
+
*
|
|
14
|
+
* Example paths:
|
|
15
|
+
* - '': The current schema.
|
|
16
|
+
* - '/': The root schema.
|
|
17
|
+
* - 'xyzzy': Find the 'xyzzy' child of the current schema.
|
|
18
|
+
* - 'xyzzy.plugh': Find the 'plugh' child of the 'xyzzy' child of the current schema.
|
|
19
|
+
* - 'child.^': The current schema if and only if the child exists.
|
|
20
|
+
* - `/.foo.bar`: Find the 'bar' property in the 'foo' child of the root.
|
|
21
|
+
* - `^`: Return the parent schema
|
|
22
|
+
* - `^^jim`: Get the grandparent schema's child named 'jim' (uncle jim)
|
|
23
|
+
* - `^.^.jim`: Same thing (extra dots are ignored.)
|
|
24
|
+
*
|
|
25
|
+
* ```js
|
|
26
|
+
* new Schema('any').transformer({'$metadata': {name: 'description', schema: {'$find-schema': '^'}}})
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
30
|
+
*/
|
|
31
|
+
export const FIND_SCHEMA_OPERATOR = {
|
|
32
|
+
keyword: 'find-schema',
|
|
33
|
+
parameters: [{parameter: 'path', required: false}],
|
|
34
|
+
|
|
35
|
+
process: (value, _target, location, options) => {
|
|
36
|
+
/** @type {string} */
|
|
37
|
+
const path = options.args?.path ?? value ?? '.';
|
|
38
|
+
|
|
39
|
+
if (typeof path !== 'string') {
|
|
40
|
+
throw new SchemaError(`$find-schema "path" must be a string, got ${formatValue(path)}`, {location});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return location.relative(path)?.schema;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
import { formatValue } from '../../helpers/format.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ## $flatten
|
|
6
|
+
*
|
|
7
|
+
* Returns a new array with sub-array elements flattened to the specified depth.
|
|
8
|
+
* Throws if the input is not an array.
|
|
9
|
+
*
|
|
10
|
+
* ### Parameters
|
|
11
|
+
* - `depth` (number, optional, default `1`): The depth to flatten. Use `Infinity` to flatten completely.
|
|
12
|
+
*
|
|
13
|
+
* ### Example
|
|
14
|
+
* ```js
|
|
15
|
+
* // Flatten one level of nesting
|
|
16
|
+
* new Schema('array').transformer('$flatten')
|
|
17
|
+
* // [[1, 2], [3, 4]] → [1, 2, 3, 4]
|
|
18
|
+
*
|
|
19
|
+
* // Flatten all levels
|
|
20
|
+
* new Schema('array').transformer({$flatten: {depth: Infinity}})
|
|
21
|
+
* // [1, [2, [3, [4]]]] → [1, 2, 3, 4]
|
|
22
|
+
*
|
|
23
|
+
* // Flatten exactly 2 levels
|
|
24
|
+
* new Schema('array').transformer({$flatten: {depth: 2}})
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
28
|
+
*/
|
|
29
|
+
export const FLATTEN_OPERATOR = {
|
|
30
|
+
keyword: 'flatten',
|
|
31
|
+
parameters: [ { parameter: 'depth', default: 1 } ],
|
|
32
|
+
|
|
33
|
+
process: (value, _target, location, options) => {
|
|
34
|
+
if (!Array.isArray(value)) {
|
|
35
|
+
throw new ConstraintError(`$flatten requires an array, got ${formatValue(value)}`, {location});
|
|
36
|
+
}
|
|
37
|
+
const depth = options.args?.['depth'] ?? 1;
|
|
38
|
+
return value.flat(depth);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ## $floor
|
|
3
|
+
*
|
|
4
|
+
* Rounds a numeric value down to the specified number of decimal places.
|
|
5
|
+
* Non-numeric values are passed through unchanged. Safe to use in normalize phase (non-throwing).
|
|
6
|
+
*
|
|
7
|
+
* ### Parameters
|
|
8
|
+
* - `precision` (number, optional): Number of decimal places to preserve. Defaults to 0 (round to integer).
|
|
9
|
+
*
|
|
10
|
+
* **Input/Output Examples**:
|
|
11
|
+
* - `$floor`: `3.7` → `3`, `9.99` → `9`, `-2.3` → `-3`
|
|
12
|
+
* - `{$floor: 2}`: `3.14159` → `3.14`, `99.999` → `99.99`, `5.1` → `5.1`
|
|
13
|
+
* - `{$floor: 1}`: `3.76` → `3.7`, `9.01` → `9.0`
|
|
14
|
+
*
|
|
15
|
+
* ### Example
|
|
16
|
+
* ```js
|
|
17
|
+
* // Truncate to integer (floor toward zero for positive numbers)
|
|
18
|
+
* new Schema('number').transformer('$floor')
|
|
19
|
+
* // 9.99 → 9
|
|
20
|
+
*
|
|
21
|
+
* // Preserve 2 decimal places, discarding extra precision
|
|
22
|
+
* new Schema('number').transformer({$floor: {precision: 2}})
|
|
23
|
+
* // 3.14159 → 3.14
|
|
24
|
+
*
|
|
25
|
+
* // Strip sub-cent precision from a price field
|
|
26
|
+
* new Schema('object', {
|
|
27
|
+
* price: new Schema('number').transformer({$floor: {precision: 2}}),
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
32
|
+
*/
|
|
33
|
+
export const FLOOR_OPERATOR = {
|
|
34
|
+
keyword: 'floor',
|
|
35
|
+
parameters: [ { parameter: 'precision', default: 0 } ],
|
|
36
|
+
|
|
37
|
+
process: (value, _target, _location, options) => {
|
|
38
|
+
const num = Number(value);
|
|
39
|
+
if (!Number.isFinite(num)) {
|
|
40
|
+
return value; // Pass through non-numeric values unchanged
|
|
41
|
+
}
|
|
42
|
+
const precision = options.args.precision;
|
|
43
|
+
const multiplier = Math.pow(10, precision);
|
|
44
|
+
|
|
45
|
+
return Math.floor(num * multiplier) / multiplier;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { deepValue } from '../../helpers/deep.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## $get
|
|
5
|
+
*
|
|
6
|
+
* Extracts a value from the input using a dot-separated path (for objects) or a numeric
|
|
7
|
+
* index (for arrays). Does not require the path to be declared as a schema property —
|
|
8
|
+
* use `$property` when schema-awareness is needed.
|
|
9
|
+
*
|
|
10
|
+
* Returns `undefined` if the path does not resolve.
|
|
11
|
+
*
|
|
12
|
+
* ### Parameters
|
|
13
|
+
* - `path` (string | number, required): Dot-separated property path or array index.
|
|
14
|
+
*
|
|
15
|
+
* ### Example
|
|
16
|
+
* ```js
|
|
17
|
+
* // Extract a nested property from an object
|
|
18
|
+
* new Schema('object').transformer({$get: {path: 'database.host'}})
|
|
19
|
+
* // {database: {host: 'localhost'}} → 'localhost'
|
|
20
|
+
*
|
|
21
|
+
* // Extract an array element by index
|
|
22
|
+
* new Schema('array').transformer({$get: {path: 0}})
|
|
23
|
+
* // ['first', 'second'] → 'first'
|
|
24
|
+
*
|
|
25
|
+
* // Use as a conditional predicate — only proceed if the path exists
|
|
26
|
+
* new Schema('object').transformer({
|
|
27
|
+
* $when: [{$get: {path: 'config.timeout'}}]
|
|
28
|
+
* })
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
32
|
+
*/
|
|
33
|
+
export const GET_OPERATOR = {
|
|
34
|
+
keyword: 'get',
|
|
35
|
+
parameters: [{parameter: 'path', required: true}],
|
|
36
|
+
|
|
37
|
+
process: (value, _target, _location, options) => {
|
|
38
|
+
const path = options.args?.path;
|
|
39
|
+
if (typeof path === 'number') {
|
|
40
|
+
return Array.isArray(value) ? value[path] : undefined;
|
|
41
|
+
}
|
|
42
|
+
return deepValue(value, path);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
|
|
2
|
+
import { FunctionValueProcessor } from '../../value-processor/function-value-processor.js';
|
|
3
|
+
import { ComposedValueProcessor } from '../../value-processor/composed-value-processor.js';
|
|
4
|
+
import { EachExecutor } from '../../executor/each-executor.js';
|
|
5
|
+
import { ConstraintError, SchemaError } from '../../errors.js';
|
|
6
|
+
import { formatValue } from '../../helpers/format.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ## $group-by
|
|
10
|
+
*
|
|
11
|
+
* Groups an array of objects by a key, returning an object whose values are arrays of elements
|
|
12
|
+
* that share that key value.
|
|
13
|
+
*
|
|
14
|
+
* - `{'$group-by': 'key'}` — groups by the named property on each element
|
|
15
|
+
* - `{'$group-by': processor}` — groups by the result of executing the processor against each element
|
|
16
|
+
* (any compiled processor spec, e.g. `'$type'`, `{$get: 'field'}`, or a function)
|
|
17
|
+
*
|
|
18
|
+
* Elements where the extracted key is `undefined` are omitted from the result.
|
|
19
|
+
* Insertion order is preserved within each group.
|
|
20
|
+
*
|
|
21
|
+
* ### Parameters
|
|
22
|
+
* - `key` (string or processor, required): Property name to group by, or a processor that extracts
|
|
23
|
+
* the grouping key from each element. Plain strings (no leading `$`) are treated as property names;
|
|
24
|
+
* all other processor specs are executed as extractors.
|
|
25
|
+
*
|
|
26
|
+
* ### Example
|
|
27
|
+
* ```js
|
|
28
|
+
* // Group an array of log entries by their severity level
|
|
29
|
+
* new Schema('array').transformer({'$group-by': 'level'})
|
|
30
|
+
* // [{level:'error', msg:'...'}, {level:'info', msg:'...'}]
|
|
31
|
+
* // → {error: [{level:'error', ...}], info: [{level:'info', ...}]}
|
|
32
|
+
*
|
|
33
|
+
* // Group by a computed key (the JS type of each element)
|
|
34
|
+
* new Schema('array').transformer({'$group-by': '$type'})
|
|
35
|
+
* // [1, 'a', 2, 'b'] → {number: [1, 2], string: ['a', 'b']}
|
|
36
|
+
*
|
|
37
|
+
* // Group by a nested property using $get
|
|
38
|
+
* new Schema('array').transformer({'$group-by': {$get: 'meta.region'}})
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
42
|
+
*/
|
|
43
|
+
export const GROUP_BY_OPERATOR = {
|
|
44
|
+
keyword: 'group-by',
|
|
45
|
+
|
|
46
|
+
build: (args) => {
|
|
47
|
+
if (!Array.isArray(args) || args.length !== 1) {
|
|
48
|
+
throw new SchemaError('$group-by requires a single key or processor argument');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const keyArg = args[0];
|
|
52
|
+
const keySpec = keyArg?.spec;
|
|
53
|
+
|
|
54
|
+
// Plain property name strings (no leading $) → property lookup per element.
|
|
55
|
+
// Processor keywords ($type), complex specs, functions → execute as extractor.
|
|
56
|
+
const keyExtractor = (typeof keySpec === 'string' && !keySpec.startsWith('$'))
|
|
57
|
+
? new FunctionValueProcessor(element => element?.[keySpec])
|
|
58
|
+
: keyArg;
|
|
59
|
+
|
|
60
|
+
return new ComposedValueProcessor(
|
|
61
|
+
new EachExecutor(
|
|
62
|
+
keyExtractor,
|
|
63
|
+
(input) => {
|
|
64
|
+
if (!Array.isArray(input)) {
|
|
65
|
+
throw new ConstraintError(`$group-by requires an array, got ${formatValue(input)}`);
|
|
66
|
+
}
|
|
67
|
+
return input;
|
|
68
|
+
},
|
|
69
|
+
(keys, input) => {
|
|
70
|
+
const result = {};
|
|
71
|
+
for (let i = 0; i < input.length; i++) {
|
|
72
|
+
const key = keys[i];
|
|
73
|
+
if (key === undefined) continue;
|
|
74
|
+
const groupKey = String(key);
|
|
75
|
+
if (!result[groupKey]) result[groupKey] = [];
|
|
76
|
+
result[groupKey].push(input[i]);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
{'$group-by': keySpec}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
};
|