@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,53 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Is Printable
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string containing only
7
+ * printable ASCII characters (code points 0x20–0x7E).
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 containing only printable ASCII
19
+ * characters (code points 0x20–0x7E).
20
+ *
21
+ * - Non‑string values emit `string.not.string`.
22
+ * - Strings containing characters outside the printable ASCII range emit
23
+ * `string.not.printable`.
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 isPrintable = async (value, path) => {
31
+ const structuralType = detectStructuralType(value);
32
+ // ------------------------------------------------------------
33
+ // Type check
34
+ // ------------------------------------------------------------
35
+ if (typeof value !== 'string') {
36
+ return [
37
+ validationEvent('error', 'string.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
38
+ ];
39
+ }
40
+ // ------------------------------------------------------------
41
+ // Printable ASCII check
42
+ // ------------------------------------------------------------
43
+ const printablePattern = /^[\x20-\x7E]+$/;
44
+ if (!printablePattern.test(value)) {
45
+ return [
46
+ validationEvent('error', 'string.not.printable', path, `${safeStringify(value)} must contain only printable ASCII characters.`, `Please use only printable characters.`, { value, expected: 'printable ASCII', actual: value }),
47
+ ];
48
+ }
49
+ // ------------------------------------------------------------
50
+ // Valid
51
+ // ------------------------------------------------------------
52
+ return [];
53
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Matches
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string matching the provided
7
+ * regular expression.
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 matching the provided regular expression.
19
+ *
20
+ * - Non‑string values emit `string.not.string`.
21
+ * - Strings that do not satisfy the pattern emit `string.is.not-match`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const matches = (pattern) => async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'string.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please provide a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Pattern match check
40
+ // ------------------------------------------------------------
41
+ if (!pattern.test(value)) {
42
+ return [
43
+ validationEvent('error', 'string.is.not-match', path, `${safeStringify(value)} must match pattern ${pattern}.`, `Please provide a value matching the required format.`, { value, expected: pattern.toString(), actual: value }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Maximum Length (Max Length)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string whose length is less
7
+ * than or equal to the provided `max` value.
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
+ * Validates that the value is a string whose length is less than or equal to
18
+ * the provided `max` value.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings longer than `max` emit `string.too.long`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const maxLength = (max) => async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Maximum-length check
40
+ // ------------------------------------------------------------
41
+ if (value.length > max) {
42
+ return [
43
+ validationEvent('error', 'string.too.long', path, `String length ${value.length} must be ≤ ${max}.`, `Please enter no more than ${max} characters.`, { value, expected: `≤ ${max}`, actual: value.length }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Minimum Length (Min Length)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string whose length is greater
7
+ * than or equal to the provided `min` value.
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
+ * Validates that the value is a string whose length is greater than or equal to
18
+ * the provided `min` value.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings shorter than `min` emit `string.too.short`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const minLength = (min) => async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Minimum-length check
40
+ // ------------------------------------------------------------
41
+ if (value.length < min) {
42
+ return [
43
+ validationEvent('error', 'string.too.short', path, `String length ${value.length} must be ≥ ${min}.`, `Please enter at least ${min} characters.`, { value, expected: `≥ ${min}`, actual: value.length }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | No Leading Whitespace (No Lead Space)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string that does not begin
7
+ * with whitespace.
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 that does not begin with whitespace.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings beginning with whitespace emit `string.has.leading-whitespace`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const noLeadSpace = async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Leading whitespace check
40
+ // ------------------------------------------------------------
41
+ if (/^\s/.test(value)) {
42
+ return [
43
+ validationEvent('error', 'string.has.leading-whitespace', path, `${safeStringify(value)} must not start with whitespace.`, `Please remove leading spaces.`, { value, expected: 'no leading space', actual: value }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | No Repeated Whitespace (No Repeat Space)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string that does not contain
7
+ * repeated consecutive space characters.
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 that does not contain repeated
19
+ * consecutive space characters.
20
+ *
21
+ * - Non‑string values emit `type.not.valid`.
22
+ * - Strings containing `" "` (two or more consecutive spaces) emit
23
+ * `string.has.repeating-whitespace`.
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 noRepeatSpace = async (value, path) => {
31
+ const structuralType = detectStructuralType(value);
32
+ // ------------------------------------------------------------
33
+ // Type check
34
+ // ------------------------------------------------------------
35
+ if (typeof value !== 'string') {
36
+ return [
37
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
38
+ ];
39
+ }
40
+ // ------------------------------------------------------------
41
+ // Repeated-space check
42
+ // ------------------------------------------------------------
43
+ if (/ {2,}/.test(value)) {
44
+ return [
45
+ validationEvent('error', 'string.has.repeating-whitespace', path, `${safeStringify(value)} must not contain repeated spaces.`, `Please remove extra spaces.`, { value, expected: 'no repeated spaces', actual: value }),
46
+ ];
47
+ }
48
+ // ------------------------------------------------------------
49
+ // Valid
50
+ // ------------------------------------------------------------
51
+ return [];
52
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | No Whitespace (No Space)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string containing no
7
+ * whitespace characters.
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 containing no whitespace characters.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings containing any whitespace (spaces, tabs, newlines, etc.) emit
22
+ * `string.has.whitespace`.
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 noSpace = async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ // ------------------------------------------------------------
32
+ // Type check
33
+ // ------------------------------------------------------------
34
+ if (typeof value !== 'string') {
35
+ return [
36
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
37
+ ];
38
+ }
39
+ // ------------------------------------------------------------
40
+ // Whitespace check
41
+ // ------------------------------------------------------------
42
+ if (/\s/.test(value)) {
43
+ return [
44
+ validationEvent('error', 'string.has.whitespace', path, `${safeStringify(value)} must not contain whitespace.`, `Please remove spaces.`, { value, expected: 'no whitespace', actual: value }),
45
+ ];
46
+ }
47
+ // ------------------------------------------------------------
48
+ // Valid
49
+ // ------------------------------------------------------------
50
+ return [];
51
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | No Trailing Whitespace (No Trail Space)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string that does not end with
7
+ * whitespace.
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 that does not end with whitespace.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings ending with whitespace emit `string.has.trailing-whitespace`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const noTrailSpace = async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Trailing whitespace check
40
+ // ------------------------------------------------------------
41
+ if (/\s$/.test(value)) {
42
+ return [
43
+ validationEvent('error', 'string.has.trailing-whitespace', path, `${safeStringify(value)} must not end with whitespace.`, `Please remove trailing spaces.`, { value, expected: 'no trailing space', actual: value }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Non-Empty
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a non-empty string.
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
+ * Validates that the value is a non-empty string.
17
+ *
18
+ * - Non‑string values emit `string.not.string`.
19
+ * - Empty strings emit `string.is.empty`.
20
+ * - Returns an empty array when the value is valid.
21
+ *
22
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
23
+ * JaneEvent objects. It preserves the provided path and supports userMessage
24
+ * overrides applied at the pipeline level.
25
+ */
26
+ export const nonEmpty = async (value, path) => {
27
+ const structuralType = detectStructuralType(value);
28
+ // ------------------------------------------------------------
29
+ // Type check
30
+ // ------------------------------------------------------------
31
+ if (typeof value !== 'string') {
32
+ return [
33
+ validationEvent('error', 'string.not.string', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
34
+ ];
35
+ }
36
+ // ------------------------------------------------------------
37
+ // Non-empty check
38
+ // ------------------------------------------------------------
39
+ if (value.length === 0) {
40
+ return [
41
+ validationEvent('error', 'string.is.empty', path, `String must not be empty.`, `Please enter a non-empty string.`, { value, expected: 'non-empty', actual: value }),
42
+ ];
43
+ }
44
+ // ------------------------------------------------------------
45
+ // Valid
46
+ // ------------------------------------------------------------
47
+ return [];
48
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Not One Of
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string that is *not* included
7
+ * in the provided `disallowed` list.
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 that is *not* included in the provided
19
+ * `disallowed` list.
20
+ *
21
+ * - Non‑string values emit `type.not.valid`.
22
+ * - Strings that appear in the disallowed list emit `string.is.disallowed`.
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 notOneOf = (disallowed) => async (value, path) => {
30
+ const structuralType = detectStructuralType(value);
31
+ // ------------------------------------------------------------
32
+ // Type check
33
+ // ------------------------------------------------------------
34
+ if (typeof value !== 'string') {
35
+ return [
36
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
37
+ ];
38
+ }
39
+ // ------------------------------------------------------------
40
+ // Disallowed membership check
41
+ // ------------------------------------------------------------
42
+ if (disallowed.includes(value)) {
43
+ return [
44
+ validationEvent('error', 'string.is.disallowed', path, `${safeStringify(value)} must not be one of: ${disallowed.join(', ')}.`, `Please enter a different value.`, { value, expected: `not in ${disallowed}`, actual: value }),
45
+ ];
46
+ }
47
+ // ------------------------------------------------------------
48
+ // Valid
49
+ // ------------------------------------------------------------
50
+ return [];
51
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | Number String (Num String)
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string containing only ASCII
7
+ * digits (`0–9`).
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 containing only ASCII digits (`0–9`).
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings containing any non-digit character emit `string.not.numeric`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const numString = async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Digit-only check
40
+ // ------------------------------------------------------------
41
+ if (!/^[0-9]+$/.test(value)) {
42
+ return [
43
+ validationEvent('error', 'string.not.numeric', path, `${safeStringify(value)} must contain only digits.`, `Please use only numbers.`, { value, expected: '0-9', actual: value }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ----------------------------------------------------------------------------
3
+ * Validators | One Of
4
+ * ----------------------------------------------------------------------------
5
+ * @package @clementine-solutions/jane
6
+ * @description Validates that the value is a string included in the
7
+ * provided `allowed` list.
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 included in the provided `allowed` list.
19
+ *
20
+ * - Non‑string values emit `type.not.valid`.
21
+ * - Strings not present in the allowed list emit `string.not.allowed`.
22
+ * - Returns an empty array when the value is valid.
23
+ *
24
+ * This rule is pure, total, async‑compatible, and returns a readonly array of
25
+ * JaneEvent objects. It preserves the provided path and supports userMessage
26
+ * overrides applied at the pipeline level.
27
+ */
28
+ export const oneOf = (allowed) => async (value, path) => {
29
+ const structuralType = detectStructuralType(value);
30
+ // ------------------------------------------------------------
31
+ // Type check
32
+ // ------------------------------------------------------------
33
+ if (typeof value !== 'string') {
34
+ return [
35
+ validationEvent('error', 'type.not.valid', path, `Expected 'string' but received '${structuralType}'.`, `Please enter a valid string.`, { value, expected: 'string', actual: structuralType }),
36
+ ];
37
+ }
38
+ // ------------------------------------------------------------
39
+ // Allowed membership check
40
+ // ------------------------------------------------------------
41
+ if (!allowed.includes(value)) {
42
+ return [
43
+ validationEvent('error', 'string.not.allowed', path, `${safeStringify(value)} must be one of: ${allowed.join(', ')}.`, `Please enter one of the allowed values.`, { value, expected: allowed, actual: value }),
44
+ ];
45
+ }
46
+ // ------------------------------------------------------------
47
+ // Valid
48
+ // ------------------------------------------------------------
49
+ return [];
50
+ };