@script-it/json-views-core 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +174 -0
- package/THIRD_PARTY_NOTICES.txt +4917 -0
- package/dist/annotation-capabilities.d.ts +17 -0
- package/dist/annotation-capabilities.js +21 -0
- package/dist/atomic-value.d.ts +3 -0
- package/dist/atomic-value.js +6 -0
- package/dist/date-type.d.ts +48 -0
- package/dist/date-type.js +244 -0
- package/dist/diagnostics.d.ts +8 -0
- package/dist/diagnostics.js +252 -0
- package/dist/document-session.d.ts +52 -0
- package/dist/document-session.js +164 -0
- package/dist/formats/conversion.d.ts +17 -0
- package/dist/formats/conversion.js +75 -0
- package/dist/formats/csv-format.d.ts +31 -0
- package/dist/formats/csv-format.js +269 -0
- package/dist/formats/document-format.d.ts +35 -0
- package/dist/formats/document-format.js +1 -0
- package/dist/formats/json-format.d.ts +12 -0
- package/dist/formats/json-format.js +109 -0
- package/dist/html-view-bindings.d.ts +4 -0
- package/dist/html-view-bindings.js +32 -0
- package/dist/html-view-limits.d.ts +1 -0
- package/dist/html-view-limits.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/inference-fields.d.ts +5 -0
- package/dist/inference-fields.js +23 -0
- package/dist/inference.d.ts +26 -0
- package/dist/inference.js +304 -0
- package/dist/json-limits.d.ts +8 -0
- package/dist/json-limits.js +25 -0
- package/dist/json-path.d.ts +14 -0
- package/dist/json-path.js +84 -0
- package/dist/json-source-patcher.d.ts +97 -0
- package/dist/json-source-patcher.js +778 -0
- package/dist/metadata.d.ts +137 -0
- package/dist/metadata.js +952 -0
- package/dist/safe-pattern.d.ts +5 -0
- package/dist/safe-pattern.js +20 -0
- package/dist/schema-validation.d.ts +3 -0
- package/dist/schema-validation.js +4 -0
- package/dist/source-default.d.ts +2 -0
- package/dist/source-default.js +39 -0
- package/dist/table-suitability.d.ts +5 -0
- package/dist/table-suitability.js +55 -0
- package/dist/type-registry.d.ts +57 -0
- package/dist/type-registry.js +238 -0
- package/dist/value-comparison.d.ts +18 -0
- package/dist/value-comparison.js +133 -0
- package/dist/view-model.d.ts +18 -0
- package/dist/view-model.js +134 -0
- package/package.json +52 -0
- package/schema/jsonviews.schema.json +102 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Script.it
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @script-it/json-views-core
|
|
2
|
+
|
|
3
|
+
Framework-free annotation compilation, validation, view projection, document sessions, and source-preserving edits.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { applyJsonPatchInSource, compileJsonViewMetadata, inspectJsonSource } from '@script-it/json-views-core'
|
|
7
|
+
const { value, diagnostics } = inspectJsonSource(source)
|
|
8
|
+
const compiled = compileJsonViewMetadata(value)
|
|
9
|
+
const nextSource = applyJsonPatchInSource(source, [{ op: 'replace', path: '/done', value: true }])
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Metadata is JSON Views' custom annotation format, not standard JSON Schema. The metadata schema is exported as `@script-it/json-views-core/schema.json`. Patterns use RE2 syntax without backreferences or look-around. Imported source must remain authoritative; inspection warns about unsafe numeric values and duplicate keys.
|
|
13
|
+
|
|
14
|
+
JSON objects, JSON arrays, and CSV use the exported format adapters. `csvFormat` normalizes rows for compilation while preserving BOM, quoting, line endings, and unrelated source bytes during edits. Use `convertToJsonViewsDocument` when array-root JSON or CSV needs embedded `$jsonviews` metadata.
|
|
15
|
+
|
|
16
|
+
`applyJsonPatchInSource` applies standard RFC 6902 operations atomically with RFC 6901 JSON Pointer paths. It preserves unrelated source bytes and reports the failed operation through `JsonPatchError`.
|
|
17
|
+
|
|
18
|
+
The complete annotation contract is documented in [Annotation specification](#annotation-specification) below.
|
|
19
|
+
|
|
20
|
+
Requires Node 22.13+ in the 22.x line or Node 24+. Browser bundlers are supported. MIT.
|
|
21
|
+
|
|
22
|
+
### Exact comparisons and resource limits
|
|
23
|
+
|
|
24
|
+
`compareJsonValues` orders booleans, numbers, strings, arrays, and objects by type, then by value (containers use lexicographic key/value ordering); null and missing values sort last. `jsonValuesEqual` uses structural, case-sensitive equality. Numeric source tokens are compared as exact decimals without expanding exponents.
|
|
25
|
+
|
|
26
|
+
For source-aware projections, pass a number-token lookup as the fifth argument to `applyJsonViewViewRows` or `projectJsonViewCollection`. Build it from non-shadowed `unsafe-number` diagnostics, keyed by `JSON.stringify(diagnostic.sourcePath)`. Without a lookup, only the supplied JavaScript values can be compared. The React viewer supplies this lookup automatically. Embedded filter operands also retain their source paths; external metadata operates on its supplied parsed values.
|
|
27
|
+
|
|
28
|
+
Structured operations support up to `MAX_JSON_DEPTH` (512) nested object/array containers. Deeper input raises `JsonDepthLimitError`, whose code is `json-depth-limit`; this is a resource limit, not invalid JSON syntax. Keep original source available for recovery. Source scanning and diagnostic traversal use explicit stacks.
|
|
29
|
+
|
|
30
|
+
## Annotation specification
|
|
31
|
+
|
|
32
|
+
Version 1 describes how JSON is inspected, validated, and presented. The annotation `schema` is a JSON Views descriptor map; it is **not** the JSON Schema vocabulary. The packaged [`jsonviews.schema.json`](./schema/jsonviews.schema.json) is a Draft 7 JSON Schema **for annotation objects**. It checks their structural shape. The compiler additionally checks paths, registered types, regex syntax, valid dates, compatible views, and values in the document.
|
|
33
|
+
|
|
34
|
+
### Document and annotation boundary
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { compileJsonViewMetadata, createDefaultTypeRegistry } from '@script-it/json-views-core'
|
|
38
|
+
|
|
39
|
+
const registry = createDefaultTypeRegistry()
|
|
40
|
+
const metadata = {
|
|
41
|
+
version: 1,
|
|
42
|
+
schema: { '$.rows[*].score': { type: 'number', minimum: 0, required: true } },
|
|
43
|
+
views: [{ name: 'Scores', path: '$.rows' }],
|
|
44
|
+
}
|
|
45
|
+
const compiled = compileJsonViewMetadata({ rows: [{ score: 3 }] }, registry, { metadata })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
An explicit `metadata` option takes precedence over embedded annotations and inference, including when its value is null or invalid. This supports JSON roots of any type without inserting a property into the user's data. Without this option, the compiler selects the root's own `$jsonviews` property. If it is absent, the compiler infers useful descriptors and views. An existing invalid annotation never triggers inferred replacement.
|
|
49
|
+
|
|
50
|
+
The compiler returns the untouched effective `metadata`, its `metadataSource` (`external`, `embedded`, or `inferred`), and a `status`: `none`, `ready`, `invalid`, or `unsupported-version`. `ready` means version 1 was processed; callers must still inspect `diagnostics`. `recognized` identifies valid, explicitly supplied version 1 annotations. `active` identifies compiled presentation/validation work; invalid or unsupported annotation versions are inactive but still carry diagnostics.
|
|
51
|
+
|
|
52
|
+
Only integer version `1` is supported. Other positive integer versions produce `unsupported-metadata-version`; malformed annotations produce `invalid-metadata`. The raw future metadata is retained for round trips and source editing. Consumers must not overwrite it with inferred metadata or version 1 settings.
|
|
53
|
+
|
|
54
|
+
### Paths and precedence
|
|
55
|
+
|
|
56
|
+
All paths start at `$`. Supported segments are `.property`, `['quoted property']`, `[0]`, and `[*]`. Quoted properties support single-quote, backslash, slash, control-character, and `\uXXXX` escapes. Array indices are nonnegative safe integers without leading zeros. A numeric-looking object key is a string property, such as `$['0']`; it is different from `$[0]`.
|
|
57
|
+
|
|
58
|
+
Wildcards match one array item **or one own dictionary property**. Recursive descent, slices, unions, JSONPath expressions, and filter expressions are not supported. View roots must be concrete; schema paths may contain wildcards. Record view fields must be `view.path + [*] + a concrete nonempty field path`, for example `$.rows[*].profile.email` for a `$.rows` collection.
|
|
59
|
+
|
|
60
|
+
Traversal reads own properties only. JSON keys including `__proto__` and `constructor` remain ordinary data. `setJsonValueAtPath` creates nested own data properties without following prototype properties or invoking inherited setters. Array construction accepts existing indices or the next consecutive index; it rejects sparse writes.
|
|
61
|
+
|
|
62
|
+
For a concrete location, schema precedence is:
|
|
63
|
+
|
|
64
|
+
1. More concrete segments win over wildcard segments.
|
|
65
|
+
2. Longer paths win where applicable.
|
|
66
|
+
3. Earlier declaration wins a tie.
|
|
67
|
+
|
|
68
|
+
Overlapping, equally specific descriptors that differ produce `schema-specificity-conflict`. This applies to dictionaries and arrays alike. Legacy `body` declarations normalize to `{ type: "markdown" }`. They do not select a special record property or limit how many text properties a record can contain.
|
|
69
|
+
|
|
70
|
+
### Descriptors and validation
|
|
71
|
+
|
|
72
|
+
Descriptors require `type`. Built-ins are `text`, `markdown`, `html`, `number`, `checkbox`, `select`, `multi-select`, `date`, `url`, and `email`. `body` is a legacy alias for Markdown. Applications register custom names through `JsonViewTypeRegistry`.
|
|
73
|
+
|
|
74
|
+
| Property | Contract |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `title`, `description`, `placeholder` | Strings |
|
|
77
|
+
| `required`, `multiline`, `defaultIncludeTime` | Booleans |
|
|
78
|
+
| `minimum`, `maximum` | Finite numeric bounds, or valid date strings for `date`; null date bounds are ignored |
|
|
79
|
+
| `pattern` | RE2 pattern string of at most 4,096 UTF-16 code units |
|
|
80
|
+
| `options` | Array of strings; observed nonempty select values are appended to the compiled options |
|
|
81
|
+
| `optionColors` | Map of option value to `gray`, `blue`, `green`, `yellow`, `orange`, `red`, `purple`, or `pink` |
|
|
82
|
+
| `step` | Positive finite number used as an editor hint |
|
|
83
|
+
|
|
84
|
+
Invalid known descriptor fields generate diagnostics and are absent from the normalized descriptor. Unknown fields are preserved for extensions. An unregistered type generates `unknown-schema-type` and is excluded from the compiled schema. `nullable` is unsupported: optional values already permit null. `select` and `multi-select` are open choices; options are editor suggestions, not a closed enumeration. `step` is an editor increment, not a divisibility constraint.
|
|
85
|
+
|
|
86
|
+
Built-in descriptors warn about properties their editor/validator does not consume. `minimum`/`maximum` apply to number and date; `step` to number; `options`/`optionColors` to choice types; `multiline` to text; `placeholder` to text, body, and date; `defaultIncludeTime` to date. Common `pattern` checks strings only, so number, checkbox, and multi-select descriptors warn that it does not constrain their non-string values. Warnings preserve the fields for host extensions. Custom type definitions can declare `descriptorProperties` to supply their supported keys; omitting it keeps the extension vocabulary open. A registration snapshots this list alongside its operator list.
|
|
87
|
+
|
|
88
|
+
### Progressive diagnostics
|
|
89
|
+
|
|
90
|
+
Start with ordinary JSON and only the annotations the task needs. Valid documents do not receive a capabilities manual. When a problem occurs, each compiler diagnostic adds `help` with a concrete `fix`, `expected` shape, a bounded `received` preview, and relevant `examples`, `allowedValues`, or `capabilities`. Examples are illustrative values/fragments, not automatic patches. Value examples satisfy the normalized active constraints. Type names and filter operator allowlists come from the current host registry, including custom registrations.
|
|
91
|
+
|
|
92
|
+
`metadataPath` identifies the exact annotation property to edit; `sourcePath` identifies affected data. For a missing required ancestor, `sourcePath` can identify the unresolved container rather than the leaf, and the repair explains the distinction. `metadataSource` tells callers whether annotations are embedded, external, or inferred. For external annotations the leading `$jsonviews` in `metadataPath` is a logical namespace: remove that first segment when addressing the separate annotation object. Do not insert it into the data.
|
|
93
|
+
|
|
94
|
+
Diagnostics report independent syntax issues together, even when a view name or root path is invalid. Data-dependent checks wait for a resolvable path. Unknown annotation, view, column, filter, and sort properties produce warnings with supported keys; warning-only views remain usable. Invalid or duplicate explicit view IDs warn about the generated replacement. Errors exclude invalid views, while the raw document remains available.
|
|
95
|
+
|
|
96
|
+
The React issue count stays compact. Open an issue's **How to fix** disclosure for repair details and every affected data path. Repeated failures with the same cause are grouped; different failure messages on the same field remain separate. Browser console and WebMCP reads and writes return the same complete help directly to agents. Repair the reported issue, then inspect again; do not coerce data or weaken validation merely to clear diagnostics. Source diagnostics likewise explain exact-token and CSV repairs; their zero-based `start`/exclusive `end` offsets refer to UTF-16 source positions.
|
|
97
|
+
|
|
98
|
+
Null and missing values are allowed unless `required: true`. Empty strings are also optional empty values for every built-in except date; a date empty string is invalid. A required descriptor applies to its entire concrete path: missing, null, or scalar intermediate objects do not hide a missing required leaf. If an ancestor before a wildcard is missing or not a collection, the diagnostic points at that unresolved container prefix. An empty existing collection has no child instances, so required child fields do not impose a minimum collection size. Empty arrays are valid multi-select values even with `required`; use a custom type if a selection count is required.
|
|
99
|
+
|
|
100
|
+
`registry.validate` is the canonical pipeline used by document compilation and `validateJsonViewSchemaValue`. It checks optionality, the registered type validator, then the common pattern constraint. This gives the document issue list and editor commits the same outcome. Custom descriptor validation failures are schema diagnostics; throwing value validators and warning providers produce diagnostics instead of escaping rendering.
|
|
101
|
+
|
|
102
|
+
### Safe pattern semantics
|
|
103
|
+
|
|
104
|
+
Patterns use [RE2JS](https://github.com/le0pard/re2js), a pure JavaScript RE2 engine. Matching uses `matcher(value).find()`, so patterns search for a match; use `^` and `$` for a whole-string constraint. There is no user-controlled native `RegExp` backtracking path. Backreferences, lookaheads, and other unsupported constructs produce `invalid-pattern`. No lookbehind feature flag is enabled. JavaScript-specific regex syntax and Unicode details must not be assumed interchangeable with RE2.
|
|
105
|
+
|
|
106
|
+
Matching is linear in input length for a fixed pattern. The compiler caps pattern size at 4,096 code units and retains at most 128 compiled patterns. These limits bound pattern input and cache count; they are not a wall-clock deadline for processing an arbitrarily large document. Trusted custom validators remain application code and must implement their own appropriate cost bounds.
|
|
107
|
+
|
|
108
|
+
### Views, filtering, and sorting
|
|
109
|
+
|
|
110
|
+
A view requires `name` and a concrete `path`. Absent `id`, the compiler assigns a deterministic identifier; duplicate IDs gain a numeric suffix. `columns` optionally supplies `{label, path}` entries. Missing or empty columns means infer columns from current rows. Labels need not be unique; projection assigns independent column IDs. Put the identifying field first: the first configured column supplies record links, Kanban headings, and opened record headings. Reordering or hiding it changes the label. View `title` is unsupported; schema `title` still labels a field.
|
|
111
|
+
|
|
112
|
+
Collections are arrays of objects or dictionaries whose values are objects. Single records render as record pages automatically; collection views use tables unless `display` selects `kanban` or `html`. `kanban` requires a record collection and `groupBy`. Optional `groupBy` and `orderPath` follow the record field path contract. `groupOrder` stores the ordered scalar lane values; values not currently present render as empty lanes. `orderPath` must differ from `groupBy` and resolve to a finite number on every record. Invalid view configuration produces diagnostics and excludes that view; it does not make the raw document unavailable.
|
|
113
|
+
|
|
114
|
+
Filters have `rules` and optional `match: 'all' | 'any'` (default `all`). Empty rules leave rows unchanged. Common operators are `eq`, `neq`, `in`, `notIn`, `gt`, `gte`, `lt`, `lte`, `contains`, `notContains`, `isEmpty`, and `isNotEmpty`. Every operator except the two presence operators requires `value`. `in` and `notIn` require an array comparison value. Equality compares JSON structure, ignoring object property order. String containment ignores case; array containment uses structural equality. Presence treats missing, null, empty string, and empty array as empty. Missing values do not satisfy non-presence common operators, including `neq`.
|
|
115
|
+
|
|
116
|
+
A type's `filterOperators` is its allowlist. Custom names are accepted when the matching registered types declare them; custom operators use `matchesFilter`. All applicable field types in the current collection must allow a configured rule. A custom matcher can return `undefined` to use common operator behavior. Unknown operators never fall through to an ordering operation. A custom operator without a declared type is rejected. `date` permits equality, inequality, ordering, and presence operators only.
|
|
117
|
+
|
|
118
|
+
Invalid date comparison operands are diagnosed at the rule's `value`; use a real date/timestamp string or a presence operator for missing dates. Filter operands are not constrained by the field's minimum/maximum bounds. A `value` on a presence rule produces a warning because it is ignored.
|
|
119
|
+
|
|
120
|
+
Sort entries have `path` and `direction: 'asc' | 'desc'`. Source order is the stable tiebreaker, and missing/null values stay last. Sort keys are resolved once per row. Each sort column uses one comparator for every pair: one homogeneous registered type uses its comparator; mixed type annotations use the generic ordering. Plugins must supply comparators that are reflexive, antisymmetric, and transitive.
|
|
121
|
+
|
|
122
|
+
### Dates: sort order and calendar predicates
|
|
123
|
+
|
|
124
|
+
Dates accept `YYYY-MM-DD`, timezone-aware RFC 3339 timestamps with seconds and optional fractional seconds, and floating timestamps without an offset. Calendar validity is checked, including leap years. Offsets are bounded by ±14:00; leap seconds and `24:00:00` are unsupported. Floating timestamps are not converted using the computer's timezone.
|
|
125
|
+
|
|
126
|
+
Sorting uses one consistent reference timeline: zoned values use their instant, calendar dates use midnight UTC as an ordering reference, and floating values use their written fields as a UTC reference. Equal reference timestamps break ties by kind: date, floating timestamp, then zoned timestamp. Zoned strings expressing the same instant and fractional value compare equal. Invalid/empty values sort last in either direction. This ordering reference does not assign a real timezone to floating dates.
|
|
127
|
+
|
|
128
|
+
A **date-only filter operand** compares the value's written calendar day for every relational operator. Thus a timestamp on `2026-01-02` in any written offset satisfies `eq`, `gte`, and `lte` against `2026-01-02`, and does not satisfy `gt` or `lt`. Timestamp filter operands use the sort order. Date-only bounds likewise compare written days; timestamp bounds use the reference timeline.
|
|
129
|
+
|
|
130
|
+
The built-in date widget exchanges canonical JSON strings. Its registry conversion hooks are identity. `parseDateValue`, `serializeDateEditorValue`, and `convertDateTimeToOffset` are separate helpers for applications needing structured date editing or explicit offset conversion.
|
|
131
|
+
|
|
132
|
+
### Extension lifecycle
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const registry = createDefaultTypeRegistry().register({
|
|
136
|
+
name: 'point',
|
|
137
|
+
validateDescriptor: (descriptor) =>
|
|
138
|
+
typeof descriptor.radius === 'number' ? undefined : 'radius must be numeric',
|
|
139
|
+
parse: (json) => (json as { x: number }).x,
|
|
140
|
+
serialize: (editorValue) => ({ x: Number(editorValue) }),
|
|
141
|
+
validate: (json) =>
|
|
142
|
+
json !== null && typeof json === 'object' && 'x' in json &&
|
|
143
|
+
typeof json.x === 'number' && Number.isFinite(json.x) ? undefined : 'Expected a point',
|
|
144
|
+
filterOperators: ['near'],
|
|
145
|
+
matchesFilter: (json, operator, expected) => operator === 'near'
|
|
146
|
+
? Math.abs((json as { x: number }).x - Number(expected)) < 2 : undefined,
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`parse` converts persisted JSON to an editor model. `serialize` converts the committed editor model back to JSON. Omitted conversion hooks are identity. The commit order is **serialize → canonical validation → strict JSON source patch → persistence**. Register a corresponding React widget for a custom visual editor. Object and array JSON values participate in this contract.
|
|
151
|
+
|
|
152
|
+
Registering or unregistering changes `registry.version` and notifies `registry.subscribe`. Definition objects and operator lists are snapshotted at registration. Use registry methods to change behavior; do not mutate objects returned by `get`. `clone()` makes an independent registry. React consumers must subscribe rather than relying only on registry object identity.
|
|
153
|
+
|
|
154
|
+
### Source preservation and plans
|
|
155
|
+
|
|
156
|
+
Keep the original source string as the authority and parse a separate inspection value. `inspectJsonSource` reports duplicate object keys, unsafe integers, overflow, underflow, negative zero, and decimal tokens changed by JavaScript-number conversion. Structured inspection uses `JSON.parse` values and therefore displays the last duplicate occurrence. Numeric diagnostics supply exact source literals to the React renderer, including large integers, overflow, underflow, negative zero, and decimal round-trip changes. Exact tokens also remain available in diagnostics and source. The renderer keeps structured inspection available and protects affected paths. Replacing an unsafe numeric token or an ancestor container is disabled. Duplicate keys also block descendant replacements whose identity is ambiguous. Unrelated scalar edits, array appends, and whole-row deletions remain available because their patches preserve retained data lexemes. Each transaction checks the latest source. A visible source-recovery editor permits exact token edits; annotation rewrites are also protected if the annotation object contains risky source tokens.
|
|
157
|
+
|
|
158
|
+
Patching helpers preserve unrelated bytes. The agent-facing mutation API accepts standard RFC 6902 JSON Patch with RFC 6901 JSON Pointer paths and applies each batch atomically. Typed internal paths distinguish array indices from property names. Replacement and removal select the last duplicate property, matching `JSON.parse`; removing it can expose an earlier duplicate. Batch replacement validates one document, scans/indexes its source once, rejects duplicate or overlapping spans, and assembles one result without repeated whole-document rewrites.
|
|
159
|
+
|
|
160
|
+
`stringifyJsonValue` accepts null, strings, booleans, finite numbers, dense arrays, and plain own-data objects (including null-prototype objects). It preserves numeric negative zero. It rejects undefined, functions, symbols, bigint, non-finite values, sparse arrays, accessors, cycles, custom object prototypes, and `toJSON` methods; no getters or conversion methods are invoked. A replacement is serialized once. Use source-level editing for numeric lexemes that a JavaScript number cannot express exactly.
|
|
161
|
+
|
|
162
|
+
Compiled metadata includes the root and each view's `value` snapshot for direct rendering. `applyJsonViewViewRows`, `projectJsonViewCollection`, and `resolveJsonViewRowPath` resolve against their explicit current-root argument. `getJsonViewViewRows(view, root)` does the same; `getJsonViewViewRows(view)` intentionally reads the compiled snapshot. Recompile when annotations or registry behavior change, or to refresh diagnostics and inferred options for a new document revision.
|
|
163
|
+
|
|
164
|
+
The synchronous compiler and scanner have no universal document-size guarantee. Table virtualization limits mounted rows, not parsing, validation, projection, or Kanban work. Source revision caching avoids unnecessary repeat work; applications handling very large documents should perform compilation/inspection in a worker and choose their own measured size budgets. The test workload covers 1,000 independent edits within a 10,000-row document, and comparator/adversarial-pattern regressions are retained in the core suite.
|
|
165
|
+
|
|
166
|
+
### Host acknowledgements and reloads
|
|
167
|
+
|
|
168
|
+
`JsonDocumentSession` keeps acknowledged source separate from the current draft. Saves resolve to accepted `{content, revision}` snapshots when a host supports revisions. The session remembers up to 32 recently acknowledged identities and ignores their delayed host echoes. Rejected drafts never enter this history. A matching host observation received during an in-flight save is provisional; after successful persistence, its explicit revision takes precedence over the response revision for the same accepted content. Opaque revision strings have no sortable age, so this rule treats the newer host observation as evidence of current state rather than comparing revision text. Different content still produces a conflict and preserves the local draft.
|
|
169
|
+
|
|
170
|
+
A revision can be a content hash, so an intentional rollback to an old `{content, revision}` pair is indistinguishable from a delayed echo. Use `receive(source, { authoritative: true })` for an explicit reload/rollback, or create a fresh document session. Unknown new revisions remain authoritative without this option. Authoritative receive still preserves conflicting unsaved drafts; use `reset()` after the save has settled to discard the draft. Hosts needing unbounded replay detection must provide their own ordered revision stream; the finite local history is not a durable event log.
|
|
171
|
+
|
|
172
|
+
### Embedded HTML views
|
|
173
|
+
|
|
174
|
+
Use `display: "html"` with `path`, a non-empty `html` string and optional `css` string inside `$jsonviews.views`. The same-file template supports source-bound values, existing field editors, native controls and repeated arrays. See [HTML views](https://github.com/script-it/json-views/blob/main/packages/react/README.md#html-views) for the format, bindings, isolation, and examples.
|