@schemd/core 0.1.1 → 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.
package/README.md CHANGED
@@ -1,119 +1,58 @@
1
1
  # @schemd/core
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@schemd/core.svg?style=flat-square)](https://www.npmjs.com/package/@schemd/core)
4
- [![CI status](https://github.com/Sirneij/schemd/actions/workflows/ci.yml/badge.svg?style=flat-square)](https://github.com/Sirneij/schemd/actions/workflows/ci.yml)
5
- [![license](https://img.shields.io/npm/l/@schemd/core.svg?style=flat-square)](https://github.com/Sirneij/schemd/blob/main/LICENSE)
3
+ Write schematics and UML as text. Get accessible, deterministic SVG.
6
4
 
7
- Write engineering diagrams as text and compile them to accessible inline SVG.
8
-
9
- Schemd supports electrical components, logic gates, quantum gates, and general system diagrams. It runs on the server or during a build, so the browser only receives SVG—no diagram runtime, DOM, or layout engine.
10
-
11
- ## Why Schemd?
12
-
13
- - Small, readable text format
14
- - Deterministic SVG output with fixed dimensions
15
- - Straight, curved, and obstacle-aware orthogonal connections
16
- - Accessible titles and descriptions
17
- - No runtime dependencies
5
+ Schemd has no runtime dependencies, browser layout pass, or DOM requirement. It works on a server or during a build.
18
6
 
19
7
  ## Install
20
8
 
21
- Schemd requires Node.js 24 or newer. Install `marked` if you want to use Markdown fences.
22
-
23
9
  ```sh
24
- npm install @schemd/core marked
10
+ npm install @schemd/core
25
11
  ```
26
12
 
27
- ## Use with Markdown
13
+ Node.js 24+ is required.
14
+
15
+ ## Quick start
28
16
 
29
17
  ```ts
30
- import { Marked } from "marked";
31
- import { schematicMarkedExtension } from "@schemd/core";
18
+ import { compileSchematic, parseSchematicFence } from "@schemd/core";
32
19
 
33
- const markdown = new Marked();
34
- markdown.use(schematicMarkedExtension());
20
+ const fence = parseSchematicFence(
21
+ 'schemd bounds="640x260" title="Sensor input"',
22
+ )!;
35
23
 
36
- const html = await markdown.parse(`
37
- \`\`\`schemd bounds="640x260" title="Sensor input"
24
+ const { svg, document, metrics } = compileSchematic(`
38
25
  port:VIN "Input" at (60, 130) #blue
39
26
  resistor:R1 "10 k\\Omega" at (220, 130) #amber
40
27
  capacitor:C1 "100 nF" at (400, 130) #cyan
41
28
 
42
29
  VIN.out -> R1.in #blue [ortho]
43
30
  R1.out -> C1.in #amber [ortho]
44
- \`\`\`
45
- `);
46
- ```
47
-
48
- ## Use the compiler directly
49
-
50
- ```ts
51
- import {
52
- parseSchematic,
53
- parseSchematicFence,
54
- renderSchematic,
55
- } from "@schemd/core";
56
-
57
- const fence = parseSchematicFence(
58
- 'schemd bounds="640x260" title="Sensor input"',
59
- );
60
-
61
- if (!fence) throw new Error("Expected a schemd fence");
62
-
63
- const diagram = parseSchematic(
64
- `port:VIN "Input" at (60, 130) #blue
65
- resistor:R1 "10 k\\Omega" at (220, 130) #amber
66
- VIN.out -> R1.in #blue [ortho]`,
67
- fence,
68
- );
69
-
70
- const svg = renderSchematic(diagram, fence);
31
+ `, fence);
71
32
  ```
72
33
 
73
- ## The language
74
-
75
- A diagram has component declarations and connections:
34
+ The DSL is intentionally small:
76
35
 
77
36
  ```text
78
37
  kind:ID "label" at (x, y) color [options]
79
38
  ID.port -> ID.port color [line|bezier|ortho]
80
39
  ```
81
40
 
82
- Available components include resistors, capacitors, inductors, diodes, transistors, grounds, ports, logic gates, quantum gates, and configurable IC blocks.
41
+ It includes electrical parts, analog devices, logic and quantum gates, configurable ICs, math labels, collision-aware routing, and wire bridges.
83
42
 
84
- Use `line`, `bezier`, or `ortho` to choose a connection style. Arrow and dot markers are also supported:
43
+ UML nodes and relations use the same syntax:
85
44
 
86
45
  ```text
87
- U1.out -> U2.in #emerald [ortho marker-end=arrow]
88
- ```
89
-
90
- See the [full documentation](https://johnowolabiidogun.dev/tools/schemd/docs/overview) for component ports, options, colors, math labels, and framework integrations.
46
+ class:User "User" at (160, 120) #slate [attributes="- id: UUID" operations="+ save(): void"]
47
+ class:Admin "Admin" at (460, 120) #blue
91
48
 
92
- ## Output modes
93
-
94
- | Mode | Use it for |
95
- | --- | --- |
96
- | `default` | Small, static SVG |
97
- | `embedded-css` | Built-in styles and responsive visuals |
98
- | `full` | Interactive diagrams with node and wire metadata |
99
-
100
- Pass a mode to `renderSchematic` or `schematicMarkedExtension`:
101
-
102
- ```ts
103
- const svg = renderSchematic(diagram, { ...fence, mode: "embedded-css" });
49
+ Admin.left -> User.right #blue [ortho generalization]
104
50
  ```
105
51
 
106
- ## Security
52
+ Class, actor, use-case, state, lifeline, note, package, initial, and final nodes are built in. Relations include association, dependency, generalization, realization, aggregation, composition, message, transition, include, and extend.
107
53
 
108
- Schemd validates input, escapes labels, limits diagram size, and returns bounded SVG. Compile diagrams on a trusted server or build system, then send the generated SVG to the browser. Do not treat arbitrary HTML as Schemd output.
54
+ Use `mode: "embedded-css"` for built-in styling or `mode: "full"` for interaction metadata. The default output stays compact and static.
109
55
 
110
- ## Development
111
-
112
- ```sh
113
- npm install
114
- npm run check
115
- npm test
116
- npm run build
117
- ```
56
+ Markdown belongs at the host boundary. Detect `schemd` fences in your server-side Markdown renderer and pass their text to `compileSchematic`; core does not ship or require a Markdown parser.
118
57
 
119
- Schemd is available under the [MIT License](https://github.com/Sirneij/schemd/blob/main/LICENSE).
58
+ [Documentation](https://johnowolabiidogun.dev/tools/schemd/docs/overview) · [Issues](https://github.com/Sirneij/schemd/issues) · [MIT](https://github.com/Sirneij/schemd/blob/main/LICENSE)
@@ -0,0 +1,16 @@
1
+ import type { CompileSchematicOptions, SchematicDocument } from './types.js';
2
+ /** Small, allocation-bounded compilation counters. */
3
+ export interface SchematicCompilationMetrics {
4
+ readonly sourceCharacters: number;
5
+ readonly components: number;
6
+ readonly connections: number;
7
+ readonly svgBytes: number;
8
+ }
9
+ /** Validated AST, rendered SVG, and useful host-side counters. */
10
+ export interface SchematicCompilation {
11
+ readonly document: SchematicDocument;
12
+ readonly svg: string;
13
+ readonly metrics: SchematicCompilationMetrics;
14
+ }
15
+ /** Parse and render a schematic with one stable public call. */
16
+ export declare function compileSchematic(source: string, options: CompileSchematicOptions): SchematicCompilation;
@@ -0,0 +1,17 @@
1
+ import { utf8ByteLength } from './limits.js';
2
+ import { parseSchematic } from './parser.js';
3
+ import { renderSchematic } from './renderer.js';
4
+ export function compileSchematic(source, options) {
5
+ const document = parseSchematic(source, options);
6
+ const svg = renderSchematic(document, options);
7
+ return {
8
+ document,
9
+ svg,
10
+ metrics: {
11
+ sourceCharacters: source.length,
12
+ components: document.components.length,
13
+ connections: document.connections.length,
14
+ svgBytes: utf8ByteLength(svg)
15
+ }
16
+ };
17
+ }
package/dist/index.d.ts CHANGED
@@ -1,16 +1,14 @@
1
1
  /**
2
2
  * Stable public entry point for the `schemd` server-side compiler.
3
3
  *
4
- * All runtime exports are dependency-free. The Marked integration imports
5
- * Marked contracts as types only, so applications pay for no Markdown runtime
6
- * unless they already provide one at the host boundary.
4
+ * All runtime exports are dependency-free and safe to run without a DOM.
7
5
  *
8
6
  * @packageDocumentation
9
7
  */
10
8
  export { parseSchematic, parseSchematicColor, parseSchematicFence } from './parser.js';
11
9
  export { renderSchematic } from './renderer.js';
12
- export { schematicMarkedExtension } from './marked-extension.js';
13
- export { mathLabelGlyphLength, mathLabelText, parseMathLabel, renderMathLabelTspans, type MathLabelSegment, type MathLabelSegmentKind } from './math-label.js';
14
- export { MAX_SCHEMATIC_COMPONENTS, MAX_SCHEMATIC_CONNECTIONS, MAX_SCHEMATIC_SOURCE_CHARACTERS, MAX_SCHEMATIC_SVG_OUTPUT_BYTES, SCHEMATIC_LIMITS } from './limits.js';
15
- export { classicalGateHeight, componentObstacleRectangle, componentRectangle, componentTextAnchors, distributedCoordinate, enumerateComponentPorts, positionIcPin, PORT_HOTSPOT_RADIUS, resolvePortPoint, routeConnections, routeConnection, SCHEMATIC_BRIDGE_RADIUS, SCHEMATIC_OBSTACLE_CLEARANCE, validateDocumentGeometry, type RoutedConnection, type ComponentTextAnchors, type ComponentPort, type IcPinSide, type SchematicRectangle } from './layout.js';
16
- export { ANALOG_KINDS, COMPONENT_KINDS, CLASSICAL_GATE_KINDS, DIODE_TYPES, GROUND_STYLES, PASSIVE_KINDS, QUANTUM_GATE_KINDS, SCHEMATIC_SIGNAL_MARKERS, SEMANTIC_COLORS, TRANSISTOR_TYPES, SCHEMD_OUTPUT_MODES, SchematicSyntaxError, type AnalogKind, type CompileSchematicOptions, type ClassicalGateComponent, type ClassicalGateKind, type ComponentKind, type DiodeComponent, type DiodeType, type GroundComponent, type GroundStyle, type IcComponent, type IntegratedCircuitComponent, type IntegratedCircuitPins, type PassiveComponent, type PassiveKind, type PortComponent, type SemanticColor, type SchematicBounds, type SchematicComponent, type SchematicConnection, type SchematicColor, type SchematicDocument, type SchematicEndpoint, type SchematicFence, type SchematicSignalMarker, type SchematicMarkedOptions, type SchematicPoint, type SchemdOutputMode, type TransistorComponent, type TransistorType, type QuantumGateComponent, type QuantumGateKind } from './types.js';
10
+ export { compileSchematic, type SchematicCompilation, type SchematicCompilationMetrics } from './compiler.js';
11
+ export { mathLabelGlyphLength, mathLabelTextWidth, mathLabelText, parseMathLabel, renderMathLabelTspans, type MathLabelSegment, type MathLabelSegmentKind } from './math-label.js';
12
+ export { MAX_SCHEMATIC_COMPONENTS, MAX_SCHEMATIC_CONNECTIONS, MAX_SCHEMATIC_WIRE_CROSSINGS, MAX_SCHEMATIC_SOURCE_CHARACTERS, MAX_SCHEMATIC_SVG_OUTPUT_BYTES, SCHEMATIC_LIMITS } from './limits.js';
13
+ export { classicalGateHeight, componentObstacleRectangle, componentRectangle, componentTextAnchors, distributedCoordinate, enumerateComponentPorts, positionIcPin, PORT_HOTSPOT_RADIUS, resolvePortPoint, resolvePortGeometry, routeConnections, routeConnection, SCHEMATIC_BRIDGE_RADIUS, SCHEMATIC_OBSTACLE_CLEARANCE, validateDocumentGeometry, type RoutedConnection, type ComponentTextAnchors, type ComponentPort, type IcPinSide, type SchematicRectangle } from './layout.js';
14
+ export { ANALOG_KINDS, COMPONENT_KINDS, CLASSICAL_GATE_KINDS, DIODE_TYPES, GROUND_STYLES, PASSIVE_KINDS, QUANTUM_GATE_KINDS, SCHEMATIC_SIGNAL_MARKERS, SEMANTIC_COLORS, TRANSISTOR_TYPES, UML_COMPONENT_KINDS, UML_RELATION_KINDS, SCHEMD_OUTPUT_MODES, SCHEMD_SEMANTIC_HOOKS, SchematicSyntaxError, type AnalogKind, type CompileSchematicOptions, type ClassicalGateComponent, type ClassicalGateKind, type ComponentKind, type DiodeComponent, type DiodeType, type GroundComponent, type GroundStyle, type IcComponent, type IntegratedCircuitComponent, type IntegratedCircuitPins, type PassiveComponent, type PassiveKind, type PortComponent, type SemanticColor, type SchematicBounds, type SchematicComponent, type SchematicConnection, type SchematicColor, type SchematicDocument, type SchematicEndpoint, type SchematicFence, type SchematicSignalMarker, type SchematicSemanticHook, type SchematicPoint, type SchemdOutputMode, type TransistorComponent, type TransistorType, type QuantumGateComponent, type QuantumGateKind, type SchematicRelationKind, type UmlActorComponent, type UmlClassComponent, type UmlComponent, type UmlComponentKind, type UmlPseudostateComponent, type UmlRelationKind, type UmlSizedComponent, type UmlStateComponent } from './types.js';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { parseSchematic, parseSchematicColor, parseSchematicFence } from './parser.js';
2
2
  export { renderSchematic } from './renderer.js';
3
- export { schematicMarkedExtension } from './marked-extension.js';
4
- export { mathLabelGlyphLength, mathLabelText, parseMathLabel, renderMathLabelTspans } from './math-label.js';
5
- export { MAX_SCHEMATIC_COMPONENTS, MAX_SCHEMATIC_CONNECTIONS, MAX_SCHEMATIC_SOURCE_CHARACTERS, MAX_SCHEMATIC_SVG_OUTPUT_BYTES, SCHEMATIC_LIMITS } from './limits.js';
6
- export { classicalGateHeight, componentObstacleRectangle, componentRectangle, componentTextAnchors, distributedCoordinate, enumerateComponentPorts, positionIcPin, PORT_HOTSPOT_RADIUS, resolvePortPoint, routeConnections, routeConnection, SCHEMATIC_BRIDGE_RADIUS, SCHEMATIC_OBSTACLE_CLEARANCE, validateDocumentGeometry } from './layout.js';
7
- export { ANALOG_KINDS, COMPONENT_KINDS, CLASSICAL_GATE_KINDS, DIODE_TYPES, GROUND_STYLES, PASSIVE_KINDS, QUANTUM_GATE_KINDS, SCHEMATIC_SIGNAL_MARKERS, SEMANTIC_COLORS, TRANSISTOR_TYPES, SCHEMD_OUTPUT_MODES, SchematicSyntaxError } from './types.js';
3
+ export { compileSchematic } from './compiler.js';
4
+ export { mathLabelGlyphLength, mathLabelTextWidth, mathLabelText, parseMathLabel, renderMathLabelTspans } from './math-label.js';
5
+ export { MAX_SCHEMATIC_COMPONENTS, MAX_SCHEMATIC_CONNECTIONS, MAX_SCHEMATIC_WIRE_CROSSINGS, MAX_SCHEMATIC_SOURCE_CHARACTERS, MAX_SCHEMATIC_SVG_OUTPUT_BYTES, SCHEMATIC_LIMITS } from './limits.js';
6
+ export { classicalGateHeight, componentObstacleRectangle, componentRectangle, componentTextAnchors, distributedCoordinate, enumerateComponentPorts, positionIcPin, PORT_HOTSPOT_RADIUS, resolvePortPoint, resolvePortGeometry, routeConnections, routeConnection, SCHEMATIC_BRIDGE_RADIUS, SCHEMATIC_OBSTACLE_CLEARANCE, validateDocumentGeometry } from './layout.js';
7
+ export { ANALOG_KINDS, COMPONENT_KINDS, CLASSICAL_GATE_KINDS, DIODE_TYPES, GROUND_STYLES, PASSIVE_KINDS, QUANTUM_GATE_KINDS, SCHEMATIC_SIGNAL_MARKERS, SEMANTIC_COLORS, TRANSISTOR_TYPES, UML_COMPONENT_KINDS, UML_RELATION_KINDS, SCHEMD_OUTPUT_MODES, SCHEMD_SEMANTIC_HOOKS, SchematicSyntaxError } from './types.js';
package/dist/layout.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @packageDocumentation
10
10
  */
11
- import { type ClassicalGateComponent, type IntegratedCircuitComponent, type SchematicComponent, type SchematicConnection, type SchematicDocument, type SchematicFence, type SchematicPoint } from './types.js';
11
+ import { type ClassicalGateComponent, type IntegratedCircuitComponent, type SchematicBounds, type SchematicComponent, type SchematicConnection, type SchematicDocument, type SchematicFence, type SchematicPoint } from './types.js';
12
12
  /** Axis-aligned rectangle expressed in absolute schematic coordinates. */
13
13
  export interface SchematicRectangle {
14
14
  /** Inclusive left extent. */
@@ -22,6 +22,8 @@ export interface SchematicRectangle {
22
22
  }
23
23
  /** Render-ready connection path and the points used for bounds validation. */
24
24
  export interface RoutedConnection {
25
+ /** Original routing strategy; crossing passes must never infer it from control points. */
26
+ readonly curve: SchematicConnection['curve'];
25
27
  /** Compact SVG path-data string. */
26
28
  d: string;
27
29
  /** At least two absolute points spanning endpoints, controls, corners, and bridge extrema. */
@@ -44,6 +46,8 @@ export interface ComponentPort {
44
46
  readonly id: string;
45
47
  /** Absolute center of the physical terminal. */
46
48
  readonly point: SchematicPoint;
49
+ /** Unit outward normal used to leave the owning component without crossing its body. */
50
+ readonly normal: SchematicPoint;
47
51
  }
48
52
  /** One edge of a polymorphic integrated-circuit body. */
49
53
  export type IcPinSide = 'left' | 'right' | 'top' | 'bottom';
@@ -88,6 +92,11 @@ export declare function positionIcPin(component: IntegratedCircuitComponent, sid
88
92
  * @throws {Error} When called with an endpoint the semantic parser did not validate.
89
93
  */
90
94
  export declare function resolvePortPoint(component: SchematicComponent, port: string): SchematicPoint;
95
+ /** Resolve a port coordinate together with the direction a route must initially travel. */
96
+ export declare function resolvePortGeometry(component: SchematicComponent, port: string): {
97
+ readonly point: SchematicPoint;
98
+ readonly normal: SchematicPoint;
99
+ };
91
100
  /**
92
101
  * Enumerate each physical terminal exactly once. Alias spellings deliberately resolve through
93
102
  * `resolvePortPoint` but do not create duplicate interactive targets.
@@ -110,9 +119,10 @@ export declare function componentObstacleRectangle(component: SchematicComponent
110
119
  *
111
120
  * @param connection - Validated directed connection.
112
121
  * @param components - Complete component map used for endpoint and obstacle lookup.
122
+ * @param bounds - Optional intrinsic routing bounds.
113
123
  * @returns SVG path data plus control/corner points for later bounds checks.
114
124
  */
115
- export declare function routeConnection(connection: SchematicConnection, components: ReadonlyMap<string, SchematicComponent>): RoutedConnection;
125
+ export declare function routeConnection(connection: SchematicConnection, components: ReadonlyMap<string, SchematicComponent>, bounds?: SchematicBounds): RoutedConnection;
116
126
  /**
117
127
  * Route connections in source order and bridge only the later trace at a true crossing.
118
128
  *
@@ -123,7 +133,7 @@ export declare function routeConnection(connection: SchematicConnection, compone
123
133
  * @param components - Complete component map.
124
134
  * @returns Routes in the same order, with crossings applied to later orthogonal traces.
125
135
  */
126
- export declare function routeConnections(connections: readonly SchematicConnection[], components: ReadonlyMap<string, SchematicComponent>): readonly RoutedConnection[];
136
+ export declare function routeConnections(connections: readonly SchematicConnection[], components: ReadonlyMap<string, SchematicComponent>, bounds?: SchematicBounds): readonly RoutedConnection[];
127
137
  /**
128
138
  * Calculate external designator and label fitting metrics.
129
139
  *
@@ -148,4 +158,4 @@ export declare function componentRectangle(component: SchematicComponent): Schem
148
158
  * @param fence - Intrinsic canvas contract.
149
159
  * @throws {SchematicSyntaxError} At the originating component or connection line.
150
160
  */
151
- export declare function validateDocumentGeometry(document: SchematicDocument, fence: SchematicFence): void;
161
+ export declare function validateDocumentGeometry(document: SchematicDocument, fence: SchematicFence, routedConnections?: readonly RoutedConnection[]): void;