@ifc-lite/flow 0.2.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.
Files changed (59) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +63 -0
  3. package/dist/availability.d.ts +28 -0
  4. package/dist/availability.d.ts.map +1 -0
  5. package/dist/availability.js +37 -0
  6. package/dist/availability.js.map +1 -0
  7. package/dist/digest.d.ts +14 -0
  8. package/dist/digest.d.ts.map +1 -0
  9. package/dist/digest.js +73 -0
  10. package/dist/digest.js.map +1 -0
  11. package/dist/document.d.ts +73 -0
  12. package/dist/document.d.ts.map +1 -0
  13. package/dist/document.js +158 -0
  14. package/dist/document.js.map +1 -0
  15. package/dist/index.d.ts +22 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +16 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/introspect.d.ts +61 -0
  20. package/dist/introspect.d.ts.map +1 -0
  21. package/dist/introspect.js +51 -0
  22. package/dist/introspect.js.map +1 -0
  23. package/dist/lift.d.ts +58 -0
  24. package/dist/lift.d.ts.map +1 -0
  25. package/dist/lift.js +213 -0
  26. package/dist/lift.js.map +1 -0
  27. package/dist/orphans.d.ts +32 -0
  28. package/dist/orphans.d.ts.map +1 -0
  29. package/dist/orphans.js +73 -0
  30. package/dist/orphans.js.map +1 -0
  31. package/dist/prepare.d.ts +13 -0
  32. package/dist/prepare.d.ts.map +1 -0
  33. package/dist/prepare.js +40 -0
  34. package/dist/prepare.js.map +1 -0
  35. package/dist/registry.d.ts +99 -0
  36. package/dist/registry.d.ts.map +1 -0
  37. package/dist/registry.js +44 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/scheduler.d.ts +91 -0
  40. package/dist/scheduler.d.ts.map +1 -0
  41. package/dist/scheduler.js +341 -0
  42. package/dist/scheduler.js.map +1 -0
  43. package/dist/table.d.ts +64 -0
  44. package/dist/table.d.ts.map +1 -0
  45. package/dist/table.js +132 -0
  46. package/dist/table.js.map +1 -0
  47. package/dist/tracking.d.ts +86 -0
  48. package/dist/tracking.d.ts.map +1 -0
  49. package/dist/tracking.js +136 -0
  50. package/dist/tracking.js.map +1 -0
  51. package/dist/values.d.ts +102 -0
  52. package/dist/values.d.ts.map +1 -0
  53. package/dist/values.js +64 -0
  54. package/dist/values.js.map +1 -0
  55. package/dist/wiring.d.ts +20 -0
  56. package/dist/wiring.d.ts.map +1 -0
  57. package/dist/wiring.js +56 -0
  58. package/dist/wiring.js.map +1 -0
  59. package/package.json +53 -0
