@mica-js/core 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/canvas/format/types.ts","../../src/canvas/format/parse.ts","../../src/canvas/format/serialize.ts","../../src/canvas/load.ts","../../src/canvas/edit.ts"],"sourcesContent":["/**\n * Schema version of the `.cnv` canvas contract (see x-botlab/mica-js#67).\n *\n * A canvas is a 2D layout: one `.cnv` binds exactly one `.sch` (see x-botlab/mica-js#6) and keeps\n * a placement per symbol id. Schematic connections stay in the `.sch`; the canvas only adds 2D\n * coordinates and rotation.\n */\nexport const CANVAS_VERSION = 1;\n\nexport type CanvasVersion = typeof CANVAS_VERSION;\n\n/** 2D placement of one symbol in a canvas. */\nexport interface CanvasPlacement {\n readonly x: number;\n readonly y: number;\n readonly rotation: number;\n}\n\nexport interface CanvasDocument {\n readonly version: CanvasVersion;\n /** Canvas identity, unique within one project's `.cnv` files. */\n readonly id: string;\n /** Project-root relative POSIX path of the bound `.sch`. */\n readonly schematic: string;\n /** Symbol id → placement; ids are stable, so renaming a designator keeps the entry. */\n readonly layout: Readonly<Record<string, CanvasPlacement>>;\n}\n","import type { Diagnostic } from '../../schematic/format/diagnostics';\nimport { SchematicError } from '../../schematic/format/errors';\nimport { parseInput } from '../../schematic/format/input';\nimport {\n forbidUnknownFields,\n hasErrors,\n isRecord,\n readIntegerField,\n readNumberField,\n readObjectField,\n readStringField,\n report,\n} from '../../schematic/format/validate';\nimport type { CanvasDocument, CanvasPlacement } from './types';\nimport { CANVAS_VERSION } from './types';\n\n/** @throws {SchematicError} when the input does not match the `.cnv` contract. */\nexport function parseCanvas(input: string | unknown): CanvasDocument {\n const diagnostics: Diagnostic[] = [];\n const parsed = parseInput(input, diagnostics);\n if (!parsed.ok) {\n throw new SchematicError(diagnostics);\n }\n const value = readDocument(parsed.value, diagnostics);\n if (value === undefined || hasErrors(diagnostics)) {\n throw new SchematicError(diagnostics);\n }\n return value;\n}\n\nfunction readDocument(value: unknown, diagnostics: Diagnostic[]): CanvasDocument | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'json/not-object', 'Canvas must be a JSON object.', []);\n return undefined;\n }\n forbidUnknownFields(value, ['version', 'id', 'schematic', 'layout'], [], diagnostics);\n const version = readVersion(value, diagnostics);\n const id = readStringField(value, 'id', [], diagnostics, { nonEmpty: true });\n const schematic = readStringField(value, 'schematic', [], diagnostics, { nonEmpty: true });\n const layout = readLayout(readObjectField(value, 'layout', [], diagnostics), diagnostics);\n if (\n version === undefined ||\n id === undefined ||\n schematic === undefined ||\n layout === undefined\n ) {\n return undefined;\n }\n return { version, id, schematic, layout };\n}\n\nfunction readVersion(\n value: Record<string, unknown>,\n diagnostics: Diagnostic[],\n): typeof CANVAS_VERSION | undefined {\n const version = readIntegerField(value, 'version', [], diagnostics);\n if (version === undefined) {\n return undefined;\n }\n if (version !== CANVAS_VERSION) {\n report(\n diagnostics,\n 'schema/unsupported-version',\n `Unsupported version ${version}; expected ${CANVAS_VERSION}.`,\n ['version'],\n );\n return undefined;\n }\n return CANVAS_VERSION;\n}\n\nfunction readLayout(\n value: Record<string, unknown> | undefined,\n diagnostics: Diagnostic[],\n): Readonly<Record<string, CanvasPlacement>> | undefined {\n if (value === undefined) {\n return undefined;\n }\n const layout: Record<string, CanvasPlacement> = Object.create(null);\n for (const symbolId of Object.keys(value)) {\n const path = ['layout', symbolId];\n if (symbolId.length === 0) {\n report(diagnostics, 'schema/invalid-value', 'Layout symbol id must not be empty.', path);\n continue;\n }\n const placement = readPlacement(value[symbolId], path, diagnostics);\n if (placement !== undefined) {\n layout[symbolId] = placement;\n }\n }\n return layout;\n}\n\nfunction readPlacement(\n value: unknown,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): CanvasPlacement | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'schema/invalid-type', 'Placement must be an object.', path);\n return undefined;\n }\n forbidUnknownFields(value, ['x', 'y', 'rotation'], path, diagnostics);\n const x = readNumberField(value, 'x', path, diagnostics);\n const y = readNumberField(value, 'y', path, diagnostics);\n const rotation = readNumberField(value, 'rotation', path, diagnostics);\n if (x === undefined || y === undefined || rotation === undefined) {\n return undefined;\n }\n return { x, y, rotation };\n}\n","import type { CanvasDocument, CanvasPlacement } from './types';\n\n/** Serializes with a fixed field order and 2-space indentation, matching the example in #67. */\nexport function serializeCanvas(canvas: CanvasDocument): string {\n const layout: Record<string, CanvasPlacement> = Object.create(null);\n for (const symbolId of Object.keys(canvas.layout).sort()) {\n const placement = canvas.layout[symbolId];\n if (placement === undefined) {\n continue;\n }\n layout[symbolId] = { x: placement.x, y: placement.y, rotation: placement.rotation };\n }\n const serializable = {\n version: canvas.version,\n id: canvas.id,\n schematic: canvas.schematic,\n layout,\n };\n return `${JSON.stringify(serializable, null, 2)}\\n`;\n}\n","import type { Diagnostic } from '../schematic/format/diagnostics';\nimport { SchematicError } from '../schematic/format/errors';\nimport type { SchematicDocument } from '../schematic/format/types';\nimport { toPointer } from '../schematic/format/validate';\nimport { parseCanvas } from './format/parse';\nimport type { CanvasDocument, CanvasPlacement } from './format/types';\n\nexport interface LoadCanvasOptions {\n /** Bound schematic; layout keys are validated against its symbols when provided. */\n readonly schematic?: SchematicDocument;\n}\n\nexport interface CanvasLayoutEntry {\n readonly symbolId: string;\n readonly placement: CanvasPlacement;\n}\n\nexport interface LoadedCanvas {\n readonly document: CanvasDocument;\n /** Layout entries sorted by symbol id, so loading is deterministic. */\n readonly placements: readonly CanvasLayoutEntry[];\n}\n\n/** Parses a canvas and validates its layout against the bound schematic. @throws {SchematicError} */\nexport function loadCanvas(\n source: string | CanvasDocument,\n options: LoadCanvasOptions = {},\n): LoadedCanvas {\n const document = parseCanvas(source);\n const diagnostics: Diagnostic[] = [];\n\n const symbolIds =\n options.schematic === undefined\n ? undefined\n : new Set(options.schematic.sheet.symbols.map((symbol) => symbol.id));\n\n const placements: CanvasLayoutEntry[] = [];\n for (const symbolId of Object.keys(document.layout).sort()) {\n const placement = document.layout[symbolId];\n if (placement === undefined) {\n continue;\n }\n if (symbolIds !== undefined && !symbolIds.has(symbolId)) {\n diagnostics.push({\n severity: 'error',\n code: 'canvas/unknown-symbol',\n message: `Canvas layout references symbol ${JSON.stringify(symbolId)} which is absent from the bound schematic.`,\n pointer: toPointer(['layout', symbolId]),\n });\n continue;\n }\n placements.push({ symbolId, placement });\n }\n\n if (diagnostics.length > 0) {\n throw new SchematicError(diagnostics);\n }\n return { document, placements };\n}\n","import type { Diagnostic } from '../schematic/format/diagnostics';\nimport { SchematicError } from '../schematic/format/errors';\nimport type { SchematicDocument } from '../schematic/format/types';\nimport { toPointer } from '../schematic/format/validate';\nimport type { CanvasDocument, CanvasPlacement } from './format/types';\n\nexport type CanvasCommand =\n | {\n readonly type: 'set-placement';\n readonly symbolId: string;\n readonly x: number;\n readonly y: number;\n readonly rotation?: number;\n }\n | { readonly type: 'remove-placement'; readonly symbolId: string }\n | { readonly type: 'bind-schematic'; readonly schematic: string };\n\nexport interface ApplyCanvasCommandOptions {\n /** Bound schematic; symbol references are validated against it when provided. */\n readonly schematic?: SchematicDocument;\n}\n\n/**\n * Applies a canvas command to a copy of `canvas`.\n *\n * @throws {SchematicError} when the command is invalid; the input canvas is never mutated.\n */\nexport function applyCanvasCommand(\n canvas: CanvasDocument,\n command: CanvasCommand,\n options: ApplyCanvasCommandOptions = {},\n): CanvasDocument {\n const diagnostics: Diagnostic[] = [];\n const layout: Record<string, CanvasPlacement> = { ...canvas.layout };\n\n switch (command.type) {\n case 'set-placement': {\n if (command.symbolId.length === 0) {\n diagnostics.push({\n severity: 'error',\n code: 'schema/invalid-value',\n message: 'Placement symbol id must not be empty.',\n pointer: toPointer(['layout']),\n });\n break;\n }\n requireKnownSymbol(command.symbolId, options, diagnostics);\n const existing = layout[command.symbolId];\n layout[command.symbolId] = {\n x: command.x,\n y: command.y,\n rotation: command.rotation ?? existing?.rotation ?? 0,\n };\n break;\n }\n case 'remove-placement': {\n if (!Object.prototype.hasOwnProperty.call(layout, command.symbolId)) {\n diagnostics.push({\n severity: 'error',\n code: 'edit/unknown-entity',\n message: `Canvas has no placement for symbol \"${command.symbolId}\".`,\n pointer: toPointer(['layout', command.symbolId]),\n });\n break;\n }\n delete layout[command.symbolId];\n break;\n }\n case 'bind-schematic': {\n if (command.schematic.length === 0) {\n diagnostics.push({\n severity: 'error',\n code: 'schema/invalid-value',\n message: 'Bound schematic reference must not be empty.',\n pointer: toPointer(['schematic']),\n });\n break;\n }\n if (diagnostics.length === 0) {\n return { ...canvas, schematic: command.schematic };\n }\n break;\n }\n default: {\n diagnostics.push({\n severity: 'error',\n code: 'edit/invalid-command',\n message: `Unsupported canvas command ${JSON.stringify((command as { type?: unknown }).type)}.`,\n });\n }\n }\n\n if (diagnostics.length > 0) {\n throw new SchematicError(diagnostics);\n }\n return { ...canvas, layout };\n}\n\nfunction requireKnownSymbol(\n symbolId: string,\n options: ApplyCanvasCommandOptions,\n diagnostics: Diagnostic[],\n): void {\n if (options.schematic === undefined) {\n return;\n }\n if (options.schematic.sheet.symbols.some((symbol) => symbol.id === symbolId)) {\n return;\n }\n diagnostics.push({\n severity: 'error',\n code: 'canvas/unknown-symbol',\n message: `Canvas layout references symbol ${JSON.stringify(symbolId)} which is absent from the bound schematic.`,\n pointer: toPointer(['layout', symbolId]),\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/canvas/format/types.ts","../../src/format/uuid.ts","../../src/canvas/format/parse.ts","../../src/canvas/format/serialize.ts"],"sourcesContent":["/**\n * Schema version of the `.cnv` canvas contract (see x-botlab/mica-js#67).\n *\n * A canvas is an independent 2D plane: it records widget instances with their placement, property\n * overrides and port-to-symbol bindings. Electrical topology stays in the `.sch` the canvas binds\n * (see x-botlab/mica-js#6); the two coordinate spaces are unrelated.\n */\nexport const CANVAS_VERSION = 1;\n\n/** Placement and size of one widget instance, in logical units. */\nexport interface WidgetPlacement {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n /** Clockwise rotation in degrees around the instance center. */\n readonly rotation: number;\n}\n\n/** Endpoint of a widget port: a port of one symbol instance in the bound schematic. */\nexport interface CanvasBindingTarget {\n readonly symbol: string;\n readonly port: string;\n}\n\n/** One widget placed on a canvas; the order in `widgets` is the drawing order (#67). */\nexport interface CanvasWidgetInstance extends WidgetPlacement {\n /** Stable identity: UUID v4, unique within the document. */\n readonly id: string;\n /** Widget reference `\"<package>:<widget>\"`; built-ins use the reserved `builtin:` namespace. */\n readonly widget: string;\n /** Property overrides keyed by the widget definition; values follow that definition (#7). */\n readonly properties?: Readonly<Record<string, unknown>>;\n /** Port key → endpoint; only bound ports take part in messaging (#10). */\n readonly bindings?: Readonly<Record<string, CanvasBindingTarget>>;\n}\n\n/** Root of a `.cnv` file; the project-root relative path is the canvas identity. */\nexport interface CanvasDocument {\n readonly version: typeof CANVAS_VERSION;\n /** Project-root relative POSIX path of the `.sch` the canvas draws and simulates against. */\n readonly schematic?: string;\n /** Widget instances in drawing order; later instances paint above earlier ones. */\n readonly widgets: readonly CanvasWidgetInstance[];\n}\n","const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Strict UUID v4 check: 8-4-4-4-12 hex with the version and variant bits fixed. */\nexport function isUuidV4(value: string): boolean {\n return UUID_V4.test(value);\n}\n","import type { Diagnostic } from '../../format/diagnostics';\nimport { SchematicError } from '../../format/errors';\nimport { parseInput } from '../../format/input';\nimport { isUuidV4 } from '../../format/uuid';\nimport {\n forbidUnknownFields,\n hasErrors,\n isRecord,\n readArrayField,\n readIntegerField,\n readNumberField,\n readStringField,\n report,\n} from '../../format/validate';\nimport type {\n CanvasBindingTarget,\n CanvasDocument,\n CanvasWidgetInstance,\n WidgetPlacement,\n} from './types';\nimport { CANVAS_VERSION } from './types';\n\n/**\n * `\"<package>:<widget>\"`; `builtin` matches the package pattern, so the same expression also\n * accepts the reserved `builtin:<widget>` form (#67).\n */\nconst WIDGET_REFERENCE = /^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*$/;\n\nconst WIDGET_FIELDS = [\n 'id',\n 'widget',\n 'x',\n 'y',\n 'width',\n 'height',\n 'rotation',\n 'properties',\n 'bindings',\n] as const;\n\n/** @throws {SchematicError} when the input does not match the `.cnv` contract. */\nexport function parseCanvas(input: string | unknown): CanvasDocument {\n const diagnostics: Diagnostic[] = [];\n const parsed = parseInput(input, diagnostics);\n if (!parsed.ok) {\n throw new SchematicError(diagnostics);\n }\n const value = readDocument(parsed.value, diagnostics);\n if (value === undefined || hasErrors(diagnostics)) {\n throw new SchematicError(diagnostics);\n }\n return value;\n}\n\nfunction readDocument(value: unknown, diagnostics: Diagnostic[]): CanvasDocument | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'json/not-object', 'Canvas must be a JSON object.', []);\n return undefined;\n }\n forbidUnknownFields(value, ['version', 'schematic', 'widgets'], [], diagnostics);\n const version = readVersion(value, diagnostics);\n const schematic = readSchematic(value, diagnostics);\n const widgets = readWidgets(readArrayField(value, 'widgets', [], diagnostics), diagnostics);\n if (version === undefined || widgets === undefined) {\n return undefined;\n }\n return schematic === undefined ? { version, widgets } : { version, schematic, widgets };\n}\n\nfunction readVersion(\n value: Record<string, unknown>,\n diagnostics: Diagnostic[],\n): typeof CANVAS_VERSION | undefined {\n const version = readIntegerField(value, 'version', [], diagnostics);\n if (version === undefined) {\n return undefined;\n }\n if (version !== CANVAS_VERSION) {\n report(\n diagnostics,\n 'schema/unsupported-version',\n `Unsupported version ${version}; expected ${CANVAS_VERSION}.`,\n ['version'],\n );\n return undefined;\n }\n return CANVAS_VERSION;\n}\n\nfunction readSchematic(\n value: Record<string, unknown>,\n diagnostics: Diagnostic[],\n): string | undefined {\n if (!hasField(value, 'schematic')) {\n return undefined;\n }\n return readStringField(value, 'schematic', [], diagnostics, { nonEmpty: true });\n}\n\nfunction readWidgets(\n raw: readonly unknown[] | undefined,\n diagnostics: Diagnostic[],\n): CanvasWidgetInstance[] | undefined {\n if (raw === undefined) {\n return undefined;\n }\n const widgets: CanvasWidgetInstance[] = [];\n const seen = new Set<string>();\n raw.forEach((item, index) => {\n const path = ['widgets', String(index)];\n const widget = readWidget(item, path, diagnostics);\n if (widget === undefined) {\n return;\n }\n if (seen.has(widget.id)) {\n report(diagnostics, 'id/duplicate', `Duplicate widget id \"${widget.id}\".`, [...path, 'id']);\n return;\n }\n seen.add(widget.id);\n widgets.push(widget);\n });\n return widgets;\n}\n\nfunction readWidget(\n value: unknown,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): CanvasWidgetInstance | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'schema/invalid-type', 'Widget instance must be an object.', path);\n return undefined;\n }\n forbidUnknownFields(value, WIDGET_FIELDS, path, diagnostics);\n const id = readId(value, path, diagnostics);\n const widget = readWidgetReference(value, path, diagnostics);\n const placement = readPlacement(value, path, diagnostics);\n const hasProperties = hasField(value, 'properties');\n const properties = hasProperties\n ? readProperties(value['properties'], [...path, 'properties'], diagnostics)\n : undefined;\n const hasBindings = hasField(value, 'bindings');\n const bindings = hasBindings\n ? readBindings(value['bindings'], [...path, 'bindings'], diagnostics)\n : undefined;\n if (\n id === undefined ||\n widget === undefined ||\n placement === undefined ||\n (hasProperties && properties === undefined) ||\n (hasBindings && bindings === undefined)\n ) {\n return undefined;\n }\n return {\n id,\n widget,\n ...placement,\n ...(properties === undefined ? {} : { properties }),\n ...(bindings === undefined ? {} : { bindings }),\n };\n}\n\nfunction readId(\n value: Record<string, unknown>,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): string | undefined {\n const id = readStringField(value, 'id', path, diagnostics, { nonEmpty: true });\n if (id === undefined) {\n return undefined;\n }\n if (!isUuidV4(id)) {\n report(diagnostics, 'schema/invalid-value', 'Field \"id\" must be a UUID v4.', [...path, 'id']);\n return undefined;\n }\n return id;\n}\n\nfunction readWidgetReference(\n value: Record<string, unknown>,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): string | undefined {\n const widget = readStringField(value, 'widget', path, diagnostics, { nonEmpty: true });\n if (widget === undefined) {\n return undefined;\n }\n if (!WIDGET_REFERENCE.test(widget)) {\n report(\n diagnostics,\n 'schema/invalid-value',\n 'Field \"widget\" must be \"<package>:<widget>\" or \"builtin:<widget>\".',\n [...path, 'widget'],\n );\n return undefined;\n }\n return widget;\n}\n\nfunction readPlacement(\n value: Record<string, unknown>,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): WidgetPlacement | undefined {\n const x = readNumberField(value, 'x', path, diagnostics);\n const y = readNumberField(value, 'y', path, diagnostics);\n const width = readPositiveNumber(value, 'width', path, diagnostics);\n const height = readPositiveNumber(value, 'height', path, diagnostics);\n const rotation = readNumberField(value, 'rotation', path, diagnostics);\n if (\n x === undefined ||\n y === undefined ||\n width === undefined ||\n height === undefined ||\n rotation === undefined\n ) {\n return undefined;\n }\n return { x, y, width, height, rotation };\n}\n\nfunction readPositiveNumber(\n value: Record<string, unknown>,\n key: string,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): number | undefined {\n const field = readNumberField(value, key, path, diagnostics);\n if (field === undefined) {\n return undefined;\n }\n if (field <= 0) {\n report(diagnostics, 'schema/invalid-value', `Field \"${key}\" must be a positive number.`, [\n ...path,\n key,\n ]);\n return undefined;\n }\n return field;\n}\n\n/**\n * Property values are opaque to the format: their types come from the widget definition (#7), so\n * only the map shape and key spelling are checked here.\n */\nfunction readProperties(\n value: unknown,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): Record<string, unknown> | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'schema/invalid-type', 'Field \"properties\" must be an object.', path);\n return undefined;\n }\n const properties: Record<string, unknown> = Object.create(null);\n let failed = false;\n for (const [key, entry] of Object.entries(value)) {\n if (key.length === 0) {\n report(diagnostics, 'schema/invalid-value', 'Property keys must not be empty.', path);\n failed = true;\n continue;\n }\n properties[key] = clonePropertyValue(entry);\n }\n return failed ? undefined : properties;\n}\n\n/** Values are copied so the parsed document never aliases the caller's input object. */\nfunction clonePropertyValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(clonePropertyValue);\n }\n const prototype = isRecord(value) ? Object.getPrototypeOf(value) : undefined;\n if (prototype !== Object.prototype && prototype !== null) {\n return value;\n }\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, entry]) => [\n key,\n clonePropertyValue(entry),\n ]),\n );\n}\n\nfunction readBindings(\n value: unknown,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): Record<string, CanvasBindingTarget> | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'schema/invalid-type', 'Field \"bindings\" must be an object.', path);\n return undefined;\n }\n const bindings: Record<string, CanvasBindingTarget> = Object.create(null);\n let failed = false;\n for (const [port, entry] of Object.entries(value)) {\n if (port.length === 0) {\n report(diagnostics, 'schema/invalid-value', 'Binding port keys must not be empty.', path);\n failed = true;\n continue;\n }\n const target = readBindingTarget(entry, [...path, port], diagnostics);\n if (target === undefined) {\n failed = true;\n continue;\n }\n bindings[port] = target;\n }\n return failed ? undefined : bindings;\n}\n\nfunction readBindingTarget(\n value: unknown,\n path: readonly string[],\n diagnostics: Diagnostic[],\n): CanvasBindingTarget | undefined {\n if (!isRecord(value)) {\n report(diagnostics, 'schema/invalid-type', 'Binding target must be an object.', path);\n return undefined;\n }\n forbidUnknownFields(value, ['symbol', 'port'], path, diagnostics);\n const symbol = readStringField(value, 'symbol', path, diagnostics, { nonEmpty: true });\n const port = readStringField(value, 'port', path, diagnostics, { nonEmpty: true });\n if (symbol === undefined || port === undefined) {\n return undefined;\n }\n return { symbol, port };\n}\n\nfunction hasField(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n","import type { CanvasBindingTarget, CanvasDocument, CanvasWidgetInstance } from './types';\n\n/**\n * Serializes with a fixed field order and 2-space indentation, matching the example in #67.\n * `properties` and `bindings` are written whenever the document carries them, even when empty, so\n * a parse / serialize round trip keeps the original shape.\n */\nexport function serializeCanvas(document: CanvasDocument): string {\n const serializable: Record<string, unknown> = { version: document.version };\n if (document.schematic !== undefined) {\n serializable['schematic'] = document.schematic;\n }\n serializable['widgets'] = document.widgets.map(serializeWidget);\n return `${JSON.stringify(serializable, null, 2)}\\n`;\n}\n\nfunction serializeWidget(widget: CanvasWidgetInstance): Record<string, unknown> {\n const serialized: Record<string, unknown> = {\n id: widget.id,\n widget: widget.widget,\n x: widget.x,\n y: widget.y,\n width: widget.width,\n height: widget.height,\n rotation: widget.rotation,\n };\n if (widget.properties !== undefined) {\n serialized['properties'] = { ...widget.properties };\n }\n if (widget.bindings !== undefined) {\n const bindings: Record<string, CanvasBindingTarget> = Object.create(null);\n for (const [port, target] of Object.entries(widget.bindings)) {\n bindings[port] = { symbol: target.symbol, port: target.port };\n }\n serialized['bindings'] = bindings;\n }\n return serialized;\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,448 @@
1
- /**
2
- * Placeholder export so the build and test pipeline has something to verify.
3
- * Replace with the virtual time and event scheduler API.
4
- */
1
+ import { EntryRef } from '@mica-js/ir';
2
+ import { IRModule } from '@mica-js/ir';
3
+ import { IRStorage } from '@mica-js/ir';
4
+ import { IRValidationOptions } from '@mica-js/ir';
5
+ import { LifecycleRef } from '@mica-js/ir';
6
+ import { RuntimeScalar } from '@mica-js/ir';
7
+ import { ScalarType } from '@mica-js/ir';
8
+
9
+ export declare function addTime(left: number, right: number): TimePs;
10
+
11
+ /** Declared state of one internal connection. */
12
+ export declare type ConnectionState = 'open' | 'closed';
13
+
14
+ export declare function createFloatingInput(seed: number, instanceId: string, pinName: string): FloatingInput;
15
+
16
+ export declare function createIRSchedulerInstance(scheduler: Scheduler_2, definition: IRSchedulerInstanceDefinition): IRSchedulerInstance;
17
+
18
+ export declare function createPowerRuntime(scheduler: Scheduler_2, definition: PowerDefinition, options: PowerOptions): PowerRuntime;
19
+
20
+ export declare function createScheduler(options?: SchedulerOptions): Scheduler_2;
21
+
22
+ export declare function createTopologyRuntime(scheduler: Scheduler_2, definition: TopologyDefinition, options: TopologyOptions): TopologyRuntime;
23
+
24
+ declare interface Details {
25
+ readonly instanceId?: string;
26
+ readonly targetName?: string;
27
+ readonly timePs: number;
28
+ readonly phase?: 'event' | 'control';
29
+ readonly eventId?: number;
30
+ readonly steps?: number;
31
+ readonly entriesAtTime?: number;
32
+ readonly cause?: unknown;
33
+ }
34
+
35
+ export declare class ElectricalConflictError extends Error {
36
+ readonly name: "ElectricalConflictError";
37
+ readonly network: ElectricalNetworkInput;
38
+ readonly contributions: readonly ElectricalContribution[];
39
+ constructor(network: ElectricalNetworkInput, contributions: readonly ElectricalContribution[]);
40
+ }
41
+
42
+ export declare interface ElectricalContribution {
43
+ readonly instanceId: string;
44
+ readonly pinName: string;
45
+ readonly kind: 'drive' | 'pull';
46
+ readonly strength: 'strong' | 'weak';
47
+ readonly voltage: number;
48
+ }
49
+
50
+ export declare interface ElectricalNetworkInput {
51
+ readonly networkId: string;
52
+ readonly pins: readonly ElectricalPinInput[];
53
+ }
54
+
55
+ export declare type ElectricalNetworkResult = {
56
+ readonly state: 'driven';
57
+ readonly voltage: number;
58
+ readonly strength: 'strong' | 'weak';
59
+ readonly contributions: readonly ElectricalContribution[];
60
+ } | {
61
+ readonly state: 'floating';
62
+ readonly digitalFallback: false;
63
+ readonly contributions: readonly ElectricalContribution[];
64
+ };
65
+
66
+ export declare interface ElectricalPinInput {
67
+ readonly instanceId: string;
68
+ readonly pinName: string;
69
+ readonly powerReady: boolean;
70
+ readonly mode: 'high-z' | 'push-pull' | 'open-drain' | 'analog';
71
+ readonly outputEnabled: boolean;
72
+ readonly pull: 'none' | 'up' | 'down';
73
+ readonly digitalIntent?: boolean;
74
+ readonly voltageIntent?: number;
75
+ readonly model: {
76
+ readonly kind: 'ideal-voltage';
77
+ readonly minVoltage: number;
78
+ readonly maxVoltage: number;
79
+ readonly lowVoltage: number;
80
+ readonly highVoltage: number;
81
+ };
82
+ }
83
+
84
+ export declare interface FloatingInput {
85
+ beginFloating(supplyVoltage?: number): void;
86
+ sample(supplyVoltage: number, timePs: number, enabled?: boolean): FloatingInputSample;
87
+ }
88
+
89
+ export declare type FloatingInputSample = {
90
+ readonly state: 'disabled';
91
+ } | {
92
+ readonly state: 'ready';
93
+ readonly voltage: number;
94
+ };
95
+
96
+ export declare interface IRSchedulerInstance {
97
+ readonly instance: SchedulerInstance;
98
+ readonly storage: IRStorage;
99
+ at(target: EntryRef, deadline: number, args: readonly RuntimeScalar[]): number;
100
+ cancel(id: number): void;
101
+ enqueueControl(target: LifecycleRef, args: readonly RuntimeScalar[]): void;
102
+ }
103
+
104
+ export declare interface IRSchedulerInstanceDefinition {
105
+ readonly instanceId: string;
106
+ readonly module: IRModule;
107
+ readonly validation: IRValidationOptions;
108
+ }
109
+
110
+ export declare const MAX_TIME_PS = 7200000000000000;
111
+
5
112
  export declare const MICA_CORE_VERSION = "0.0.0";
6
113
 
114
+ export declare interface PowerDefinition {
115
+ readonly topology: TopologyDefinition;
116
+ readonly devices: readonly PowerDeviceDefinition[];
117
+ }
118
+
119
+ export declare interface PowerDeviceDefinition {
120
+ readonly instanceId: string;
121
+ readonly powerDomains: Readonly<Record<string, PowerDomainDeclaration>>;
122
+ readonly pins?: Readonly<Record<string, PowerPinBinding>>;
123
+ }
124
+
125
+ export declare interface PowerDigitalSample {
126
+ readonly value: 0 | 1;
127
+ readonly ready: boolean;
128
+ readonly source: PowerDigitalSource;
129
+ }
130
+
131
+ export declare type PowerDigitalSource = 'sampled' | 'floating' | 'threshold-range' | 'gated';
132
+
133
+ export declare interface PowerDomainChange extends PowerDomainSnapshot {
134
+ readonly timePs: TimePs;
135
+ readonly previousState: PowerDomainState;
136
+ readonly reasons: readonly PowerDownReason[];
137
+ }
138
+
139
+ export declare interface PowerDomainDeclaration {
140
+ /** Pin name of a `kind: 'power'` pin declared by the same device. */
141
+ readonly supply: string;
142
+ /** Pin name of a `kind: 'gnd'` pin declared by the same device. */
143
+ readonly ground: string;
144
+ readonly voltage: {
145
+ /** Power-up threshold in volts; strictly greater than `turnOff`. */
146
+ readonly turnOn: number;
147
+ /** Power-down threshold in volts; finite and nonnegative. */
148
+ readonly turnOff: number;
149
+ };
150
+ /** Same-device domains that must be on; unique and acyclic. */
151
+ readonly dependsOn?: readonly string[];
152
+ }
153
+
154
+ export declare interface PowerDomainObserver {
155
+ onPowerDomainChange(changes: readonly PowerDomainChange[], snapshot: readonly PowerDomainSnapshot[]): void;
156
+ }
157
+
158
+ export declare interface PowerDomainSnapshot {
159
+ readonly instanceId: string;
160
+ readonly domainId: string;
161
+ readonly state: PowerDomainState;
162
+ /** Supply voltage relative to the fixed global 0 V reference, or null. */
163
+ readonly voltage: number | null;
164
+ readonly groundReady: boolean;
165
+ readonly dependenciesReady: boolean;
166
+ }
167
+
168
+ export declare type PowerDomainState = 'off' | 'on';
169
+
170
+ export declare type PowerDownReason = 'ground-not-ready' | 'supply-indeterminate' | 'dependency-off' | 'below-turn-off';
171
+
172
+ export declare class PowerFeedbackError extends Error {
173
+ readonly name: "PowerFeedbackError";
174
+ readonly timePs: TimePs;
175
+ readonly rounds: number;
176
+ readonly maxRounds: number;
177
+ readonly domains: readonly PowerDomainSnapshot[];
178
+ constructor(timePs: TimePs, rounds: number, maxRounds: number, domains: readonly PowerDomainSnapshot[]);
179
+ }
180
+
181
+ export declare interface PowerFloatingOptions {
182
+ /** u32 seed used by `mica-floating-v2`. */
183
+ readonly seed: number;
184
+ }
185
+
186
+ export declare type PowerInputMode = 'two-state' | 'three-state';
187
+
188
+ export declare interface PowerLevels {
189
+ /** Proportion of the domain voltage at or below which the input is low. */
190
+ readonly low: number;
191
+ /** Proportion of the domain voltage at or above which the input is high. */
192
+ readonly high: number;
193
+ }
194
+
195
+ export declare interface PowerOptions {
196
+ /** Scheduler instance identity for the power control target; must be unique. */
197
+ readonly instanceId: string;
198
+ /** Topology scheduler identity; defaults to `${instanceId}:topology`. */
199
+ readonly topologyInstanceId?: string;
200
+ /** Complete held-intent snapshot, one entry per declared topology pin. */
201
+ readonly pinStates: readonly ElectricalPinInput[];
202
+ /** Enables deterministic analog floating sampling through the topology layer. */
203
+ readonly floating?: PowerFloatingOptions;
204
+ /** Digital input interpretation; defaults to three-state. */
205
+ readonly inputMode?: PowerInputMode;
206
+ /** Maximum power propagation entries per virtual time; defaults to 10000. */
207
+ readonly maxPropagationRounds?: number;
208
+ readonly observer?: PowerDomainObserver;
209
+ }
210
+
211
+ export declare interface PowerPinBinding {
212
+ /** Signal pin binding to a domain declared by the same device. */
213
+ readonly powerDomain?: string;
214
+ /** Optional proportional input levels; requires `powerDomain`. */
215
+ readonly levels?: PowerLevels;
216
+ }
217
+
218
+ export declare interface PowerPinGate {
219
+ readonly instanceId: string;
220
+ readonly pinName: string;
221
+ readonly domainId: string | null;
222
+ readonly ready: boolean;
223
+ readonly reason: PowerPinGateReason;
224
+ }
225
+
226
+ export declare type PowerPinGateReason = 'powered' | 'opening' | 'domain-off' | 'no-domain';
227
+
228
+ export declare interface PowerRuntime {
229
+ /** Registered control instance; use `destroy`, not the scheduler directly. */
230
+ readonly instance: SchedulerInstance;
231
+ readonly inputMode: PowerInputMode;
232
+ /** Submit an atomic topology connection patch, then re-evaluate power. */
233
+ submit(patch: TopologyConnectionPatch): void;
234
+ /** Replace held pin intents; gating is applied in the public control phase. */
235
+ updatePinStates(states: readonly ElectricalPinInput[]): void;
236
+ /** Request an electrical resolution point, then re-evaluate power. */
237
+ refresh(pins?: readonly TopologyPinRef[]): void;
238
+ connectionState(instanceId: string, connectionId: string): ConnectionState;
239
+ networks(): readonly TopologyNetwork[];
240
+ networkOf(pin: TopologyPinRef): TopologyNetwork | undefined;
241
+ floatingInput(pin: TopologyPinRef): FloatingInput | undefined;
242
+ domain(instanceId: string, domainId: string): PowerDomainSnapshot;
243
+ domains(instanceId?: string): readonly PowerDomainSnapshot[];
244
+ pinGate(pin: TopologyPinRef): PowerPinGate;
245
+ /** Last submitted held intent; for domain pins the electrical gate is owned by the runtime. */
246
+ pinIntent(pin: TopologyPinRef): ElectricalPinInput;
247
+ sampleDigital(pin: TopologyPinRef): PowerDigitalSample;
248
+ sampleVoltage(pin: TopologyPinRef): PowerVoltageSample;
249
+ /** Replace or clear the single domain-change observer. */
250
+ observe(observer: PowerDomainObserver | undefined): void;
251
+ destroy(): void;
252
+ }
253
+
254
+ export declare interface PowerVoltageSample {
255
+ readonly voltage: number;
256
+ readonly ready: boolean;
257
+ readonly source: PowerVoltageSource;
258
+ }
259
+
260
+ export declare type PowerVoltageSource = 'sampled' | 'floating' | 'gated';
261
+
262
+ export declare function resolveElectricalNetwork(input: ElectricalNetworkInput): ElectricalNetworkResult;
263
+
264
+ declare interface Scheduler_2 {
265
+ readonly now: TimePs;
266
+ readonly state: 'paused' | 'running' | 'faulted';
267
+ readonly error: SchedulerError | undefined;
268
+ addInstance(definition: SchedulerInstanceDefinition): SchedulerInstance;
269
+ enqueueControl(instance: SchedulerInstance, target: SchedulerTarget, args: readonly RuntimeScalar[]): void;
270
+ destroyInstance(instance: SchedulerInstance): void;
271
+ start(options?: SchedulerRunOptions): SchedulerRunResult;
272
+ pause(): void;
273
+ step(): SchedulerRunResult;
274
+ }
275
+ export { Scheduler_2 as Scheduler }
276
+
277
+ export declare class SchedulerError extends Error {
278
+ readonly code: SchedulerErrorCode;
279
+ readonly name = "SchedulerError";
280
+ readonly instanceId: string | undefined;
281
+ readonly targetName: string | undefined;
282
+ readonly timePs: number;
283
+ readonly phase: 'event' | 'control' | undefined;
284
+ readonly eventId: number | undefined;
285
+ readonly steps: number;
286
+ readonly entriesAtTime: number;
287
+ readonly cause: unknown;
288
+ constructor(code: SchedulerErrorCode, message: string, details: Details);
289
+ }
290
+
291
+ export declare type SchedulerErrorCode = 'invalid-options' | 'invalid-instance' | 'invalid-target' | 'invalid-argument' | 'invalid-event-id' | 'event-id-exhausted' | 'reentrant-execution' | 'executor-contract' | 'entry-budget-exhausted' | 'time-budget-exhausted' | 'execution-failed' | 'scheduler-faulted';
292
+
293
+ export declare interface SchedulerExecutionContext {
294
+ readonly instanceId: string;
295
+ readonly timePs: TimePs;
296
+ readonly phase: 'event' | 'control';
297
+ readonly eventId: number;
298
+ readonly remainingSteps: number;
299
+ consumeSteps(count?: number): void;
300
+ }
301
+
302
+ export declare interface SchedulerExecutor {
303
+ execute(target: SchedulerTarget, args: readonly RuntimeScalar[], context: SchedulerExecutionContext): void;
304
+ }
305
+
306
+ export declare interface SchedulerInstance {
307
+ readonly instanceId: string;
308
+ at(target: SchedulerTarget, deadline: number, args: readonly RuntimeScalar[]): number;
309
+ cancel(id: number): void;
310
+ }
311
+
312
+ export declare interface SchedulerInstanceDefinition {
313
+ readonly instanceId: string;
314
+ readonly targets: readonly SchedulerTarget[];
315
+ readonly executor: SchedulerExecutor;
316
+ }
317
+
318
+ export declare interface SchedulerOptions {
319
+ readonly maxStepsPerEntry?: number;
320
+ readonly maxEntriesPerTime?: number;
321
+ }
322
+
323
+ export declare interface SchedulerRunOptions {
324
+ readonly until?: number;
325
+ readonly maxEntries?: number;
326
+ }
327
+
328
+ export declare interface SchedulerRunResult {
329
+ readonly timePs: TimePs;
330
+ readonly executed: number;
331
+ readonly reason: 'empty' | 'until' | 'entry-limit' | 'paused';
332
+ }
333
+
334
+ export declare interface SchedulerTarget {
335
+ readonly name: string;
336
+ readonly kind: 'event' | 'control';
337
+ readonly params: readonly ScalarType[];
338
+ }
339
+
340
+ export declare function subtractTime(later: number, earlier: number): TimePs;
341
+
342
+ declare const timeBrand: unique symbol;
343
+
344
+ export declare type TimePs = number & {
345
+ readonly [timeBrand]: 'TimePs';
346
+ };
347
+
348
+ export declare function timePs(value: number): TimePs;
349
+
350
+ export declare type TimeUnit = 'ps' | 'ns' | 'us' | 'ms' | 's';
351
+
352
+ /** Static internal connection declared by a device instance. */
353
+ export declare interface TopologyConnectionDeclaration {
354
+ readonly instanceId: string;
355
+ readonly connectionId: string;
356
+ readonly pins: readonly [string, string];
357
+ /** Defaults to `open`. */
358
+ readonly initial?: ConnectionState;
359
+ }
360
+
361
+ /** One atomic multi-touch commit for a single instance. */
362
+ export declare interface TopologyConnectionPatch {
363
+ readonly instanceId: string;
364
+ readonly connections: readonly TopologyConnectionUpdate[];
365
+ }
366
+
367
+ export declare interface TopologyConnectionUpdate {
368
+ readonly connectionId: string;
369
+ readonly state: ConnectionState;
370
+ }
371
+
372
+ export declare interface TopologyDefinition {
373
+ readonly pins: readonly TopologyPinDeclaration[];
374
+ readonly wires: readonly TopologyExternalWire[];
375
+ readonly connections: readonly TopologyConnectionDeclaration[];
376
+ }
377
+
378
+ /** Immutable external wiring supplied by the circuit layer. */
379
+ export declare interface TopologyExternalWire {
380
+ readonly wireId: string;
381
+ readonly pins: readonly TopologyPinRef[];
382
+ /** True when this wire belongs to the explicit global GND node. */
383
+ readonly globalGnd?: boolean;
384
+ }
385
+
386
+ export declare interface TopologyFloatingOptions {
387
+ /** u32 seed used by `mica-floating-v2`. */
388
+ readonly seed: number;
389
+ /** Current supply for the pin, or `undefined` while it is not known/ready. */
390
+ readonly supplyVoltage: (pin: TopologyPinRef) => number | undefined;
391
+ /** Defaults to true; false keeps floating episodes uninitialized while they still count. */
392
+ readonly samplingEnabled?: (pin: TopologyPinRef) => boolean;
393
+ }
394
+
395
+ export declare interface TopologyNetwork {
396
+ /**
397
+ * Canonical identity, `net:<escaped instanceId>/<escaped pinName>` of the smallest member.
398
+ * `%` and `/` are percent-escaped, so distinct raw identities never collide.
399
+ */
400
+ readonly networkId: string;
401
+ readonly pins: readonly TopologyPinRef[];
402
+ /** A `gnd` pin in this network reaches a wire marked `globalGnd`. */
403
+ readonly groundReady: boolean;
404
+ /** `undefined` only after a failed electrical resolution left the committed network unresolved. */
405
+ readonly result: ElectricalNetworkResult | undefined;
406
+ }
407
+
408
+ export declare interface TopologyOptions {
409
+ /** Scheduler instance identity; must be unique and is never reused. */
410
+ readonly instanceId: string;
411
+ /** Exactly one committed electrical state per declared pin. */
412
+ readonly pinStates: readonly ElectricalPinInput[];
413
+ readonly floating?: TopologyFloatingOptions;
414
+ }
415
+
416
+ export declare interface TopologyPinDeclaration extends TopologyPinRef {
417
+ readonly kind: 'signal' | 'power' | 'gnd';
418
+ }
419
+
420
+ /** Identity of one physical pin. */
421
+ export declare interface TopologyPinRef {
422
+ readonly instanceId: string;
423
+ readonly pinName: string;
424
+ }
425
+
426
+ export declare interface TopologyRuntime {
427
+ /** Registered control instance; use `submit`/`refresh`/`destroy`, not the scheduler directly. */
428
+ readonly instance: SchedulerInstance;
429
+ /** Validate and queue one atomic connection patch at the next control phase. */
430
+ submit(patch: TopologyConnectionPatch): void;
431
+ /** Validate and queue partial pin-state updates at the next control phase. */
432
+ updatePinStates(states: readonly ElectricalPinInput[]): void;
433
+ /** Queue an electrical resolution point for the given pins, or every network when omitted. */
434
+ refresh(pins?: readonly TopologyPinRef[]): void;
435
+ connectionState(instanceId: string, connectionId: string): ConnectionState;
436
+ networks(): readonly TopologyNetwork[];
437
+ networkOf(pin: TopologyPinRef): TopologyNetwork | undefined;
438
+ /**
439
+ * Floating state for a declared pin; `undefined` when floating is not configured.
440
+ * The topology owns `beginFloating`; read values through `sample` only.
441
+ */
442
+ floatingInput(pin: TopologyPinRef): FloatingInput | undefined;
443
+ destroy(): void;
444
+ }
445
+
446
+ export declare function toTimePs(value: number, unit: TimeUnit): TimePs;
447
+
7
448
  export { }