@texuli/spec 0.3.0 → 0.4.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 -14
- package/dist/build.d.ts +5 -0
- package/dist/build.js +1 -0
- package/dist/canonical.js +20 -13
- package/dist/catalog.d.ts +9 -3
- package/dist/catalog.js +7 -1
- package/dist/codegen/index.d.ts +2 -2
- package/dist/codegen/index.js +2 -2
- package/dist/codegen/kotlin.d.ts +6 -0
- package/dist/codegen/kotlin.js +80 -8
- package/dist/conformance.d.ts +11 -2
- package/dist/conformance.js +93 -2
- package/dist/contract.d.ts +112 -0
- package/dist/contract.js +196 -0
- package/dist/dialect.d.ts +10 -1
- package/dist/dialect.js +6 -1
- package/dist/generated/typescript/blueprint.d.ts +103 -5
- package/dist/generated/typescript/blueprint.js +1 -1
- package/dist/generated/typescript/catalog-schema.d.ts +35 -0
- package/dist/generated/typescript/catalog-schema.js +1 -1
- package/dist/generated/typescript/diagnostics.d.ts +10 -1
- package/dist/generated/typescript/diagnostics.js +1 -1
- package/dist/generated/typescript/manifest.js +1 -1
- package/dist/generated/typescript/vocabulary.d.ts +152 -4
- package/dist/generated/typescript/vocabulary.js +27 -2
- package/dist/generated/typescript/workflow.d.ts +84 -0
- package/dist/generated/typescript/workflow.js +3 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.js +9 -3
- package/dist/migrations/0.2.0-0.3.0.d.ts +7 -0
- package/dist/migrations/0.2.0-0.3.0.js +10 -0
- package/dist/migrations/0.3.0-0.4.0.d.ts +9 -0
- package/dist/migrations/0.3.0-0.4.0.js +12 -0
- package/dist/migrations/index.d.ts +15 -0
- package/dist/migrations/index.js +53 -0
- package/dist/migrations/types.d.ts +14 -0
- package/dist/migrations/types.js +1 -0
- package/dist/surface.d.ts +60 -0
- package/dist/surface.js +162 -0
- package/dist/validate.d.ts +89 -14
- package/dist/validate.js +725 -64
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workflow.d.ts +15 -0
- package/dist/workflow.js +256 -0
- package/package.json +13 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state surface's node rules (spec 0.3.0): where the state-only nodes
|
|
3
|
+
* may sit and what they must name, exactly as `@texuli/player` refuses them
|
|
4
|
+
* at paint time, so a blueprint that validates always paints.
|
|
5
|
+
*
|
|
6
|
+
* - Forms (code `action`): `form-field` and `form-submit` sit inside an
|
|
7
|
+
* `action-form`; forms never nest; a form names an intent-like action; a
|
|
8
|
+
* field has an intent-like name, unique in its form, and writes a declared
|
|
9
|
+
* variable of its type (`number` fields a number, the others a string).
|
|
10
|
+
* - Controls (code `binding`): each control names a declared variable of
|
|
11
|
+
* the type it writes.
|
|
12
|
+
* - Host-bound variables (code `binding`): a variable with a `source` is the
|
|
13
|
+
* host's; no control or field writes it.
|
|
14
|
+
* - Flow nodes (code `state`): `flow-view` names a declared view and
|
|
15
|
+
* `flow-action` an event some transition handles; neither appears
|
|
16
|
+
* without a flow.
|
|
17
|
+
*
|
|
18
|
+
* Inputs are read from the raw envelope (`surfaceInputs`) so every
|
|
19
|
+
* validator applies the same rules to the same data. Framework-free; never
|
|
20
|
+
* evaluates anything.
|
|
21
|
+
*/
|
|
22
|
+
/** The spec's `intentName` pattern (pinned to `SPEC_PATTERNS` by the spec tests); no imports keep this module lean. */
|
|
23
|
+
export declare const SURFACE_INTENT_NAME: RegExp;
|
|
24
|
+
/** The spec's `listText` pattern (the contract's `SPEC_PATTERNS.listText` is this string). */
|
|
25
|
+
export declare const LIST_TEXT_PATTERN = "^[^\\u0000-\\u001f\\u007f-\\u009f\\u061c\\u180e\\u200b\\u200e\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]*$";
|
|
26
|
+
/** The state type each control writes (mirrors the catalog's `CONTROL_STATE_TYPES`). */
|
|
27
|
+
export declare const SPEC_CONTROL_STATE_TYPES: Readonly<Record<string, string>>;
|
|
28
|
+
/** The player's issue code each spec code stands for (`action-binding` → `action`, …). */
|
|
29
|
+
export declare const SURFACE_PLAYER_CODES: Readonly<{
|
|
30
|
+
readonly 'action-binding': "action";
|
|
31
|
+
readonly 'control-binding': "binding";
|
|
32
|
+
readonly 'host-binding': "binding";
|
|
33
|
+
readonly 'flow-binding': "state";
|
|
34
|
+
}>;
|
|
35
|
+
export type SurfaceCode = (typeof SURFACE_PLAYER_CODES)[keyof typeof SURFACE_PLAYER_CODES];
|
|
36
|
+
export interface SurfaceIssue {
|
|
37
|
+
code: SurfaceCode;
|
|
38
|
+
/** Child indices from the root: `[]` is the root, `[0, 2]` its first child's third child. */
|
|
39
|
+
at: readonly number[];
|
|
40
|
+
message: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SurfaceInputs {
|
|
43
|
+
/** Declared variables (type, and whether a node may write it); `null` without `state` or `flow`. */
|
|
44
|
+
declarations: ReadonlyMap<string, {
|
|
45
|
+
type: string;
|
|
46
|
+
writable: boolean;
|
|
47
|
+
}> | null;
|
|
48
|
+
/** The flow's views and handled events; `null` without a flow. */
|
|
49
|
+
flow: {
|
|
50
|
+
views: readonly string[];
|
|
51
|
+
events: readonly string[];
|
|
52
|
+
} | null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Read the surface inputs from a raw envelope, as the player does: an
|
|
56
|
+
* envelope with `state` or `flow` has declarations (empty with only a flow).
|
|
57
|
+
*/
|
|
58
|
+
export declare function surfaceInputs(envelope: unknown): SurfaceInputs;
|
|
59
|
+
/** Check one tree root against the surface rules; one issue per refused node and rule. */
|
|
60
|
+
export declare function checkStateSurface(root: unknown, inputs: SurfaceInputs): SurfaceIssue[];
|
package/dist/surface.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state surface's node rules (spec 0.3.0): where the state-only nodes
|
|
3
|
+
* may sit and what they must name, exactly as `@texuli/player` refuses them
|
|
4
|
+
* at paint time, so a blueprint that validates always paints.
|
|
5
|
+
*
|
|
6
|
+
* - Forms (code `action`): `form-field` and `form-submit` sit inside an
|
|
7
|
+
* `action-form`; forms never nest; a form names an intent-like action; a
|
|
8
|
+
* field has an intent-like name, unique in its form, and writes a declared
|
|
9
|
+
* variable of its type (`number` fields a number, the others a string).
|
|
10
|
+
* - Controls (code `binding`): each control names a declared variable of
|
|
11
|
+
* the type it writes.
|
|
12
|
+
* - Host-bound variables (code `binding`): a variable with a `source` is the
|
|
13
|
+
* host's; no control or field writes it.
|
|
14
|
+
* - Flow nodes (code `state`): `flow-view` names a declared view and
|
|
15
|
+
* `flow-action` an event some transition handles; neither appears
|
|
16
|
+
* without a flow.
|
|
17
|
+
*
|
|
18
|
+
* Inputs are read from the raw envelope (`surfaceInputs`) so every
|
|
19
|
+
* validator applies the same rules to the same data. Framework-free; never
|
|
20
|
+
* evaluates anything.
|
|
21
|
+
*/
|
|
22
|
+
/** The spec's `intentName` pattern (pinned to `SPEC_PATTERNS` by the spec tests); no imports keep this module lean. */
|
|
23
|
+
export const SURFACE_INTENT_NAME = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/u;
|
|
24
|
+
/** The spec's `listText` pattern (the contract's `SPEC_PATTERNS.listText` is this string). */
|
|
25
|
+
export const LIST_TEXT_PATTERN = '^[^\\u0000-\\u001f\\u007f-\\u009f\\u061c\\u180e\\u200b\\u200e\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]*$';
|
|
26
|
+
/** The state type each control writes (mirrors the catalog's `CONTROL_STATE_TYPES`). */
|
|
27
|
+
export const SPEC_CONTROL_STATE_TYPES =
|
|
28
|
+
/* @__PURE__ */ Object.freeze({
|
|
29
|
+
'control-toggle': 'boolean',
|
|
30
|
+
'control-choice': 'enum',
|
|
31
|
+
'control-slider': 'number',
|
|
32
|
+
'control-filter': 'string',
|
|
33
|
+
});
|
|
34
|
+
/** The player's issue code each spec code stands for (`action-binding` → `action`, …). */
|
|
35
|
+
export const SURFACE_PLAYER_CODES = /* @__PURE__ */ Object.freeze({
|
|
36
|
+
'action-binding': 'action',
|
|
37
|
+
'control-binding': 'binding',
|
|
38
|
+
'host-binding': 'binding',
|
|
39
|
+
'flow-binding': 'state',
|
|
40
|
+
});
|
|
41
|
+
const isBag = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
42
|
+
const strings = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : [];
|
|
43
|
+
/**
|
|
44
|
+
* Read the surface inputs from a raw envelope, as the player does: an
|
|
45
|
+
* envelope with `state` or `flow` has declarations (empty with only a flow).
|
|
46
|
+
*/
|
|
47
|
+
export function surfaceInputs(envelope) {
|
|
48
|
+
if (!isBag(envelope))
|
|
49
|
+
return { declarations: null, flow: null };
|
|
50
|
+
const hasState = Object.hasOwn(envelope, 'state');
|
|
51
|
+
const hasFlow = Object.hasOwn(envelope, 'flow');
|
|
52
|
+
let declarations = null;
|
|
53
|
+
if (hasState || hasFlow) {
|
|
54
|
+
declarations = new Map();
|
|
55
|
+
const state = isBag(envelope.state) ? envelope.state : {};
|
|
56
|
+
for (const [name, raw] of Object.entries(state)) {
|
|
57
|
+
if (isBag(raw) && typeof raw.type === 'string') {
|
|
58
|
+
declarations.set(name, { type: raw.type, writable: !Object.hasOwn(raw, 'source') });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const raw = envelope.flow;
|
|
63
|
+
const flow = isBag(raw)
|
|
64
|
+
? {
|
|
65
|
+
views: strings(raw.views),
|
|
66
|
+
events: Array.isArray(raw.transitions)
|
|
67
|
+
? raw.transitions.flatMap((t) => (isBag(t) && typeof t.on === 'string' ? [t.on] : []))
|
|
68
|
+
: [],
|
|
69
|
+
}
|
|
70
|
+
: null;
|
|
71
|
+
return { declarations, flow };
|
|
72
|
+
}
|
|
73
|
+
/** Check one tree root against the surface rules; one issue per refused node and rule. */
|
|
74
|
+
export function checkStateSurface(root, inputs) {
|
|
75
|
+
const issues = [];
|
|
76
|
+
const { declarations, flow } = inputs;
|
|
77
|
+
const events = new Set(flow?.events ?? []);
|
|
78
|
+
function visit(node, at, form) {
|
|
79
|
+
if (!isBag(node) || at.length > 64)
|
|
80
|
+
return;
|
|
81
|
+
const fail = (code, message) => issues.push({ code, at, message });
|
|
82
|
+
const id = typeof node.id === 'string' ? node.id : '';
|
|
83
|
+
const props = isBag(node.props) ? node.props : {};
|
|
84
|
+
let scope = form;
|
|
85
|
+
// Controls.
|
|
86
|
+
const wanted = Object.hasOwn(SPEC_CONTROL_STATE_TYPES, id)
|
|
87
|
+
? SPEC_CONTROL_STATE_TYPES[id]
|
|
88
|
+
: undefined;
|
|
89
|
+
if (wanted !== undefined) {
|
|
90
|
+
const name = props.state;
|
|
91
|
+
const declaration = typeof name === 'string' ? declarations?.get(name) : undefined;
|
|
92
|
+
if (!declarations) {
|
|
93
|
+
fail('binding', `"${id}" needs declared local state; this blueprint declares none.`);
|
|
94
|
+
}
|
|
95
|
+
else if (typeof name !== 'string' || !declaration) {
|
|
96
|
+
fail('binding', `"${id}" names no declared state variable.`);
|
|
97
|
+
}
|
|
98
|
+
else if (declaration.type !== wanted) {
|
|
99
|
+
fail('binding', `"${id}" writes a ${wanted}, but "${name}" is a ${declaration.type}.`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Flow nodes.
|
|
103
|
+
if (id === 'flow-view' || id === 'flow-action') {
|
|
104
|
+
if (!flow) {
|
|
105
|
+
fail('state', `"${id}" needs a declared flow; this blueprint declares none.`);
|
|
106
|
+
}
|
|
107
|
+
else if (id === 'flow-view' &&
|
|
108
|
+
(typeof props.name !== 'string' || !flow.views.includes(props.name))) {
|
|
109
|
+
fail('state', '"flow-view" names no declared view.');
|
|
110
|
+
}
|
|
111
|
+
else if (id === 'flow-action' &&
|
|
112
|
+
(typeof props.event !== 'string' || !events.has(props.event))) {
|
|
113
|
+
fail('state', '"flow-action" fires an event no transition handles.');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Forms.
|
|
117
|
+
if (id === 'action-form') {
|
|
118
|
+
if (form)
|
|
119
|
+
fail('action', '"action-form" cannot nest inside another form.');
|
|
120
|
+
if (typeof props.action !== 'string' || !SURFACE_INTENT_NAME.test(props.action)) {
|
|
121
|
+
fail('action', '"action-form" needs an action name like "request-access".');
|
|
122
|
+
}
|
|
123
|
+
scope = new Set();
|
|
124
|
+
}
|
|
125
|
+
else if (id === 'form-field' || id === 'form-submit') {
|
|
126
|
+
if (!form)
|
|
127
|
+
fail('action', `"${id}" must be inside an "action-form".`);
|
|
128
|
+
else if (id === 'form-field') {
|
|
129
|
+
const { name, state, kind } = props;
|
|
130
|
+
const declaration = typeof state === 'string' ? declarations?.get(state) : undefined;
|
|
131
|
+
const type = kind === 'number' ? 'number' : 'string';
|
|
132
|
+
if (typeof name !== 'string' || !SURFACE_INTENT_NAME.test(name))
|
|
133
|
+
fail('action', '"form-field" needs a field name.');
|
|
134
|
+
else if (form.has(name))
|
|
135
|
+
fail('action', `Field name "${name}" is used twice in one form.`);
|
|
136
|
+
else
|
|
137
|
+
form.add(name);
|
|
138
|
+
if (!declarations)
|
|
139
|
+
fail('action', '"form-field" needs declared local state; this blueprint declares none.');
|
|
140
|
+
else if (!declaration)
|
|
141
|
+
fail('action', '"form-field" names no declared state variable.');
|
|
142
|
+
else if (declaration.type !== type) {
|
|
143
|
+
fail('action', `A ${String(kind ?? 'text')} field writes a ${type}, but "${String(state)}" is a ${declaration.type}.`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Host-bound variables are the host's to write.
|
|
148
|
+
const writes = wanted !== undefined || id === 'form-field';
|
|
149
|
+
if (writes && typeof props.state === 'string') {
|
|
150
|
+
const declaration = declarations?.get(props.state);
|
|
151
|
+
if (declaration && !declaration.writable) {
|
|
152
|
+
fail('binding', `"${id}" cannot write "${props.state}": its value comes from the host.`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(node.children)) {
|
|
156
|
+
for (const [index, child] of node.children.entries())
|
|
157
|
+
visit(child, [...at, index], scope);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
visit(root, [], null);
|
|
161
|
+
return issues;
|
|
162
|
+
}
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,27 +1,102 @@
|
|
|
1
|
-
import type { SpecDiagnostic, SpecDiagnosticCode, SpecValidation } from './generated/typescript/diagnostics.js';
|
|
1
|
+
import type { SpecDiagnostic, SpecDiagnosticCode, SpecValidation, SpecWarning } from './generated/typescript/diagnostics.js';
|
|
2
2
|
import type { SpecCatalog } from './catalog.js';
|
|
3
|
+
import { type SpecStateType } from './contract.js';
|
|
3
4
|
import { type Schema } from './dialect.js';
|
|
4
|
-
export type { SpecDiagnostic, SpecDiagnosticCode, SpecValidation };
|
|
5
|
+
export type { SpecDiagnostic, SpecDiagnosticCode, SpecValidation, SpecWarning };
|
|
6
|
+
/**
|
|
7
|
+
* Checks one workflow graph against the workflow schema:
|
|
8
|
+
* `validateWorkflowGraph` from `@texuli/spec/workflow`. The root never
|
|
9
|
+
* imports it, so blueprints without workflows do not pay for it.
|
|
10
|
+
*/
|
|
11
|
+
export type WorkflowGraphValidator = (graph: unknown, workflowSchema: Schema) => SpecValidation;
|
|
5
12
|
export interface SpecDocuments {
|
|
6
13
|
blueprintSchema: Schema;
|
|
7
14
|
catalog: SpecCatalog;
|
|
15
|
+
/**
|
|
16
|
+
* `schemas/workflow.schema.json`. Workflow state and `workflowGraph` props
|
|
17
|
+
* need it and {@link SpecDocuments.validateWorkflowGraph}; without both
|
|
18
|
+
* they fail closed (`state`, `prop-type`).
|
|
19
|
+
*/
|
|
20
|
+
workflowSchema?: Schema;
|
|
21
|
+
/** `validateWorkflowGraph` from `@texuli/spec/workflow`, for hosts that render workflows. */
|
|
22
|
+
validateWorkflowGraph?: WorkflowGraphValidator;
|
|
23
|
+
}
|
|
24
|
+
/** The workflow schema and its validator, when the host supplied both. */
|
|
25
|
+
export interface WorkflowSupport {
|
|
26
|
+
schema: Schema;
|
|
27
|
+
validate: WorkflowGraphValidator;
|
|
28
|
+
}
|
|
29
|
+
/** One declared variable with its defaults applied; `valid: false` when its declaration was refused. */
|
|
30
|
+
export interface SpecStateVariable {
|
|
31
|
+
type: SpecStateType;
|
|
32
|
+
valid: boolean;
|
|
33
|
+
/** The first-paint value (the declared `initial` or the type's default). */
|
|
34
|
+
initial: unknown;
|
|
35
|
+
/** No `source`: the blueprint may write it. */
|
|
36
|
+
writable: boolean;
|
|
37
|
+
values?: readonly string[];
|
|
38
|
+
min?: number;
|
|
39
|
+
max?: number;
|
|
40
|
+
maxLength?: number;
|
|
41
|
+
maxItems?: number;
|
|
42
|
+
}
|
|
43
|
+
/** The declared flow, as the validator reads it. */
|
|
44
|
+
export interface SpecFlowInfo {
|
|
45
|
+
views: readonly string[];
|
|
46
|
+
events: ReadonlySet<string>;
|
|
47
|
+
}
|
|
48
|
+
export interface TreeOptions {
|
|
49
|
+
portable?: boolean;
|
|
50
|
+
path?: string;
|
|
51
|
+
/** Declared variables by name (from {@link checkStateDeclarations}). Without it, every `$state` is unknown. */
|
|
52
|
+
state?: ReadonlyMap<string, SpecStateVariable>;
|
|
53
|
+
/** The declared flow, or `null`/omitted when none. */
|
|
54
|
+
flow?: SpecFlowInfo | null;
|
|
55
|
+
/** The root property schemas resolve against ({@link contractRoot}). */
|
|
56
|
+
root?: Schema;
|
|
57
|
+
/** Receives advisory findings (`deprecated`). */
|
|
58
|
+
warnings?: SpecWarning[];
|
|
59
|
+
/** Checks `workflowGraph` positions; without it they fail closed. */
|
|
60
|
+
workflow?: WorkflowSupport;
|
|
8
61
|
}
|
|
9
62
|
/**
|
|
10
63
|
* Validate a blueprint envelope against the spec alone: the envelope schema,
|
|
11
|
-
* then every node against the catalog
|
|
12
|
-
* names, prop kinds and enum values,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
64
|
+
* the declared state and flow, then every node against the catalog
|
|
65
|
+
* vocabulary (closed ids, closed prop names, prop kinds and enum values,
|
|
66
|
+
* property schemas, required props, no platform-extension props from data,
|
|
67
|
+
* a `slot` that names a slot prop of the parent, bindings, two-way `bind`,
|
|
68
|
+
* `on` events and their closed actions) and the declared profile. A `when`
|
|
69
|
+
* condition is checked for shape only; the runtime formula parser checks
|
|
70
|
+
* its operands. With `catalogHash`, an envelope bound to another catalog is
|
|
71
|
+
* refused. Deprecated components and props add `warnings` (never failing).
|
|
72
|
+
* This is the shared, target-neutral contract; URL policy, limits, grammar
|
|
73
|
+
* and rendering stay in the runtime validators (`@texuli/catalog/validate`).
|
|
19
74
|
*/
|
|
20
75
|
export declare function validateBlueprint(input: unknown, documents: SpecDocuments, options?: {
|
|
21
76
|
catalogHash?: string;
|
|
22
77
|
}): SpecValidation;
|
|
78
|
+
/**
|
|
79
|
+
* Read the envelope's `state` (code `state`): at most 64 variables, safe
|
|
80
|
+
* names, the fields each type takes, and an initial value of the declared
|
|
81
|
+
* type. One diagnostic per refused declaration; a refused declaration stays
|
|
82
|
+
* declared (so bindings to it are not also `unknown-state`). Shape problems
|
|
83
|
+
* the schema reports are not repeated.
|
|
84
|
+
*/
|
|
85
|
+
export declare function checkStateDeclarations(input: unknown, out: SpecDiagnostic[], workflow?: WorkflowSupport): Map<string, SpecStateVariable>;
|
|
86
|
+
/**
|
|
87
|
+
* A list value: at most `maxItems` items, each `{ id, ...fields }` with a
|
|
88
|
+
* unique item key and at most 16 scalar fields (string ≤ 1000, finite
|
|
89
|
+
* number, boolean) named like state variables. Strings follow the
|
|
90
|
+
* `listText` rule: a draggable item's text never hides or reorders itself.
|
|
91
|
+
*/
|
|
92
|
+
export declare function listProblem(value: unknown, maxItems: number): {
|
|
93
|
+
at: string;
|
|
94
|
+
message: string;
|
|
95
|
+
} | null;
|
|
96
|
+
/**
|
|
97
|
+
* Read the envelope's `flow` (code `state`): distinct views, an initial and
|
|
98
|
+
* transitions that name declared views (or `*` as a source).
|
|
99
|
+
*/
|
|
100
|
+
export declare function checkFlow(input: unknown, out: SpecDiagnostic[]): SpecFlowInfo | null;
|
|
23
101
|
/** Check one catalog tree against the vocabulary. See {@link validateBlueprint}. */
|
|
24
|
-
export declare function validateTree(tree: unknown, catalog: SpecCatalog, options?:
|
|
25
|
-
portable?: boolean;
|
|
26
|
-
path?: string;
|
|
27
|
-
}): SpecDiagnostic[];
|
|
102
|
+
export declare function validateTree(tree: unknown, catalog: SpecCatalog, options?: TreeOptions): SpecDiagnostic[];
|