@jarenjs/core 0.72.2 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ARCHITECTURE.md CHANGED
@@ -83,7 +83,7 @@ flowchart TB
83
83
  Integer["integer.js<br/>Int8/16/32/64 validation"]
84
84
  Float["float.js<br/>Float16/32/64 validation"]
85
85
  BigIntModule["bigint.js<br/>BigInt utilities"]
86
- NumberModule["number.js<br/>Number coercion"]
86
+ NumberModule["number.js<br/>Coercion and JSON number grammar"]
87
87
  end
88
88
 
89
89
  subgraph CollectionModules["Collection Modules"]
package/README.md CHANGED
@@ -12,7 +12,7 @@ None of it depends on JSON Schema: every module can be used standalone in any Ja
12
12
  | `@jarenjs/core/array` | array helpers (`isUniqueArray`, `getUniqueArray`, `includesAll`, ...) |
13
13
  | `@jarenjs/core/object` | deep equality (`equalsDeep`, JSON-only `equalsJson`), the `isJsonObject` and deep `isJsonValue` predicates, `__proto__`-safe `setObjectMember`, `deepFreeze`, map/set merging |
14
14
  | `@jarenjs/core/string` | Unicode string helpers (`countCodePoints`, `compareCodePoints`, ...), regex compilation and repeatable `createRegExpTester` predicates, the suite's one content hash (`fnv1a` and the `hashContent` fingerprint over it) and `kebabCase` |
15
- | `@jarenjs/core/cache` | the bounded LRU (`createBoundedCache`), the reference-keyed `createWeakCache`, and `createSemanticCache` — keyed by what a value IS, for caches whose entries decide a result |
15
+ | `@jarenjs/core/cache` | the bounded LRU with key deletion (`createBoundedCache`), the reference-keyed `createWeakCache`, and `createSemanticCache` — keyed by what a value IS, for caches whose entries decide a result |
16
16
  | `@jarenjs/core/random` | the suite's one seeded generator (`mulberry32`, pinned sequence, ToUint32 seed) and the draws built on it: `randomInt` over a half-open range, in-place Fisher–Yates `shuffle`, and `drawDistinct` — `k` distinct indices from one stream |
17
17
  | `@jarenjs/core/runtime` | the runtime record — `createRuntime({ now, uuid, random, zoneProvider })`, frozen, defaulting member for member to the platform's own (`Date.now`, `crypto.randomUUID`, `Math.random`, no zone provider) — that the store (its query deadlines included), the jobs engine, the migration runner, every contract binding and the contract memory ledger take as `runtime`, so a deterministic run is configured once; a subsystem's own explicit option wins over the record, and the record reaches hosts, never query compilation |
18
18
  | `@jarenjs/core/stats` | descriptive statistics over a sample: `mean`, sample `variance`/`stddev`, the midpoint `median`, and `quantile(values, p, { method })` — `p` on 0..1 under a NAMED rule, `'nearest-rank'` or `'linear'`, because a default would decide silently; an empty sample answers `undefined`, never `0` |
@@ -21,7 +21,7 @@ None of it depends on JSON Schema: every module can be used standalone in any Ja
21
21
  | `@jarenjs/core/scan` | char-code constants and predicates for recursive-descent parsers |
22
22
  | `@jarenjs/core/message` | the message template/catalog compiler shared by the validator and the form layer |
23
23
  | `@jarenjs/core/color` | pure color math (`lerpColor` — hex `#rrggbb` interpolation) |
24
- | `@jarenjs/core/number` | boolean/number/integer coercion helpers (`isIntishType`, ...) |
24
+ | `@jarenjs/core/number` | boolean/number/integer coercion helpers (`isIntishType`, ...) and `isJsonNumberString`, the strict lexical JSON-number predicate shared by query casts and schema normalization; conversion and overflow policy stay with each caller |
25
25
  | `@jarenjs/core/integer` | `int8` ... `uint64` ranges and validators |
26
26
  | `@jarenjs/core/float` | `float16` ... `float64` constants, validators, increment/decrement |