package/dist/table.js ADDED
@@ -0,0 +1,132 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ export const COLUMN_TYPES = [
5
+ 'string', 'real', 'integer', 'boolean', 'logical', 'label', 'identifier', 'text', 'enum', 'reference', 'list',
6
+ ];
7
+ /** Structural validation of an untrusted table value. */
8
+ export function validateTable(value, path = 'table') {
9
+ const problems = [];
10
+ if (!value || typeof value !== 'object')
11
+ return [{ path, message: 'must be an object' }];
12
+ const t = value;
13
+ if (!Array.isArray(t.columns))
14
+ problems.push({ path: `${path}.columns`, message: 'must be an array' });
15
+ if (!Array.isArray(t.rows))
16
+ problems.push({ path: `${path}.rows`, message: 'must be an array' });
17
+ if (typeof t.key !== 'string' || t.key.length === 0)
18
+ problems.push({ path: `${path}.key`, message: 'must name the key column' });
19
+ if (problems.length > 0)
20
+ return problems;
21
+ const names = new Set();
22
+ t.columns.forEach((c, i) => {
23
+ const col = c;
24
+ const p = `${path}.columns[${i}]`;
25
+ if (typeof col.name !== 'string' || col.name.length === 0)
26
+ problems.push({ path: `${p}.name`, message: 'must be a non-empty string' });
27
+ else if (names.has(col.name))
28
+ problems.push({ path: `${p}.name`, message: `duplicate column "${col.name}"` });
29
+ else
30
+ names.add(col.name);
31
+ if (!COLUMN_TYPES.includes(col.type))
32
+ problems.push({ path: `${p}.type`, message: `unknown column type "${String(col.type)}"` });
33
+ if (col.unit !== undefined && typeof col.unit !== 'string')
34
+ problems.push({ path: `${p}.unit`, message: 'must be a string' });
35
+ if (col.binding !== undefined) {
36
+ const b = col.binding;
37
+ if (!b || typeof b.pset !== 'string' || typeof b.prop !== 'string')
38
+ problems.push({ path: `${p}.binding`, message: 'must be { pset, prop }' });
39
+ }
40
+ });
41
+ if (typeof t.key === 'string' && !names.has(t.key))
42
+ problems.push({ path: `${path}.key`, message: `key column "${t.key}" is not a column` });
43
+ t.rows.forEach((r, i) => {
44
+ if (!r || typeof r !== 'object' || Array.isArray(r)) {
45
+ problems.push({ path: `${path}.rows[${i}]`, message: 'must be an object' });
46
+ return;
47
+ }
48
+ for (const [k, v] of Object.entries(r)) {
49
+ if (!names.has(k))
50
+ problems.push({ path: `${path}.rows[${i}].${k}`, message: 'not a declared column' });
51
+ else if (v !== null && typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean') {
52
+ problems.push({ path: `${path}.rows[${i}].${k}`, message: 'cell must be string, number, boolean or null' });
53
+ }
54
+ }
55
+ });
56
+ return problems;
57
+ }
58
+ export function column(table, name) {
59
+ return table.columns.find((c) => c.name === name);
60
+ }
61
+ /** The row key as a group key; `null`/missing keys are reported, never coerced. */
62
+ export function rowKey(table, row) {
63
+ const v = row[table.key];
64
+ if (v === null || v === undefined || v === '')
65
+ return null;
66
+ return String(v);
67
+ }
68
+ /** Split rows into branches by a column's value (defaults to the key column). */
69
+ export function groupRows(table, by = table.key) {
70
+ const branches = new Map();
71
+ const unkeyed = [];
72
+ for (const row of table.rows) {
73
+ const v = row[by];
74
+ if (v === null || v === undefined || v === '') {
75
+ unkeyed.push(row);
76
+ continue;
77
+ }
78
+ const k = String(v);
79
+ const branch = branches.get(k);
80
+ if (branch)
81
+ branch.push(row);
82
+ else
83
+ branches.set(k, [row]);
84
+ }
85
+ return { branches, unkeyed };
86
+ }
87
+ /**
88
+ * Widen a long-format table into one row per `rowKey` with a column per
89
+ * distinct `colKey` value. The pivoted column's type is taken from the
90
+ * `valueCol` column; a duplicate (rowKey, colKey) pair keeps the last value
91
+ * and is reported, and a `colKey` that names the key column is refused
92
+ * (`collisions`) rather than overwriting the row's identity.
93
+ */
94
+ export function pivot(table, rowKeyCol, colKeyCol, valueCol) {
95
+ const valueColumn = column(table, valueCol);
96
+ const rows = new Map();
97
+ const colNames = new Set();
98
+ let duplicates = 0;
99
+ let collisions = 0;
100
+ for (const row of table.rows) {
101
+ const rk = row[rowKeyCol];
102
+ const ck = row[colKeyCol];
103
+ if (rk === null || rk === undefined || rk === '' || ck === null || ck === undefined || ck === '')
104
+ continue;
105
+ const rkey = String(rk);
106
+ const cname = String(ck);
107
+ // A pivoted column named like the key column (a long-format row whose
108
+ // `Prop` is literally `GlobalId`) would overwrite the row's identity with
109
+ // its value. Two distinct things, never merged: the row is counted and
110
+ // skipped, not silently folded into the key.
111
+ if (cname === rowKeyCol) {
112
+ collisions += 1;
113
+ continue;
114
+ }
115
+ colNames.add(cname);
116
+ let target = rows.get(rkey);
117
+ if (!target) {
118
+ target = { [rowKeyCol]: rk };
119
+ rows.set(rkey, target);
120
+ }
121
+ if (cname in target)
122
+ duplicates += 1;
123
+ target[cname] = row[valueCol] ?? null;
124
+ }
125
+ const keyColumn = column(table, rowKeyCol) ?? { name: rowKeyCol, type: 'identifier' };
126
+ const columns = [
127
+ keyColumn,
128
+ ...[...colNames].map((name) => ({ name, type: valueColumn?.type ?? 'string', unit: valueColumn?.unit })),
129
+ ];
130
+ return { table: { columns, rows: [...rows.values()], key: rowKeyCol }, duplicates, collisions };
131
+ }
132
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import type { TrackingMode } from './document.js';
2
+ import type { GroupKey } from './values.js';
3
+ export interface TrackedEntry {
4
+ readonly globalId: string;
5
+ /** Digest of the inputs that produced this element. */
6
+ readonly digest: string;
7
+ }
8
+ export interface TrackedSet {
9
+ readonly trackingKey: string;
10
+ /** Bumped on every `replace` run so fresh GlobalIds stay deterministic. */
11
+ readonly generation: number;
12
+ readonly entries: Readonly<Record<GroupKey, TrackedEntry>>;
13
+ /**
14
+ * Type of the node that made the set. Recorded so that a set whose node
15
+ * was deleted from the graph can still be removed from the model by that
16
+ * type's `remove` — without it the elements outlive the node that made
17
+ * them, the orphan this whole module exists to prevent.
18
+ */
19
+ readonly nodeType?: string;
20
+ }
21
+ export declare const TRACKING_SIDECAR_VERSION = 1;
22
+ /** Shape check for a set read from storage: `load()` promises a `TrackedSet`, not whatever a hand-edited sidecar holds. */
23
+ export declare function isTrackedSet(value: unknown): value is TrackedSet;
24
+ /** The `sets` record of a sidecar, or undefined when any set is malformed. */
25
+ export declare function trackedSetsFrom(sets: unknown): Record<string, TrackedSet> | undefined;
26
+ /** `<graph>.tracking.json` */
27
+ export interface TrackingSidecar {
28
+ readonly version: number;
29
+ /** Layer stack id or file hash the sets were made against. */
30
+ readonly pinnedTo: string;
31
+ readonly sets: Readonly<Record<string, TrackedSet>>;
32
+ }
33
+ /** Where a run reads and writes tracked sets (a sidecar file, browser storage, memory). */
34
+ export interface TrackingStore {
35
+ load(trackingKey: string): TrackedSet | undefined;
36
+ save(set: TrackedSet): void;
37
+ /** Every tracking key the store holds, so a run can find sets no node claims any more. */
38
+ keys(): readonly string[];
39
+ delete(trackingKey: string): void;
40
+ }
41
+ /** In-memory store: tests, and hosts that have not chosen a sidecar yet. */
42
+ export declare class MemoryTrackingStore implements TrackingStore {
43
+ private readonly sets;
44
+ load(trackingKey: string): TrackedSet | undefined;
45
+ save(set: TrackedSet): void;
46
+ keys(): readonly string[];
47
+ delete(trackingKey: string): void;
48
+ }
49
+ export interface DesiredLane {
50
+ readonly laneKey: GroupKey;
51
+ readonly digest: string;
52
+ }
53
+ export interface TrackingPlan {
54
+ readonly mode: TrackingMode;
55
+ readonly create: readonly {
56
+ laneKey: GroupKey;
57
+ globalId: string;
58
+ }[];
59
+ readonly update: readonly {
60
+ laneKey: GroupKey;
61
+ globalId: string;
62
+ }[];
63
+ readonly keep: readonly {
64
+ laneKey: GroupKey;
65
+ globalId: string;
66
+ }[];
67
+ readonly remove: readonly {
68
+ laneKey: GroupKey;
69
+ globalId: string;
70
+ }[];
71
+ /** The set to persist after the plan is applied. */
72
+ readonly next: TrackedSet;
73
+ /** Lane keys that appeared more than once: only the first is tracked. */
74
+ readonly duplicateLanes: readonly GroupKey[];
75
+ }
76
+ export declare function emptyTrackedSet(trackingKey: string): TrackedSet;
77
+ export declare function planTracking(previous: TrackedSet, desired: readonly DesiredLane[], mode: TrackingMode): TrackingPlan;
78
+ export declare class TrackingPinMismatch extends Error {
79
+ readonly expected: string;
80
+ readonly actual: string;
81
+ constructor(expected: string, actual: string);
82
+ }
83
+ /** Read one node's set from a sidecar; refuses a sidecar pinned to another model state. */
84
+ export declare function trackedSetFrom(sidecar: TrackingSidecar | undefined, pinnedTo: string, trackingKey: string): TrackedSet;
85
+ export declare function withTrackedSet(sidecar: TrackingSidecar | undefined, pinnedTo: string, set: TrackedSet): TrackingSidecar;
86
+ //# sourceMappingURL=tracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Element tracking: how a write node's output survives re-runs.
6
+ *
7
+ * Each write node owns a *tracked set*: the lane keys it produced last time
8
+ * and the GlobalId + input digest of each. A re-run plans, per lane:
9
+ *
10
+ * create — lane is new (GlobalId = trackingGuid(trackingKey, laneKey))
11
+ * update — lane exists, digest changed
12
+ * keep — lane exists, digest equal (nothing to write)
13
+ * remove — lane vanished (tombstone; the orphan Dynamo leaves behind)
14
+ *
15
+ * This is Rhino.Inside.Revit's "remember what each output added" made
16
+ * explicit, keyed by the user-visible `trackingKey` instead of the node's
17
+ * position in a file. Sets are pinned to the model state they were made
18
+ * against (layer stack id or file hash), so a set from another model is
19
+ * refused rather than adopted by accident.
20
+ */
21
+ import { trackingGuid } from './digest.js';
22
+ export const TRACKING_SIDECAR_VERSION = 1;
23
+ /** Shape check for a set read from storage: `load()` promises a `TrackedSet`, not whatever a hand-edited sidecar holds. */
24
+ export function isTrackedSet(value) {
25
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
26
+ return false;
27
+ const v = value;
28
+ if (typeof v.trackingKey !== 'string' || typeof v.generation !== 'number' || !Number.isInteger(v.generation))
29
+ return false;
30
+ if (v.nodeType !== undefined && typeof v.nodeType !== 'string')
31
+ return false;
32
+ if (typeof v.entries !== 'object' || v.entries === null || Array.isArray(v.entries))
33
+ return false;
34
+ return Object.values(v.entries).every((e) => typeof e === 'object' && e !== null && typeof e.globalId === 'string' && typeof e.digest === 'string');
35
+ }
36
+ /** The `sets` record of a sidecar, or undefined when any set is malformed. */
37
+ export function trackedSetsFrom(sets) {
38
+ if (typeof sets !== 'object' || sets === null || Array.isArray(sets))
39
+ return undefined;
40
+ const out = {};
41
+ for (const [key, value] of Object.entries(sets)) {
42
+ if (!isTrackedSet(value) || value.trackingKey !== key)
43
+ return undefined;
44
+ out[key] = value;
45
+ }
46
+ return out;
47
+ }
48
+ /** In-memory store: tests, and hosts that have not chosen a sidecar yet. */
49
+ export class MemoryTrackingStore {
50
+ sets = new Map();
51
+ load(trackingKey) {
52
+ return this.sets.get(trackingKey);
53
+ }
54
+ save(set) {
55
+ this.sets.set(set.trackingKey, set);
56
+ }
57
+ keys() {
58
+ return [...this.sets.keys()];
59
+ }
60
+ delete(trackingKey) {
61
+ this.sets.delete(trackingKey);
62
+ }
63
+ }
64
+ export function emptyTrackedSet(trackingKey) {
65
+ return { trackingKey, generation: 0, entries: {} };
66
+ }
67
+ export function planTracking(previous, desired, mode) {
68
+ const create = [];
69
+ const update = [];
70
+ const keep = [];
71
+ const remove = [];
72
+ const duplicateLanes = [];
73
+ const nextEntries = {};
74
+ if (mode === 'disabled') {
75
+ return { mode, create, update, keep, remove, next: previous, duplicateLanes };
76
+ }
77
+ const generation = mode === 'replace' ? previous.generation + 1 : previous.generation;
78
+ const guidKey = generation === 0 ? previous.trackingKey : `${previous.trackingKey}#${generation}`;
79
+ const seen = new Set();
80
+ for (const lane of desired) {
81
+ if (seen.has(lane.laneKey)) {
82
+ duplicateLanes.push(lane.laneKey);
83
+ continue;
84
+ }
85
+ seen.add(lane.laneKey);
86
+ const prev = mode === 'update' ? previous.entries[lane.laneKey] : undefined;
87
+ if (!prev) {
88
+ const globalId = trackingGuid(guidKey, lane.laneKey);
89
+ create.push({ laneKey: lane.laneKey, globalId });
90
+ nextEntries[lane.laneKey] = { globalId, digest: lane.digest };
91
+ }
92
+ else if (prev.digest !== lane.digest) {
93
+ update.push({ laneKey: lane.laneKey, globalId: prev.globalId });
94
+ nextEntries[lane.laneKey] = { globalId: prev.globalId, digest: lane.digest };
95
+ }
96
+ else {
97
+ keep.push({ laneKey: lane.laneKey, globalId: prev.globalId });
98
+ nextEntries[lane.laneKey] = prev;
99
+ }
100
+ }
101
+ // `replace` re-creates every lane under a fresh GlobalId, so every previous
102
+ // element is removed — otherwise the old set is orphaned, not replaced.
103
+ for (const [laneKey, entry] of Object.entries(previous.entries)) {
104
+ if (mode === 'replace' || !seen.has(laneKey))
105
+ remove.push({ laneKey, globalId: entry.globalId });
106
+ }
107
+ return { mode, create, update, keep, remove, next: { trackingKey: previous.trackingKey, generation, entries: nextEntries }, duplicateLanes };
108
+ }
109
+ export class TrackingPinMismatch extends Error {
110
+ expected;
111
+ actual;
112
+ constructor(expected, actual) {
113
+ super(`tracking sidecar is pinned to ${expected}, current model state is ${actual}`);
114
+ this.expected = expected;
115
+ this.actual = actual;
116
+ this.name = 'TrackingPinMismatch';
117
+ }
118
+ }
119
+ /** Read one node's set from a sidecar; refuses a sidecar pinned to another model state. */
120
+ export function trackedSetFrom(sidecar, pinnedTo, trackingKey) {
121
+ if (!sidecar)
122
+ return emptyTrackedSet(trackingKey);
123
+ if (sidecar.version !== TRACKING_SIDECAR_VERSION)
124
+ throw new Error(`unsupported tracking sidecar version ${sidecar.version}`);
125
+ if (sidecar.pinnedTo !== pinnedTo)
126
+ throw new TrackingPinMismatch(sidecar.pinnedTo, pinnedTo);
127
+ return sidecar.sets[trackingKey] ?? emptyTrackedSet(trackingKey);
128
+ }
129
+ export function withTrackedSet(sidecar, pinnedTo, set) {
130
+ return {
131
+ version: TRACKING_SIDECAR_VERSION,
132
+ pinnedTo,
133
+ sets: { ...(sidecar?.pinnedTo === pinnedTo ? sidecar.sets : {}), [set.trackingKey]: set },
134
+ };
135
+ }
136
+ //# sourceMappingURL=tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracking.js","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The flow data model.
3
+ *
4
+ * Every value travelling along an edge is wrapped in an explicit container
5
+ * (`FlowData`) that says how it is structured — one item, an ordered list,
6
+ * or a group of lists keyed by string. Nodes never sniff shapes: a port
7
+ * declares the `access` it wants and the scheduler lifts the node over the
8
+ * container (see `lift.ts`). That single rule replaces Grasshopper's data
9
+ * trees (paths, Path Mapper, Simplify) and Dynamo's list levels with one
10
+ * keyed level, which is what BIM data actually is: keyed by GlobalId,
11
+ * storey, sheet name, grid intersection.
12
+ *
13
+ * Values are plain data. An entity is a *handle* (`EntityRef`), never a copy
14
+ * of its properties; nodes read what they need through `bim.*` on demand.
15
+ */
16
+ /** How a port consumes or produces data. */
17
+ export type Access = 'item' | 'list' | 'group';
18
+ /** How an `item` port is lifted over lists (Dynamo lacing). */
19
+ export type Lacing = 'shortest' | 'longest' | 'cross';
20
+ /** A group key: a string so it survives JSON and sidecars unchanged. */
21
+ export type GroupKey = string;
22
+ export type FlowData<T = unknown> = {
23
+ readonly kind: 'item';
24
+ readonly value: T;
25
+ } | {
26
+ readonly kind: 'list';
27
+ readonly items: readonly T[];
28
+ } | {
29
+ readonly kind: 'group';
30
+ readonly branches: ReadonlyMap<GroupKey, readonly T[]>;
31
+ };
32
+ export declare function item<T>(value: T): FlowData<T>;
33
+ export declare function list<T>(items: readonly T[]): FlowData<T>;
34
+ export declare function group<T>(branches: ReadonlyMap<GroupKey, readonly T[]> | Iterable<readonly [GroupKey, readonly T[]]>): FlowData<T>;
35
+ /** The branch key a plain list occupies when a `group` port receives it. */
36
+ export declare const SINGLE_BRANCH: GroupKey;
37
+ /** Total item count regardless of structure. */
38
+ export declare function countItems(data: FlowData): number;
39
+ /** Flatten any structure to a list, branch order preserved. */
40
+ export declare function flatten<T>(data: FlowData<T>): readonly T[];
41
+ /** View any structure as a group: an item or list becomes the single branch. */
42
+ export declare function asGroup<T>(data: FlowData<T>): ReadonlyMap<GroupKey, readonly T[]>;
43
+ export type Scalar = string | number | boolean | null;
44
+ /**
45
+ * An entity handle. `globalId` is the identity that survives reloads,
46
+ * exports and layer publishes; `modelId`/`expressId` are the host's
47
+ * session-scoped address for it and may be re-resolved. Keys, joins and
48
+ * tracking use `globalId`; reads through `bim.*` use the address.
49
+ */
50
+ export interface EntityRef {
51
+ readonly globalId: string;
52
+ readonly modelId?: string;
53
+ readonly expressId?: number;
54
+ }
55
+ export type Point = readonly [number, number, number];
56
+ export interface Polyline {
57
+ readonly points: readonly Point[];
58
+ readonly closed: boolean;
59
+ }
60
+ export interface Placement {
61
+ readonly position: Point;
62
+ /** Rotation about Z in degrees. */
63
+ readonly rotationZ: number;
64
+ }
65
+ /** Parametric profiles — the shapes `@ifc-lite/create` can author. No BRep. */
66
+ export type Profile = {
67
+ readonly kind: 'rectangle';
68
+ readonly width: number;
69
+ readonly depth: number;
70
+ } | {
71
+ readonly kind: 'circle';
72
+ readonly radius: number;
73
+ } | {
74
+ readonly kind: 'hollowCircle';
75
+ readonly radius: number;
76
+ readonly wallThickness: number;
77
+ } | {
78
+ readonly kind: 'hollowRectangle';
79
+ readonly width: number;
80
+ readonly depth: number;
81
+ readonly wallThickness: number;
82
+ } | {
83
+ readonly kind: 'I' | 'L' | 'T' | 'U';
84
+ readonly width: number;
85
+ readonly depth: number;
86
+ readonly webThickness: number;
87
+ readonly flangeThickness: number;
88
+ };
89
+ /** The value kinds a port can carry. `any` accepts everything (Watch, Script). */
90
+ export type ValueKind = 'scalar' | 'entity' | 'point' | 'polyline' | 'placement' | 'profile' | 'elementSpec' | 'table' | 'any';
91
+ /** A port's static type: what kind of value, and how it is structured. */
92
+ export interface PortType {
93
+ readonly kind: ValueKind;
94
+ readonly access: Access;
95
+ }
96
+ /**
97
+ * Whether a value produced on `from` can be consumed by `to`.
98
+ * Structure is always adaptable (the scheduler lifts), so only the value
99
+ * kind is checked; `any` matches both ways.
100
+ */
101
+ export declare function isAssignable(from: PortType, to: PortType): boolean;
102
+ //# sourceMappingURL=values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"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"}
package/dist/values.js ADDED
@@ -0,0 +1,64 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ export function item(value) {
5
+ return { kind: 'item', value };
6
+ }
7
+ export function list(items) {
8
+ return { kind: 'list', items };
9
+ }
10
+ export function group(branches) {
11
+ return { kind: 'group', branches: branches instanceof Map ? branches : new Map(branches) };
12
+ }
13
+ /** The branch key a plain list occupies when a `group` port receives it. */
14
+ export const SINGLE_BRANCH = '';
15
+ /** Total item count regardless of structure. */
16
+ export function countItems(data) {
17
+ switch (data.kind) {
18
+ case 'item':
19
+ return 1;
20
+ case 'list':
21
+ return data.items.length;
22
+ case 'group': {
23
+ let n = 0;
24
+ for (const items of data.branches.values())
25
+ n += items.length;
26
+ return n;
27
+ }
28
+ }
29
+ }
30
+ /** Flatten any structure to a list, branch order preserved. */
31
+ export function flatten(data) {
32
+ switch (data.kind) {
33
+ case 'item':
34
+ return [data.value];
35
+ case 'list':
36
+ return data.items;
37
+ case 'group': {
38
+ const out = [];
39
+ for (const items of data.branches.values())
40
+ out.push(...items);
41
+ return out;
42
+ }
43
+ }
44
+ }
45
+ /** View any structure as a group: an item or list becomes the single branch. */
46
+ export function asGroup(data) {
47
+ switch (data.kind) {
48
+ case 'item':
49
+ return new Map([[SINGLE_BRANCH, [data.value]]]);
50
+ case 'list':
51
+ return new Map([[SINGLE_BRANCH, data.items]]);
52
+ case 'group':
53
+ return data.branches;
54
+ }
55
+ }
56
+ /**
57
+ * Whether a value produced on `from` can be consumed by `to`.
58
+ * Structure is always adaptable (the scheduler lifts), so only the value
59
+ * kind is checked; `any` matches both ways.
60
+ */
61
+ export function isAssignable(from, to) {
62
+ return from.kind === 'any' || to.kind === 'any' || from.kind === to.kind;
63
+ }
64
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.js","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAkC/D,MAAM,UAAU,IAAI,CAAI,KAAQ;IAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,IAAI,CAAI,KAAmB;IACzC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,KAAK,CAAI,QAA2F;IAClH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,YAAY,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC7F,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,aAAa,GAAa,EAAE,CAAC;AAE1C,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,CAAC,CAAC;QACX,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;YACV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;gBAAE,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC;YAC9D,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,OAAO,CAAI,IAAiB;IAC1C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAQ,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;YAC/D,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,OAAO,CAAI,IAAiB;IAC1C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,KAAK,MAAM;YACT,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChD,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;AACH,CAAC;AAyDD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,EAAY;IACvD,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Registry-aware validation: the half `validateFlowDocument` cannot do.
3
+ *
4
+ * The document validator is structural — it can say `edges[0].from` is
5
+ * `[nodeId, port]` and that the node exists, but not that the node HAS that
6
+ * port, because it deliberately works without a registry. Everything that
7
+ * needs to know what a node type actually declares lives here: unknown node
8
+ * types, edge endpoints naming ports that do not exist, type-incompatible
9
+ * edges, and Player `inputs` / graph `outputs` pointing at parameters and
10
+ * ports that are not there.
11
+ *
12
+ * Without this, a graph whose declared output names a missing port passed
13
+ * validation, reported `ok: true`, exited 0 — and then produced nothing for
14
+ * that output at run time. A validator that cannot see the defect it is
15
+ * asked about reads as success, which is worse than not running at all.
16
+ */
17
+ import type { FlowDocument, DocumentProblem } from './document.js';
18
+ import type { NodeRegistry } from './registry.js';
19
+ export declare function validateFlowWiring(doc: FlowDocument, registry: NodeRegistry<unknown>): DocumentProblem[];
20
+ //# sourceMappingURL=wiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../src/wiring.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,eAAe,EAAE,CAmDxG"}
package/dist/wiring.js ADDED
@@ -0,0 +1,56 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { isAssignable } from './values.js';
5
+ export function validateFlowWiring(doc, registry) {
6
+ const problems = [];
7
+ const add = (path, message) => problems.push({ path, message });
8
+ const defOf = (nodeId) => {
9
+ const node = doc.nodes.find((n) => n.id === nodeId);
10
+ return node ? registry.get(node.type) : undefined;
11
+ };
12
+ doc.nodes.forEach((n, i) => {
13
+ if (!registry.get(n.type))
14
+ add(`nodes[${i}]`, `unknown node type "${n.type}" (${n.id})`);
15
+ });
16
+ doc.edges.forEach((e, i) => {
17
+ const from = defOf(e.from[0])?.outputs.find((p) => p.name === e.from[1]);
18
+ const to = defOf(e.to[0])?.inputs.find((p) => p.name === e.to[1]);
19
+ if (defOf(e.from[0]) && !from)
20
+ add(`edges[${i}].from`, `node "${e.from[0]}" has no output "${e.from[1]}"`);
21
+ if (defOf(e.to[0]) && !to)
22
+ add(`edges[${i}].to`, `node "${e.to[0]}" has no input "${e.to[1]}"`);
23
+ if (from && to && !isAssignable(from.type, to.type)) {
24
+ add(`edges[${i}]`, `${e.from[0]}.${e.from[1]} (${from.type.kind}) cannot feed ${e.to[0]}.${e.to[1]} (${to.type.kind})`);
25
+ }
26
+ });
27
+ doc.inputs.forEach((input, i) => {
28
+ const def = defOf(input.nodeId);
29
+ if (def && !def.params.some((p) => p.name === input.param)) {
30
+ add(`inputs[${i}]`, `node "${input.nodeId}" has no parameter "${input.param}"`);
31
+ }
32
+ });
33
+ doc.outputs.forEach((output, i) => {
34
+ const def = defOf(output.nodeId);
35
+ if (def && !def.outputs.some((p) => p.name === output.port)) {
36
+ add(`outputs[${i}]`, `node "${output.nodeId}" has no output "${output.port}"`);
37
+ }
38
+ });
39
+ // Required inputs with nothing connected: the scheduler fails the node at
40
+ // run time, so a validator that stayed silent here would promise a run it
41
+ // knows cannot happen.
42
+ for (const node of doc.nodes) {
43
+ const def = registry.get(node.type);
44
+ if (!def)
45
+ continue;
46
+ for (const port of def.inputs) {
47
+ if (port.optional)
48
+ continue;
49
+ if (!doc.edges.some((e) => e.to[0] === node.id && e.to[1] === port.name)) {
50
+ add(`nodes[${doc.nodes.indexOf(node)}]`, `required input "${port.name}" of "${node.id}" is not connected`);
51
+ }
52
+ }
53
+ }
54
+ return problems;
55
+ }
56
+ //# sourceMappingURL=wiring.js.map