@clementine-solutions/jane-io 1.0.1 → 1.0.3
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/dist/core/analysis/diff.js +88 -0
- package/dist/core/analysis/explain.js +117 -0
- package/dist/core/analysis/index.js +26 -0
- package/dist/core/analysis/replay.js +68 -0
- package/dist/core/analysis/telemetry.js +123 -0
- package/dist/core/boundary-rules/at-most-one.js +38 -0
- package/dist/core/boundary-rules/conditionally-required.js +44 -0
- package/dist/core/boundary-rules/date-range.js +39 -0
- package/dist/core/boundary-rules/index.js +21 -0
- package/dist/core/boundary-rules/mutually-exclusive.js +38 -0
- package/dist/core/boundary-rules/no-unknown-fields.js +39 -0
- package/dist/core/boundary-rules/require-all.js +39 -0
- package/dist/core/boundary-rules/require-one.js +41 -0
- package/dist/core/common/events.js +82 -0
- package/dist/core/common/fluent.js +429 -0
- package/dist/core/common/index.js +31 -0
- package/dist/core/common/policy.js +550 -0
- package/dist/core/common/utilities.js +177 -0
- package/dist/core/common/wildcard.js +63 -0
- package/dist/core/field-path/construct.js +189 -0
- package/dist/core/field-path/format.js +154 -0
- package/dist/core/field-path/index.js +26 -0
- package/dist/core/field-path/utilities.js +138 -0
- package/dist/core/field-path/walk.js +80 -0
- package/dist/core/fluent-registry.js +151 -0
- package/dist/core/normalizers/array/compact-sparse-array.js +40 -0
- package/dist/core/normalizers/array/flatten-one-level.js +45 -0
- package/dist/core/normalizers/array/remove-empty-string-items.js +34 -0
- package/dist/core/normalizers/array/remove-null-items.js +34 -0
- package/dist/core/normalizers/array/remove-undefined-items.js +34 -0
- package/dist/core/normalizers/date/invalid-date-to-undefined.js +35 -0
- package/dist/core/normalizers/index.js +46 -0
- package/dist/core/normalizers/normalizer-register.js +41 -0
- package/dist/core/normalizers/number/infinity-to-undefined.js +35 -0
- package/dist/core/normalizers/number/nan-to-undefined.js +34 -0
- package/dist/core/normalizers/number/normalize-negative-zero.js +33 -0
- package/dist/core/normalizers/object/remove-empty-array-keys.js +38 -0
- package/dist/core/normalizers/object/remove-empty-object-keys.js +42 -0
- package/dist/core/normalizers/object/remove-empty-string-keys.js +37 -0
- package/dist/core/normalizers/object/remove-null-keys.js +37 -0
- package/dist/core/normalizers/object/remove-undefined-keys.js +37 -0
- package/dist/core/normalizers/string/collapse-whitespace.js +35 -0
- package/dist/core/normalizers/string/empty-to-undefined.js +33 -0
- package/dist/core/normalizers/string/trim.js +34 -0
- package/dist/core/parsers/index.js +43 -0
- package/dist/core/parsers/parse-array-string.js +36 -0
- package/dist/core/parsers/parse-bigint-string.js +33 -0
- package/dist/core/parsers/parse-binary-string.js +33 -0
- package/dist/core/parsers/parse-boolean-string.js +27 -0
- package/dist/core/parsers/parse-date-string.js +30 -0
- package/dist/core/parsers/parse-duration-string.js +37 -0
- package/dist/core/parsers/parse-hex-string.js +29 -0
- package/dist/core/parsers/parse-integer-string.js +30 -0
- package/dist/core/parsers/parse-json-string.js +35 -0
- package/dist/core/parsers/parse-numeric-string.js +29 -0
- package/dist/core/parsers/parse-object-string.js +36 -0
- package/dist/core/parsers/parse-octal-string.js +33 -0
- package/dist/core/parsers/parse-scientific-notation-string.js +30 -0
- package/dist/core/parsers/parse-url-string.js +36 -0
- package/dist/core/pipeline/boundary.js +256 -0
- package/dist/core/pipeline/contain.js +339 -0
- package/dist/core/pipeline/index.js +37 -0
- package/dist/core/pipeline/normalize.js +76 -0
- package/dist/core/pipeline/parse.js +91 -0
- package/dist/core/pipeline/pipeline.js +418 -0
- package/dist/core/pipeline/scan.js +115 -0
- package/dist/core/pipeline/validate.js +74 -0
- package/dist/core/scanners/any/scan-for-sentinels.js +35 -0
- package/dist/core/scanners/array/array-is-deep.js +38 -0
- package/dist/core/scanners/array/array-is-heterogenous.js +39 -0
- package/dist/core/scanners/array/array-is-large.js +32 -0
- package/dist/core/scanners/bigint/bigint-is-large.js +34 -0
- package/dist/core/scanners/bigint/bigint-not-safe.js +34 -0
- package/dist/core/scanners/date/date-is-before-epoch.js +32 -0
- package/dist/core/scanners/date/date-is-far-future.js +32 -0
- package/dist/core/scanners/date/date-is-invalid.js +31 -0
- package/dist/core/scanners/index.js +58 -0
- package/dist/core/scanners/number/number-is-infinite.js +31 -0
- package/dist/core/scanners/number/number-is-nan.js +31 -0
- package/dist/core/scanners/number/number-is-too-large.js +33 -0
- package/dist/core/scanners/number/number-is-unsafe-integer.js +31 -0
- package/dist/core/scanners/object/object-has-circular-references.js +43 -0
- package/dist/core/scanners/object/object-has-many-keys.js +33 -0
- package/dist/core/scanners/object/object-is-deep.js +38 -0
- package/dist/core/scanners/scanner-registry.js +36 -0
- package/dist/core/scanners/string/string-has-unsafe-unicode.js +32 -0
- package/dist/core/scanners/string/string-has-whitespace-edges.js +31 -0
- package/dist/core/scanners/string/string-is-long.js +32 -0
- package/dist/core/scanners/unknown/unknown-not-scannable.js +34 -0
- package/dist/core/shapes/analysis.js +11 -0
- package/dist/core/shapes/boundary.js +11 -0
- package/dist/core/shapes/events.js +10 -0
- package/dist/core/shapes/field-path.js +10 -0
- package/dist/core/shapes/index.js +11 -0
- package/dist/core/shapes/normalize.js +11 -0
- package/dist/core/shapes/parse.js +11 -0
- package/dist/core/shapes/pipeline.js +11 -0
- package/dist/core/shapes/policy.js +11 -0
- package/dist/core/shapes/public.js +10 -0
- package/dist/core/shapes/scan.js +11 -0
- package/dist/core/shapes/validate.js +11 -0
- package/dist/core/validators/array/array-max-items.js +42 -0
- package/dist/core/validators/array/array-min-items.js +42 -0
- package/dist/core/validators/array/array.js +34 -0
- package/dist/core/validators/array/excludes.js +47 -0
- package/dist/core/validators/array/has-unique-items.js +46 -0
- package/dist/core/validators/array/includes.js +46 -0
- package/dist/core/validators/array/items-equal.js +42 -0
- package/dist/core/validators/array/no-empty-string-items.js +46 -0
- package/dist/core/validators/array/no-null-items.js +46 -0
- package/dist/core/validators/array/no-undefined-items.js +45 -0
- package/dist/core/validators/array/non-empty-array.js +45 -0
- package/dist/core/validators/array/not-sparse.js +44 -0
- package/dist/core/validators/bigint/bigint-equals.js +57 -0
- package/dist/core/validators/bigint/bigint-max.js +63 -0
- package/dist/core/validators/bigint/bigint-min.js +87 -0
- package/dist/core/validators/bigint/bigint-negative.js +73 -0
- package/dist/core/validators/bigint/bigint-non-negative.js +72 -0
- package/dist/core/validators/bigint/bigint-non-positive.js +72 -0
- package/dist/core/validators/bigint/bigint-positive.js +72 -0
- package/dist/core/validators/bigint/bigint-safe.js +75 -0
- package/dist/core/validators/bigint/bigint.js +38 -0
- package/dist/core/validators/boolean/boolean.js +39 -0
- package/dist/core/validators/boolean/is-false.js +48 -0
- package/dist/core/validators/boolean/is-true.js +48 -0
- package/dist/core/validators/common/is-country-code.js +36 -0
- package/dist/core/validators/common/is-currency-code.js +36 -0
- package/dist/core/validators/common/is-email-strict.js +36 -0
- package/dist/core/validators/common/is-email.js +36 -0
- package/dist/core/validators/common/is-ip.js +37 -0
- package/dist/core/validators/common/is-phone-strict.js +36 -0
- package/dist/core/validators/common/is-phone.js +36 -0
- package/dist/core/validators/common/is-port.js +35 -0
- package/dist/core/validators/common/is-postal-code.js +36 -0
- package/dist/core/validators/common/is-url.js +38 -0
- package/dist/core/validators/common/is-uuid.js +36 -0
- package/dist/core/validators/date/before-epoch.js +56 -0
- package/dist/core/validators/date/date-now-required.js +48 -0
- package/dist/core/validators/date/is-date.js +47 -0
- package/dist/core/validators/date/is-far-future.js +46 -0
- package/dist/core/validators/date/is-future.js +59 -0
- package/dist/core/validators/date/is-past.js +59 -0
- package/dist/core/validators/date/not-after.js +66 -0
- package/dist/core/validators/date/not-before.js +66 -0
- package/dist/core/validators/date/same-day.js +60 -0
- package/dist/core/validators/date/same-month.js +59 -0
- package/dist/core/validators/date/same-year.js +56 -0
- package/dist/core/validators/date/too-early.js +57 -0
- package/dist/core/validators/date/too-late.js +57 -0
- package/dist/core/validators/date/weekday.js +65 -0
- package/dist/core/validators/date/weekend.js +56 -0
- package/dist/core/validators/index.js +139 -0
- package/dist/core/validators/nullish/is-null-or-undefined.js +40 -0
- package/dist/core/validators/nullish/is-null.js +39 -0
- package/dist/core/validators/nullish/is-undefined.js +39 -0
- package/dist/core/validators/number/finite.js +40 -0
- package/dist/core/validators/number/integer.js +40 -0
- package/dist/core/validators/number/less-than.js +39 -0
- package/dist/core/validators/number/max.js +39 -0
- package/dist/core/validators/number/min.js +39 -0
- package/dist/core/validators/number/more-than.js +39 -0
- package/dist/core/validators/number/negative.js +38 -0
- package/dist/core/validators/number/non-negative.js +37 -0
- package/dist/core/validators/number/non-positive.js +37 -0
- package/dist/core/validators/number/number.js +31 -0
- package/dist/core/validators/number/positive.js +38 -0
- package/dist/core/validators/number/safe-integer.js +42 -0
- package/dist/core/validators/object/deep-equals.js +47 -0
- package/dist/core/validators/object/has-key.js +42 -0
- package/dist/core/validators/object/has-value.js +59 -0
- package/dist/core/validators/object/keys-equal.js +47 -0
- package/dist/core/validators/object/max-keys.js +43 -0
- package/dist/core/validators/object/min-keys.js +43 -0
- package/dist/core/validators/object/missing-key.js +42 -0
- package/dist/core/validators/object/no-empty-array-values.js +44 -0
- package/dist/core/validators/object/no-empty-object-values.js +44 -0
- package/dist/core/validators/object/no-null-values.js +44 -0
- package/dist/core/validators/object/no-undefined-values.js +44 -0
- package/dist/core/validators/object/non-empty-object.js +40 -0
- package/dist/core/validators/object/only-keys.js +43 -0
- package/dist/core/validators/object/plain-object.js +35 -0
- package/dist/core/validators/string/alpha-num.js +50 -0
- package/dist/core/validators/string/alpha.js +51 -0
- package/dist/core/validators/string/chars-equal.js +49 -0
- package/dist/core/validators/string/ends-with.js +50 -0
- package/dist/core/validators/string/is-ascii.js +53 -0
- package/dist/core/validators/string/is-printable.js +53 -0
- package/dist/core/validators/string/matches.js +50 -0
- package/dist/core/validators/string/max-length.js +50 -0
- package/dist/core/validators/string/min-length.js +50 -0
- package/dist/core/validators/string/no-lead-space.js +50 -0
- package/dist/core/validators/string/no-repeat-space.js +52 -0
- package/dist/core/validators/string/no-space.js +51 -0
- package/dist/core/validators/string/no-trail-space.js +50 -0
- package/dist/core/validators/string/non-empty.js +48 -0
- package/dist/core/validators/string/not-one-of.js +51 -0
- package/dist/core/validators/string/num-string.js +50 -0
- package/dist/core/validators/string/one-of.js +50 -0
- package/dist/core/validators/string/starts-with.js +50 -0
- package/dist/core/validators/string/string.js +39 -0
- package/dist/core/validators/string/trimmed.js +51 -0
- package/dist/index.js +26 -0
- package/package.json +28 -3
- package/dist/test.d.ts +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | String Has Whitespace Edges
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags strings with leading or trailing whitespace, surfacing
|
|
7
|
+
* subtle formatting or input‑shape inconsistencies early.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Flags strings with leading or trailing whitespace.
|
|
17
|
+
*
|
|
18
|
+
* Edge whitespace often indicates accidental padding, formatting mistakes, or
|
|
19
|
+
* subtle input‑shape inconsistencies. This rule highlights those anomalies
|
|
20
|
+
* before normalization or policy logic is applied.
|
|
21
|
+
*/
|
|
22
|
+
export const stringHasWhitespaceEdges = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'string')
|
|
24
|
+
return [];
|
|
25
|
+
if (raw !== raw.trim()) {
|
|
26
|
+
return [
|
|
27
|
+
scanEvent('warn', 'string.has.whitespace-edges', path, 'String has leading or trailing whitespace.', 'This text has extra spaces at the edges.', { raw }),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | String Is Long
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Warns when text exceeds a conservative length threshold,
|
|
7
|
+
* highlighting oversized or potentially adversarial input.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Warns when a string exceeds a conservative maximum length.
|
|
17
|
+
*
|
|
18
|
+
* Extremely long text can signal malformed payloads, denial‑of‑service
|
|
19
|
+
* attempts, or unbounded user input. This rule surfaces oversized strings
|
|
20
|
+
* early so containment and validation layers can respond safely.
|
|
21
|
+
*/
|
|
22
|
+
export const stringIsLong = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'string')
|
|
24
|
+
return [];
|
|
25
|
+
const max = 10_000;
|
|
26
|
+
if (raw.length > max) {
|
|
27
|
+
return [
|
|
28
|
+
scanEvent('warn', 'string.is.long', path, `String length ${raw.length} exceeds safe threshold ${max}.`, 'This text is very long.', { length: raw.length, max }),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Unknown Not Scannable
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags values whose structural type cannot be determined,
|
|
7
|
+
* surfacing opaque or unpredictable inputs that cannot be
|
|
8
|
+
* scanned safely.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Internal Modules *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
import { detectStructuralType } from '../../../core/pipeline';
|
|
16
|
+
import { scanEvent } from '../../pipeline';
|
|
17
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
18
|
+
|* Implementation *|
|
|
19
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
20
|
+
/**
|
|
21
|
+
* Flags values whose structural type cannot be determined.
|
|
22
|
+
*
|
|
23
|
+
* Unknown values have no predictable shape, traversal semantics, or guarantees
|
|
24
|
+
* about behavior. They may be callable, throw on access, or vary across realms.
|
|
25
|
+
* This rule surfaces opaque inputs early so containment, validation, and policy
|
|
26
|
+
* layers can decide how to handle them safely.
|
|
27
|
+
*/
|
|
28
|
+
export const unknownNotScannable = (raw, path) => {
|
|
29
|
+
if (detectStructuralType(raw) !== 'unknown')
|
|
30
|
+
return [];
|
|
31
|
+
return [
|
|
32
|
+
scanEvent('warn', 'unknown.not.scannable', path, 'Value has an unknown structural type and cannot be scanned safely.', 'This value cannot be scanned safely.', { value: raw }),
|
|
33
|
+
];
|
|
34
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Analysis
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define the structures used for diff, explain,
|
|
7
|
+
* replay, and telemetry analysis.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Boundary
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define the structure, policy surface, and
|
|
7
|
+
* results of boundary evaluation.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Event
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Structured observations emitted by each pipeline phase.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Field Path
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Structural paths that locate positions inside JSON‑like data.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Barrel File
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Central export surface for all shape families in this
|
|
7
|
+
* module.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Normalize
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define mode‑aware value transformations during
|
|
7
|
+
* normalization.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Parse
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define how raw strings are converted into typed
|
|
7
|
+
* values.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Pipeline
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define the structural contracts between
|
|
7
|
+
* pipeline stages.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Policy
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Configuration shapes that control how boundaries interpret
|
|
7
|
+
* and act on events.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Public
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Stable result and input shapes exposed by the public API.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Scan
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define how raw input is inspected and converted
|
|
7
|
+
* into safe JSON‑like form.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Shapes | Validate
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Shapes that define rule‑driven correctness checks during
|
|
7
|
+
* validation.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Array Maximum Items (Array Max Items)
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array does not exceed a maximum number of
|
|
7
|
+
* items.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { validationEvent } from '../../pipeline';
|
|
12
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Validate that an array does not exceed a maximum number of items.
|
|
18
|
+
*
|
|
19
|
+
* This rule checks:
|
|
20
|
+
* - The value is structurally an array
|
|
21
|
+
* - The array length is less than or equal to the provided maximum
|
|
22
|
+
*
|
|
23
|
+
* Emits:
|
|
24
|
+
* - array.not.array
|
|
25
|
+
* - array.too.long
|
|
26
|
+
*
|
|
27
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
28
|
+
*/
|
|
29
|
+
export const arrayMaxItems = (max) => async (value, path) => {
|
|
30
|
+
const structuralType = detectStructuralType(value);
|
|
31
|
+
if (!Array.isArray(value)) {
|
|
32
|
+
return [
|
|
33
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (value.length > max) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.too.long', path, `Array length ${value.length} must be ≤ ${max}.`, `Please provide no more than ${max} items.`, { value, expected: `≤ ${max}`, actual: value.length }),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Array Minimum Items (Array Min Items)
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array contains at least a minimum number of
|
|
7
|
+
* items.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { validationEvent } from '../../pipeline';
|
|
12
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Validate that an array contains at least a minimum number of items.
|
|
18
|
+
*
|
|
19
|
+
* This rule checks:
|
|
20
|
+
* - The value is structurally an array
|
|
21
|
+
* - The array length is greater than or equal to the provided minimum
|
|
22
|
+
*
|
|
23
|
+
* Emits:
|
|
24
|
+
* - array.not.array
|
|
25
|
+
* - array.too.short
|
|
26
|
+
*
|
|
27
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
28
|
+
*/
|
|
29
|
+
export const arrayMinItems = (min) => async (value, path) => {
|
|
30
|
+
const structuralType = detectStructuralType(value);
|
|
31
|
+
if (!Array.isArray(value)) {
|
|
32
|
+
return [
|
|
33
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (value.length < min) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.too.short', path, `Array length ${value.length} must be ≥ ${min}.`, `Please provide at least ${min} items.`, { value, expected: `≥ ${min}`, actual: value.length }),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Array
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that a value is structurally an array.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
import { validationEvent } from '../../pipeline';
|
|
11
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Validate that a value is structurally an array.
|
|
17
|
+
*
|
|
18
|
+
* This rule checks:
|
|
19
|
+
* - The value is an array according to JavaScript semantics
|
|
20
|
+
*
|
|
21
|
+
* Emits:
|
|
22
|
+
* - array.not.array
|
|
23
|
+
*
|
|
24
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
25
|
+
*/
|
|
26
|
+
export const array = async (value, path) => {
|
|
27
|
+
const structuralType = detectStructuralType(value);
|
|
28
|
+
if (!Array.isArray(value)) {
|
|
29
|
+
return [
|
|
30
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Excludes
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array does not include a specific
|
|
7
|
+
* disallowed item.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { validationEvent } from '../../pipeline';
|
|
12
|
+
import { safeStringify } from '../../common';
|
|
13
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
14
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
15
|
+
|* Implementation *|
|
|
16
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
17
|
+
/**
|
|
18
|
+
* Validate that an array does not include a specific disallowed item.
|
|
19
|
+
*
|
|
20
|
+
* This rule checks:
|
|
21
|
+
* - The value is structurally an array
|
|
22
|
+
* - The array does not contain the provided item (using Array.prototype.includes)
|
|
23
|
+
*
|
|
24
|
+
* Emits:
|
|
25
|
+
* - array.not.array
|
|
26
|
+
* - array.has.invalid-value
|
|
27
|
+
*
|
|
28
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
29
|
+
*/
|
|
30
|
+
export const excludes = (item) => async (value, path) => {
|
|
31
|
+
const structuralType = detectStructuralType(value);
|
|
32
|
+
if (!Array.isArray(value)) {
|
|
33
|
+
return [
|
|
34
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
if (value.includes(item)) {
|
|
38
|
+
return [
|
|
39
|
+
validationEvent('error', 'array.has.invalid-value', path, `Array must not include ${safeStringify(item)}.`, `Please remove the disallowed item.`, {
|
|
40
|
+
value,
|
|
41
|
+
expected: `exclude ${safeStringify(item)}`,
|
|
42
|
+
actual: value,
|
|
43
|
+
}),
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
return [];
|
|
47
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Has Unique Items
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array contains only unique items.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
import { validationEvent } from '../../pipeline';
|
|
11
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Validate that an array contains only unique items.
|
|
17
|
+
*
|
|
18
|
+
* This rule checks:
|
|
19
|
+
* - The value is structurally an array
|
|
20
|
+
* - The array does not contain duplicate items (using reference and value equality via Set)
|
|
21
|
+
*
|
|
22
|
+
* Emits:
|
|
23
|
+
* - array.not.array
|
|
24
|
+
* - array.not.unique
|
|
25
|
+
*
|
|
26
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
27
|
+
*/
|
|
28
|
+
export const hasUniqueItems = async (value, path) => {
|
|
29
|
+
const structuralType = detectStructuralType(value);
|
|
30
|
+
if (!Array.isArray(value)) {
|
|
31
|
+
return [
|
|
32
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
const uniqueSet = new Set(value);
|
|
36
|
+
if (uniqueSet.size !== value.length) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.not.unique', path, `Array must contain only unique items.`, `Please remove duplicate items.`, {
|
|
39
|
+
value,
|
|
40
|
+
expected: 'unique items',
|
|
41
|
+
actual: 'duplicates found',
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Includes
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array includes a specific required item.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
import { validationEvent } from '../../pipeline';
|
|
11
|
+
import { safeStringify } from '../../common';
|
|
12
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Validate that an array includes a specific required item.
|
|
18
|
+
*
|
|
19
|
+
* This rule checks:
|
|
20
|
+
* - The value is structurally an array
|
|
21
|
+
* - The array contains the provided item (using Array.prototype.includes)
|
|
22
|
+
*
|
|
23
|
+
* Emits:
|
|
24
|
+
* - array.not.array
|
|
25
|
+
* - array.is.missing-value
|
|
26
|
+
*
|
|
27
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
28
|
+
*/
|
|
29
|
+
export const includes = (item) => async (value, path) => {
|
|
30
|
+
const structuralType = detectStructuralType(value);
|
|
31
|
+
if (!Array.isArray(value)) {
|
|
32
|
+
return [
|
|
33
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (!value.includes(item)) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.is.missing-value', path, `Array must include ${safeStringify(item)}.`, `Please include the required item.`, {
|
|
39
|
+
value,
|
|
40
|
+
expected: `includes ${safeStringify(item)}`,
|
|
41
|
+
actual: value,
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | Items Equal
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array contains exactly the specified
|
|
7
|
+
* number of items.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { validationEvent } from '../../pipeline';
|
|
12
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Validate that an array contains exactly the specified number of items.
|
|
18
|
+
*
|
|
19
|
+
* This rule checks:
|
|
20
|
+
* - The value is structurally an array
|
|
21
|
+
* - The array length matches the exact required count
|
|
22
|
+
*
|
|
23
|
+
* Emits:
|
|
24
|
+
* - array.not.array
|
|
25
|
+
* - array.has.invalid-length
|
|
26
|
+
*
|
|
27
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
28
|
+
*/
|
|
29
|
+
export const itemsEqual = (exact) => async (value, path) => {
|
|
30
|
+
const structuralType = detectStructuralType(value);
|
|
31
|
+
if (!Array.isArray(value)) {
|
|
32
|
+
return [
|
|
33
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (value.length !== exact) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.has.invalid-length', path, `Array length ${value.length} must be exactly ${exact}.`, `Please provide exactly ${exact} items.`, { value, expected: exact, actual: value.length }),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | No Empty String Items
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array does not contain empty string items.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
import { validationEvent } from '../../pipeline';
|
|
11
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Validate that an array does not contain empty string items.
|
|
17
|
+
*
|
|
18
|
+
* This rule checks:
|
|
19
|
+
* - The value is structurally an array
|
|
20
|
+
* - No element in the array is an empty string ("")
|
|
21
|
+
*
|
|
22
|
+
* Emits:
|
|
23
|
+
* - array.not.array
|
|
24
|
+
* - array.has.empty-strings
|
|
25
|
+
*
|
|
26
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
27
|
+
*/
|
|
28
|
+
export const noEmptyStringItems = async (value, path) => {
|
|
29
|
+
const structuralType = detectStructuralType(value);
|
|
30
|
+
if (!Array.isArray(value)) {
|
|
31
|
+
return [
|
|
32
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
const containsEmptyString = value.some((item) => item === '');
|
|
36
|
+
if (containsEmptyString) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.has.empty-strings', path, `Array must not contain empty strings.`, `Please remove empty string items.`, {
|
|
39
|
+
value,
|
|
40
|
+
expected: 'no empty strings',
|
|
41
|
+
actual: 'contains empty string',
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Validators | No Null Items
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Validate that an array does not contain null items.
|
|
7
|
+
* @see https://jane-io.com
|
|
8
|
+
* ----------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
import { validationEvent } from '../../pipeline';
|
|
11
|
+
import { detectStructuralType } from '../../pipeline/scan';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Validate that an array does not contain null items.
|
|
17
|
+
*
|
|
18
|
+
* This rule checks:
|
|
19
|
+
* - The value is structurally an array
|
|
20
|
+
* - No element in the array is strictly equal to null
|
|
21
|
+
*
|
|
22
|
+
* Emits:
|
|
23
|
+
* - array.not.array
|
|
24
|
+
* - array.has.null-items
|
|
25
|
+
*
|
|
26
|
+
* This rule is async-compatible and returns a readonly array of JaneEvent objects.
|
|
27
|
+
*/
|
|
28
|
+
export const noNullItems = async (value, path) => {
|
|
29
|
+
const structuralType = detectStructuralType(value);
|
|
30
|
+
if (!Array.isArray(value)) {
|
|
31
|
+
return [
|
|
32
|
+
validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${structuralType}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: structuralType }),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
const containsNull = value.some((item) => item === null);
|
|
36
|
+
if (containsNull) {
|
|
37
|
+
return [
|
|
38
|
+
validationEvent('error', 'array.has.null-items', path, `Array must not contain null values.`, `Please remove null items.`, {
|
|
39
|
+
value,
|
|
40
|
+
expected: 'no null items',
|
|
41
|
+
actual: 'contains null',
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
};
|