27
27
  | `@jarenjs/core/bigint` | bigint helpers (`BigInt_min`, `BigInt_MinMax`, ...) |
@@ -1,18 +1,13 @@
1
1
  /**
2
- * @file The suite's one bounded-cache primitive. Before this file the
3
- * FIFO-512 delete-oldest map was written five times (the query engine's
4
- * string cache, the JSONPath query cache, forms' three pointer caches)
5
- * with a sixth divergent flush-all variant in forms' regex cache and a
6
- * true LRU in the view projection memo. One implementation, one policy:
2
+ * @file The suite's bounded-cache primitive for compiled queries,
3
+ * pointers, regular expressions and view projections. One eviction policy
4
+ * keeps each consumer's retained working set bounded:
7
5
  *
8
6
  * - **LRU with recency refresh**: a `get` hit re-inserts the entry, so
9
7
  * the evicted entry is the least recently USED, not the oldest
10
- * inserted. (FIFO versus LRU was never result-observable at any call
11
- * site — both bound memory; LRU keeps hot entries hotter.)
8
+ * inserted.
12
9
  * - **Evict at `size >= limit` before inserting a new key**, so the
13
- * cache never holds more than `limit` entries. (The old sites
14
- * disagreed between `>=`-before and `>`-after; the capacity is the
15
- * same, the invariant here is simply "never above `limit`".)
10
+ * cache never holds more than `limit` entries for a positive integer limit.
16
11
  * - `undefined` is the miss sentinel: a cache MUST NOT store
17
12
  * `undefined` as a value (store `null` for "computed, negative" —
18
13
  * the regex cache does exactly that).
@@ -44,6 +39,11 @@ export type BoundedCache<K, V> = {
44
39
  * or compute-and-insert in one step.
45
40
  */
46
41
  getOrCreate: (key: K, create: (key: K) => V) => V;
42
+ /**
43
+ * - Drop one entry; true when the
44
+ * key existed, including an entry whose value was undefined.
45
+ */
46
+ delete: (key: K) => boolean;
47
47
  /**
48
48
  * - Drop every entry.
49
49
  */
