@clementine-solutions/jane-io 1.0.1 → 1.0.2

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.
Files changed (204) hide show
  1. package/dist/core/analysis/diff.js +88 -0
  2. package/dist/core/analysis/explain.js +117 -0
  3. package/dist/core/analysis/index.js +26 -0
  4. package/dist/core/analysis/replay.js +68 -0
  5. package/dist/core/analysis/telemetry.js +123 -0
  6. package/dist/core/boundary-rules/at-most-one.js +38 -0
  7. package/dist/core/boundary-rules/conditionally-required.js +44 -0
  8. package/dist/core/boundary-rules/date-range.js +39 -0
  9. package/dist/core/boundary-rules/index.js +21 -0
  10. package/dist/core/boundary-rules/mutually-exclusive.js +38 -0
  11. package/dist/core/boundary-rules/no-unknown-fields.js +39 -0
  12. package/dist/core/boundary-rules/require-all.js +39 -0
  13. package/dist/core/boundary-rules/require-one.js +41 -0
  14. package/dist/core/common/events.js +82 -0
  15. package/dist/core/common/fluent.js +429 -0
  16. package/dist/core/common/index.js +31 -0
  17. package/dist/core/common/policy.js +550 -0
  18. package/dist/core/common/utilities.js +177 -0
  19. package/dist/core/common/wildcard.js +63 -0
  20. package/dist/core/field-path/construct.js +189 -0
  21. package/dist/core/field-path/format.js +154 -0
  22. package/dist/core/field-path/index.js +26 -0
  23. package/dist/core/field-path/utilities.js +138 -0
  24. package/dist/core/field-path/walk.js +80 -0
  25. package/dist/core/fluent-registry.js +151 -0
  26. package/dist/core/normalizers/array/compact-sparse-array.js +40 -0
  27. package/dist/core/normalizers/array/flatten-one-level.js +45 -0
  28. package/dist/core/normalizers/array/remove-empty-string-items.js +34 -0
  29. package/dist/core/normalizers/array/remove-null-items.js +34 -0
  30. package/dist/core/normalizers/array/remove-undefined-items.js +34 -0
  31. package/dist/core/normalizers/date/invalid-date-to-undefined.js +35 -0
  32. package/dist/core/normalizers/index.js +46 -0
  33. package/dist/core/normalizers/normalizer-register.js +41 -0
  34. package/dist/core/normalizers/number/infinity-to-undefined.js +35 -0
  35. package/dist/core/normalizers/number/nan-to-undefined.js +34 -0
  36. package/dist/core/normalizers/number/normalize-negative-zero.js +33 -0
  37. package/dist/core/normalizers/object/remove-empty-array-keys.js +38 -0
  38. package/dist/core/normalizers/object/remove-empty-object-keys.js +42 -0
  39. package/dist/core/normalizers/object/remove-empty-string-keys.js +37 -0
  40. package/dist/core/normalizers/object/remove-null-keys.js +37 -0
  41. package/dist/core/normalizers/object/remove-undefined-keys.js +37 -0
  42. package/dist/core/normalizers/string/collapse-whitespace.js +35 -0
  43. package/dist/core/normalizers/string/empty-to-undefined.js +33 -0
  44. package/dist/core/normalizers/string/trim.js +34 -0
  45. package/dist/core/parsers/index.js +43 -0
  46. package/dist/core/parsers/parse-array-string.js +36 -0
  47. package/dist/core/parsers/parse-bigint-string.js +33 -0
  48. package/dist/core/parsers/parse-binary-string.js +33 -0
  49. package/dist/core/parsers/parse-boolean-string.js +27 -0
  50. package/dist/core/parsers/parse-date-string.js +30 -0
  51. package/dist/core/parsers/parse-duration-string.js +37 -0
  52. package/dist/core/parsers/parse-hex-string.js +29 -0
  53. package/dist/core/parsers/parse-integer-string.js +30 -0
  54. package/dist/core/parsers/parse-json-string.js +35 -0
  55. package/dist/core/parsers/parse-numeric-string.js +29 -0
  56. package/dist/core/parsers/parse-object-string.js +36 -0
  57. package/dist/core/parsers/parse-octal-string.js +33 -0
  58. package/dist/core/parsers/parse-scientific-notation-string.js +30 -0
  59. package/dist/core/parsers/parse-url-string.js +36 -0
  60. package/dist/core/pipeline/boundary.js +256 -0
  61. package/dist/core/pipeline/contain.js +339 -0
  62. package/dist/core/pipeline/index.js +37 -0
  63. package/dist/core/pipeline/normalize.js +76 -0
  64. package/dist/core/pipeline/parse.js +91 -0
  65. package/dist/core/pipeline/pipeline.js +418 -0
  66. package/dist/core/pipeline/scan.js +115 -0
  67. package/dist/core/pipeline/validate.js +74 -0
  68. package/dist/core/scanners/any/scan-for-sentinels.js +35 -0
  69. package/dist/core/scanners/array/array-is-deep.js +38 -0
  70. package/dist/core/scanners/array/array-is-heterogenous.js +39 -0
  71. package/dist/core/scanners/array/array-is-large.js +32 -0
  72. package/dist/core/scanners/bigint/bigint-is-large.js +34 -0
  73. package/dist/core/scanners/bigint/bigint-not-safe.js +34 -0
  74. package/dist/core/scanners/date/date-is-before-epoch.js +32 -0
  75. package/dist/core/scanners/date/date-is-far-future.js +32 -0
  76. package/dist/core/scanners/date/date-is-invalid.js +31 -0
  77. package/dist/core/scanners/index.js +58 -0
  78. package/dist/core/scanners/number/number-is-infinite.js +31 -0
  79. package/dist/core/scanners/number/number-is-nan.js +31 -0
  80. package/dist/core/scanners/number/number-is-too-large.js +33 -0
  81. package/dist/core/scanners/number/number-is-unsafe-integer.js +31 -0
  82. package/dist/core/scanners/object/object-has-circular-references.js +43 -0
  83. package/dist/core/scanners/object/object-has-many-keys.js +33 -0
  84. package/dist/core/scanners/object/object-is-deep.js +38 -0
  85. package/dist/core/scanners/scanner-registry.js +36 -0
  86. package/dist/core/scanners/string/string-has-unsafe-unicode.js +32 -0
  87. package/dist/core/scanners/string/string-has-whitespace-edges.js +31 -0
  88. package/dist/core/scanners/string/string-is-long.js +32 -0
  89. package/dist/core/scanners/unknown/unknown-not-scannable.js +34 -0
  90. package/dist/core/shapes/analysis.js +11 -0
  91. package/dist/core/shapes/boundary.js +11 -0
  92. package/dist/core/shapes/events.js +10 -0
  93. package/dist/core/shapes/field-path.js +10 -0
  94. package/dist/core/shapes/index.js +11 -0
  95. package/dist/core/shapes/normalize.js +11 -0
  96. package/dist/core/shapes/parse.js +11 -0
  97. package/dist/core/shapes/pipeline.js +11 -0
  98. package/dist/core/shapes/policy.js +11 -0
  99. package/dist/core/shapes/public.js +10 -0
  100. package/dist/core/shapes/scan.js +11 -0
  101. package/dist/core/shapes/validate.js +11 -0
  102. package/dist/core/validators/array/array-max-items.js +42 -0
  103. package/dist/core/validators/array/array-min-items.js +42 -0
  104. package/dist/core/validators/array/array.js +34 -0
  105. package/dist/core/validators/array/excludes.js +47 -0
  106. package/dist/core/validators/array/has-unique-items.js +46 -0
  107. package/dist/core/validators/array/includes.js +46 -0
  108. package/dist/core/validators/array/items-equal.js +42 -0
  109. package/dist/core/validators/array/no-empty-string-items.js +46 -0
  110. package/dist/core/validators/array/no-null-items.js +46 -0
  111. package/dist/core/validators/array/no-undefined-items.js +45 -0
  112. package/dist/core/validators/array/non-empty-array.js +45 -0
  113. package/dist/core/validators/array/not-sparse.js +44 -0
  114. package/dist/core/validators/bigint/bigint-equals.js +57 -0
  115. package/dist/core/validators/bigint/bigint-max.js +63 -0
  116. package/dist/core/validators/bigint/bigint-min.js +87 -0
  117. package/dist/core/validators/bigint/bigint-negative.js +73 -0
  118. package/dist/core/validators/bigint/bigint-non-negative.js +72 -0
  119. package/dist/core/validators/bigint/bigint-non-positive.js +72 -0
  120. package/dist/core/validators/bigint/bigint-positive.js +72 -0
  121. package/dist/core/validators/bigint/bigint-safe.js +75 -0
  122. package/dist/core/validators/bigint/bigint.js +38 -0
  123. package/dist/core/validators/boolean/boolean.js +39 -0
  124. package/dist/core/validators/boolean/is-false.js +48 -0
  125. package/dist/core/validators/boolean/is-true.js +48 -0
  126. package/dist/core/validators/common/is-country-code.js +36 -0
  127. package/dist/core/validators/common/is-currency-code.js +36 -0
  128. package/dist/core/validators/common/is-email-strict.js +36 -0
  129. package/dist/core/validators/common/is-email.js +36 -0
  130. package/dist/core/validators/common/is-ip.js +37 -0
  131. package/dist/core/validators/common/is-phone-strict.js +36 -0
  132. package/dist/core/validators/common/is-phone.js +36 -0
  133. package/dist/core/validators/common/is-port.js +35 -0
  134. package/dist/core/validators/common/is-postal-code.js +36 -0
  135. package/dist/core/validators/common/is-url.js +38 -0
  136. package/dist/core/validators/common/is-uuid.js +36 -0
  137. package/dist/core/validators/date/before-epoch.js +56 -0
  138. package/dist/core/validators/date/date-now-required.js +48 -0
  139. package/dist/core/validators/date/is-date.js +47 -0
  140. package/dist/core/validators/date/is-far-future.js +46 -0
  141. package/dist/core/validators/date/is-future.js +59 -0
  142. package/dist/core/validators/date/is-past.js +59 -0
  143. package/dist/core/validators/date/not-after.js +66 -0
  144. package/dist/core/validators/date/not-before.js +66 -0
  145. package/dist/core/validators/date/same-day.js +60 -0
  146. package/dist/core/validators/date/same-month.js +59 -0
  147. package/dist/core/validators/date/same-year.js +56 -0
  148. package/dist/core/validators/date/too-early.js +57 -0
  149. package/dist/core/validators/date/too-late.js +57 -0
  150. package/dist/core/validators/date/weekday.js +65 -0
  151. package/dist/core/validators/date/weekend.js +56 -0
  152. package/dist/core/validators/index.js +139 -0
  153. package/dist/core/validators/nullish/is-null-or-undefined.js +40 -0
  154. package/dist/core/validators/nullish/is-null.js +39 -0
  155. package/dist/core/validators/nullish/is-undefined.js +39 -0
  156. package/dist/core/validators/number/finite.js +40 -0
  157. package/dist/core/validators/number/integer.js +40 -0
  158. package/dist/core/validators/number/less-than.js +39 -0
  159. package/dist/core/validators/number/max.js +39 -0
  160. package/dist/core/validators/number/min.js +39 -0
  161. package/dist/core/validators/number/more-than.js +39 -0
  162. package/dist/core/validators/number/negative.js +38 -0
  163. package/dist/core/validators/number/non-negative.js +37 -0
  164. package/dist/core/validators/number/non-positive.js +37 -0
  165. package/dist/core/validators/number/number.js +31 -0
  166. package/dist/core/validators/number/positive.js +38 -0
  167. package/dist/core/validators/number/safe-integer.js +42 -0
  168. package/dist/core/validators/object/deep-equals.js +47 -0
  169. package/dist/core/validators/object/has-key.js +42 -0
  170. package/dist/core/validators/object/has-value.js +59 -0
  171. package/dist/core/validators/object/keys-equal.js +47 -0
  172. package/dist/core/validators/object/max-keys.js +43 -0
  173. package/dist/core/validators/object/min-keys.js +43 -0
  174. package/dist/core/validators/object/missing-key.js +42 -0
  175. package/dist/core/validators/object/no-empty-array-values.js +44 -0
  176. package/dist/core/validators/object/no-empty-object-values.js +44 -0
  177. package/dist/core/validators/object/no-null-values.js +44 -0
  178. package/dist/core/validators/object/no-undefined-values.js +44 -0
  179. package/dist/core/validators/object/non-empty-object.js +40 -0
  180. package/dist/core/validators/object/only-keys.js +43 -0
  181. package/dist/core/validators/object/plain-object.js +35 -0
  182. package/dist/core/validators/string/alpha-num.js +50 -0
  183. package/dist/core/validators/string/alpha.js +51 -0
  184. package/dist/core/validators/string/chars-equal.js +49 -0
  185. package/dist/core/validators/string/ends-with.js +50 -0
  186. package/dist/core/validators/string/is-ascii.js +53 -0
  187. package/dist/core/validators/string/is-printable.js +53 -0
  188. package/dist/core/validators/string/matches.js +50 -0
  189. package/dist/core/validators/string/max-length.js +50 -0
  190. package/dist/core/validators/string/min-length.js +50 -0
  191. package/dist/core/validators/string/no-lead-space.js +50 -0
  192. package/dist/core/validators/string/no-repeat-space.js +52 -0
  193. package/dist/core/validators/string/no-space.js +51 -0
  194. package/dist/core/validators/string/no-trail-space.js +50 -0
  195. package/dist/core/validators/string/non-empty.js +48 -0
  196. package/dist/core/validators/string/not-one-of.js +51 -0
  197. package/dist/core/validators/string/num-string.js +50 -0
  198. package/dist/core/validators/string/one-of.js +50 -0
  199. package/dist/core/validators/string/starts-with.js +50 -0
  200. package/dist/core/validators/string/string.js +39 -0
  201. package/dist/core/validators/string/trimmed.js +51 -0
  202. package/dist/index.js +26 -0
  203. package/dist/test.js +12 -0
  204. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | No Undefined Items
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validate that an array does not contain undefined 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 undefined items.
17
+ *
18
+ * This rule checks:
19
+ * - The value is structurally an array
20
+ * - No element in the array is strictly equal to undefined
21
+ *
22
+ * Emits:
23
+ * - array.not.array
24
+ * - array.has.undefined-items
25
+ *
26
+ * This rule is async-compatible and returns a readonly array of JaneEvent objects.
27
+ */
28
+ export const noUndefinedItems = async (value, path) => {
29
+ const type = detectStructuralType(value);
30
+ if (!Array.isArray(value)) {
31
+ return [
32
+ validationEvent('error', 'array.not.array', path, `Expected 'array' but received '${type}'.`, `Please provide a valid array.`, { value, expected: 'array', actual: type }),
33
+ ];
34
+ }
35
+ for (let i = 0; i < value.length; i++) {
36
+ const isHole = !(i in value);
37
+ const isUndefined = value[i] === undefined;
38
+ if (isHole || isUndefined) {
39
+ return [
40
+ validationEvent('error', 'array.has.undefined-items', path, `Array must not contain undefined values.`, `Please remove undefined items.`, { value, expected: 'no undefined items', actual: 'contains undefined' }),
41
+ ];
42
+ }
43
+ }
44
+ return [];
45
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Non-Empty Array
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validate that an array is not empty.
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 is not empty.
17
+ *
18
+ * This rule checks:
19
+ * - The value is structurally an array
20
+ * - The array contains at least one item
21
+ *
22
+ * Emits:
23
+ * - array.not.array
24
+ * - array.is.empty
25
+ *
26
+ * This rule is async-compatible and returns a readonly array of JaneEvent objects.
27
+ */
28
+ export const nonEmptyArray = 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
+ if (value.length === 0) {
36
+ return [
37
+ validationEvent('error', 'array.is.empty', path, `Array must not be empty.`, `Please provide at least one item.`, {
38
+ value,
39
+ expected: 'non-empty array',
40
+ actual: value.length,
41
+ }),
42
+ ];
43
+ }
44
+ return [];
45
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Not Sparse
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validate that an array does not contain empty (sparse)
7
+ * slots.
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 contain empty (sparse) slots.
18
+ *
19
+ * This rule checks:
20
+ * - The value is structurally an array
21
+ * - Every index from 0 to length - 1 exists (no holes)
22
+ *
23
+ * Emits:
24
+ * - array.not.array
25
+ * - array.is.sparse
26
+ *
27
+ * This rule is async-compatible and returns a readonly array of JaneEvent objects.
28
+ */
29
+ export const notSparse = 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
+ for (let index = 0; index < value.length; index++) {
37
+ if (!(index in value)) {
38
+ return [
39
+ validationEvent('error', 'array.is.sparse', path, `Array must not contain empty slots.`, `Please remove empty array positions.`, { value, expected: 'no holes', actual: 'sparse array' }),
40
+ ];
41
+ }
42
+ }
43
+ return [];
44
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Equals
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string representing a BigInt
7
+ * equal to `target`.
8
+ * @see https://jane-io.com
9
+ * ----------------------------------------------------------------------------
10
+ */
11
+ import { validationEvent } from '../../pipeline';
12
+ import { detectStructuralType } from '../../pipeline/scan';
13
+ import { safeStringify } from '../../common';
14
+ /* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
15
+ |* Implementation *|
16
+ \* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
17
+ /**
18
+ * Validates that the value is a string representing a BigInt equal to `target`.
19
+ *
20
+ * - Non‑string values emit `bigint.not.string`.
21
+ * - Strings that cannot be parsed as BigInt emit `bigint.not.bigint`.
22
+ * - Parsed BigInt values that do not equal `target` emit `bigint.not.equal`.
23
+ * - Returns an empty array when the value is valid.
24
+ *
25
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
26
+ * JaneEvent objects. It preserves the provided path and supports userMessage
27
+ * overrides applied at the pipeline level.
28
+ */
29
+ export const bigintEquals = (target) => async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ if (typeof value !== 'string') {
32
+ return [
33
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
34
+ ];
35
+ }
36
+ // Explicit empty-string check
37
+ if (value.length === 0) {
38
+ return [
39
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
40
+ ];
41
+ }
42
+ let parsed;
43
+ try {
44
+ parsed = BigInt(value);
45
+ }
46
+ catch {
47
+ return [
48
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
49
+ ];
50
+ }
51
+ if (parsed !== target) {
52
+ return [
53
+ validationEvent('error', 'bigint.not.equal', path, `${safeStringify(value)} must equal ${target}.`, `Please provide the correct bigint value.`, { value, expected: target, actual: parsed }),
54
+ ];
55
+ }
56
+ return [];
57
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Maximum (Bigint Max)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string representing a BigInt
7
+ * less than or equal to the provided `max`.
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
+ * Validates that the value is a string representing a BigInt less than or
19
+ * equal to the provided `max`.
20
+ *
21
+ * - Non‑string values emit `bigint.not.string`.
22
+ * - Empty strings and non‑parseable strings emit `bigint.not.bigint`.
23
+ * - Parsed BigInt values greater than `max` emit `bigint.too.large`.
24
+ * - Returns an empty array when the value is valid.
25
+ *
26
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
27
+ * JaneEvent objects. It preserves the provided path and supports userMessage
28
+ * overrides applied at the pipeline level.
29
+ */
30
+ export const bigintMax = (max) => {
31
+ const rule = async (value, path) => {
32
+ const structuralType = detectStructuralType(value);
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ if (value.length === 0) {
39
+ return [
40
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
41
+ ];
42
+ }
43
+ let parsed;
44
+ try {
45
+ parsed = BigInt(value);
46
+ }
47
+ catch {
48
+ return [
49
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
50
+ ];
51
+ }
52
+ if (parsed > max) {
53
+ return [
54
+ validationEvent('error', 'bigint.too.large', path, `${safeStringify(value)} must be ≤ ${max}.`, `Please provide a value less than or equal to ${max}.`, { max, actual: parsed }),
55
+ ];
56
+ }
57
+ return [];
58
+ };
59
+ // Prevent Jane from serializing the rule and losing the bigint
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ rule.__janeFactory = true;
62
+ return rule;
63
+ };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Minimum (Bigint Min)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Ensures the input is a string representing a BigInt that is
7
+ * greater than or equal to the provided `min` value.
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
+ * Ensures the input is a string representing a BigInt that is
19
+ * greater than or equal to the provided `min` value.
20
+ *
21
+ * This validator follows Jane’s standard BigInt conventions:
22
+ * - The input must be a string. Non‑string values emit `bigint.not.string`.
23
+ * - Empty strings and non‑parseable strings emit `bigint.not.bigint`.
24
+ * - Parsed BigInt values smaller than `min` emit `bigint.too.small`.
25
+ *
26
+ * The rule is pure, total, async‑compatible, and preserves the
27
+ * provided path. It also supports userMessage overrides applied
28
+ * at the pipeline level.
29
+ */
30
+ export const bigintMin = (min) => {
31
+ // The returned function is the actual validator. We attach a
32
+ // factory marker below so Jane preserves the closure and does
33
+ // not attempt to serialize the `min` bigint.
34
+ const rule = async (value, path) => {
35
+ const structuralType = detectStructuralType(value);
36
+ // ------------------------------------------------------------
37
+ // Type check — the input must be a string.
38
+ // ------------------------------------------------------------
39
+ if (typeof value !== 'string') {
40
+ return [
41
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
42
+ ];
43
+ }
44
+ // ------------------------------------------------------------
45
+ // Empty-string check — BigInt("") parses as 0n, which is
46
+ // rarely what users intend. We treat empty strings as invalid.
47
+ // ------------------------------------------------------------
48
+ if (value.length === 0) {
49
+ return [
50
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
51
+ ];
52
+ }
53
+ // ------------------------------------------------------------
54
+ // Parse check — attempt to convert the string into a BigInt.
55
+ // Any failure (invalid characters, formatting, etc.) results
56
+ // in a `bigint.not.bigint` event.
57
+ // ------------------------------------------------------------
58
+ let parsed;
59
+ try {
60
+ parsed = BigInt(value);
61
+ }
62
+ catch {
63
+ return [
64
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
65
+ ];
66
+ }
67
+ // ------------------------------------------------------------
68
+ // Minimum check — ensure the parsed value is ≥ the provided `min`.
69
+ // ------------------------------------------------------------
70
+ if (parsed < min) {
71
+ return [
72
+ validationEvent('error', 'bigint.too.small', path, `${safeStringify(value)} must be ≥ ${min}.`, `Please provide a bigint at least ${min}.`, { value, expected: `≥ ${min}`, actual: parsed }),
73
+ ];
74
+ }
75
+ // ------------------------------------------------------------
76
+ // Valid — return an empty array to indicate success.
77
+ // ------------------------------------------------------------
78
+ return [];
79
+ };
80
+ // ------------------------------------------------------------
81
+ // Factory marker — prevents Jane from serializing the rule and
82
+ // losing the `min` bigint. This ensures the closure is preserved.
83
+ // ------------------------------------------------------------
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ rule.__janeFactory = true;
86
+ return rule;
87
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Negative
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Ensures the input is a string representing a negative
7
+ * BigInt value.
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
+ * Ensures the input is a string representing a negative BigInt value.
19
+ *
20
+ * This validator follows Jane’s standard BigInt conventions:
21
+ * - The input must be a string. Non‑string values emit `bigint.not.string`.
22
+ * - Empty strings and non‑parseable strings emit `bigint.not.bigint`.
23
+ * - Parsed BigInt values greater than or equal to 0 emit `bigint.not.negative`.
24
+ *
25
+ * The rule is pure, total, async‑compatible, and preserves the provided path.
26
+ * It also supports userMessage overrides applied at the pipeline level.
27
+ */
28
+ export const bigintNegative = async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check — the input must be a string.
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Empty-string check — BigInt("") parses as 0n, which is
40
+ // rarely what users intend. We treat empty strings as invalid.
41
+ // ------------------------------------------------------------
42
+ if (value.length === 0) {
43
+ return [
44
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
45
+ ];
46
+ }
47
+ // ------------------------------------------------------------
48
+ // Parse check — attempt to convert the string into a BigInt.
49
+ // Any failure (invalid characters, formatting, etc.) results
50
+ // in a `bigint.not.bigint` event.
51
+ // ------------------------------------------------------------
52
+ let parsed;
53
+ try {
54
+ parsed = BigInt(value);
55
+ }
56
+ catch {
57
+ return [
58
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
59
+ ];
60
+ }
61
+ // ------------------------------------------------------------
62
+ // Negativity check — ensure the parsed value is strictly < 0.
63
+ // ------------------------------------------------------------
64
+ if (parsed >= 0n) {
65
+ return [
66
+ validationEvent('error', 'bigint.not.negative', path, `${safeStringify(value)} must be < 0.`, `Please provide a negative bigint.`, { value, expected: '< 0', actual: parsed }),
67
+ ];
68
+ }
69
+ // ------------------------------------------------------------
70
+ // Valid — return an empty array to indicate success.
71
+ // ------------------------------------------------------------
72
+ return [];
73
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Non-Negative
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Ensures the input is a string representing a BigInt that is
7
+ * greater than or equal to zero.
8
+ * @see https://jane-io.com
9
+ * ----------------------------------------------------------------------------
10
+ */
11
+ import { validationEvent } from '../../pipeline';
12
+ import { detectStructuralType } from '../../pipeline/scan';
13
+ import { safeStringify } from '../../common';
14
+ /* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
15
+ |* Implementation *|
16
+ \* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
17
+ /**
18
+ * Ensures the input is a string representing a BigInt that is greater than or
19
+ * equal to zero.
20
+ *
21
+ * - Non-string values emit `bigint.not.string`.
22
+ * - Empty strings and non-parseable strings emit `bigint.not.bigint`.
23
+ * - Parsed BigInt values < 0 emit `bigint.not.non-negative`.
24
+ *
25
+ * This rule is pure, total, async-compatible, and preserves the
26
+ * provided path. It supports userMessage overrides applied at the
27
+ * pipeline level.
28
+ */
29
+ export const bigintNonNegative = async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ // ------------------------------------------------------------
32
+ // Type check — the input must be a string.
33
+ // ------------------------------------------------------------
34
+ if (typeof value !== 'string') {
35
+ return [
36
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
37
+ ];
38
+ }
39
+ // ------------------------------------------------------------
40
+ // Empty-string check — BigInt("") parses as 0n, which is
41
+ // rarely what users intend. We treat empty strings as invalid.
42
+ // ------------------------------------------------------------
43
+ if (value.length === 0) {
44
+ return [
45
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
46
+ ];
47
+ }
48
+ // ------------------------------------------------------------
49
+ // Parse check — attempt to convert the string into a BigInt.
50
+ // ------------------------------------------------------------
51
+ let parsed;
52
+ try {
53
+ parsed = BigInt(value);
54
+ }
55
+ catch {
56
+ return [
57
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
58
+ ];
59
+ }
60
+ // ------------------------------------------------------------
61
+ // Non-negative check — ensure the parsed value is ≥ 0.
62
+ // ------------------------------------------------------------
63
+ if (parsed < 0n) {
64
+ return [
65
+ validationEvent('error', 'bigint.not.non-negative', path, `${safeStringify(value)} must be ≥ 0.`, `Please provide zero or a positive bigint.`, { value, expected: '≥ 0', actual: parsed }),
66
+ ];
67
+ }
68
+ // ------------------------------------------------------------
69
+ // Valid — return an empty array to indicate success.
70
+ // ------------------------------------------------------------
71
+ return [];
72
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Non-Positive
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Ensures the input is a string representing a BigInt that is
7
+ * less than or equal to zero.
8
+ * @see https://jane-io.com
9
+ * ----------------------------------------------------------------------------
10
+ */
11
+ import { validationEvent } from '../../pipeline';
12
+ import { detectStructuralType } from '../../pipeline/scan';
13
+ import { safeStringify } from '../../common';
14
+ /* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
15
+ |* Implementation *|
16
+ \* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
17
+ /**
18
+ * Ensures the input is a string representing a BigInt that is less than or
19
+ * equal to zero.
20
+ *
21
+ * - Non-string values emit `bigint.not.string`.
22
+ * - Empty strings and non-parseable strings emit `bigint.not.bigint`.
23
+ * - Parsed BigInt values > 0 emit `bigint.not.non-positive`.
24
+ *
25
+ * This rule is pure, total, async-compatible, and preserves the
26
+ * provided path. It supports userMessage overrides applied at the
27
+ * pipeline level.
28
+ */
29
+ export const bigintNonPositive = async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ // ------------------------------------------------------------
32
+ // Type check — the input must be a string.
33
+ // ------------------------------------------------------------
34
+ if (typeof value !== 'string') {
35
+ return [
36
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
37
+ ];
38
+ }
39
+ // ------------------------------------------------------------
40
+ // Empty-string check — BigInt("") parses as 0n, which is
41
+ // rarely what users intend. We treat empty strings as invalid.
42
+ // ------------------------------------------------------------
43
+ if (value.length === 0) {
44
+ return [
45
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
46
+ ];
47
+ }
48
+ // ------------------------------------------------------------
49
+ // Parse check — attempt to convert the string into a BigInt.
50
+ // ------------------------------------------------------------
51
+ let parsed;
52
+ try {
53
+ parsed = BigInt(value);
54
+ }
55
+ catch {
56
+ return [
57
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
58
+ ];
59
+ }
60
+ // ------------------------------------------------------------
61
+ // Non-positive check — ensure the parsed value is ≤ 0.
62
+ // ------------------------------------------------------------
63
+ if (parsed > 0n) {
64
+ return [
65
+ validationEvent('error', 'bigint.not.non-positive', path, `${safeStringify(value)} must be ≤ 0.`, `Please provide zero or a negative bigint.`, { value, expected: '≤ 0', actual: parsed }),
66
+ ];
67
+ }
68
+ // ------------------------------------------------------------
69
+ // Valid — return an empty array to indicate success.
70
+ // ------------------------------------------------------------
71
+ return [];
72
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Bigint Positive
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Ensures the input is a string representing a BigInt that is
7
+ * strictly greater than zero.
8
+ * @see https://jane-io.com
9
+ * ----------------------------------------------------------------------------
10
+ */
11
+ import { validationEvent } from '../../pipeline';
12
+ import { detectStructuralType } from '../../pipeline/scan';
13
+ import { safeStringify } from '../../common';
14
+ /* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— *\
15
+ |* Implementation *|
16
+ \* ——— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ————— * ——— */
17
+ /**
18
+ * Ensures the input is a string representing a BigInt that is strictly greater
19
+ * than zero.
20
+ *
21
+ * - Non-string values emit `bigint.not.string`.
22
+ * - Empty strings and non-parseable strings emit `bigint.not.bigint`.
23
+ * - Parsed BigInt values ≤ 0 emit `bigint.not.positive`.
24
+ *
25
+ * This rule is pure, total, async-compatible, and preserves the
26
+ * provided path. It supports userMessage overrides applied at the
27
+ * pipeline level.
28
+ */
29
+ export const bigintPositive = async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ // ------------------------------------------------------------
32
+ // Type check — the input must be a string.
33
+ // ------------------------------------------------------------
34
+ if (typeof value !== 'string') {
35
+ return [
36
+ validationEvent('error', 'bigint.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid bigint string.`, { value, expected: 'string', actual: structuralType }),
37
+ ];
38
+ }
39
+ // ------------------------------------------------------------
40
+ // Empty-string check — BigInt("") parses as 0n, which is
41
+ // rarely what users intend. We treat empty strings as invalid.
42
+ // ------------------------------------------------------------
43
+ if (value.length === 0) {
44
+ return [
45
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
46
+ ];
47
+ }
48
+ // ------------------------------------------------------------
49
+ // Parse check — attempt to convert the string into a BigInt.
50
+ // ------------------------------------------------------------
51
+ let parsed;
52
+ try {
53
+ parsed = BigInt(value);
54
+ }
55
+ catch {
56
+ return [
57
+ validationEvent('error', 'bigint.not.bigint', path, `${safeStringify(value)} is not a valid bigint literal.`, `Please provide a valid bigint string.`, { value, expected: 'bigint literal', actual: value }),
58
+ ];
59
+ }
60
+ // ------------------------------------------------------------
61
+ // Positivity check — ensure the parsed value is strictly > 0.
62
+ // ------------------------------------------------------------
63
+ if (parsed <= 0n) {
64
+ return [
65
+ validationEvent('error', 'bigint.not.positive', path, `${safeStringify(value)} must be > 0.`, `Please provide a positive bigint.`, { value, expected: '> 0', actual: parsed }),
66
+ ];
67
+ }
68
+ // ------------------------------------------------------------
69
+ // Valid — return an empty array to indicate success.
70
+ // ------------------------------------------------------------
71
+ return [];
72
+ };