@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,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Array Is Heterogeneous
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Warns when an array contains mixed structural types,
|
|
7
|
+
* indicating inconsistent data shape.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
12
|
+
|* Internal Modules *|
|
|
13
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
14
|
+
import { detectStructuralType } from '../../../core/pipeline';
|
|
15
|
+
import { scanEvent } from '../../pipeline';
|
|
16
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
17
|
+
|* Implementation *|
|
|
18
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
19
|
+
/**
|
|
20
|
+
* Flags arrays whose length exceeds a conservative safety threshold.
|
|
21
|
+
*
|
|
22
|
+
* Emits a warning when the list is unusually large, helping prevent
|
|
23
|
+
* excessive memory usage or pathological input shapes during scanning.
|
|
24
|
+
*/
|
|
25
|
+
export const arrayIsHeterogeneous = (raw, path) => {
|
|
26
|
+
if (!Array.isArray(raw))
|
|
27
|
+
return [];
|
|
28
|
+
if (raw.length < 2)
|
|
29
|
+
return [];
|
|
30
|
+
const firstType = detectStructuralType(raw[0]);
|
|
31
|
+
for (let i = 1; i < raw.length; i++) {
|
|
32
|
+
if (detectStructuralType(raw[i]) !== firstType) {
|
|
33
|
+
return [
|
|
34
|
+
scanEvent('warn', 'array.is.heterogeneous', path, 'Array contains mixed element types.', 'This list contains different kinds of values.', { firstType, mixedType: detectStructuralType(raw[i]) }),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Array Is Large
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags arrays whose length exceeds a conservative safety
|
|
7
|
+
* threshold.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Detects containment sentinels produced during safe‑clone operations.
|
|
17
|
+
*
|
|
18
|
+
* Flags any sentinel string as a fatal structural hazard, emitting a
|
|
19
|
+
* scan event that identifies the hazard code and the original sentinel
|
|
20
|
+
* value for downstream analysis and policy decisions.
|
|
21
|
+
*/
|
|
22
|
+
export const arrayIsLarge = (raw, path) => {
|
|
23
|
+
if (!Array.isArray(raw))
|
|
24
|
+
return [];
|
|
25
|
+
const max = 10_000;
|
|
26
|
+
if (raw.length > max) {
|
|
27
|
+
return [
|
|
28
|
+
scanEvent('warn', 'array.is.large', path, `Array length ${raw.length} exceeds safe threshold ${max}.`, 'This list is very large.', { length: raw.length, max }),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Bigint Is Large
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags BigInt values that fall outside JavaScript’s safe
|
|
7
|
+
* integer range, surfacing numbers that cannot be reliably
|
|
8
|
+
* represented or compared using standard numeric APIs.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
import { scanEvent } from '../../pipeline';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Flags `BigInt` values whose bit‑length exceeds a safe structural boundary.
|
|
18
|
+
*
|
|
19
|
+
* Extremely large integers can stress memory, break downstream serializers,
|
|
20
|
+
* and indicate adversarial or malformed input. This rule surfaces oversized
|
|
21
|
+
* values early so validators and policy layers can decide how to handle them.
|
|
22
|
+
*/
|
|
23
|
+
export const bigintIsLarge = (raw, path) => {
|
|
24
|
+
if (typeof raw !== 'bigint')
|
|
25
|
+
return [];
|
|
26
|
+
const maxBits = 2048;
|
|
27
|
+
const bitLength = raw === 0n ? 1 : raw.toString(2).length;
|
|
28
|
+
if (bitLength > maxBits) {
|
|
29
|
+
return [
|
|
30
|
+
scanEvent('warn', 'bigint.is.large', path, `BigInt exceeds safe bit-length threshold ${maxBits} bits.`, 'This number is too large to safely handle.', { bitLength, maxBits }),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Bigint Not Safe
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Detects BigInt values whose bit-length exceeds a safe
|
|
7
|
+
* structural threshold, highlighting oversized or adversarial
|
|
8
|
+
* integers before deeper validation occurs.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
import { scanEvent } from '../../pipeline';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Flags `BigInt` values that fall outside JavaScript’s safe integer range.
|
|
18
|
+
*
|
|
19
|
+
* While `BigInt` itself is unbounded, many systems assume values remain within
|
|
20
|
+
* the safe `number` range for interoperability. This rule highlights integers
|
|
21
|
+
* that cannot be safely represented or compared using standard numeric APIs.
|
|
22
|
+
*/
|
|
23
|
+
export const bigintNotSafe = (raw, path) => {
|
|
24
|
+
if (typeof raw !== 'bigint')
|
|
25
|
+
return [];
|
|
26
|
+
const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
|
|
27
|
+
const minSafe = BigInt(Number.MIN_SAFE_INTEGER);
|
|
28
|
+
if (raw > maxSafe || raw < minSafe) {
|
|
29
|
+
return [
|
|
30
|
+
scanEvent('warn', 'bigint.not.safe', path, 'BigInt exceeds JavaScript safe integer range.', 'This number is outside the safe range.', { value: raw.toString(), maxSafe, minSafe }),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Date Is Before Epoch
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags Date values that occur before the Unix epoch,
|
|
7
|
+
* surfacing malformed or legacy timestamps early in scanning.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Flags Date values that occur before the Unix epoch (1970‑01‑01).
|
|
17
|
+
*
|
|
18
|
+
* Dates earlier than the epoch often indicate malformed input, legacy
|
|
19
|
+
* serialization issues, or unexpected coercions. This rule surfaces those
|
|
20
|
+
* anomalies early so downstream validators can respond appropriately.
|
|
21
|
+
*/
|
|
22
|
+
export const dateIsBeforeEpoch = (raw, path) => {
|
|
23
|
+
if (!(raw instanceof Date))
|
|
24
|
+
return [];
|
|
25
|
+
const epoch = 0;
|
|
26
|
+
if (raw.getTime() < epoch) {
|
|
27
|
+
return [
|
|
28
|
+
scanEvent('warn', 'date.is.before-epoch', path, 'Date occurs before Unix epoch (1970-01-01).', 'This date is earlier than 1970.', { timestamp: raw.getTime(), epoch }),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Date Is Far Future
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Detects Date values that fall far beyond a safe future
|
|
7
|
+
* boundary, highlighting unrealistic or adversarial timestamps.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Detects Date values that fall far beyond a conservative future boundary.
|
|
17
|
+
*
|
|
18
|
+
* Extremely future‑dated timestamps can signal corrupted data, unrealistic
|
|
19
|
+
* scheduling values, or adversarial input. This rule highlights such values
|
|
20
|
+
* before they propagate into business logic or policy layers.
|
|
21
|
+
*/
|
|
22
|
+
export const dateIsFarFuture = (raw, path) => {
|
|
23
|
+
if (!(raw instanceof Date))
|
|
24
|
+
return [];
|
|
25
|
+
const max = new Date('2100-01-01T00:00:00.000Z').getTime();
|
|
26
|
+
if (raw.getTime() > max) {
|
|
27
|
+
return [
|
|
28
|
+
scanEvent('warn', 'date.is.far-future', path, 'Date occurs far in the future beyond safe bounds.', 'This date is far in the future.', { timestamp: raw.getTime(), max }),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Date Is Invalid
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Warns when a Date instance resolves to an invalid timestamp,
|
|
7
|
+
* ensuring parsing failures are surfaced explicitly.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Warns when a Date instance resolves to an invalid (NaN) timestamp.
|
|
17
|
+
*
|
|
18
|
+
* Invalid Date objects commonly arise from parsing failures or unexpected
|
|
19
|
+
* transformations. This rule ensures they are surfaced explicitly rather than
|
|
20
|
+
* silently passing through the scan pipeline.
|
|
21
|
+
*/
|
|
22
|
+
export const dateIsInvalid = (raw, path) => {
|
|
23
|
+
if (!(raw instanceof Date))
|
|
24
|
+
return [];
|
|
25
|
+
if (Number.isNaN(raw.getTime())) {
|
|
26
|
+
return [
|
|
27
|
+
scanEvent('warn', 'date.is.invalid', path, 'Date value is invalid (NaN timestamp).', 'This date is not valid.', { value: raw }),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Barrel File
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Re‑exports all scanner modules, providing a single,
|
|
7
|
+
* consolidated entry point for the scanning subsystem.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
12
|
+
|* All Values *|
|
|
13
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
14
|
+
export { scanForSentinels } from './any/scan-for-sentinels';
|
|
15
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
16
|
+
|* Array Values *|
|
|
17
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
18
|
+
export { arrayIsDeep } from './array/array-is-deep';
|
|
19
|
+
export { arrayIsHeterogeneous } from './array/array-is-heterogenous';
|
|
20
|
+
export { arrayIsLarge } from './array/array-is-large';
|
|
21
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
22
|
+
|* Bigint Values *|
|
|
23
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
24
|
+
export { bigintIsLarge } from './bigint/bigint-is-large';
|
|
25
|
+
export { bigintNotSafe } from './bigint/bigint-not-safe';
|
|
26
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
27
|
+
|* Date Values *|
|
|
28
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
29
|
+
export { dateIsBeforeEpoch } from './date/date-is-before-epoch';
|
|
30
|
+
export { dateIsFarFuture } from './date/date-is-far-future';
|
|
31
|
+
export { dateIsInvalid } from './date/date-is-invalid';
|
|
32
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
33
|
+
|* Number Values *|
|
|
34
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
35
|
+
export { numberIsInfinite } from './number/number-is-infinite';
|
|
36
|
+
export { numberIsNaN } from './number/number-is-nan';
|
|
37
|
+
export { numberIsTooLarge } from './number/number-is-too-large';
|
|
38
|
+
export { numberIsUnsafeInteger } from './number/number-is-unsafe-integer';
|
|
39
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
40
|
+
|* Object Values *|
|
|
41
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
42
|
+
export { objectHasCircularReferences } from './object/object-has-circular-references';
|
|
43
|
+
export { objectHasManyKeys } from './object/object-has-many-keys';
|
|
44
|
+
export { objectIsDeep } from './object/object-is-deep';
|
|
45
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
46
|
+
|* String Values *|
|
|
47
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
48
|
+
export { stringHasUnsafeUnicode } from './string/string-has-unsafe-unicode';
|
|
49
|
+
export { stringHasWhitespaceEdges } from './string/string-has-whitespace-edges';
|
|
50
|
+
export { stringIsLong } from './string/string-is-long';
|
|
51
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
52
|
+
|* Unknown Values *|
|
|
53
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
54
|
+
export { unknownNotScannable } from './unknown/unknown-not-scannable';
|
|
55
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
56
|
+
|* Registry *|
|
|
57
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
58
|
+
export { scanRuleRegistry } from './scanner-registry';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Number Is Infinite
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags numeric values that resolve to Infinity, surfacing
|
|
7
|
+
* calculation errors or malformed inputs before they propagate.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Flags numeric values that are infinite rather than finite.
|
|
17
|
+
*
|
|
18
|
+
* Infinite values often indicate upstream calculation errors, division
|
|
19
|
+
* anomalies, or malformed input. This rule surfaces them early so downstream
|
|
20
|
+
* logic never assumes a safe, bounded number.
|
|
21
|
+
*/
|
|
22
|
+
export const numberIsInfinite = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'number')
|
|
24
|
+
return [];
|
|
25
|
+
if (!Number.isFinite(raw)) {
|
|
26
|
+
return [
|
|
27
|
+
scanEvent('warn', 'number.not.finite', path, 'Value is infinite, which is not a safe numeric value.', 'This number is infinite.', { value: raw }),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Number Is NaN
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Detects numeric values that evaluate to NaN, ensuring failed
|
|
7
|
+
* arithmetic or parsing does not silently pass through scanning.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Detects numeric values that resolve to NaN.
|
|
17
|
+
*
|
|
18
|
+
* NaN commonly arises from failed arithmetic, invalid parsing, or unexpected
|
|
19
|
+
* coercions. This rule ensures such values are treated as structurally unsafe
|
|
20
|
+
* rather than silently propagating through the scan pipeline.
|
|
21
|
+
*/
|
|
22
|
+
export const numberIsNaN = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'number')
|
|
24
|
+
return [];
|
|
25
|
+
if (Number.isNaN(raw)) {
|
|
26
|
+
return [
|
|
27
|
+
scanEvent('warn', 'number.not.number', path, 'Value is NaN, which is not a safe numeric value.', 'This number is not valid.', { value: raw }),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Number Is Too Large
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Warns when a number exceeds a conservative magnitude limit,
|
|
7
|
+
* highlighting values that may indicate corrupted or adversarial
|
|
8
|
+
* input.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
import { scanEvent } from '../../pipeline';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Warns when a numeric value exceeds a conservative magnitude threshold.
|
|
18
|
+
*
|
|
19
|
+
* Extremely large numbers can signal corrupted data, unrealistic inputs, or
|
|
20
|
+
* adversarial payloads. This rule highlights values that may cause overflow,
|
|
21
|
+
* precision loss, or performance issues in downstream systems.
|
|
22
|
+
*/
|
|
23
|
+
export const numberIsTooLarge = (raw, path) => {
|
|
24
|
+
if (typeof raw !== 'number')
|
|
25
|
+
return [];
|
|
26
|
+
const max = 1e15;
|
|
27
|
+
if (Math.abs(raw) > max) {
|
|
28
|
+
return [
|
|
29
|
+
scanEvent('warn', 'number.is.too-large', path, `Number magnitude ${raw} exceeds safe threshold ${max}.`, 'This number is extremely large.', { value: raw, max }),
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Number Is Unsafe Integer
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags integers outside JavaScript’s safe integer range,
|
|
7
|
+
* preventing precision‑loss issues in comparisons or arithmetic.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Flags integers that fall outside JavaScript’s safe integer range.
|
|
17
|
+
*
|
|
18
|
+
* Values beyond the safe range cannot be represented precisely using standard
|
|
19
|
+
* numeric operations. This rule surfaces whole numbers that may behave
|
|
20
|
+
* unpredictably in comparisons, arithmetic, or serialization.
|
|
21
|
+
*/
|
|
22
|
+
export const numberIsUnsafeInteger = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'number')
|
|
24
|
+
return [];
|
|
25
|
+
if (Number.isInteger(raw) && !Number.isSafeInteger(raw)) {
|
|
26
|
+
return [
|
|
27
|
+
scanEvent('warn', 'number.not.safe-integer', path, `Integer ${raw} exceeds JavaScript's safe integer range.`, 'This whole number is outside the safe range.', { value: raw }),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Object Has Circular References
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Detects self‑referential object graphs that can break
|
|
7
|
+
* serializers, confuse diffing logic, or trigger unbounded
|
|
8
|
+
* recursion during analysis.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
import { scanEvent } from '../../pipeline';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Implementation *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Detects objects that contain circular references.
|
|
18
|
+
*
|
|
19
|
+
* Cyclic structures can break serializers, confuse diffing logic, and cause
|
|
20
|
+
* unbounded recursion during analysis. This rule surfaces self‑referential
|
|
21
|
+
* shapes early so containment and policy layers can respond safely.
|
|
22
|
+
*/
|
|
23
|
+
export const objectHasCircularReferences = (raw, path) => {
|
|
24
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
|
|
25
|
+
return [];
|
|
26
|
+
const seen = new WeakSet();
|
|
27
|
+
const stack = [raw];
|
|
28
|
+
while (stack.length > 0) {
|
|
29
|
+
const current = stack.pop();
|
|
30
|
+
if (seen.has(current)) {
|
|
31
|
+
return [
|
|
32
|
+
scanEvent('warn', 'object.has.circular-references', path, 'Object contains circular references.', 'This object refers to itself.', {}),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
seen.add(current);
|
|
36
|
+
for (const value of Object.values(current)) {
|
|
37
|
+
if (value && typeof value === 'object') {
|
|
38
|
+
stack.push(value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Object Has Many Keys
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Flags objects whose number of own properties exceeds a safe
|
|
7
|
+
* threshold, surfacing unusually wide or adversarial shapes.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Flags objects whose number of own enumerable keys exceeds a safe limit.
|
|
17
|
+
*
|
|
18
|
+
* Extremely wide objects often indicate malformed payloads, accidental
|
|
19
|
+
* fan‑out, or adversarial input. This rule highlights unusually large
|
|
20
|
+
* property maps before they stress memory or downstream processing.
|
|
21
|
+
*/
|
|
22
|
+
export const objectHasManyKeys = (raw, path) => {
|
|
23
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
|
|
24
|
+
return [];
|
|
25
|
+
const maxKeys = 500;
|
|
26
|
+
const count = Object.keys(raw).length;
|
|
27
|
+
if (count > maxKeys) {
|
|
28
|
+
return [
|
|
29
|
+
scanEvent('warn', 'object.has.many-keys', path, `Object has ${count} keys, exceeding safe threshold ${maxKeys}.`, 'This object has many properties.', { count, maxKeys }),
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | Object Is Deep
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Warns when an object’s nesting depth surpasses a conservative
|
|
7
|
+
* structural limit, highlighting shapes that may cause stack
|
|
8
|
+
* pressure or pathological traversal costs.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Internal Modules *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
import { measureDepth } from '../../../core/pipeline';
|
|
16
|
+
import { scanEvent } from '../../pipeline';
|
|
17
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
18
|
+
|* Implementation *|
|
|
19
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
20
|
+
/**
|
|
21
|
+
* Warns when an object’s nesting depth exceeds a conservative structural bound.
|
|
22
|
+
*
|
|
23
|
+
* Deeply nested shapes can cause stack pressure, slow traversal, and
|
|
24
|
+
* pathological input patterns. This rule surfaces excessive depth early so
|
|
25
|
+
* containment can replace or constrain hazardous structures.
|
|
26
|
+
*/
|
|
27
|
+
export const objectIsDeep = (raw, path) => {
|
|
28
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
29
|
+
return [];
|
|
30
|
+
const depth = measureDepth(raw);
|
|
31
|
+
const max = 50;
|
|
32
|
+
if (depth > max) {
|
|
33
|
+
return [
|
|
34
|
+
scanEvent('warn', 'object.is.deep', path, `Object depth ${depth} exceeds safe threshold ${max}.`, 'This object is deeply nested.', { depth, max }),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
return [];
|
|
38
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Public | Scanner Registry
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Exposes the full mapping of structural types to their
|
|
7
|
+
* associated scan rules, defining Jane’s public scanning
|
|
8
|
+
* configuration surface.
|
|
9
|
+
* @see https://jane-io.com
|
|
10
|
+
* ----------------------------------------------------------------------------
|
|
11
|
+
*/
|
|
12
|
+
import { arrayIsDeep, arrayIsHeterogeneous, arrayIsLarge, bigintIsLarge, bigintNotSafe, dateIsBeforeEpoch, dateIsFarFuture, dateIsInvalid, numberIsInfinite, numberIsNaN, numberIsTooLarge, numberIsUnsafeInteger, objectHasCircularReferences, objectHasManyKeys, objectIsDeep, scanForSentinels, stringHasUnsafeUnicode, stringHasWhitespaceEdges, stringIsLong, unknownNotScannable, } from '.';
|
|
13
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
14
|
+
|* Scan Rule Registry *|
|
|
15
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
16
|
+
/**
|
|
17
|
+
* Central registry mapping structural types to the scan rules that evaluate
|
|
18
|
+
* them. This defines the composition and ordering of Jane’s scanning pipeline,
|
|
19
|
+
* ensuring each detected type is checked against the appropriate structural,
|
|
20
|
+
* safety, and shape‑integrity rules.
|
|
21
|
+
*/
|
|
22
|
+
export const scanRuleRegistry = {
|
|
23
|
+
all: [scanForSentinels],
|
|
24
|
+
string: [stringIsLong, stringHasUnsafeUnicode, stringHasWhitespaceEdges],
|
|
25
|
+
number: [numberIsInfinite, numberIsNaN, numberIsTooLarge, numberIsUnsafeInteger],
|
|
26
|
+
boolean: [],
|
|
27
|
+
array: [arrayIsLarge, arrayIsDeep, arrayIsHeterogeneous],
|
|
28
|
+
object: [objectIsDeep, objectHasCircularReferences, objectHasManyKeys],
|
|
29
|
+
date: [dateIsInvalid, dateIsBeforeEpoch, dateIsFarFuture],
|
|
30
|
+
unknown: [unknownNotScannable],
|
|
31
|
+
/**
|
|
32
|
+
* The following types can only be accepted by explicitly setting the
|
|
33
|
+
* `bigint`, `set`, or `map` property (in `exceptions`) to `true`.
|
|
34
|
+
*/
|
|
35
|
+
bigint: [bigintIsLarge, bigintNotSafe],
|
|
36
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ----------------------------------------------------------------------------
|
|
3
|
+
* Scanners | String Has Unsafe Unicode
|
|
4
|
+
* ----------------------------------------------------------------------------
|
|
5
|
+
* @package @clementine-solutions/jane
|
|
6
|
+
* @description Detects Unicode bidi control characters that can obscure
|
|
7
|
+
* text rendering or introduce security‑relevant ambiguity.
|
|
8
|
+
* @see https://jane-io.com
|
|
9
|
+
* ----------------------------------------------------------------------------
|
|
10
|
+
*/
|
|
11
|
+
import { scanEvent } from '../../pipeline';
|
|
12
|
+
/* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
|
|
13
|
+
|* Implementation *|
|
|
14
|
+
\* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
|
|
15
|
+
/**
|
|
16
|
+
* Detects the presence of Unicode bidi control characters.
|
|
17
|
+
*
|
|
18
|
+
* These invisible characters can alter text rendering, obscure intent, or
|
|
19
|
+
* introduce security risks. This rule surfaces unsafe Unicode so downstream
|
|
20
|
+
* layers never operate on misleading or adversarial text.
|
|
21
|
+
*/
|
|
22
|
+
export const stringHasUnsafeUnicode = (raw, path) => {
|
|
23
|
+
if (typeof raw !== 'string')
|
|
24
|
+
return [];
|
|
25
|
+
const unsafe = /[\u202A\u202B\u202D\u202E\u202C\u2066\u2067\u2068\u2069]/;
|
|
26
|
+
if (unsafe.test(raw)) {
|
|
27
|
+
return [
|
|
28
|
+
scanEvent('warn', 'string.has.unsafe-unicode', path, 'String contains unsafe Unicode bidi control characters.', 'This text contains unsafe Unicode characters.', {}),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
};
|