@texuli/spec 0.6.0 → 0.8.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/README.md +80 -9
- package/dist/build.d.ts +9 -0
- package/dist/build.js +12 -0
- package/dist/catalog.d.ts +3 -2
- package/dist/catalog.js +3 -2
- package/dist/codegen/index.d.ts +1 -1
- package/dist/codegen/index.js +1 -1
- package/dist/codegen/kotlin.js +3 -0
- package/dist/conformance.d.ts +1 -1
- package/dist/conformance.js +23 -4
- package/dist/contract.d.ts +11 -1
- package/dist/contract.js +17 -0
- package/dist/generated/typescript/blueprint.d.ts +340 -6
- package/dist/generated/typescript/blueprint.js +1 -1
- package/dist/generated/typescript/catalog-schema.d.ts +5 -0
- package/dist/generated/typescript/catalog-schema.js +1 -1
- package/dist/generated/typescript/diagnostics.d.ts +1 -1
- package/dist/generated/typescript/diagnostics.js +1 -1
- package/dist/generated/typescript/manifest.js +1 -1
- package/dist/generated/typescript/vocabulary.d.ts +34 -2
- package/dist/generated/typescript/vocabulary.js +8 -2
- package/dist/generated/typescript/workflow.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/migrations/0.6.0-0.7.0.d.ts +10 -0
- package/dist/migrations/0.6.0-0.7.0.js +13 -0
- package/dist/migrations/0.7.0-0.8.0.d.ts +8 -0
- package/dist/migrations/0.7.0-0.8.0.js +11 -0
- package/dist/migrations/index.js +4 -0
- package/dist/source.d.ts +90 -0
- package/dist/source.js +366 -0
- package/dist/validate.d.ts +9 -0
- package/dist/validate.js +60 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -14,9 +14,23 @@ by Texuli's Kotlin Multiplatform twin. The package is framework-free: no
|
|
|
14
14
|
DOM, no Svelte, no Node APIs and no runtime dependencies.
|
|
15
15
|
|
|
16
16
|
> **Status: 0.x release.** Texuli is in development. The packages are
|
|
17
|
-
> published to npm as `0.
|
|
18
|
-
> stable release). Under 0.x, a new minor (`0.
|
|
19
|
-
> changes, so pin the exact version or use `^0.
|
|
17
|
+
> published to npm as `0.8.0`, a pre-1.0 release (1.0.0 will be the first
|
|
18
|
+
> stable release). Under 0.x, a new minor (`0.9.0`) may contain breaking
|
|
19
|
+
> changes, so pin the exact version or use `^0.8.0`, which accepts only 0.8.x.
|
|
20
|
+
|
|
21
|
+
> **New in `0.8.0`.** `@texuli/spec@0.8.0` carries **spec 0.8.0**, which adds
|
|
22
|
+
> data-source bindings (the `@texuli/spec/source` subpath), the
|
|
23
|
+
> agent-emittable `schema-form`, `canvas`, `spreadsheet`, `data-dashboard`
|
|
24
|
+
> and `data-dashboard-widget` ids with their closed shapes, the closed
|
|
25
|
+
> expression AST, and the pinned `schemas/canvas.schema.json`. Every
|
|
26
|
+
> `0.7.0` envelope migrates by stamping `spec`.
|
|
27
|
+
|
|
28
|
+
> **New in `0.7.0`.** `@texuli/spec@0.7.0` carries **spec 0.7.0**, which adds
|
|
29
|
+
> an optional node `key` (unique in the tree), the agent-emittable
|
|
30
|
+
> `document` id with its `$defs.document` shape, the `patchDocument` edit
|
|
31
|
+
> op with a bounded RFC 6902 patch, and the pinned
|
|
32
|
+
> `schemas/document.schema.json`. Every `0.6.0` envelope migrates by
|
|
33
|
+
> stamping `spec`.
|
|
20
34
|
|
|
21
35
|
> **New in `0.6.0`.** `@texuli/spec@0.6.0` carries **spec 0.6.0**: the
|
|
22
36
|
> closed motion vocabulary (`@texuli/spec/motion`, below), and the new
|
|
@@ -61,7 +75,7 @@ import {
|
|
|
61
75
|
validateInstance,
|
|
62
76
|
} from '@texuli/spec';
|
|
63
77
|
|
|
64
|
-
SPEC_VERSION; // the spec version: '0.
|
|
78
|
+
SPEC_VERSION; // the spec version: '0.8.0' in @texuli/spec@0.8.0
|
|
65
79
|
SPEC_COMPONENT_IDS.includes('alert'); // true: the closed component vocabulary
|
|
66
80
|
|
|
67
81
|
// The dialect validator: a closed subset of JSON Schema 2020-12.
|
|
@@ -93,7 +107,7 @@ import { type Schema, type SpecCatalog, validateBlueprint } from '@texuli/spec';
|
|
|
93
107
|
import { migrateBlueprint } from '@texuli/spec/migrate';
|
|
94
108
|
import { validateWorkflowGraph } from '@texuli/spec/workflow';
|
|
95
109
|
|
|
96
|
-
const migrated = migrateBlueprint(blueprint); // 0.2.0 → … → 0.
|
|
110
|
+
const migrated = migrateBlueprint(blueprint); // 0.2.0 → … → 0.7.0 → 0.8.0; never throws
|
|
97
111
|
const result = validateBlueprint(migrated.blueprint, {
|
|
98
112
|
blueprintSchema: blueprintSchemaJson as Schema,
|
|
99
113
|
catalog: componentsJson as SpecCatalog,
|
|
@@ -114,7 +128,11 @@ refused state or flow declaration), `unknown-state` (a binding or action
|
|
|
114
128
|
names no declared variable), `binding` (a malformed, misplaced, read-only or
|
|
115
129
|
ill-fitting binding), `action` (an action with the wrong fields or target),
|
|
116
130
|
`unknown-event` (an `on` key the component does not fire) and `workflow` (a
|
|
117
|
-
workflow graph rule)
|
|
131
|
+
workflow graph rule), from spec 0.7.0, `duplicate-key` (a node key used
|
|
132
|
+
twice in the tree), and, from spec 0.8.0, `source` (a malformed, misplaced or
|
|
133
|
+
ill-fitting data-source binding, or any binding when the host passes no
|
|
134
|
+
`sources`) and `unknown-source` (a source the host never registered).
|
|
135
|
+
Deprecated components and props add a `deprecated`
|
|
118
136
|
warning without failing.
|
|
119
137
|
|
|
120
138
|
## What's inside
|
|
@@ -127,6 +145,7 @@ warning without failing.
|
|
|
127
145
|
| `@texuli/spec/surface` | Runtime: the state surface rules every validator shares (no imports) | `checkStateSurface`, `surfaceInputs`, `SPEC_CONTROL_STATE_TYPES`, `SURFACE_PLAYER_CODES`, `LIST_TEXT_PATTERN` |
|
|
128
146
|
| `@texuli/spec/motion` | Runtime (new in `0.6.0`, spec `0.6.0`): the closed motion vocabulary and its check, shared by the catalog and the player ([motion.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/motion.md)) | `SPEC_MOTION_PRESETS`, `SPEC_MOTION_DURATIONS`, `SPEC_MOTION_STAGGERS`, `SPEC_MOTION_LEVELS`, `checkNodeMotion`, `checkEnvelopeMotion` |
|
|
129
147
|
| `@texuli/spec/stream` | Runtime, opt-in (new in `0.6.0`): streamed blueprints ([stream.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/stream.md)) | `createJsonTokenizer`, `createBlueprintAssembler`, `createBlueprintStream`, `STREAM_NODE_ORDER` |
|
|
148
|
+
| `@texuli/spec/source` | Runtime (new in `0.8.0`, spec `0.8.0`): data-source bindings, shared by the spec validator, `@texuli/catalog` and the player ([source.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/source.md)) | `checkSourceBinding`, `isSourceBinding`, `SOURCE_BINDING_KEY`, `SPEC_SOURCE_LIMITS`, `SPEC_SOURCE_FILTER_OPERATORS`, `SpecSourceDescriptor` |
|
|
130
149
|
| `@texuli/spec/codegen` | Build time: generation and conformance | `buildSpec`, `projectCatalog`, `checkConformance`, `checkCatalogContract`, `formatJson`, `nextSpecVersion`, `checkVersionHistory` |
|
|
131
150
|
|
|
132
151
|
## Key guarantees
|
|
@@ -162,6 +181,12 @@ warning without failing.
|
|
|
162
181
|
motion tokens: a blueprint never carries CSS, keyframes, milliseconds or
|
|
163
182
|
code, and anything else is refused. The `0.5.0 → 0.6.0` migration only
|
|
164
183
|
stamps `spec`.
|
|
184
|
+
- **Documents as data (spec 0.7.0, new in `0.7.0`).** A
|
|
185
|
+
`document` node's `doc` must have the document shape (`$defs.document`);
|
|
186
|
+
the document's own vocabulary and URL policy are checked by
|
|
187
|
+
`@texuli/document` through `@texuli/catalog`'s `validateDraft`. Agents
|
|
188
|
+
edit documents with `patchDocument` (at most 1,000 RFC 6902 operations),
|
|
189
|
+
addressed by node `key`.
|
|
165
190
|
- **Streams parse, never guess.** `@texuli/spec/stream` (new in `0.6.0`)
|
|
166
191
|
reads a blueprint split anywhere in linear time under a byte budget and a
|
|
167
192
|
depth cap, reports a node only once its shell (everything but
|
|
@@ -181,6 +206,44 @@ warning without failing.
|
|
|
181
206
|
nodes without a matching view or event, and writers of a host-bound
|
|
182
207
|
variable. The spec, `@texuli/catalog`'s `validateDraft` and the Kotlin
|
|
183
208
|
twin run the same rules.
|
|
209
|
+
- **Data as a named source, never a request (spec 0.8.0, new in `0.8.0`).** A
|
|
210
|
+
component's `sourceable` prop may read rows with
|
|
211
|
+
`{"$source": name, "query": {...}, "map": {...}}`: an opaque name the host
|
|
212
|
+
registered, and a closed query (projection, the `@texuli/data` grid filter
|
|
213
|
+
model, sort, search, a page size). It is checked against the host's source
|
|
214
|
+
descriptors (`SpecDocuments.sources`) and refused without them; nothing in
|
|
215
|
+
it is a URL, SQL or code
|
|
216
|
+
([source.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/source.md)).
|
|
217
|
+
- **Forms as data, never patterns or code (spec 0.8.0, new in `0.8.0`).** The
|
|
218
|
+
agent-emittable `schema-form` id carries a closed form schema
|
|
219
|
+
(`$defs.formSchema`): fields of 15 closed types in sections or steps,
|
|
220
|
+
named formats and host validator names (never a regular expression),
|
|
221
|
+
and conditions and cross-field rules in the closed expression AST of
|
|
222
|
+
`@texuli/core/expression` (`$defs.expression`, the `numberFormula` and
|
|
223
|
+
`condition` shapes extended with strings, booleans, field references and
|
|
224
|
+
calls to a closed function table). The schema checks the shape; the
|
|
225
|
+
forms validator (`@texuli/forms/model`, `checkForm` in `validateDraft`)
|
|
226
|
+
checks the rest at the host's tier. The Kotlin twin decodes the shape and
|
|
227
|
+
its list caps and paints a placeholder (planned).
|
|
228
|
+
- **Dashboards as data (spec 0.8.0, new in `0.8.0`).** The agent-emittable
|
|
229
|
+
`data-dashboard` id holds `data-dashboard-widget` children (`widgetId`,
|
|
230
|
+
`title` and a `place` in grid units); widget content is ordinary catalog
|
|
231
|
+
nodes, so its data comes only from host sources. The dashboard's `layout`
|
|
232
|
+
(a bounded list of `{id, x, y, w, h}` grid units) is bindable and
|
|
233
|
+
sourceable, so a state or a host source persists what people arrange. The
|
|
234
|
+
schema bounds the grid units; `@texuli/catalog` checks the composition
|
|
235
|
+
(widgets only directly in a dashboard, unique ids) on the web. The Kotlin
|
|
236
|
+
twin decodes the props and paints a placeholder (planned).
|
|
237
|
+
- **Spreadsheets as data, formulas in a closed grammar (spec 0.8.0,
|
|
238
|
+
new in `0.8.0`).** The agent-emittable `spreadsheet` id (not `sheet`, which
|
|
239
|
+
is the texuli `Sheet` overlay) carries a sheet in its `sheet` prop
|
|
240
|
+
(`$defs.sheet`, `$defs.sheetTab`): `format` `texuli-sheet`, 1 to 16 tabs
|
|
241
|
+
of `{ id, name, rows, columns, cells }` with cells keyed by A1 address.
|
|
242
|
+
The schema checks that envelope and its caps; the sheet validator
|
|
243
|
+
(`@texuli/sheets/model`, `checkSheet` in `validateDraft`) parses every
|
|
244
|
+
formula with the sheet grammar (no `INDIRECT`, `OFFSET` or `RAND`, a
|
|
245
|
+
closed function set). The Kotlin twin decodes the envelope and its caps;
|
|
246
|
+
painting it is planned.
|
|
184
247
|
- **List item text never hides or reorders itself.** String fields of list
|
|
185
248
|
state items refuse control characters, bidirectional overrides and
|
|
186
249
|
isolates, and invisible formatting characters (`SPEC_PATTERNS.listText`;
|
|
@@ -210,9 +273,15 @@ catalog hash, and from 0.3.0 may declare the exact spec version it was
|
|
|
210
273
|
written for (`spec`; omitted means 0.2.0). `migrateBlueprint`
|
|
211
274
|
(`@texuli/spec/migrate`) brings an
|
|
212
275
|
envelope up to the current spec with pure, per-version steps
|
|
213
|
-
(`src/migrations/`: `0.2.0 → 0.3.0`, `0.3.0 → 0.4.0`, `0.4.0 → 0.5.0
|
|
214
|
-
`0.5.0 → 0.6.0`,
|
|
215
|
-
|
|
276
|
+
(`src/migrations/`: `0.2.0 → 0.3.0`, `0.3.0 → 0.4.0`, `0.4.0 → 0.5.0`,
|
|
277
|
+
`0.5.0 → 0.6.0`, `0.6.0 → 0.7.0` and `0.7.0 → 0.8.0`, each of which only
|
|
278
|
+
stamps `spec`); a compatible version range is planned, not built.
|
|
279
|
+
`@texuli/spec@0.8.0` carries spec `0.8.0` (digest
|
|
280
|
+
`f6b6388280d247eb9c3106a925111f35b90d1ec3b59c23652542f06a9f103daf`), which
|
|
281
|
+
adds data-source bindings, forms, canvases, dashboards and spreadsheets;
|
|
282
|
+
`@texuli/spec@0.7.0` carried spec `0.7.0` (digest
|
|
283
|
+
`43e44fa9a198d337d686b4e2d86882a06a676ae1e1c1f02d023b3a525795a8b2`), which
|
|
284
|
+
adds node keys and documents; `@texuli/spec@0.6.0` carried spec `0.6.0` (digest
|
|
216
285
|
`37141b85b9ab9f02af849a62a9c97ba729d6c5c2705130290bcdf45b308ea4cc`), which
|
|
217
286
|
adds the closed motion vocabulary (ADR-012); `@texuli/spec@0.5.0` carried
|
|
218
287
|
spec `0.5.0`, which added the `data-cohort-table`,
|
|
@@ -238,6 +307,8 @@ conformance harness) are in
|
|
|
238
307
|
[motion.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/motion.md)
|
|
239
308
|
- Streamed blueprints (the incremental tokenizer, the canonical order and
|
|
240
309
|
node shells; new in `0.6.0`): [stream.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/stream.md)
|
|
310
|
+
- Data-source bindings (spec 0.8.0; new in `0.8.0`):
|
|
311
|
+
[source.md](https://github.com/DailybotHQ/texuli/blob/main/packages/spec/docs/source.md)
|
|
241
312
|
- The Kotlin Multiplatform twin that consumes the generated models:
|
|
242
313
|
[native/README.md](https://github.com/DailybotHQ/texuli/blob/main/native/README.md)
|
|
243
314
|
- Architecture: [ARCHITECTURE.md](https://github.com/DailybotHQ/texuli/blob/main/docs/ARCHITECTURE.md)
|
package/dist/build.d.ts
CHANGED
|
@@ -3,6 +3,15 @@ import { SPEC_VERSION } from './version.js';
|
|
|
3
3
|
export { SPEC_VERSION };
|
|
4
4
|
/** Where normative files live inside the package. */
|
|
5
5
|
export declare const NORMATIVE_DIRS: readonly ["schemas/", "catalog/", "fixtures/"];
|
|
6
|
+
/**
|
|
7
|
+
* Normative schemas that are pinned by digest but are not in the dialect and
|
|
8
|
+
* generate nothing: they are exported by a higher-layer engine and kept here
|
|
9
|
+
* so the contract pins the exact version agents write against. Spec 0.7.0
|
|
10
|
+
* pins `@texuli/document`'s JSON Schema export (ADR-011) and spec 0.8.0
|
|
11
|
+
* `@texuli/canvas`'s (ADR-012); freshness tests in `@texuli/catalog` keep
|
|
12
|
+
* them equal to `documentJsonSchema()` and `canvasJsonSchema()`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const EXTERNAL_SCHEMAS: readonly string[];
|
|
6
15
|
/** The schema documents, their generated names and output files. */
|
|
7
16
|
export declare const SCHEMA_UNITS: readonly [{
|
|
8
17
|
readonly name: "blueprint";
|
package/dist/build.js
CHANGED
|
@@ -7,6 +7,18 @@ import { SPEC_VERSION } from "./version.js";
|
|
|
7
7
|
export { SPEC_VERSION };
|
|
8
8
|
/** Where normative files live inside the package. */
|
|
9
9
|
export const NORMATIVE_DIRS = ['schemas/', 'catalog/', 'fixtures/'];
|
|
10
|
+
/**
|
|
11
|
+
* Normative schemas that are pinned by digest but are not in the dialect and
|
|
12
|
+
* generate nothing: they are exported by a higher-layer engine and kept here
|
|
13
|
+
* so the contract pins the exact version agents write against. Spec 0.7.0
|
|
14
|
+
* pins `@texuli/document`'s JSON Schema export (ADR-011) and spec 0.8.0
|
|
15
|
+
* `@texuli/canvas`'s (ADR-012); freshness tests in `@texuli/catalog` keep
|
|
16
|
+
* them equal to `documentJsonSchema()` and `canvasJsonSchema()`.
|
|
17
|
+
*/
|
|
18
|
+
export const EXTERNAL_SCHEMAS = Object.freeze([
|
|
19
|
+
'schemas/canvas.schema.json',
|
|
20
|
+
'schemas/document.schema.json',
|
|
21
|
+
]);
|
|
10
22
|
/** The schema documents, their generated names and output files. */
|
|
11
23
|
export const SCHEMA_UNITS = [
|
|
12
24
|
{ name: 'blueprint', prefix: 'Blueprint', ts: 'blueprint.ts', kt: 'Blueprint.kt' },
|
package/dist/catalog.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export interface BuiltCatalogLike {
|
|
|
26
26
|
emit: readonly string[];
|
|
27
27
|
events?: readonly SpecEventName[];
|
|
28
28
|
bindable?: readonly string[];
|
|
29
|
+
sourceable?: readonly string[];
|
|
29
30
|
deprecated?: SpecDeprecation;
|
|
30
31
|
props: readonly {
|
|
31
32
|
name: string;
|
|
@@ -39,8 +40,8 @@ export interface BuiltCatalogLike {
|
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
42
|
* Project a built catalog into the spec vocabulary. Deterministic: components
|
|
42
|
-
* sorted by id, props by name, emit tiers, events
|
|
43
|
-
* events, bindable, property schemas and deprecations only when present. Capability is `unknown`
|
|
43
|
+
* sorted by id, props by name, emit tiers, events, bindable and sourceable
|
|
44
|
+
* props sorted; events, bindable, sourceable, property schemas and deprecations only when present. Capability is `unknown`
|
|
44
45
|
* unless `capabilities` (the reviewed `catalog/capabilities.json`) records an
|
|
45
46
|
* audited value (ADR-003: no id is portable until audited).
|
|
46
47
|
*/
|
package/dist/catalog.js
CHANGED
|
@@ -13,8 +13,8 @@ export const WEB_ONLY_KINDS = ['slot', 'event', 'unknown'];
|
|
|
13
13
|
export const WEB_ONLY_PROP_NAMES = ['class', 'className', 'style', 'renderer'];
|
|
14
14
|
/**
|
|
15
15
|
* Project a built catalog into the spec vocabulary. Deterministic: components
|
|
16
|
-
* sorted by id, props by name, emit tiers, events
|
|
17
|
-
* events, bindable, property schemas and deprecations only when present. Capability is `unknown`
|
|
16
|
+
* sorted by id, props by name, emit tiers, events, bindable and sourceable
|
|
17
|
+
* props sorted; events, bindable, sourceable, property schemas and deprecations only when present. Capability is `unknown`
|
|
18
18
|
* unless `capabilities` (the reviewed `catalog/capabilities.json`) records an
|
|
19
19
|
* audited value (ADR-003: no id is portable until audited).
|
|
20
20
|
*/
|
|
@@ -45,6 +45,7 @@ export function projectCatalog(catalog, catalogHash, capabilities = {}) {
|
|
|
45
45
|
})),
|
|
46
46
|
...(entry.events?.length ? { events: [...entry.events].sort() } : {}),
|
|
47
47
|
...(entry.bindable?.length ? { bindable: [...entry.bindable].sort() } : {}),
|
|
48
|
+
...(entry.sourceable?.length ? { sourceable: [...entry.sourceable].sort() } : {}),
|
|
48
49
|
...(entry.deprecated ? { deprecated: { ...entry.deprecated } } : {}),
|
|
49
50
|
}));
|
|
50
51
|
return { catalogHash, components };
|
package/dist/codegen/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* projection, the committed-file JSON format and the conformance harness.
|
|
5
5
|
* Pure functions: callers read and write the files.
|
|
6
6
|
*/
|
|
7
|
-
export { buildSpec, KOTLIN_OUT, NORMATIVE_DIRS, SCHEMA_UNITS, type SpecBuild, TS_OUT, } from '../build.js';
|
|
7
|
+
export { buildSpec, EXTERNAL_SCHEMAS, KOTLIN_OUT, NORMATIVE_DIRS, SCHEMA_UNITS, type SpecBuild, TS_OUT, } from '../build.js';
|
|
8
8
|
export { prettyJson } from '../canonical.js';
|
|
9
9
|
export { type BuiltCatalogLike, projectCatalog } from '../catalog.js';
|
|
10
10
|
export { type ConformanceIssue, checkCatalogContract, checkConformance, deprecationExpired, } from '../conformance.js';
|
package/dist/codegen/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* projection, the committed-file JSON format and the conformance harness.
|
|
5
5
|
* Pure functions: callers read and write the files.
|
|
6
6
|
*/
|
|
7
|
-
export { buildSpec, KOTLIN_OUT, NORMATIVE_DIRS, SCHEMA_UNITS, TS_OUT, } from "../build.js";
|
|
7
|
+
export { buildSpec, EXTERNAL_SCHEMAS, KOTLIN_OUT, NORMATIVE_DIRS, SCHEMA_UNITS, TS_OUT, } from "../build.js";
|
|
8
8
|
export { prettyJson } from "../canonical.js";
|
|
9
9
|
export { projectCatalog } from "../catalog.js";
|
|
10
10
|
export { checkCatalogContract, checkConformance, deprecationExpired, } from "../conformance.js";
|
package/dist/codegen/kotlin.js
CHANGED
|
@@ -391,6 +391,9 @@ export function vocabularyToKotlin(catalog, stamp) {
|
|
|
391
391
|
if (c.bindable) {
|
|
392
392
|
lines.push(`${INDENT}${INDENT}${INDENT}bindable = listOf(${c.bindable.map(kotlinString).join(', ')}),`);
|
|
393
393
|
}
|
|
394
|
+
if (c.sourceable) {
|
|
395
|
+
lines.push(`${INDENT}${INDENT}${INDENT}sourceable = listOf(${c.sourceable.map(kotlinString).join(', ')}),`);
|
|
396
|
+
}
|
|
394
397
|
if (c.deprecated)
|
|
395
398
|
lines.push(`${INDENT}${INDENT}${INDENT}deprecated = ${deprecationExpr(c.deprecated)},`);
|
|
396
399
|
lines.push(`${INDENT}${INDENT}),`);
|
package/dist/conformance.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface ConformanceIssue {
|
|
|
9
9
|
* Run the spec's conformance harness (spec/Compose design §7.1 and §7.3)
|
|
10
10
|
* over the normative files and the committed outputs (`manifest.json`,
|
|
11
11
|
* `generated-manifest.json` and every generated file):
|
|
12
|
-
* - every schema stays in the dialect;
|
|
12
|
+
* - every schema stays in the dialect (except the pinned `EXTERNAL_SCHEMAS`);
|
|
13
13
|
* - `catalog/components.json` and `catalog/capabilities.json` are valid;
|
|
14
14
|
* - the manifest digests match the normative files;
|
|
15
15
|
* - regenerating gives byte-identical TypeScript and Kotlin, with no file
|
package/dist/conformance.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildSpec } from "./build.js";
|
|
1
|
+
import { buildSpec, EXTERNAL_SCHEMAS } from "./build.js";
|
|
2
2
|
import { CAPABILITIES } from "./catalog.js";
|
|
3
3
|
import { checkPropSchema, defCollisions } from "./contract.js";
|
|
4
4
|
import { checkSchemaDocument, isRecord, validateInstance } from "./dialect.js";
|
|
@@ -9,7 +9,7 @@ import { validateWorkflowGraph } from "./workflow.js";
|
|
|
9
9
|
* Run the spec's conformance harness (spec/Compose design §7.1 and §7.3)
|
|
10
10
|
* over the normative files and the committed outputs (`manifest.json`,
|
|
11
11
|
* `generated-manifest.json` and every generated file):
|
|
12
|
-
* - every schema stays in the dialect;
|
|
12
|
+
* - every schema stays in the dialect (except the pinned `EXTERNAL_SCHEMAS`);
|
|
13
13
|
* - `catalog/components.json` and `catalog/capabilities.json` are valid;
|
|
14
14
|
* - the manifest digests match the normative files;
|
|
15
15
|
* - regenerating gives byte-identical TypeScript and Kotlin, with no file
|
|
@@ -26,7 +26,8 @@ export function checkConformance(normative, committed) {
|
|
|
26
26
|
const issues = [];
|
|
27
27
|
const json = (path) => JSON.parse(normative[path] ?? 'null');
|
|
28
28
|
const schemas = {};
|
|
29
|
-
|
|
29
|
+
const dialectSchemas = Object.keys(normative).filter((p) => p.startsWith('schemas/') && !EXTERNAL_SCHEMAS.includes(p));
|
|
30
|
+
for (const path of dialectSchemas) {
|
|
30
31
|
const schema = json(path);
|
|
31
32
|
schemas[path] = schema;
|
|
32
33
|
for (const issue of checkSchemaDocument(schema)) {
|
|
@@ -134,7 +135,15 @@ export function checkConformance(normative, committed) {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
if (blueprintSchema) {
|
|
137
|
-
|
|
138
|
+
// The fixture host's data sources (spec 0.8.0): source bindings are checked against them.
|
|
139
|
+
const host = json('fixtures/sources.json');
|
|
140
|
+
const documents = {
|
|
141
|
+
blueprintSchema,
|
|
142
|
+
catalog,
|
|
143
|
+
workflowSchema,
|
|
144
|
+
validateWorkflowGraph,
|
|
145
|
+
...(host?.sources ? { sources: host.sources } : {}),
|
|
146
|
+
};
|
|
138
147
|
for (const path of Object.keys(normative).filter((p) => p.startsWith('fixtures/golden/'))) {
|
|
139
148
|
const result = validateBlueprint(json(path), documents);
|
|
140
149
|
for (const d of result.diagnostics) {
|
|
@@ -187,6 +196,16 @@ export function checkCatalogContract(catalog, specVersion = SPEC_VERSION) {
|
|
|
187
196
|
});
|
|
188
197
|
}
|
|
189
198
|
}
|
|
199
|
+
for (const name of component.sourceable ?? []) {
|
|
200
|
+
const prop = component.props.find((p) => p.name === name);
|
|
201
|
+
if (!prop || prop.extension || prop.kind !== 'array') {
|
|
202
|
+
issues.push({
|
|
203
|
+
check: 'prop-schema',
|
|
204
|
+
path,
|
|
205
|
+
message: `${component.id}: sourceable "${name}" is not a portable array prop`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
190
209
|
if (new Set(component.events ?? []).size !== (component.events ?? []).length) {
|
|
191
210
|
issues.push({ check: 'catalog', path, message: `${component.id}: events repeat` });
|
|
192
211
|
}
|
package/dist/contract.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type SpecActionOp = (typeof SPEC_ACTION_OPS)[number];
|
|
|
21
21
|
export declare const SPEC_EVENT_NAMES: readonly ["press", "change", "select", "submit", "dismiss", "move"];
|
|
22
22
|
export type SpecEventName = (typeof SPEC_EVENT_NAMES)[number];
|
|
23
23
|
/** The `$ref` targets a catalog property schema may name. */
|
|
24
|
-
export declare const SPEC_PROP_REFS: readonly ["binding", "reorder", "action", "eventMap", "condition", "workflowGraph"];
|
|
24
|
+
export declare const SPEC_PROP_REFS: readonly ["binding", "reorder", "action", "eventMap", "condition", "workflowGraph", "document", "formSchema", "canvas", "sheet"];
|
|
25
25
|
/** The fields each action op takes (besides `op`) and the ones it needs. */
|
|
26
26
|
export declare const ACTION_FIELDS: Readonly<Record<SpecActionOp, {
|
|
27
27
|
readonly allowed: readonly string[];
|
|
@@ -54,6 +54,13 @@ export declare const SPEC_LIMITS: Readonly<{
|
|
|
54
54
|
workflowStringLength: 2000;
|
|
55
55
|
/** Deepest prop value walked for nested bindings. */
|
|
56
56
|
propDepth: 32;
|
|
57
|
+
/** Top-level blocks a `document` node's doc may hold (`$defs.document.blocks`). */
|
|
58
|
+
documentBlocks: 2000;
|
|
59
|
+
/** Operations one `patchDocument` patch may carry (`$defs.documentPatch`, ADR-011). */
|
|
60
|
+
documentPatchOps: 1000;
|
|
61
|
+
/** Shapes and connectors a `canvas` node's canvas may hold at its top level (`$defs.canvas`). */
|
|
62
|
+
canvasShapes: 5000;
|
|
63
|
+
canvasConnectors: 5000;
|
|
57
64
|
}>;
|
|
58
65
|
/** The name patterns, as the schemas write them. */
|
|
59
66
|
export declare const SPEC_PATTERNS: Readonly<{
|
|
@@ -62,6 +69,8 @@ export declare const SPEC_PATTERNS: Readonly<{
|
|
|
62
69
|
flowName: "^[a-z][a-z0-9-]{0,31}$";
|
|
63
70
|
intentName: "^[A-Za-z][A-Za-z0-9_-]{0,63}$";
|
|
64
71
|
itemKey: "^[A-Za-z0-9._:-]{1,64}$";
|
|
72
|
+
/** A node's stable instance id (spec 0.7.0, ADR-014), unique in its tree. */
|
|
73
|
+
nodeKey: "^[A-Za-z0-9._:-]{1,64}$";
|
|
65
74
|
groupName: "^[a-z][a-z0-9-]{0,31}$";
|
|
66
75
|
workflowId: "^[A-Za-z0-9._:-]{1,64}$";
|
|
67
76
|
workflowFieldName: "^[a-z][A-Za-z0-9_]{0,31}$";
|
|
@@ -88,6 +97,7 @@ export declare const SPEC_REGEX: Readonly<{
|
|
|
88
97
|
dataName: RegExp;
|
|
89
98
|
intentName: RegExp;
|
|
90
99
|
itemKey: RegExp;
|
|
100
|
+
nodeKey: RegExp;
|
|
91
101
|
listText: RegExp;
|
|
92
102
|
}>;
|
|
93
103
|
/**
|
package/dist/contract.js
CHANGED
|
@@ -32,6 +32,13 @@ export const SPEC_PROP_REFS = [
|
|
|
32
32
|
'eventMap',
|
|
33
33
|
'condition',
|
|
34
34
|
'workflowGraph',
|
|
35
|
+
'document',
|
|
36
|
+
// Spec 0.8.0 (ADR-015): the closed form schema of a `schema-form` node.
|
|
37
|
+
'formSchema',
|
|
38
|
+
// Spec 0.8.0 (ADR-012): the canvas a `canvas` node carries (envelope only).
|
|
39
|
+
'canvas',
|
|
40
|
+
// Spec 0.8.0 (ADR-015): the sheet a `spreadsheet` node carries (envelope only).
|
|
41
|
+
'sheet',
|
|
35
42
|
];
|
|
36
43
|
/** The fields each action op takes (besides `op`) and the ones it needs. */
|
|
37
44
|
export const ACTION_FIELDS = Object.freeze({
|
|
@@ -76,6 +83,13 @@ export const SPEC_LIMITS = Object.freeze({
|
|
|
76
83
|
workflowStringLength: 2000,
|
|
77
84
|
/** Deepest prop value walked for nested bindings. */
|
|
78
85
|
propDepth: 32,
|
|
86
|
+
/** Top-level blocks a `document` node's doc may hold (`$defs.document.blocks`). */
|
|
87
|
+
documentBlocks: 2000,
|
|
88
|
+
/** Operations one `patchDocument` patch may carry (`$defs.documentPatch`, ADR-011). */
|
|
89
|
+
documentPatchOps: 1000,
|
|
90
|
+
/** Shapes and connectors a `canvas` node's canvas may hold at its top level (`$defs.canvas`). */
|
|
91
|
+
canvasShapes: 5000,
|
|
92
|
+
canvasConnectors: 5000,
|
|
79
93
|
});
|
|
80
94
|
/** The name patterns, as the schemas write them. */
|
|
81
95
|
export const SPEC_PATTERNS = Object.freeze({
|
|
@@ -84,6 +98,8 @@ export const SPEC_PATTERNS = Object.freeze({
|
|
|
84
98
|
flowName: '^[a-z][a-z0-9-]{0,31}$',
|
|
85
99
|
intentName: '^[A-Za-z][A-Za-z0-9_-]{0,63}$',
|
|
86
100
|
itemKey: '^[A-Za-z0-9._:-]{1,64}$',
|
|
101
|
+
/** A node's stable instance id (spec 0.7.0, ADR-014), unique in its tree. */
|
|
102
|
+
nodeKey: '^[A-Za-z0-9._:-]{1,64}$',
|
|
87
103
|
groupName: '^[a-z][a-z0-9-]{0,31}$',
|
|
88
104
|
workflowId: '^[A-Za-z0-9._:-]{1,64}$',
|
|
89
105
|
workflowFieldName: '^[a-z][A-Za-z0-9_]{0,31}$',
|
|
@@ -110,6 +126,7 @@ export const SPEC_REGEX = Object.freeze({
|
|
|
110
126
|
dataName: new RegExp(SPEC_PATTERNS.dataName, 'u'),
|
|
111
127
|
intentName: new RegExp(SPEC_PATTERNS.intentName, 'u'),
|
|
112
128
|
itemKey: new RegExp(SPEC_PATTERNS.itemKey, 'u'),
|
|
129
|
+
nodeKey: new RegExp(SPEC_PATTERNS.nodeKey, 'u'),
|
|
113
130
|
listText: new RegExp(SPEC_PATTERNS.listText, 'u'),
|
|
114
131
|
});
|
|
115
132
|
/**
|