@@ -62,6 +62,8 @@ export type BoundedCache<K, V> = {
62
62
  * the least recently used entry when the cache is full.
63
63
  * @property {(key: K, create: (key: K) => V) => V} getOrCreate - Lookup
64
64
  * or compute-and-insert in one step.
65
+ * @property {(key: K) => boolean} delete - Drop one entry; true when the
66
+ * key existed, including an entry whose value was undefined.
65
67
  * @property {() => void} clear - Drop every entry.
66
68
  * @property {() => number} size - Current entry count.
67
69
  */
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Whether a string is exactly one JSON number (RFC 8259 section 6), with
3
+ * no surrounding whitespace. This checks spelling only: `1e999` is valid
4
+ * even though converting it to a JavaScript number overflows. Callers
5
+ * choose their own conversion, finiteness and safe-integer policies.
6
+ * @param {unknown} value - The value to check, without coercion
7
+ * @returns {boolean} True for a string matching the complete number grammar
8
+ */
9
+ export declare function isJsonNumberString(value: unknown): boolean;
1
10
  /**
2
11
  * Checks if the given data is of boolean type or boolean-like (the strings 'true' or 'false').
3
12
  * @param {any} data - The data to check.
@@ -1,16 +1,13 @@
1
1
  /**
2
- * @file The runtime record: the host facts every subsystem that needs
3
- * one used to take separately the clock, secure identifiers,
4
- * randomness and the zone provider — as one frozen record a host builds
2
+ * @file The runtime record: the clock, secure identifiers, randomness
3
+ * and the zone provider as one frozen record a host builds
5
4
  * once and hands to the store, the jobs engine, the migration runner and
6
5
  * the http binding. Nothing here IS a clock, a random source or a zone
7
6
  * database: the defaults are the platform's own (`Date.now`,
8
- * `crypto.randomUUID`, `Math.random`, and no zone provider, which keeps
9
- * a named zone the refusal it always was), so adopting the record changes
10
- * nothing a consumer can observe. What it buys is that a deterministic
11
- * run a fixed clock, a seeded generator, a counting identifier — is
12
- * configured in one place, and that four subsystems can no longer
13
- * disagree about what time it is.
7
+ * `crypto.randomUUID`, `Math.random`, and no zone provider). Named zones
8
+ * require an injected provider. A deterministic run a fixed clock,
9
+ * a seeded generator, a counting identifier is configured in one place
10
+ * so the subsystems agree about time and identity.
14
11
  *
15
12
  * Precedence is fixed: a subsystem's own explicit option wins over the
16
13
  * record's member, which wins over the built-in default. The options are
@@ -1,13 +1,10 @@
1
1
  /**
2
2
  * @file The JSON Schema constraint-keyword vocabulary, grouped by the
3
- * value family each keyword constrains. Before this file the same
4
- * keyword lists were spelled four times (forms' constraint extraction,
5
- * emit's dropped-constraint table, the validator's `$data` dispatch
6
- * order and its `$ref`-sibling detection) and a keyword added to one
7
- * list silently missed the others. Each site composes the list it wants
8
- * from these groups and appends its own extras; the loops stay where
9
- * they are, because the drift risk was always in the data, not the
10
- * code.
3
+ * value family each keyword constrains. Forms' constraint extraction,
4
+ * emit's dropped-constraint table and the validator's dispatch and
5
+ * `$ref`-sibling detection compose their lists from these shared groups
6
+ * and append their own extras. Consumers own their processing loops;
7
+ * the shared vocabulary keeps keyword membership consistent.
11
8
  *
12
9
  * ORDER IS PART OF THE CONTRACT: the validator's `$data` dispatch
13
10
  * applies keywords in list order and its error order is observable
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jarenjs/core",
3
3
  "private": false,
4
- "version": "0.72.2",
4
+ "version": "0.73.0",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./dist/types/index.d.ts",
package/src/cache.js CHANGED
@@ -1,19 +1,14 @@
1
1
  //@ts-check
2
2
  /**
3
- * @file The suite's one bounded-cache primitive. Before this file the
4
- * FIFO-512 delete-oldest map was written five times (the query engine's
5
- * string cache, the JSONPath query cache, forms' three pointer caches)
6
- * with a sixth divergent flush-all variant in forms' regex cache and a
7
- * true LRU in the view projection memo. One implementation, one policy:
3
+ * @file The suite's bounded-cache primitive for compiled queries,
4
+ * pointers, regular expressions and view projections. One eviction policy
5
+ * keeps each consumer's retained working set bounded:
8
6
  *
9
7
  * - **LRU with recency refresh**: a `get` hit re-inserts the entry, so
10
8
  * the evicted entry is the least recently USED, not the oldest
11
- * inserted. (FIFO versus LRU was never result-observable at any call
12
- * site — both bound memory; LRU keeps hot entries hotter.)
9
+ * inserted.
13
10
  * - **Evict at `size >= limit` before inserting a new key**, so the
14
- * cache never holds more than `limit` entries. (The old sites
15
- * disagreed between `>=`-before and `>`-after; the capacity is the
16
- * same, the invariant here is simply "never above `limit`".)
11
+ * cache never holds more than `limit` entries for a positive integer limit.
17
12
  * - `undefined` is the miss sentinel: a cache MUST NOT store
18
13
  * `undefined` as a value (store `null` for "computed, negative" —
19
14
  * the regex cache does exactly that).
@@ -41,6 +36,8 @@ import { semanticKey } from './object.js';
41
36
  * the least recently used entry when the cache is full.
42
37
  * @property {(key: K, create: (key: K) => V) => V} getOrCreate - Lookup
43
38
  * or compute-and-insert in one step.
39
+ * @property {(key: K) => boolean} delete - Drop one entry; true when the
40
+ * key existed, including an entry whose value was undefined.
44
41
  * @property {() => void} clear - Drop every entry.
45
42
  * @property {() => number} size - Current entry count.
46
43
  */
@@ -84,7 +81,8 @@ export function createBoundedCache(limit) {
84
81
  return value;
85
82
  }
86
83
 
87
- return { get, set, getOrCreate, clear: () => map.clear(), size: () => map.size };
84
+ return { get, set, getOrCreate, delete: (key) => map.delete(key),
85
+ clear: () => map.clear(), size: () => map.size };
88
86
  }
