@mica-js/document 0.0.0-stage → 0.1.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.
@@ -0,0 +1,69 @@
1
+ //#region src/format/value.ts
2
+ /** Where an image / binary property value lives (#7). */
3
+ var ASSET_MODES = [
4
+ "file",
5
+ "inline",
6
+ "store"
7
+ ];
8
+ function isAssetMode(value) {
9
+ return typeof value === "string" && ASSET_MODES.includes(value);
10
+ }
11
+ function isAssetReference(value) {
12
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
13
+ const record = value;
14
+ return typeof record["src"] === "string" && isAssetMode(record["mode"]);
15
+ }
16
+ /**
17
+ * `file` mode payload rules (#7): a project-root relative POSIX path that never escapes the
18
+ * project root and never turns into a URL.
19
+ */
20
+ function assetPathError(src) {
21
+ if (src.startsWith("/")) return "must be relative to the project root, not absolute";
22
+ if (/^[A-Za-z]:/.test(src)) return "must not carry a drive letter";
23
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(src)) return "must not be a URL";
24
+ if (src.includes("\\")) return "must use POSIX separators";
25
+ const escaping = src.split("/").find((segment) => segment === ".." || segment.startsWith("~"));
26
+ if (escaping !== void 0) return `must stay inside the project root (segment "${escaping}")`;
27
+ }
28
+ /** `inline` mode payload: base64 text, so hosts decode without guessing the encoding. */
29
+ function base64Error(src) {
30
+ return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(src) ? void 0 : "must be base64 text";
31
+ }
32
+ /** Payload problem for a resource reference `src`, or `undefined` when it is well formed. */
33
+ function assetSrcError(mode, src) {
34
+ if (mode === "inline") return base64Error(src);
35
+ return mode === "file" ? assetPathError(src) : void 0;
36
+ }
37
+ //#endregion
38
+ //#region src/format/errors.ts
39
+ /**
40
+ * Thrown when input violates the schematic format contract.
41
+ * `diagnostics` carries every problem found, so callers can report them all at once.
42
+ */
43
+ var SchematicError = class extends Error {
44
+ diagnostics;
45
+ constructor(diagnostics) {
46
+ super(buildMessage(diagnostics));
47
+ this.name = "SchematicError";
48
+ this.diagnostics = diagnostics;
49
+ }
50
+ /** Code of the first diagnostic, for coarse programmatic handling. */
51
+ get code() {
52
+ return this.diagnostics[0]?.code;
53
+ }
54
+ };
55
+ function buildMessage(diagnostics) {
56
+ const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
57
+ const [first, ...rest] = errors.length > 0 ? errors : diagnostics;
58
+ if (first === void 0) return "Schematic validation failed.";
59
+ const location = first.pointer === void 0 || first.pointer === "" ? "" : ` at ${first.pointer}`;
60
+ const suffix = rest.length === 0 ? "" : ` (and ${rest.length} more)`;
61
+ return `${first.code}${location}: ${first.message}${suffix}`;
62
+ }
63
+ function throwIfErrors(diagnostics) {
64
+ if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) throw new SchematicError(diagnostics);
65
+ }
66
+ //#endregion
67
+ export { assetSrcError as a, isAssetReference as c, assetPathError as i, throwIfErrors as n, base64Error as o, ASSET_MODES as r, isAssetMode as s, SchematicError as t };
68
+
69
+ //# sourceMappingURL=errors-7cnIjhnV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-7cnIjhnV.js","names":[],"sources":["../src/format/value.ts","../src/format/errors.ts"],"sourcesContent":["/** 2D point shared by the `.sch` and `.cnv` contracts. */\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/** Where an image / binary property value lives (#7). */\nexport type AssetMode = 'file' | 'inline' | 'store';\n\n/**\n * Reference to a project asset instead of inline bytes (#7): `file` is a project-root relative\n * POSIX path, `inline` is base64 text and `store` is a host resource identifier.\n */\nexport interface AssetReference {\n readonly src: string;\n readonly mode: AssetMode;\n}\n\n/**\n * Instance property value stored in `symbol.properties` (see #6 / #7): a scalar, a resource\n * reference for `image` / `binary` properties, or `null` for an explicitly cleared nullable one.\n */\nexport type PropertyValue = string | number | boolean | AssetReference | null;\n\n/** Where an image / binary property value lives (#7). */\nexport const ASSET_MODES = ['file', 'inline', 'store'] as const;\n\nexport function isAssetMode(value: unknown): value is AssetMode {\n return typeof value === 'string' && (ASSET_MODES as readonly string[]).includes(value);\n}\n\nexport function isAssetReference(value: unknown): value is AssetReference {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n const record = value as Record<string, unknown>;\n return typeof record['src'] === 'string' && isAssetMode(record['mode']);\n}\n\n/**\n * `file` mode payload rules (#7): a project-root relative POSIX path that never escapes the\n * project root and never turns into a URL.\n */\nexport function assetPathError(src: string): string | undefined {\n if (src.startsWith('/')) {\n return 'must be relative to the project root, not absolute';\n }\n if (/^[A-Za-z]:/.test(src)) {\n return 'must not carry a drive letter';\n }\n if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(src)) {\n return 'must not be a URL';\n }\n if (src.includes('\\\\')) {\n return 'must use POSIX separators';\n }\n const escaping = src.split('/').find((segment) => segment === '..' || segment.startsWith('~'));\n if (escaping !== undefined) {\n return `must stay inside the project root (segment \"${escaping}\")`;\n }\n return undefined;\n}\n\n/** `inline` mode payload: base64 text, so hosts decode without guessing the encoding. */\nexport function base64Error(src: string): string | undefined {\n return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(src)\n ? undefined\n : 'must be base64 text';\n}\n\n/** Payload problem for a resource reference `src`, or `undefined` when it is well formed. */\nexport function assetSrcError(mode: AssetMode, src: string): string | undefined {\n if (mode === 'inline') {\n return base64Error(src);\n }\n return mode === 'file' ? assetPathError(src) : undefined;\n}\n","import type { Diagnostic, DiagnosticCode } from './diagnostics';\n\n/**\n * Thrown when input violates the schematic format contract.\n * `diagnostics` carries every problem found, so callers can report them all at once.\n */\nexport class SchematicError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n super(buildMessage(diagnostics));\n this.name = 'SchematicError';\n this.diagnostics = diagnostics;\n }\n\n /** Code of the first diagnostic, for coarse programmatic handling. */\n get code(): DiagnosticCode | undefined {\n return this.diagnostics[0]?.code;\n }\n}\n\nfunction buildMessage(diagnostics: readonly Diagnostic[]): string {\n const errors = diagnostics.filter((diagnostic) => diagnostic.severity === 'error');\n const relevant = errors.length > 0 ? errors : diagnostics;\n const [first, ...rest] = relevant;\n if (first === undefined) {\n return 'Schematic validation failed.';\n }\n const location =\n first.pointer === undefined || first.pointer === '' ? '' : ` at ${first.pointer}`;\n const suffix = rest.length === 0 ? '' : ` (and ${rest.length} more)`;\n return `${first.code}${location}: ${first.message}${suffix}`;\n}\n\nexport function throwIfErrors(diagnostics: readonly Diagnostic[]): void {\n if (diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n throw new SchematicError(diagnostics);\n }\n}\n"],"mappings":";;AAyBA,IAAa,cAAc;CAAC;CAAQ;CAAU;AAAO;AAErD,SAAgB,YAAY,OAAoC;CAC9D,OAAO,OAAO,UAAU,YAAa,YAAkC,SAAS,KAAK;AACvF;AAEA,SAAgB,iBAAiB,OAAyC;CACxE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,OAAO;CAET,MAAM,SAAS;CACf,OAAO,OAAO,OAAO,WAAW,YAAY,YAAY,OAAO,OAAO;AACxE;;;;;AAMA,SAAgB,eAAe,KAAiC;CAC9D,IAAI,IAAI,WAAW,GAAG,GACpB,OAAO;CAET,IAAI,aAAa,KAAK,GAAG,GACvB,OAAO;CAET,IAAI,4BAA4B,KAAK,GAAG,GACtC,OAAO;CAET,IAAI,IAAI,SAAS,IAAI,GACnB,OAAO;CAET,MAAM,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,YAAY,YAAY,QAAQ,QAAQ,WAAW,GAAG,CAAC;CAC7F,IAAI,aAAa,KAAA,GACf,OAAO,+CAA+C,SAAS;AAGnE;;AAGA,SAAgB,YAAY,KAAiC;CAC3D,OAAO,mEAAmE,KAAK,GAAG,IAC9E,KAAA,IACA;AACN;;AAGA,SAAgB,cAAc,MAAiB,KAAiC;CAC9E,IAAI,SAAS,UACX,OAAO,YAAY,GAAG;CAExB,OAAO,SAAS,SAAS,eAAe,GAAG,IAAI,KAAA;AACjD;;;;;;;ACtEA,IAAa,iBAAb,cAAoC,MAAM;CACxC;CAEA,YAAY,aAAoC;EAC9C,MAAM,aAAa,WAAW,CAAC;EAC/B,KAAK,OAAO;EACZ,KAAK,cAAc;CACrB;;CAGA,IAAI,OAAmC;EACrC,OAAO,KAAK,YAAY,EAAE,EAAE;CAC9B;AACF;AAEA,SAAS,aAAa,aAA4C;CAChE,MAAM,SAAS,YAAY,QAAQ,eAAe,WAAW,aAAa,OAAO;CAEjF,MAAM,CAAC,OAAO,GAAG,QADA,OAAO,SAAS,IAAI,SAAS;CAE9C,IAAI,UAAU,KAAA,GACZ,OAAO;CAET,MAAM,WACJ,MAAM,YAAY,KAAA,KAAa,MAAM,YAAY,KAAK,KAAK,OAAO,MAAM;CAC1E,MAAM,SAAS,KAAK,WAAW,IAAI,KAAK,SAAS,KAAK,OAAO;CAC7D,OAAO,GAAG,MAAM,OAAO,SAAS,IAAI,MAAM,UAAU;AACtD;AAEA,SAAgB,cAAc,aAA0C;CACtE,IAAI,YAAY,MAAM,eAAe,WAAW,aAAa,OAAO,GAClE,MAAM,IAAI,eAAe,WAAW;AAExC"}
@@ -0,0 +1,182 @@
1
+ import { TimePs } from '@mica-js/core';
2
+
3
+ /** Where an image / binary property value lives (#7). */
4
+ export declare const ASSET_MODES: readonly ["file", "inline", "store"];
5
+
6
+ /** Where an image / binary property value lives (#7). */
7
+ export declare type AssetMode = 'file' | 'inline' | 'store';
8
+
9
+ /**
10
+ * `file` mode payload rules (#7): a project-root relative POSIX path that never escapes the
11
+ * project root and never turns into a URL.
12
+ */
13
+ export declare function assetPathError(src: string): string | undefined;
14
+
15
+ /**
16
+ * Reference to a project asset instead of inline bytes (#7): `file` is a project-root relative
17
+ * POSIX path, `inline` is base64 text and `store` is a host resource identifier.
18
+ */
19
+ export declare interface AssetReference {
20
+ readonly src: string;
21
+ readonly mode: AssetMode;
22
+ }
23
+
24
+ /** Payload problem for a resource reference `src`, or `undefined` when it is well formed. */
25
+ export declare function assetSrcError(mode: AssetMode, src: string): string | undefined;
26
+
27
+ /** `inline` mode payload: base64 text, so hosts decode without guessing the encoding. */
28
+ export declare function base64Error(src: string): string | undefined;
29
+
30
+ /** Pending `message` records a port accepts before it starts rejecting with backpressure. */
31
+ export declare const DEFAULT_TOPIC_CAPACITY = 64;
32
+
33
+ /** Delivery a port gets when it omits the optional `delivery` field (RFC 0017 default table). */
34
+ export declare function defaultDelivery(type: PayloadType): DeliveryKind;
35
+
36
+ /**
37
+ * Delivery semantics of one topic port (RFC 0017).
38
+ *
39
+ * `level` treats the payload as the current value of the port, so only the last delivery of a step
40
+ * takes effect; `message` treats every publish as one record that must all arrive in order.
41
+ */
42
+ export declare const DELIVERY_KINDS: readonly ["level", "message"];
43
+
44
+ export declare type DeliveryKind = (typeof DELIVERY_KINDS)[number];
45
+
46
+ export declare interface Diagnostic {
47
+ readonly severity: DiagnosticSeverity;
48
+ readonly code: DiagnosticCode;
49
+ /** Human readable English message; the `code` is the stable contract. */
50
+ readonly message: string;
51
+ /** JSON Pointer to the offending member, e.g. `/sheet/symbols/0/id`. */
52
+ readonly pointer?: string;
53
+ readonly entity?: DiagnosticEntity;
54
+ readonly related?: readonly DiagnosticRelated[];
55
+ }
56
+
57
+ export declare type DiagnosticCode = 'json/invalid' | 'json/not-object' | 'schema/unsupported-version' | 'schema/missing-field' | 'schema/invalid-type' | 'schema/invalid-value' | 'schema/unknown-field' | 'id/duplicate' | 'device/invalid-reference' | 'device/unresolved' | 'device/invalid-package' | 'device/duplicate-package' | 'device/reserved-namespace' | 'device/duplicate-device' | 'device/invalid-description' | 'device/unknown-pin' | 'device/no-symbol' | 'wire/invalid-points' | 'wire/not-orthogonal' | 'junction/unknown-wire' | 'junction/duplicate-wire' | 'junction/off-wire' | 'symbol/missing-net' | 'symbol/unsupported-field' | 'symbol/designator-duplicate' | 'net/naming-conflict' | 'canvas/unknown-symbol' | 'canvas/unknown-widget' | 'canvas/unknown-property' | 'canvas/unknown-port' | 'canvas/unknown-schematic' | 'canvas/unknown-target-port' | 'topic/type-mismatch' | 'type/unknown' | 'edit/unknown-entity' | 'edit/invalid-command';
58
+
59
+ export declare interface DiagnosticEntity {
60
+ readonly kind: 'symbol' | 'wire' | 'junction';
61
+ readonly id: string;
62
+ }
63
+
64
+ export declare interface DiagnosticRelated {
65
+ readonly pointer?: string;
66
+ }
67
+
68
+ export declare type DiagnosticSeverity = 'error' | 'warning';
69
+
70
+ export declare function isAssetMode(value: unknown): value is AssetMode;
71
+
72
+ export declare function isAssetReference(value: unknown): value is AssetReference;
73
+
74
+ /** Payload types are nominal for now: only an exact match is assignable. */
75
+ export declare function isAssignable(from: PayloadType, to: PayloadType): boolean;
76
+
77
+ /** Resolves a written `delivery` value, or `undefined` when it is not one of the two kinds. */
78
+ export declare function parseDeliveryKind(value: unknown): DeliveryKind | undefined;
79
+
80
+ /** Resolves a written payload type name, or `undefined` when it names no known type. */
81
+ export declare function parsePayloadType(value: string): PayloadType | undefined;
82
+
83
+ /** Payload type names of the Mica value model (see #10). */
84
+ export declare const PAYLOAD_TYPES: readonly ["boolean", "number", "string", "vec2d", "vec3d", "bytes", "bytes<rgb565>", "bytes<segments>"];
85
+
86
+ export declare type PayloadType = (typeof PAYLOAD_TYPES)[number];
87
+
88
+ /** 2D point shared by the `.sch` and `.cnv` contracts. */
89
+ export declare interface Point {
90
+ readonly x: number;
91
+ readonly y: number;
92
+ }
93
+
94
+ /**
95
+ * Instance property value stored in `symbol.properties` (see #6 / #7): a scalar, a resource
96
+ * reference for `image` / `binary` properties, or `null` for an explicitly cleared nullable one.
97
+ */
98
+ export declare type PropertyValue = string | number | boolean | AssetReference | null;
99
+
100
+ /**
101
+ * Declared delivery wins; the payload type decides when the port leaves it out.
102
+ *
103
+ * `declared` is `unknown` on purpose: the value arrives from a written descriptor, so an
104
+ * unparsable value falls back to the default instead of failing here. Validating the written value
105
+ * belongs to the loader that reads the descriptor.
106
+ */
107
+ export declare function resolveDelivery(declared: unknown, type: PayloadType): DeliveryKind;
108
+
109
+ /**
110
+ * Thrown when input violates the schematic format contract.
111
+ * `diagnostics` carries every problem found, so callers can report them all at once.
112
+ */
113
+ export declare class SchematicError extends Error {
114
+ readonly diagnostics: readonly Diagnostic[];
115
+ constructor(diagnostics: readonly Diagnostic[]);
116
+ /** Code of the first diagnostic, for coarse programmatic handling. */
117
+ get code(): DiagnosticCode | undefined;
118
+ }
119
+
120
+ /** A violation RFC 0017 reports instead of aborting the simulation. */
121
+ export declare interface TopicDeliveryDiagnostic {
122
+ readonly code: TopicDeliveryDiagnosticCode;
123
+ readonly message: string;
124
+ readonly port?: string;
125
+ }
126
+
127
+ export declare type TopicDeliveryDiagnosticCode = 'topic/backpressure' | 'topic/mixed-read';
128
+
129
+ /** One payload on its way to a port, with the virtual time it was published at (RFC 0017). */
130
+ export declare interface TopicEnvelope<T = unknown> {
131
+ readonly payload: T;
132
+ /** Publication time; `flushOutputs` publishes use the end of the step they ran in. */
133
+ readonly simTime: TimePs;
134
+ }
135
+
136
+ /**
137
+ * Per-port delivery queue of RFC 0017.
138
+ *
139
+ * A step posts what the previous step published; the receiver reads it once, then `endStep()`
140
+ * drops the step's records. `level` keeps only the newest record and remembers the effective value
141
+ * across steps, `message` keeps every record in publish order and reports backpressure instead of
142
+ * growing past `capacity`.
143
+ */
144
+ export declare class TopicInbox<T = unknown> {
145
+ #private;
146
+ constructor(options: TopicInboxOptions);
147
+ get delivery(): DeliveryKind;
148
+ get capacity(): number;
149
+ /** Records waiting for the current step. */
150
+ get pending(): number;
151
+ /** Effective value of a `level` port, including steps that received nothing. */
152
+ get current(): T | undefined;
153
+ /**
154
+ * Accepts one record.
155
+ *
156
+ * Returns `false` when a `message` port is at capacity: the record is rejected and reported, the
157
+ * records already accepted stay untouched.
158
+ */
159
+ post(envelope: TopicEnvelope<T>): boolean;
160
+ /** Payload the port received in this step, or `undefined` when the step was silent. */
161
+ takeInput(): T | undefined;
162
+ /** Every record the port received in this step, in publish order. */
163
+ takeInputs(): readonly TopicEnvelope<T>[];
164
+ /**
165
+ * Ends the step: drops the records it carried and forgets which read method it used.
166
+ *
167
+ * A `level` value stays available through {@link current}, because the effective value outlives
168
+ * the step that set it.
169
+ */
170
+ endStep(): void;
171
+ }
172
+
173
+ export declare interface TopicInboxOptions {
174
+ readonly delivery: DeliveryKind;
175
+ /** Deepest pending queue a `message` port accepts; `level` ports always hold one value. */
176
+ readonly capacity?: number;
177
+ /** Port name, echoed in diagnostics so a receiver can attribute them. */
178
+ readonly port?: string;
179
+ readonly onDiagnostic?: (diagnostic: TopicDeliveryDiagnostic) => void;
180
+ }
181
+
182
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as DELIVERY_KINDS, c as parseDeliveryKind, i as DEFAULT_TOPIC_CAPACITY, l as resolveDelivery, n as isAssignable, o as TopicInbox, r as parsePayloadType, s as defaultDelivery, t as PAYLOAD_TYPES } from "./type-name-B6Vkwj77.js";
2
+ import { a as assetSrcError, c as isAssetReference, i as assetPathError, o as base64Error, r as ASSET_MODES, s as isAssetMode, t as SchematicError } from "./errors-7cnIjhnV.js";
3
+ export { ASSET_MODES, DEFAULT_TOPIC_CAPACITY, DELIVERY_KINDS, PAYLOAD_TYPES, SchematicError, TopicInbox, assetPathError, assetSrcError, base64Error, defaultDelivery, isAssetMode, isAssetReference, isAssignable, parseDeliveryKind, parsePayloadType, resolveDelivery };