@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,235 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Built-in country rules. Each entry maps a country calling code to:
|
|
5
|
+
* - `lengths` — accepted subscriber digit counts (after country code)
|
|
6
|
+
* - `validate` — optional regex applied to subscriber digits
|
|
7
|
+
* - `national` — `#`-template for national formatting
|
|
8
|
+
* - `international` — `#`-template for international formatting (after `+CC `)
|
|
9
|
+
*
|
|
10
|
+
* Users can extend via the `countries` parameter; custom entries are merged
|
|
11
|
+
* over these defaults (allowing override). Custom entries do not require
|
|
12
|
+
* `validate` — only `lengths` and templates are needed.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_COUNTRY_RULES = {
|
|
15
|
+
// NANP: area code (NPA) and exchange (NXX) cannot start with 0 or 1
|
|
16
|
+
'1': {
|
|
17
|
+
lengths: [10],
|
|
18
|
+
validate: /^[2-9]\d{2}[2-9]\d{6}$/,
|
|
19
|
+
national: '(###) ###-####',
|
|
20
|
+
international: '### ### ####',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Strip characters commonly used as phone number formatting.
|
|
26
|
+
* Preserves digits and a leading `+`.
|
|
27
|
+
* @param {string} value
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function stripFormatting(value) {
|
|
31
|
+
const trimmed = value.trim();
|
|
32
|
+
if (trimmed.startsWith('+')) {
|
|
33
|
+
return '+' + trimmed.slice(1).replace(/\D/g, '');
|
|
34
|
+
}
|
|
35
|
+
return trimmed.replace(/\D/g, '');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Replace each `#` in a template with the next digit from `digits`.
|
|
40
|
+
* @param {string} digits
|
|
41
|
+
* @param {string} template
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
function applyTemplate(digits, template) {
|
|
45
|
+
let i = 0;
|
|
46
|
+
return template.replace(/#/g, () => digits[i++] ?? '');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* ## $phone
|
|
51
|
+
*
|
|
52
|
+
* Validates and normalizes a phone number string.
|
|
53
|
+
*
|
|
54
|
+
* Strips common formatting (spaces, dashes, dots, parentheses, slashes) and
|
|
55
|
+
* validates the remaining digits against country-specific rules when available,
|
|
56
|
+
* or generic E.164 length rules otherwise.
|
|
57
|
+
*
|
|
58
|
+
* **Output format** is controlled by the `international` parameter:
|
|
59
|
+
* - When `false` (default): national format for the default country
|
|
60
|
+
* (e.g. `(212) 555-1234` for country code `1`).
|
|
61
|
+
* - When `true`: international format with country code prefix
|
|
62
|
+
* (e.g. `+1 212 555 1234`).
|
|
63
|
+
*
|
|
64
|
+
* Numbers without a `+` prefix are assumed to belong to the default `country`.
|
|
65
|
+
* A leading country code without `+` is recognized when it produces a valid
|
|
66
|
+
* subscriber length (e.g. `12125551234` is treated as `+1 2125551234`).
|
|
67
|
+
*
|
|
68
|
+
* **NANP validation (country code `1`):** area codes and exchanges must not
|
|
69
|
+
* start with `0` or `1`, matching North American Numbering Plan rules.
|
|
70
|
+
*
|
|
71
|
+
* **Not supported:** extensions, vanity letters (1-800-FLOWERS), international
|
|
72
|
+
* dialing prefixes (`00`, `011`), short codes, or emergency numbers. This
|
|
73
|
+
* processor targets typical subscriber phone numbers as entered in forms or
|
|
74
|
+
* configuration files.
|
|
75
|
+
*
|
|
76
|
+
* ### Parameters
|
|
77
|
+
* - `international` (boolean, default `false`): When `false`, only numbers
|
|
78
|
+
* matching the default `country` code are accepted, and output uses the
|
|
79
|
+
* national format. When `true`, any valid international number is accepted,
|
|
80
|
+
* and output uses the international format with `+CC` prefix.
|
|
81
|
+
* - `country` (string, default `'1'`): Default country calling code applied
|
|
82
|
+
* to numbers entered without a `+` prefix.
|
|
83
|
+
* - `countries` (object, default `null`): Optional map of country calling
|
|
84
|
+
* codes to rule objects, merged over the built-in rules. Each rule object
|
|
85
|
+
* may contain:
|
|
86
|
+
* - `lengths` (number[]) — accepted subscriber digit counts
|
|
87
|
+
* - `validate` (RegExp, optional) — pattern the subscriber digits must match
|
|
88
|
+
* - `national` (string) — `#`-template for national formatting
|
|
89
|
+
* - `international` (string) — `#`-template for international formatting
|
|
90
|
+
*
|
|
91
|
+
* ### Example
|
|
92
|
+
* ```js
|
|
93
|
+
* // Basic US number validation and national formatting
|
|
94
|
+
* new Schema('string').validator('$phone')
|
|
95
|
+
*
|
|
96
|
+
* // Accept international numbers
|
|
97
|
+
* new Schema('string').validator({'$phone': {international: true}})
|
|
98
|
+
*
|
|
99
|
+
* // Default to UK numbers
|
|
100
|
+
* new Schema('string').validator({'$phone': {
|
|
101
|
+
* country: '44',
|
|
102
|
+
* countries: {
|
|
103
|
+
* '44': {lengths: [10], national: '#### ### ####', international: '#### ### ####'}
|
|
104
|
+
* }
|
|
105
|
+
* }})
|
|
106
|
+
*
|
|
107
|
+
* // Compact storage: compose with space/punctuation stripping
|
|
108
|
+
* new Schema('string').normalizer({$pipeline: ['$trim', '$phone']})
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
112
|
+
*/
|
|
113
|
+
export const PHONE_CONSTRAINT = {
|
|
114
|
+
keyword: 'phone',
|
|
115
|
+
parameters: [
|
|
116
|
+
{ parameter: 'international', type: 'boolean', default: false },
|
|
117
|
+
{ parameter: 'country', default: '1' },
|
|
118
|
+
{ parameter: 'countries', default: null },
|
|
119
|
+
],
|
|
120
|
+
|
|
121
|
+
process: (value, _target, _location, options) => {
|
|
122
|
+
const { international, country, countries: customCountries } = options.args;
|
|
123
|
+
const rules = customCountries
|
|
124
|
+
? { ...DEFAULT_COUNTRY_RULES, ...customCountries }
|
|
125
|
+
: DEFAULT_COUNTRY_RULES;
|
|
126
|
+
|
|
127
|
+
const stripped = stripFormatting(value);
|
|
128
|
+
|
|
129
|
+
// After stripping, must be digits with optional leading +
|
|
130
|
+
if (!stripped || !/^\+?\d+$/.test(stripped)) {
|
|
131
|
+
throw new ConstraintError('Invalid phone number format');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let countryCode;
|
|
135
|
+
let subscriber = '';
|
|
136
|
+
|
|
137
|
+
if (stripped.startsWith('+')) {
|
|
138
|
+
const digits = stripped.slice(1);
|
|
139
|
+
|
|
140
|
+
// Match known country codes (ITU codes are prefix-free, 1-3 digits)
|
|
141
|
+
let matched = false;
|
|
142
|
+
for (const len of [1, 2, 3]) {
|
|
143
|
+
if (len > digits.length) break;
|
|
144
|
+
const candidate = digits.slice(0, len);
|
|
145
|
+
if (rules[candidate]) {
|
|
146
|
+
countryCode = candidate;
|
|
147
|
+
subscriber = digits.slice(len);
|
|
148
|
+
matched = true;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!matched) {
|
|
154
|
+
if (!international) {
|
|
155
|
+
throw new ConstraintError(
|
|
156
|
+
`Phone number country code does not match +${country}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
// Unknown country — generic E.164 validation (total 7-15 digits)
|
|
160
|
+
if (digits.length < 7 || digits.length > 15) {
|
|
161
|
+
throw new ConstraintError('Invalid phone number length');
|
|
162
|
+
}
|
|
163
|
+
return '+' + digits;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// No + prefix — match against default country
|
|
168
|
+
const countryRules = rules[country];
|
|
169
|
+
countryCode = country;
|
|
170
|
+
|
|
171
|
+
if (countryRules) {
|
|
172
|
+
const withCC = countryRules.lengths.map(l => l + country.length);
|
|
173
|
+
if (withCC.includes(stripped.length) && stripped.startsWith(country)) {
|
|
174
|
+
// Leading country code without + (e.g. 12125551234)
|
|
175
|
+
subscriber = stripped.slice(country.length);
|
|
176
|
+
}
|
|
177
|
+
else if (countryRules.lengths.includes(stripped.length)) {
|
|
178
|
+
// National number (e.g. 2125551234)
|
|
179
|
+
subscriber = stripped;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
throw new ConstraintError(
|
|
183
|
+
`Invalid phone number length for country code +${country}`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// No rules for default country — accept digits as subscriber
|
|
189
|
+
subscriber = stripped;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Reject international numbers when not accepted
|
|
194
|
+
if (!international && countryCode !== country) {
|
|
195
|
+
throw new ConstraintError(
|
|
196
|
+
`International numbers not accepted; expected country code +${country}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Country-specific validation
|
|
201
|
+
const countryRules = rules[countryCode];
|
|
202
|
+
if (countryRules) {
|
|
203
|
+
if (!countryRules.lengths.includes(subscriber.length)) {
|
|
204
|
+
throw new ConstraintError(
|
|
205
|
+
`Invalid phone number length for country code +${countryCode}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
if (countryRules.validate && !countryRules.validate.test(subscriber)) {
|
|
209
|
+
throw new ConstraintError(
|
|
210
|
+
`Invalid phone number for country code +${countryCode}`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Generic E.164: total digits (cc + subscriber) must be 7-15
|
|
216
|
+
const total = countryCode.length + subscriber.length;
|
|
217
|
+
if (total < 7 || total > 15) {
|
|
218
|
+
throw new ConstraintError('Invalid phone number length');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Format output
|
|
223
|
+
if (international) {
|
|
224
|
+
if (countryRules?.international) {
|
|
225
|
+
return `+${countryCode} ${applyTemplate(subscriber, countryRules.international)}`;
|
|
226
|
+
}
|
|
227
|
+
return `+${countryCode}${subscriber}`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (countryRules?.national) {
|
|
231
|
+
return applyTemplate(subscriber, countryRules.national);
|
|
232
|
+
}
|
|
233
|
+
return subscriber;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
import { ComposedValueProcessor } from '../../value-processor/composed-value-processor.js';
|
|
3
|
+
import { FunctionValueProcessor } from '../../value-processor/function-value-processor.js';
|
|
4
|
+
import { ArrayExecutor } from '../../executor/array-executor.js';
|
|
5
|
+
import { map } from '../../helpers/object.js';
|
|
6
|
+
import { ConstraintError, SchemaError } from '../../errors.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ## $pick
|
|
10
|
+
*
|
|
11
|
+
* Returns a new object or dense array containing only the specified keys/indices from the input.
|
|
12
|
+
* Keys not present in the input are silently omitted from the result.
|
|
13
|
+
* For arrays, numeric indices are selected and the result is a dense (packed) array.
|
|
14
|
+
*
|
|
15
|
+
* ### Parameters
|
|
16
|
+
* - Array of key names or indices (string[]|number[], required): The keys/indices to retain.
|
|
17
|
+
*
|
|
18
|
+
* ### Example
|
|
19
|
+
* ```js
|
|
20
|
+
* // Retain only 'id' and 'name' from an object
|
|
21
|
+
* new Schema('object').transformer({$pick: ['id', 'name']})
|
|
22
|
+
* // {id: 1, name: 'Alice', secret: 'xyz'} → {id: 1, name: 'Alice'}
|
|
23
|
+
*
|
|
24
|
+
* // Select the first and third elements from an array
|
|
25
|
+
* new Schema('array').transformer({$pick: [0, 2]})
|
|
26
|
+
* // ['a', 'b', 'c', 'd'] → ['a', 'c']
|
|
27
|
+
*
|
|
28
|
+
* // Strip sensitive fields from a user record before returning
|
|
29
|
+
* new Schema('object').transformer({$pick: ['id', 'username', 'email', 'role']})
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
33
|
+
*/
|
|
34
|
+
export const PICK_OPERATOR = {
|
|
35
|
+
keyword: 'pick',
|
|
36
|
+
|
|
37
|
+
build: (args) => {
|
|
38
|
+
if (!Array.isArray(args) || args.length === 0) {
|
|
39
|
+
throw new SchemaError('$pick requires a non-empty array of key names');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const argsSpec = map(args, v => v.spec);
|
|
43
|
+
|
|
44
|
+
return new FunctionValueProcessor(
|
|
45
|
+
(value, _target, location, options) => {
|
|
46
|
+
const keys = Array.isArray(options.args) ? options.args : [];
|
|
47
|
+
if (typeof value !== 'object' || value === null) {
|
|
48
|
+
throw new ConstraintError(`$pick requires an object or array input`, {location});
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
return keys.filter(k => k >= 0 && k < value.length).map(k => value[k]);
|
|
52
|
+
}
|
|
53
|
+
const result = {};
|
|
54
|
+
for (const k of keys) {
|
|
55
|
+
if (k in value) result[k] = value[k];
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
},
|
|
59
|
+
new ComposedValueProcessor(new ArrayExecutor(args), argsSpec)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { PipelineExecutor } from '../../executor/pipeline-executor.js';
|
|
2
|
+
|
|
3
|
+
import { ComposedValueProcessor } from '../../value-processor/composed-value-processor.js';
|
|
4
|
+
import { map } from '../../helpers/object.js';
|
|
5
|
+
import { ResolverError } from '../../errors.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @import {ValueProcessorDefinition} from '../../value-processor/value-processor.js'
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ## $pipeline
|
|
13
|
+
*
|
|
14
|
+
* Executes a sequence of processors in order, passing the output of each processor
|
|
15
|
+
* as input to the next. The final processor's output becomes the result.
|
|
16
|
+
*
|
|
17
|
+
* **Note**: Handler arrays (normalizers, validators, etc.) implicitly create pipelines,
|
|
18
|
+
* so this processor is rarely used directly. It's primarily used internally by the
|
|
19
|
+
* schema compiler to aggregate handler arrays into single compiled processors.
|
|
20
|
+
*
|
|
21
|
+
* ### Parameters
|
|
22
|
+
* - `processors` (`Array<ProcessorSpec>`, required): Array of processor specifications to execute in sequence.
|
|
23
|
+
* Each element can be a string keyword (e.g., `'$trim'`), a parameterized processor object
|
|
24
|
+
* (e.g., `{$range: {min: 0}}`), a RegExp, or a function.
|
|
25
|
+
*
|
|
26
|
+
* **Behavior**: Processors execute left-to-right. If any processor throws an error, the pipeline
|
|
27
|
+
* stops and the error propagates. Each processor receives the output of the previous processor
|
|
28
|
+
* as its input value.
|
|
29
|
+
*
|
|
30
|
+
* ### Example
|
|
31
|
+
* ```js
|
|
32
|
+
* // Explicit pipeline (equivalent to passing an array to .normalizer())
|
|
33
|
+
* new Schema('string').normalizer({$pipeline: ['$trim', '$lowercase', '$alphanum']})
|
|
34
|
+
*
|
|
35
|
+
* // Use $pipeline inside a conditional to chain processors on a branch
|
|
36
|
+
* new Schema('string').transformer({
|
|
37
|
+
* $if: [
|
|
38
|
+
* '$numeric',
|
|
39
|
+
* {$pipeline: ['$number', {$clamp: {min: 0, max: 100}}]},
|
|
40
|
+
* ]
|
|
41
|
+
* })
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @type {ValueProcessorDefinition}
|
|
45
|
+
*/
|
|
46
|
+
export const PIPELINE_OPERATOR = {
|
|
47
|
+
keyword: 'pipeline',
|
|
48
|
+
build: (args) => {
|
|
49
|
+
if (!Array.isArray(args)) {
|
|
50
|
+
throw new ResolverError('$pipeline requires an array of processors');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const descriptions = args.map(arg => arg.description ?? '').filter(Boolean);
|
|
54
|
+
const description = descriptions.length > 1
|
|
55
|
+
? descriptions.map(d => (d.includes('|') || d.includes('&')) ? `(${d})` : d).join(' >> ')
|
|
56
|
+
: descriptions[0]
|
|
57
|
+
const spec = {$pipeline: map(args, arg => arg.spec)}
|
|
58
|
+
|
|
59
|
+
return new ComposedValueProcessor(new PipelineExecutor(args), spec, description);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## $port
|
|
5
|
+
*
|
|
6
|
+
* Validates that a value is a valid TCP/UDP port number (1-65535).
|
|
7
|
+
* Accepts numeric values or strings that can be converted to numbers.
|
|
8
|
+
* Returns the value as a number or a string, depending on the underlying schema.
|
|
9
|
+
* (defaults to a number).
|
|
10
|
+
*
|
|
11
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
12
|
+
*/
|
|
13
|
+
export const PORT_CONSTRAINT = {
|
|
14
|
+
keyword: 'port',
|
|
15
|
+
process: (value, _target, location) => {
|
|
16
|
+
const num = Number(value);
|
|
17
|
+
if (!(Number.isInteger(num) && num >= 1 && num <= 65535)) {
|
|
18
|
+
throw new ConstraintError('Port must be between 1 and 65535');
|
|
19
|
+
}
|
|
20
|
+
return location.schema.options.type === 'string'? `${num}` : num;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ConstraintError } from '../../errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## $positive
|
|
5
|
+
*
|
|
6
|
+
* Validates that a numeric value is positive (greater than 0).
|
|
7
|
+
* Input must already be a number; use `$number` in a prior normalizer if coercion from string is needed.
|
|
8
|
+
*
|
|
9
|
+
* See also:
|
|
10
|
+
* - `$negative` to enforce the opposite constraint
|
|
11
|
+
* - `$range` if you want "non-negative" ( greater than or equal to 0) semantics.
|
|
12
|
+
*
|
|
13
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
14
|
+
*/
|
|
15
|
+
export const POSITIVE_CONSTRAINT = {
|
|
16
|
+
keyword: 'positive',
|
|
17
|
+
process: (value) => {
|
|
18
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
|
|
19
|
+
throw new ConstraintError('Must be a positive number');
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CompiledSchema } from '../../compiled-schema.js';
|
|
2
|
+
import { SchemaError } from '../../errors.js';
|
|
3
|
+
import { formatValue } from '../../helpers/format.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ## $process
|
|
7
|
+
*
|
|
8
|
+
* Process the incoming value according to the provided schema
|
|
9
|
+
*
|
|
10
|
+
* Important note: the provided schema is run in isolation in a private local context, which means
|
|
11
|
+
* that it (and its handlers) have no access to the outer schema or the global target value, and all
|
|
12
|
+
* paths are relative to the root of the provided schema.
|
|
13
|
+
*
|
|
14
|
+
* ### Parameters
|
|
15
|
+
* - `schema` (CompiledSchema, required): the compiled schema to apply to the input value.
|
|
16
|
+
* Any `Schema` found in a handler pipeline will be automatically compiled;
|
|
17
|
+
* Use `$compile` to produce a `CompiledSchema` from a `Schema` literal value.
|
|
18
|
+
*
|
|
19
|
+
* ### Example
|
|
20
|
+
* ```js
|
|
21
|
+
* import { Schema, SchemaResolver } from '@versionzero/schema';
|
|
22
|
+
*
|
|
23
|
+
* // Compile a reusable sub-schema and run values through it
|
|
24
|
+
* const resolver = new SchemaResolver();
|
|
25
|
+
* const portSchema = await resolver.compile(
|
|
26
|
+
* new Schema('number').validator({$range: {min: 1, max: 65535}})
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* // portSchema is automatically compiled:
|
|
30
|
+
* new Schema('object', {
|
|
31
|
+
* port: new Schema('any').validator({$process: {schema: portSchema}}),
|
|
32
|
+
* })
|
|
33
|
+
*
|
|
34
|
+
* // Use $compile inline to compile-then-process in a single pipeline
|
|
35
|
+
* const mySchema = new Schema('string').validator('$non-empty');
|
|
36
|
+
* new Schema('any').normalizer([{$compile: {$literal: mySchema}}, '$process'])
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @type {import('../../value-processor/value-processor.js').ValueProcessorDefinition}
|
|
40
|
+
*/
|
|
41
|
+
export const PROCESS_OPERATOR = {
|
|
42
|
+
keyword: 'process',
|
|
43
|
+
parameters: [ { parameter: 'schema', required: true } ],
|
|
44
|
+
|
|
45
|
+
process: (value, _target, location, options) => {
|
|
46
|
+
|
|
47
|
+
const schema = options.args.schema;
|
|
48
|
+
|
|
49
|
+
if (!(schema instanceof CompiledSchema)) {
|
|
50
|
+
throw new SchemaError(`Schema argument must be an instance of CompiledSchema, got ${formatValue(schema)})`, {location});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return schema._process(value); // do not pass options, or outer schema context/paths will leak in!
|
|
54
|
+
}
|
|
55
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { SchemaError } from '../../errors.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## $property
|
|
5
|
+
*
|
|
6
|
+
* Extracts a named property value from an object. This operator is useful for accessing
|
|
7
|
+
* nested properties or extracting specific fields during processing pipelines.
|
|
8
|
+
*
|
|
9
|
+
* Returns `undefined` if the current value is not an object or if the property doesn't exist.
|
|
10
|
+
* Throws a `SchemaError` if the specified property name is not defined in the schema.
|
|
11
|
+
*
|
|
12
|
+
* ### Parameters
|
|
13
|
+
* - `name` (string, required): The name of the schema-defined property to extract from the input object.
|
|
14
|
+
* The property must be declared in the current schema; use `$get` for arbitrary path access without
|
|
15
|
+
* schema awareness.
|
|
16
|
+
*
|
|
17
|
+
* ### Example
|
|
18
|
+
* ```js
|
|
19
|
+
* // Conditionally require 'apiKey' only when 'useApiKey' is true
|
|
20
|
+
* new Schema('object', {
|
|
21
|
+
* useApiKey: new Schema('boolean'),
|
|
22
|
+
* apiKey: new Schema('string').validator({
|
|
23
|
+
* $if: [{$property: 'useApiKey'}, '$non-empty']
|
|
24
|
+
* }),
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* // Discriminate a union using a schema property value
|
|
28
|
+
* new Schema('object', {
|
|
29
|
+
* type: new Schema('string'),
|
|
30
|
+
* config: new Schema('any'),
|
|
31
|
+
* }).discriminator({$property: 'type'})
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
35
|
+
*/
|
|
36
|
+
export const PROPERTY_OPERATOR = {
|
|
37
|
+
keyword: 'property',
|
|
38
|
+
parameters: [{parameter: 'name', required: true}],
|
|
39
|
+
process: (value, _target, location, options) => {
|
|
40
|
+
const propertyName = options.args.name;
|
|
41
|
+
if (propertyName === undefined) {
|
|
42
|
+
throw new SchemaError('$property expects a property name', {location})
|
|
43
|
+
}
|
|
44
|
+
if (location.schema.getPropertySchema(propertyName) === undefined) {
|
|
45
|
+
throw new SchemaError(`Unknown $property ${propertyName}`, {location});
|
|
46
|
+
}
|
|
47
|
+
return (typeof value === 'object' && value !== null)? value[propertyName] : undefined;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
import { ConstraintError, ResolverError } from '../../errors.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ## $range
|
|
6
|
+
*
|
|
7
|
+
* Validates that a numeric value falls within the specified range (inclusive).
|
|
8
|
+
* Can specify minimum, maximum, or both bounds.
|
|
9
|
+
*
|
|
10
|
+
* ### Parameters
|
|
11
|
+
* - `min` (number, optional): Minimum value (inclusive). If omitted, no lower bound.
|
|
12
|
+
* - `max` (number, optional): Maximum value (inclusive). If omitted, no upper bound.
|
|
13
|
+
*
|
|
14
|
+
* ### Example
|
|
15
|
+
* ```js
|
|
16
|
+
* // Object form with named parameters
|
|
17
|
+
* new Schema('number').validator({$range: {min: 1, max: 100}})
|
|
18
|
+
*
|
|
19
|
+
* // Array form [min, max]
|
|
20
|
+
* new Schema('number').validator({$range: [1, 65535]})
|
|
21
|
+
*
|
|
22
|
+
* // Only a lower bound (percentage, must be non-negative)
|
|
23
|
+
* new Schema('number').validator({$range: {min: 0}})
|
|
24
|
+
*
|
|
25
|
+
* // Only an upper bound
|
|
26
|
+
* new Schema('number').validator({$range: {max: 255}})
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* See also: `$positive` and `$negative` for common named ranges.
|
|
30
|
+
*
|
|
31
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
32
|
+
*/
|
|
33
|
+
export const RANGE_CONSTRAINT = {
|
|
34
|
+
keyword: 'range',
|
|
35
|
+
parameters: [ { parameter: 'min', type: 'number', default: undefined }, { parameter: 'max', type: 'number', default: undefined } ],
|
|
36
|
+
|
|
37
|
+
process: (value, _target, _location, options) => {
|
|
38
|
+
const { min, max } = options.args;
|
|
39
|
+
|
|
40
|
+
const num = Number(value);
|
|
41
|
+
if (!Number.isFinite(num)) {
|
|
42
|
+
throw new ConstraintError('Value must be a number');
|
|
43
|
+
}
|
|
44
|
+
if (min !== undefined && num < min) {
|
|
45
|
+
throw new ConstraintError(`Value must be at least ${min}`);
|
|
46
|
+
}
|
|
47
|
+
if (max !== undefined && num > max) {
|
|
48
|
+
throw new ConstraintError(`Value must be at most ${max}`);
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
},
|
|
52
|
+
describe: (args) => {
|
|
53
|
+
|
|
54
|
+
if (!args) {
|
|
55
|
+
return undefined; // should never happen
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const minProcessor = (Array.isArray(args)? args[0] : args.min);
|
|
59
|
+
const maxProcessor = (Array.isArray(args)? args[1] : args.max);
|
|
60
|
+
|
|
61
|
+
const min = minProcessor?.description;
|
|
62
|
+
const max = maxProcessor?.description;
|
|
63
|
+
|
|
64
|
+
return min !== undefined && max !== undefined
|
|
65
|
+
? `${min}-${max}`
|
|
66
|
+
: min !== undefined
|
|
67
|
+
? `≥${min}`
|
|
68
|
+
: max !== undefined
|
|
69
|
+
? `≤${max}`
|
|
70
|
+
: undefined
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { deepValue } from '../../helpers/deep.js';
|
|
2
|
+
|
|
3
|
+
import { SchemaError } from '../../errors.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ## $reference
|
|
7
|
+
*
|
|
8
|
+
* Returns the value at the referenced path (relative to the current schema) in the target data, or undefined if not set.
|
|
9
|
+
*
|
|
10
|
+
* Throws a `SchemaError` if the specified path is not defined in the schema.
|
|
11
|
+
*
|
|
12
|
+
* ### Parameters
|
|
13
|
+
* - `path` (string, required): path from the current schema into the top-level target object; must be a valid
|
|
14
|
+
* schema path (dot-separated, supports / for absolute or ^ for parents).
|
|
15
|
+
* - `pending` (boolean, optional, default: false): If true will fall back to any pending value not yet in the target data.
|
|
16
|
+
* - `completed` (boolean, optional, default: false): If true, will only return a value if the reference is completed (useful for checking if all children are handled).
|
|
17
|
+
*
|
|
18
|
+
* ### Example
|
|
19
|
+
* ```js
|
|
20
|
+
* // Validate 'port' is within range only when 'ssl' is enabled at the top level
|
|
21
|
+
* new Schema('object', {
|
|
22
|
+
* ssl: new Schema('boolean'),
|
|
23
|
+
* port: new Schema('number').validator({
|
|
24
|
+
* $if: [{$reference: 'ssl'}, {$range: {min: 443, max: 443}}]
|
|
25
|
+
* }),
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* // Cross-field consistency: confirm 'passwordConfirm' matches 'password'
|
|
29
|
+
* new Schema('object', {
|
|
30
|
+
* password: new Schema('string'),
|
|
31
|
+
* passwordConfirm: new Schema('string').validator(
|
|
32
|
+
* (value, target) => value === target.password || undefined
|
|
33
|
+
* ),
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
* ### See Also
|
|
37
|
+
* - Use `$property` for getting a named child value.
|
|
38
|
+
* - Use `$get` for getting values under the input value (without the path needing to be in the schema.)
|
|
39
|
+
*
|
|
40
|
+
* @type {import("../../value-processor/value-processor.js").ValueProcessorDefinition}
|
|
41
|
+
*/
|
|
42
|
+
export const REFERENCE_OPERATOR = {
|
|
43
|
+
keyword: 'reference',
|
|
44
|
+
parameters: [{parameter: 'path', required: true}, {parameter: 'pending', required: false, default: false}, {parameter: 'completed', required: false, type: 'boolean', default: false}],
|
|
45
|
+
process: (_, target, location, options) => {
|
|
46
|
+
const path = options.args.path;
|
|
47
|
+
if (path === undefined) {
|
|
48
|
+
throw new SchemaError('$reference expects a path')
|
|
49
|
+
}
|
|
50
|
+
const state = options.state.getRelativeState(path);
|
|
51
|
+
|
|
52
|
+
const requireCompleted = options.args.completed;
|
|
53
|
+
|
|
54
|
+
if (state === undefined) {
|
|
55
|
+
if (requireCompleted) {
|
|
56
|
+
return undefined; // welp.
|
|
57
|
+
}
|
|
58
|
+
// We're lost. Maybe we can find it in the target data?
|
|
59
|
+
const resolvedLocation = location.relative(path);
|
|
60
|
+
return resolvedLocation? deepValue(target, resolvedLocation.path) : undefined;
|
|
61
|
+
}
|
|
62
|
+
if (requireCompleted && !state.completed) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
if (state.value !== undefined) {
|
|
66
|
+
return state.value;
|
|
67
|
+
}
|
|
68
|
+
if (options.args.pending) {
|
|
69
|
+
return state.pending;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
},
|
|
73
|
+
/*
|
|
74
|
+
description: `${path}`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
*/
|
|
79
|
+
};
|