89
87
 
90
88
  /**
package/src/number.js CHANGED
@@ -1,5 +1,19 @@
1
1
  //@ts-check
2
2
 
3
+ const JSON_NUMBER_RE = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/;
4
+
5
+ /**
6
+ * Whether a string is exactly one JSON number (RFC 8259 section 6), with
7
+ * no surrounding whitespace. This checks spelling only: `1e999` is valid
8
+ * even though converting it to a JavaScript number overflows. Callers
9
+ * choose their own conversion, finiteness and safe-integer policies.
10
+ * @param {unknown} value - The value to check, without coercion
11
+ * @returns {boolean} True for a string matching the complete number grammar
12
+ */
13
+ export function isJsonNumberString(value) {
14
+ return typeof value === 'string' && JSON_NUMBER_RE.test(value);
15
+ }
16
+
3
17
  /**
4
18
  * Checks if the given data is of boolean type or boolean-like (the strings 'true' or 'false').
5
19
  * @param {any} data - The data to check.
package/src/runtime.js CHANGED
@@ -1,17 +1,14 @@
1
1
  //@ts-check
2
2
  /**
3
- * @file The runtime record: the host facts every subsystem that needs
4
- * one used to take separately the clock, secure identifiers,
5
- * randomness and the zone provider — as one frozen record a host builds
3
+ * @file The runtime record: the clock, secure identifiers, randomness
4
+ * and the zone provider as one frozen record a host builds
6
5
  * once and hands to the store, the jobs engine, the migration runner and
7
6
  * the http binding. Nothing here IS a clock, a random source or a zone
8
7
  * database: the defaults are the platform's own (`Date.now`,
9
- * `crypto.randomUUID`, `Math.random`, and no zone provider, which keeps
10
- * a named zone the refusal it always was), so adopting the record changes
11
- * nothing a consumer can observe. What it buys is that a deterministic
12
- * run a fixed clock, a seeded generator, a counting identifier — is
13
- * configured in one place, and that four subsystems can no longer
14
- * disagree about what time it is.
8
+ * `crypto.randomUUID`, `Math.random`, and no zone provider). Named zones
9
+ * require an injected provider. A deterministic run a fixed clock,
10
+ * a seeded generator, a counting identifier is configured in one place
11
+ * so the subsystems agree about time and identity.
15
12
  *
16
13
  * Precedence is fixed: a subsystem's own explicit option wins over the
17
14
  * record's member, which wins over the built-in default. The options are
package/src/schema.js CHANGED
@@ -1,14 +1,11 @@
1
1
  //@ts-check
2
2
  /**
3
3
  * @file The JSON Schema constraint-keyword vocabulary, grouped by the
4
- * value family each keyword constrains. Before this file the same
5
- * keyword lists were spelled four times (forms' constraint extraction,
6
- * emit's dropped-constraint table, the validator's `$data` dispatch
7
- * order and its `$ref`-sibling detection) and a keyword added to one
8
- * list silently missed the others. Each site composes the list it wants
9
- * from these groups and appends its own extras; the loops stay where
10
- * they are, because the drift risk was always in the data, not the
11
- * code.
4
+ * value family each keyword constrains. Forms' constraint extraction,
5
+ * emit's dropped-constraint table and the validator's dispatch and
6
+ * `$ref`-sibling detection compose their lists from these shared groups
7
+ * and append their own extras. Consumers own their processing loops;
8
+ * the shared vocabulary keeps keyword membership consistent.
12
9
  *
13
10
  * ORDER IS PART OF THE CONTRACT: the validator's `$data` dispatch
14
11
  * applies keywords in list order and its error order is observable