schematex 0.4.3 → 0.5.2

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 (98) hide show
  1. package/README.md +36 -7
  2. package/dist/ai/ai-sdk.cjs +19 -13
  3. package/dist/ai/ai-sdk.cjs.map +1 -1
  4. package/dist/ai/ai-sdk.d.cts +4 -3
  5. package/dist/ai/ai-sdk.d.ts +4 -3
  6. package/dist/ai/ai-sdk.js +15 -9
  7. package/dist/ai/ai-sdk.js.map +1 -1
  8. package/dist/ai/index.cjs +16 -12
  9. package/dist/ai/index.d.cts +20 -153
  10. package/dist/ai/index.d.ts +20 -153
  11. package/dist/ai/index.js +4 -4
  12. package/dist/api-C5SECOxZ.d.cts +69 -0
  13. package/dist/api-Cr_MxttI.d.ts +69 -0
  14. package/dist/browser.cjs +24 -6
  15. package/dist/browser.cjs.map +1 -1
  16. package/dist/browser.d.cts +12 -3
  17. package/dist/browser.d.ts +12 -3
  18. package/dist/browser.js +14 -6
  19. package/dist/browser.js.map +1 -1
  20. package/dist/{chunk-SMXU3KYA.cjs → chunk-4QPDZJAL.cjs} +6337 -120
  21. package/dist/chunk-4QPDZJAL.cjs.map +1 -0
  22. package/dist/{chunk-N3SLYVNW.cjs → chunk-HK56GQQP.cjs} +751 -80
  23. package/dist/chunk-HK56GQQP.cjs.map +1 -0
  24. package/dist/{chunk-KWQTF6ZL.js → chunk-OK5ZS3LU.js} +6330 -119
  25. package/dist/chunk-OK5ZS3LU.js.map +1 -0
  26. package/dist/{chunk-2Z543TC3.cjs → chunk-QMTWG6JL.cjs} +1297 -1151
  27. package/dist/chunk-QMTWG6JL.cjs.map +1 -0
  28. package/dist/{chunk-VITE3MZQ.cjs → chunk-QTNPMIO2.cjs} +99 -5
  29. package/dist/chunk-QTNPMIO2.cjs.map +1 -0
  30. package/dist/{chunk-6IGSKU6D.js → chunk-UFTYX73U.js} +99 -5
  31. package/dist/chunk-UFTYX73U.js.map +1 -0
  32. package/dist/{chunk-J7JWMQD5.js → chunk-VCH7RI5H.js} +1297 -1151
  33. package/dist/chunk-VCH7RI5H.js.map +1 -0
  34. package/dist/{chunk-UBTKM2TB.js → chunk-VKPCR7BG.js} +751 -81
  35. package/dist/chunk-VKPCR7BG.js.map +1 -0
  36. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  37. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  38. package/dist/diagrams/circuit/index.cjs +7 -7
  39. package/dist/diagrams/circuit/index.d.cts +1 -1
  40. package/dist/diagrams/circuit/index.d.ts +1 -1
  41. package/dist/diagrams/circuit/index.js +1 -1
  42. package/dist/diagrams/ecomap/index.d.cts +1 -1
  43. package/dist/diagrams/ecomap/index.d.ts +1 -1
  44. package/dist/diagrams/entity/index.d.cts +1 -1
  45. package/dist/diagrams/entity/index.d.ts +1 -1
  46. package/dist/diagrams/fishbone/index.d.cts +1 -1
  47. package/dist/diagrams/fishbone/index.d.ts +1 -1
  48. package/dist/diagrams/flowchart/index.cjs +7 -7
  49. package/dist/diagrams/flowchart/index.d.cts +2 -2
  50. package/dist/diagrams/flowchart/index.d.ts +2 -2
  51. package/dist/diagrams/flowchart/index.js +1 -1
  52. package/dist/diagrams/genogram/index.d.cts +1 -1
  53. package/dist/diagrams/genogram/index.d.ts +1 -1
  54. package/dist/diagrams/ladder/index.d.cts +1 -1
  55. package/dist/diagrams/ladder/index.d.ts +1 -1
  56. package/dist/diagrams/logic/index.d.cts +1 -1
  57. package/dist/diagrams/logic/index.d.ts +1 -1
  58. package/dist/diagrams/orgchart/index.d.cts +1 -1
  59. package/dist/diagrams/orgchart/index.d.ts +1 -1
  60. package/dist/diagrams/pedigree/index.d.cts +1 -1
  61. package/dist/diagrams/pedigree/index.d.ts +1 -1
  62. package/dist/diagrams/phylo/index.d.cts +1 -1
  63. package/dist/diagrams/phylo/index.d.ts +1 -1
  64. package/dist/diagrams/sld/index.d.cts +1 -1
  65. package/dist/diagrams/sld/index.d.ts +1 -1
  66. package/dist/diagrams/sociogram/index.d.cts +1 -1
  67. package/dist/diagrams/sociogram/index.d.ts +1 -1
  68. package/dist/diagrams/timing/index.d.cts +1 -1
  69. package/dist/diagrams/timing/index.d.ts +1 -1
  70. package/dist/diagrams/venn/index.d.cts +1 -1
  71. package/dist/diagrams/venn/index.d.ts +1 -1
  72. package/dist/{index-DYpJXJcy.d.cts → index-BD2yDfQM.d.cts} +1 -1
  73. package/dist/{index-BeUVaQiD.d.ts → index-C30zQWZI.d.ts} +1 -1
  74. package/dist/index.cjs +35 -11
  75. package/dist/index.d.cts +10 -4
  76. package/dist/index.d.ts +10 -4
  77. package/dist/index.js +3 -3
  78. package/dist/react.cjs +8 -10
  79. package/dist/react.cjs.map +1 -1
  80. package/dist/react.d.cts +3 -2
  81. package/dist/react.d.ts +3 -2
  82. package/dist/react.js +8 -10
  83. package/dist/react.js.map +1 -1
  84. package/dist/tools-BHWaJPOl.d.ts +153 -0
  85. package/dist/tools-DlpuE76u.d.cts +153 -0
  86. package/dist/{types-DKdo-Ua_.d.cts → types-WTr9W5Ud.d.cts} +3 -3
  87. package/dist/{types-DKdo-Ua_.d.ts → types-WTr9W5Ud.d.ts} +3 -3
  88. package/package.json +2 -2
  89. package/dist/api-BIj9t4Oc.d.cts +0 -22
  90. package/dist/api-BIj9t4Oc.d.ts +0 -22
  91. package/dist/chunk-2Z543TC3.cjs.map +0 -1
  92. package/dist/chunk-6IGSKU6D.js.map +0 -1
  93. package/dist/chunk-J7JWMQD5.js.map +0 -1
  94. package/dist/chunk-KWQTF6ZL.js.map +0 -1
  95. package/dist/chunk-N3SLYVNW.cjs.map +0 -1
  96. package/dist/chunk-SMXU3KYA.cjs.map +0 -1
  97. package/dist/chunk-UBTKM2TB.js.map +0 -1
  98. package/dist/chunk-VITE3MZQ.cjs.map +0 -1
@@ -4,582 +4,6 @@ var chunkD7EHZFK4_cjs = require('./chunk-D7EHZFK4.cjs');
4
4
  var chunkNAGUZFXX_cjs = require('./chunk-NAGUZFXX.cjs');
5
5
  var chunk3WNW5Y7P_cjs = require('./chunk-3WNW5Y7P.cjs');
6
6
 
7
- // src/diagrams/circuit/netlist.ts
8
- var NetlistParseError = class extends Error {
9
- constructor(message, line) {
10
- super(message);
11
- this.line = line;
12
- this.name = "NetlistParseError";
13
- }
14
- line;
15
- };
16
- var PREFIX_MAP = {
17
- R: { type: "resistor", pins: ["start", "end"] },
18
- C: { type: "capacitor", pins: ["start", "end"] },
19
- L: { type: "inductor", pins: ["start", "end"] },
20
- D: { type: "diode", pins: ["start", "end"] },
21
- // anode → start, cathode → end
22
- V: { type: "voltage_source", pins: ["plus", "minus"] },
23
- I: { type: "current_source", pins: ["plus", "minus"] },
24
- Q: { type: "npn", pins: ["c", "b", "e"] },
25
- M: { type: "nmos", pins: ["d", "g", "s"] },
26
- J: { type: "jfet_n", pins: ["d", "g", "s"] },
27
- S: { type: "switch_spst", pins: ["start", "end"] },
28
- F: { type: "fuse", pins: ["start", "end"] },
29
- B: { type: "battery", pins: ["plus", "minus"] },
30
- K: { type: "relay_coil", pins: ["start", "end"] },
31
- U: { type: "generic_ic", pins: [] },
32
- // pins declared via pins="..." attr
33
- X: { type: "generic_ic", pins: [] },
34
- W: { type: "wire", pins: ["start", "end"] },
35
- // explicit wire (non-SPICE convention, common in EE textbooks)
36
- T: { type: "terminal_block", pins: [] }
37
- // pins via pins="..."
38
- };
39
- var TYPE_ALIASES = {
40
- vsource: "voltage_source",
41
- isource: "current_source",
42
- acsource: "ac_source",
43
- ecap: "electrolytic_cap",
44
- pot: "potentiometer",
45
- gnd: "ground",
46
- ic: "generic_ic",
47
- reg: "voltage_regulator",
48
- timer555: "555_timer",
49
- transistor: "npn",
50
- tb: "terminal_block",
51
- junction_box: "terminal_block",
52
- jbox: "terminal_block",
53
- enclosure: "terminal_block"
54
- };
55
- var GROUND_REF = /^(0|gnd|ground|earth|pe|agnd|dgnd|gnda|gndd|vss|com)(_\w+|\d+)?$/i;
56
- function isGroundRef(s) {
57
- return GROUND_REF.test(s);
58
- }
59
- function tokenize(line) {
60
- const tokens = [];
61
- let i = 0;
62
- while (i < line.length) {
63
- const ch = line[i];
64
- if (ch === " " || ch === " ") {
65
- i++;
66
- continue;
67
- }
68
- if (ch === '"') {
69
- const end = line.indexOf('"', i + 1);
70
- tokens.push(line.slice(i, end < 0 ? line.length : end + 1));
71
- i = end < 0 ? line.length : end + 1;
72
- continue;
73
- }
74
- let j = i;
75
- while (j < line.length && line[j] !== " " && line[j] !== " ") {
76
- if (line[j] === "=" && line[j + 1] === '"') {
77
- const end = line.indexOf('"', j + 2);
78
- j = end < 0 ? line.length : end + 1;
79
- break;
80
- }
81
- j++;
82
- }
83
- tokens.push(line.slice(i, j));
84
- i = j;
85
- }
86
- return tokens;
87
- }
88
- function isKeyEqVal(tok) {
89
- const eq = tok.indexOf("=");
90
- return eq > 0 && /^[a-zA-Z_][\w]*$/.test(tok.slice(0, eq));
91
- }
92
- function parseKV(tok) {
93
- const eq = tok.indexOf("=");
94
- const key = tok.slice(0, eq).trim();
95
- let val = tok.slice(eq + 1).trim();
96
- if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
97
- return [key, val];
98
- }
99
- function parseNetlist(body, title2) {
100
- const components = [];
101
- const netByName = /* @__PURE__ */ new Map();
102
- const pinMap = {};
103
- let autoGnd = 0;
104
- const ensureNet = (name) => {
105
- let n = netByName.get(name);
106
- if (!n) {
107
- n = { id: name, anchors: [] };
108
- netByName.set(name, n);
109
- }
110
- return n;
111
- };
112
- const lines = body.split("\n").map((l) => l.replace(/\r$/, ""));
113
- for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
114
- const raw = lines[lineIdx];
115
- const stripped = raw.replace(/#.*$/, "").trim();
116
- if (!stripped) continue;
117
- const tokens = tokenize(stripped);
118
- if (tokens.length < 2) {
119
- throw new NetlistParseError(
120
- `Netlist line must have at least ID + one net: "${stripped}"`,
121
- lineIdx + 1
122
- );
123
- }
124
- const id = tokens[0];
125
- if (!/^[a-zA-Z_][\w]*$/.test(id)) {
126
- throw new NetlistParseError(`Invalid component id: "${id}"`, lineIdx + 1);
127
- }
128
- let cursor = 1;
129
- const netRefs = [];
130
- while (cursor < tokens.length && !isKeyEqVal(tokens[cursor])) {
131
- netRefs.push(tokens[cursor]);
132
- cursor++;
133
- }
134
- const kv = {};
135
- for (; cursor < tokens.length; cursor++) {
136
- if (!isKeyEqVal(tokens[cursor])) {
137
- throw new NetlistParseError(
138
- `Expected key=value after nets, got "${tokens[cursor]}"`,
139
- lineIdx + 1
140
- );
141
- }
142
- const [k, v] = parseKV(tokens[cursor]);
143
- kv[k] = v;
144
- }
145
- const prefix = id[0].toUpperCase();
146
- const defaults = PREFIX_MAP[prefix];
147
- let cType;
148
- let pinOrder;
149
- if (kv.type) {
150
- const t = kv.type.toLowerCase();
151
- cType = TYPE_ALIASES[t] ?? t;
152
- pinOrder = defaults?.pins ?? ["p1", "p2"];
153
- } else if (defaults) {
154
- cType = defaults.type;
155
- pinOrder = defaults.pins;
156
- } else if (isGroundRef(id)) {
157
- cType = "ground";
158
- pinOrder = ["start"];
159
- } else {
160
- throw new NetlistParseError(
161
- `Cannot infer type from id "${id}". Either rename to a SPICE-prefix id (R*, C*, L*, D*, V*, I*, Q*, M*, J*, S*, F*, B*, K*, U*, X*, W*, T*) or pass an explicit \`type=<name>\` attribute (e.g. \`${id} ... type=resistor\`). Schematex circuit covers electrical schematics only \u2014 hydraulic/pneumatic prefixes (EV*, BOMBA*, TANK*, etc.) are not supported.`,
162
- lineIdx + 1
163
- );
164
- }
165
- const expectedPins = pinOrder.length;
166
- let valueFromTail;
167
- if (netRefs.length > expectedPins && expectedPins > 0) {
168
- const tail = netRefs.slice(expectedPins);
169
- netRefs.length = expectedPins;
170
- const first = tail[0].toLowerCase();
171
- if (TYPE_ALIASES[first]) {
172
- cType = TYPE_ALIASES[first];
173
- } else if (first === "npn" || first === "pnp" || first === "nmos" || first === "pmos" || first === "jfet_n" || first === "jfet_p" || first === "zener" || first === "schottky" || first === "led" || first === "photodiode") {
174
- cType = first;
175
- if (first === "pnp") pinOrder = ["c", "b", "e"];
176
- if (first === "pmos" || first === "jfet_p") pinOrder = ["d", "g", "s"];
177
- } else {
178
- valueFromTail = tail.join(" ");
179
- }
180
- if (tail.length > 1 && !valueFromTail) {
181
- valueFromTail = tail.slice(1).join(" ");
182
- }
183
- }
184
- if (cType === "ground" || cType === "gnd_signal" || cType === "gnd_chassis" || cType === "gnd_digital") {
185
- pinOrder = ["start"];
186
- }
187
- if (cType === "terminal_block") {
188
- const pinsAttr = kv.pins ?? kv.terminals;
189
- const labels = pinsAttr ? pinsAttr.split(",").map((s) => s.trim()).filter(Boolean) : Array.from({ length: Math.max(netRefs.length, 1) }, (_, i) => `t${i + 1}`);
190
- pinOrder = labels.map(
191
- (label, idx) => label.toLowerCase().replace(/[^a-z0-9]+/g, "_") || `t${idx + 1}`
192
- );
193
- }
194
- if (netRefs.length < pinOrder.length) {
195
- throw new NetlistParseError(
196
- `Component ${id} (${cType}) expects ${pinOrder.length} nets, got ${netRefs.length}`,
197
- lineIdx + 1
198
- );
199
- }
200
- const pins = {};
201
- for (let p = 0; p < pinOrder.length; p++) {
202
- let net = netRefs[p];
203
- if (isGroundRef(net)) net = "GND";
204
- pins[pinOrder[p]] = net;
205
- ensureNet(net).anchors.push(`${id}.${pinOrder[p]}`);
206
- }
207
- pinMap[id] = pins;
208
- const comp = {
209
- id,
210
- componentType: cType,
211
- direction: "right",
212
- label: kv.label ?? id,
213
- value: kv.value ?? valueFromTail,
214
- attrs: {}
215
- };
216
- for (const [k, v] of Object.entries(kv)) {
217
- if (k === "label" || k === "value" || k === "type") continue;
218
- comp.attrs[k] = v;
219
- }
220
- components.push(comp);
221
- }
222
- if (netByName.has("GND")) {
223
- const hasGroundSym = components.some(
224
- (c) => c.componentType === "ground" || c.componentType === "gnd_signal" || c.componentType === "gnd_chassis" || c.componentType === "gnd_digital"
225
- );
226
- if (!hasGroundSym) {
227
- const gId = `_GND${autoGnd++}`;
228
- components.push({
229
- id: gId,
230
- componentType: "ground",
231
- direction: "down",
232
- label: void 0,
233
- value: void 0,
234
- attrs: { auto: "true" }
235
- });
236
- pinMap[gId] = { start: "GND" };
237
- ensureNet("GND").anchors.push(`${gId}.start`);
238
- }
239
- }
240
- const nets = Array.from(netByName.values());
241
- return {
242
- type: "circuit",
243
- title: title2,
244
- components,
245
- nets,
246
- pinMap,
247
- mode: "netlist"
248
- };
249
- }
250
-
251
- // src/diagrams/circuit/parser.ts
252
- var CircuitParseError = class extends Error {
253
- constructor(message) {
254
- super(message);
255
- this.name = "CircuitParseError";
256
- }
257
- };
258
- var COMPONENT_TYPES = /* @__PURE__ */ new Set([
259
- "resistor",
260
- "potentiometer",
261
- "rheostat",
262
- "thermistor_ntc",
263
- "thermistor_ptc",
264
- "ldr",
265
- "varistor",
266
- "fuse",
267
- "fuse_slow",
268
- "capacitor",
269
- "electrolytic_cap",
270
- "variable_cap",
271
- "inductor",
272
- "inductor_iron",
273
- "inductor_ferrite",
274
- "variable_inductor",
275
- "ferrite_bead",
276
- "crystal",
277
- "transformer",
278
- "diode",
279
- "zener",
280
- "schottky",
281
- "led",
282
- "photodiode",
283
- "varactor",
284
- "tvs_diode",
285
- "bridge_rectifier",
286
- "npn",
287
- "pnp",
288
- "darlington_npn",
289
- "darlington_pnp",
290
- "nmos",
291
- "pmos",
292
- "nmos_depletion",
293
- "jfet_n",
294
- "jfet_p",
295
- "igbt",
296
- "scr",
297
- "triac",
298
- "diac",
299
- "phototransistor",
300
- "optocoupler",
301
- "opamp",
302
- "comparator",
303
- "schmitt_buffer",
304
- "tri_state_buffer",
305
- "instrumentation_amp",
306
- "generic_ic",
307
- "voltage_regulator",
308
- "dc_dc_converter",
309
- "555_timer",
310
- "voltage_source",
311
- "current_source",
312
- "ac_source",
313
- "battery",
314
- "vcc",
315
- "ground",
316
- "gnd_signal",
317
- "gnd_chassis",
318
- "gnd_digital",
319
- "switch_spst",
320
- "switch_spdt",
321
- "switch_dpdt",
322
- "push_no",
323
- "push_nc",
324
- "relay_coil",
325
- "relay_no",
326
- "relay_nc",
327
- "motor",
328
- "speaker",
329
- "microphone",
330
- "buzzer",
331
- "ammeter",
332
- "voltmeter",
333
- "wattmeter",
334
- "oscilloscope",
335
- "wire",
336
- "dot",
337
- "label",
338
- "port",
339
- "test_point",
340
- "no_connect",
341
- "antenna"
342
- ]);
343
- var ALIASES = {
344
- vsource: "voltage_source",
345
- isource: "current_source",
346
- acsource: "ac_source",
347
- ecap: "electrolytic_cap",
348
- pot: "potentiometer",
349
- xtal: "crystal",
350
- xfmr: "transformer",
351
- transistor: "npn",
352
- bjt_npn: "npn",
353
- bjt_pnp: "pnp",
354
- mosfet_n: "nmos",
355
- mosfet_p: "pmos",
356
- gnd: "ground",
357
- ic: "generic_ic",
358
- reg: "voltage_regulator",
359
- timer555: "555_timer",
360
- therm: "thermistor_ntc",
361
- ntc: "thermistor_ntc",
362
- ptc: "thermistor_ptc",
363
- ths: "thermistor_ntc"
364
- };
365
- var EXTRA_TYPES = /* @__PURE__ */ new Set(["lamp"]);
366
- function normalizeType(raw) {
367
- const lower = raw.toLowerCase();
368
- if (ALIASES[lower]) return ALIASES[lower];
369
- if (COMPONENT_TYPES.has(lower)) {
370
- return lower;
371
- }
372
- if (EXTRA_TYPES.has(lower)) {
373
- return lower;
374
- }
375
- return null;
376
- }
377
- var DIRECTIONS = /* @__PURE__ */ new Set(["right", "left", "up", "down"]);
378
- function parseAttrs(rest) {
379
- const out = { attrs: {} };
380
- const tokens = [];
381
- let i = 0;
382
- while (i < rest.length) {
383
- const ch = rest[i];
384
- if (ch === " " || ch === " ") {
385
- i++;
386
- continue;
387
- }
388
- if (ch === '"') {
389
- const end = rest.indexOf('"', i + 1);
390
- const tok = rest.slice(i, end < 0 ? rest.length : end + 1);
391
- tokens.push(tok);
392
- i = end < 0 ? rest.length : end + 1;
393
- continue;
394
- }
395
- let j = i;
396
- while (j < rest.length && rest[j] !== " " && rest[j] !== " ") {
397
- if (rest[j] === "=" && rest[j + 1] === '"') {
398
- const end = rest.indexOf('"', j + 2);
399
- j = end < 0 ? rest.length : end + 1;
400
- break;
401
- }
402
- j++;
403
- }
404
- tokens.push(rest.slice(i, j));
405
- i = j;
406
- }
407
- for (const tok of tokens) {
408
- if (!tok) continue;
409
- if (DIRECTIONS.has(tok.toLowerCase())) {
410
- out.direction = tok.toLowerCase();
411
- continue;
412
- }
413
- const eq = tok.indexOf("=");
414
- if (eq > 0) {
415
- const key = tok.slice(0, eq).trim();
416
- let val = tok.slice(eq + 1).trim();
417
- if (val.startsWith('"') && val.endsWith('"')) {
418
- val = val.slice(1, -1);
419
- }
420
- if (key === "label") out.label = val;
421
- else if (key === "value") out.value = val;
422
- else if (key === "at") out.at = val;
423
- else if (key === "length") out.length = val;
424
- else out.attrs[key] = val;
425
- continue;
426
- }
427
- out.attrs[tok] = "true";
428
- }
429
- return out;
430
- }
431
- function parseCircuit(text2) {
432
- const rawLines = text2.split("\n");
433
- const firstMeaningful = rawLines.map((l) => l.replace(/#.*$/, "").trim()).find((l) => l.length > 0) ?? "";
434
- if (/^circuit\b.*\bnetlist\s*$/i.test(firstMeaningful)) {
435
- const netlistTitle = chunkNAGUZFXX_cjs.matchQuotedTitle(firstMeaningful);
436
- let headerIdx = -1;
437
- for (let i = 0; i < rawLines.length; i++) {
438
- const s = rawLines[i].replace(/#.*$/, "").trim();
439
- if (s.length > 0) {
440
- headerIdx = i;
441
- break;
442
- }
443
- }
444
- const body = rawLines.slice(headerIdx + 1).join("\n");
445
- return parseNetlist(body, netlistTitle);
446
- }
447
- const lines = text2.split("\n").map((l) => l.replace(/\r$/, ""));
448
- let title2;
449
- const components = [];
450
- const nets = [];
451
- const netByName = /* @__PURE__ */ new Map();
452
- let autoId = 0;
453
- let pendingAt;
454
- const mkId = (prefix) => `${prefix}_${autoId++}`;
455
- for (const rawLine of lines) {
456
- const stripped = rawLine.replace(/#.*$/, "").trim();
457
- if (!stripped) continue;
458
- if (/^circuit\b/i.test(stripped)) {
459
- const t = chunkNAGUZFXX_cjs.matchQuotedTitle(stripped);
460
- if (t !== void 0) title2 = t;
461
- continue;
462
- }
463
- const atMatch = stripped.match(/^at:\s*(.+)$/i);
464
- if (atMatch) {
465
- pendingAt = atMatch[1].trim();
466
- continue;
467
- }
468
- const netDecl = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*$/i);
469
- if (netDecl) {
470
- const name = netDecl[1];
471
- if (!netByName.has(name)) {
472
- const n = { id: name, anchors: [] };
473
- netByName.set(name, n);
474
- nets.push(n);
475
- }
476
- continue;
477
- }
478
- const netDotMatch = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*:\s*dot\s*$/i);
479
- if (netDotMatch) {
480
- const name = netDotMatch[1];
481
- let n = netByName.get(name);
482
- if (!n) {
483
- n = { id: name, anchors: [] };
484
- netByName.set(name, n);
485
- nets.push(n);
486
- }
487
- const id = mkId("dot");
488
- components.push({
489
- id,
490
- componentType: "dot",
491
- direction: "right",
492
- at: pendingAt,
493
- attrs: { net: name }
494
- });
495
- n.anchors.push(`${id}.end`);
496
- pendingAt = `${id}.end`;
497
- continue;
498
- }
499
- const labelMatch = stripped.match(/^label\s+"([^"]*)"(?:\s+(right|left|up|down))?\s*$/i);
500
- if (labelMatch) {
501
- const id = mkId("lbl");
502
- components.push({
503
- id,
504
- componentType: "label",
505
- direction: labelMatch[2]?.toLowerCase() ?? "right",
506
- at: pendingAt,
507
- label: labelMatch[1]
508
- });
509
- continue;
510
- }
511
- const wireMatch = stripped.match(/^wire(?:\s+(right|left|up|down))?(?:\s+(\d+)(?:px)?)?\s*$/i);
512
- if (wireMatch) {
513
- const id = mkId("w");
514
- components.push({
515
- id,
516
- componentType: "wire",
517
- direction: wireMatch[1]?.toLowerCase() ?? "right",
518
- at: pendingAt,
519
- attrs: wireMatch[2] ? { length: wireMatch[2] } : {}
520
- });
521
- pendingAt = `${id}.end`;
522
- continue;
523
- }
524
- const bareMatch = stripped.match(/^([a-zA-Z_][\w]*)(\s+.*)?$/);
525
- const colonMatch = stripped.match(/^([a-zA-Z_][\w]*)\s*:\s*([a-zA-Z_][\w]*)(\s+.*)?$/);
526
- if (colonMatch) {
527
- const id = colonMatch[1];
528
- const typeStr = colonMatch[2];
529
- const norm = normalizeType(typeStr);
530
- if (!norm) {
531
- throw new CircuitParseError(`Unknown component type: ${typeStr}`);
532
- }
533
- const rest = colonMatch[3] ?? "";
534
- const parsed = parseAttrs(rest);
535
- const comp = {
536
- id,
537
- componentType: norm,
538
- direction: parsed.direction ?? "right",
539
- at: parsed.at ?? pendingAt,
540
- label: parsed.label,
541
- value: parsed.value,
542
- attrs: parsed.attrs
543
- };
544
- if (parsed.length) {
545
- comp.attrs = { ...comp.attrs, length: parsed.length };
546
- }
547
- components.push(comp);
548
- pendingAt = `${id}.end`;
549
- continue;
550
- }
551
- if (bareMatch) {
552
- const typeStr = bareMatch[1];
553
- const norm = normalizeType(typeStr);
554
- if (!norm) {
555
- continue;
556
- }
557
- const rest = bareMatch[2] ?? "";
558
- const parsed = parseAttrs(rest);
559
- const id = mkId(norm);
560
- const comp = {
561
- id,
562
- componentType: norm,
563
- direction: parsed.direction ?? "right",
564
- at: parsed.at ?? pendingAt,
565
- label: parsed.label,
566
- value: parsed.value,
567
- attrs: parsed.attrs
568
- };
569
- components.push(comp);
570
- pendingAt = `${id}.end`;
571
- continue;
572
- }
573
- }
574
- return {
575
- type: "circuit",
576
- title: title2,
577
- components,
578
- nets,
579
- mode: "positional"
580
- };
581
- }
582
-
583
7
  // src/diagrams/circuit/symbols.ts
584
8
  var BODY = 'class="schematex-circuit-body"';
585
9
  var FILL = 'class="schematex-circuit-fill"';
@@ -642,6 +66,7 @@ var crystal = {
642
66
  };
643
67
  var transformer = {
644
68
  length: 60,
69
+ netlistPins: ["p1", "p2", "s1", "s2"],
645
70
  anchors: {
646
71
  start: { x: 0, y: 0 },
647
72
  end: { x: 60, y: 0 },
@@ -662,717 +87,1438 @@ var transformer = {
662
87
  lineWire(55, 0, 60, 0)
663
88
  ].join("")
664
89
  };
665
- var voltage_source = {
90
+ var voltage_source = {
91
+ length: 40,
92
+ netlistPins: ["plus", "minus"],
93
+ // plus/minus aliases: end = +, start = − (matches on-symbol label)
94
+ anchors: {
95
+ start: { x: 0, y: 0 },
96
+ end: { x: 40, y: 0 },
97
+ minus: { x: 0, y: 0 },
98
+ plus: { x: 40, y: 0 }
99
+ },
100
+ svg: () => [
101
+ lineWire(0, 0, 8, 0),
102
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
103
+ `<text x="16" y="-2" class="schematex-circuit-pol">+</text>`,
104
+ `<text x="23" y="8" class="schematex-circuit-pol">\u2212</text>`,
105
+ lineWire(32, 0, 40, 0)
106
+ ].join("")
107
+ };
108
+ var current_source = {
109
+ length: 40,
110
+ netlistPins: ["plus", "minus"],
111
+ anchors: {
112
+ start: { x: 0, y: 0 },
113
+ end: { x: 40, y: 0 },
114
+ minus: { x: 0, y: 0 },
115
+ plus: { x: 40, y: 0 }
116
+ },
117
+ svg: () => [
118
+ lineWire(0, 0, 8, 0),
119
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
120
+ `<line x1="14" y1="0" x2="24" y2="0" ${BODY}/>`,
121
+ `<polygon points="26,0 20,-4 20,4" ${FILL}/>`,
122
+ lineWire(32, 0, 40, 0)
123
+ ].join("")
124
+ };
125
+ var ac_source = {
126
+ length: 40,
127
+ netlistPins: ["plus", "minus"],
128
+ anchors: {
129
+ start: { x: 0, y: 0 },
130
+ end: { x: 40, y: 0 },
131
+ minus: { x: 0, y: 0 },
132
+ plus: { x: 40, y: 0 }
133
+ },
134
+ svg: () => [
135
+ lineWire(0, 0, 8, 0),
136
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
137
+ `<path d="M 14,0 Q 17,-6 20,0 Q 23,6 26,0" fill="none" ${BODY}/>`,
138
+ lineWire(32, 0, 40, 0)
139
+ ].join("")
140
+ };
141
+ var battery = {
142
+ length: 24,
143
+ netlistPins: ["plus", "minus"],
144
+ anchors: {
145
+ start: { x: 0, y: 0 },
146
+ end: { x: 24, y: 0 },
147
+ minus: { x: 0, y: 0 },
148
+ plus: { x: 24, y: 0 }
149
+ },
150
+ svg: () => [
151
+ lineWire(0, 0, 8, 0),
152
+ `<line x1="8" y1="-8" x2="8" y2="8" ${BODY}/>`,
153
+ `<line x1="12" y1="-4" x2="12" y2="4" ${BODY}/>`,
154
+ `<line x1="14" y1="-8" x2="14" y2="8" ${BODY}/>`,
155
+ `<line x1="18" y1="-4" x2="18" y2="4" ${BODY}/>`,
156
+ lineWire(18, 0, 24, 0)
157
+ ].join("")
158
+ };
159
+ var ground = {
160
+ length: 20,
161
+ anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
162
+ // Drawn as a "terminal" — vertical connection at start, earth lines below
163
+ svg: () => [
164
+ `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
165
+ `<line x1="10" y1="-8" x2="10" y2="8" ${BODY}/>`,
166
+ `<line x1="6" y1="4" x2="14" y2="4" ${BODY}/>`,
167
+ `<line x1="8" y1="8" x2="12" y2="8" ${BODY}/>`
168
+ ].join("")
169
+ };
170
+ var gnd_signal = {
171
+ length: 20,
172
+ anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
173
+ svg: () => [
174
+ `<line x1="0" y1="0" x2="8" y2="0" ${WIRE}/>`,
175
+ `<polygon points="8,-6 8,6 16,0" ${FILL}/>`
176
+ ].join("")
177
+ };
178
+ var vcc = {
179
+ length: 20,
180
+ anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
181
+ svg: () => [
182
+ `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
183
+ `<line x1="4" y1="-6" x2="16" y2="-6" ${BODY}/>`
184
+ ].join("")
185
+ };
186
+ var diode = {
187
+ length: 30,
188
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
189
+ svg: () => [
190
+ lineWire(0, 0, 8, 0),
191
+ `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
192
+ `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
193
+ lineWire(22, 0, 30, 0)
194
+ ].join("")
195
+ };
196
+ var zener = {
197
+ length: 30,
198
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
199
+ svg: () => [
200
+ lineWire(0, 0, 8, 0),
201
+ `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
202
+ `<path d="M 18,-10 L 22,-8 L 22,8 L 26,10" fill="none" ${BODY}/>`,
203
+ lineWire(22, 0, 30, 0)
204
+ ].join("")
205
+ };
206
+ var schottky = {
207
+ length: 30,
208
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
209
+ svg: () => [
210
+ lineWire(0, 0, 8, 0),
211
+ `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
212
+ `<path d="M 18,-4 L 18,-8 L 22,-8 L 22,8 L 26,8 L 26,4" fill="none" ${BODY}/>`,
213
+ lineWire(22, 0, 30, 0)
214
+ ].join("")
215
+ };
216
+ var led = {
217
+ length: 30,
218
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
219
+ svg: () => [
220
+ lineWire(0, 0, 8, 0),
221
+ `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
222
+ `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
223
+ lineWire(22, 0, 30, 0),
224
+ // outward light arrows
225
+ `<path d="M 12,-10 L 20,-18 M 18,-18 L 20,-18 L 20,-16" fill="none" ${BODY}/>`,
226
+ `<path d="M 16,-10 L 24,-18 M 22,-18 L 24,-18 L 24,-16" fill="none" ${BODY}/>`
227
+ ].join("")
228
+ };
229
+ var photodiode = {
230
+ length: 30,
231
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
232
+ svg: () => [
233
+ lineWire(0, 0, 8, 0),
234
+ `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
235
+ `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
236
+ lineWire(22, 0, 30, 0),
237
+ // inward light arrows
238
+ `<path d="M 20,-18 L 12,-10 M 12,-12 L 12,-10 L 14,-10" fill="none" ${BODY}/>`,
239
+ `<path d="M 24,-18 L 16,-10 M 16,-12 L 16,-10 L 18,-10" fill="none" ${BODY}/>`
240
+ ].join("")
241
+ };
242
+ var npn = {
243
+ length: 40,
244
+ netlistPins: ["c", "b", "e"],
245
+ // base at left, collector up-right, emitter down-right
246
+ anchors: {
247
+ start: { x: 0, y: 0 },
248
+ end: { x: 40, y: -16 },
249
+ base: { x: 0, y: 0 },
250
+ collector: { x: 40, y: -16 },
251
+ emitter: { x: 40, y: 16 },
252
+ b: { x: 0, y: 0 },
253
+ c: { x: 40, y: -16 },
254
+ e: { x: 40, y: 16 }
255
+ },
256
+ svg: () => [
257
+ `<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
258
+ `<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
259
+ lineWire(0, 0, 14, 0),
260
+ `<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
261
+ lineWire(30, -12, 40, -16),
262
+ `<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
263
+ lineWire(30, 12, 40, 16),
264
+ // NPN arrow (outward on emitter)
265
+ `<polygon points="30,12 24,10 26,16" ${FILL}/>`
266
+ ].join("")
267
+ };
268
+ var pnp = {
269
+ length: 40,
270
+ netlistPins: ["c", "b", "e"],
271
+ anchors: {
272
+ start: { x: 0, y: 0 },
273
+ end: { x: 40, y: -16 },
274
+ base: { x: 0, y: 0 },
275
+ collector: { x: 40, y: 16 },
276
+ emitter: { x: 40, y: -16 },
277
+ b: { x: 0, y: 0 },
278
+ c: { x: 40, y: 16 },
279
+ e: { x: 40, y: -16 }
280
+ },
281
+ svg: () => [
282
+ `<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
283
+ `<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
284
+ lineWire(0, 0, 14, 0),
285
+ `<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
286
+ lineWire(30, -12, 40, -16),
287
+ `<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
288
+ lineWire(30, 12, 40, 16),
289
+ // PNP arrow (inward on emitter → toward base line)
290
+ `<polygon points="14,-6 20,-4 18,-10" ${FILL}/>`
291
+ ].join("")
292
+ };
293
+ var nmos = {
294
+ length: 40,
295
+ netlistPins: ["d", "g", "s"],
296
+ anchors: {
297
+ start: { x: 0, y: 0 },
298
+ end: { x: 40, y: -16 },
299
+ gate: { x: 0, y: 0 },
300
+ drain: { x: 40, y: -16 },
301
+ source: { x: 40, y: 16 },
302
+ g: { x: 0, y: 0 },
303
+ d: { x: 40, y: -16 },
304
+ s: { x: 40, y: 16 }
305
+ },
306
+ svg: () => [
307
+ lineWire(0, 0, 14, 0),
308
+ `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
309
+ `<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
310
+ `<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
311
+ `<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
312
+ `<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
313
+ lineWire(32, -8, 40, -16),
314
+ `<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
315
+ lineWire(32, 8, 40, 16),
316
+ `<polygon points="22,0 18,-4 18,4" ${FILL}/>`
317
+ ].join("")
318
+ };
319
+ var pmos = {
320
+ length: 40,
321
+ netlistPins: ["d", "g", "s"],
322
+ anchors: {
323
+ start: { x: 0, y: 0 },
324
+ end: { x: 40, y: -16 },
325
+ gate: { x: 0, y: 0 },
326
+ source: { x: 40, y: -16 },
327
+ drain: { x: 40, y: 16 },
328
+ g: { x: 0, y: 0 },
329
+ s: { x: 40, y: -16 },
330
+ d: { x: 40, y: 16 }
331
+ },
332
+ svg: () => [
333
+ lineWire(0, 0, 14, 0),
334
+ `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
335
+ `<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
336
+ `<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
337
+ `<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
338
+ `<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
339
+ lineWire(32, -8, 40, -16),
340
+ `<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
341
+ lineWire(32, 8, 40, 16),
342
+ `<polygon points="14,0 18,-4 18,4" ${FILL}/>`
343
+ ].join("")
344
+ };
345
+ var jfet_n = {
666
346
  length: 40,
667
- // plus/minus aliases: end = +, start = − (matches on-symbol label)
347
+ netlistPins: ["d", "g", "s"],
668
348
  anchors: {
669
349
  start: { x: 0, y: 0 },
670
- end: { x: 40, y: 0 },
671
- minus: { x: 0, y: 0 },
672
- plus: { x: 40, y: 0 }
350
+ end: { x: 40, y: -16 },
351
+ gate: { x: 0, y: 0 },
352
+ drain: { x: 40, y: -16 },
353
+ source: { x: 40, y: 16 },
354
+ g: { x: 0, y: 0 },
355
+ d: { x: 40, y: -16 },
356
+ s: { x: 40, y: 16 }
673
357
  },
674
358
  svg: () => [
675
- lineWire(0, 0, 8, 0),
676
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
677
- `<text x="16" y="-2" class="schematex-circuit-pol">+</text>`,
678
- `<text x="23" y="8" class="schematex-circuit-pol">\u2212</text>`,
679
- lineWire(32, 0, 40, 0)
359
+ lineWire(0, 0, 14, 0),
360
+ `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
361
+ `<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
362
+ lineWire(32, -8, 40, -16),
363
+ `<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
364
+ lineWire(32, 8, 40, 16),
365
+ `<polygon points="14,0 10,-4 10,4" ${FILL}/>`
680
366
  ].join("")
681
367
  };
682
- var current_source = {
368
+ var jfet_p = {
683
369
  length: 40,
370
+ netlistPins: ["d", "g", "s"],
684
371
  anchors: {
685
372
  start: { x: 0, y: 0 },
686
- end: { x: 40, y: 0 },
687
- minus: { x: 0, y: 0 },
688
- plus: { x: 40, y: 0 }
373
+ end: { x: 40, y: -16 },
374
+ gate: { x: 0, y: 0 },
375
+ drain: { x: 40, y: -16 },
376
+ source: { x: 40, y: 16 },
377
+ g: { x: 0, y: 0 },
378
+ d: { x: 40, y: -16 },
379
+ s: { x: 40, y: 16 }
689
380
  },
690
381
  svg: () => [
691
- lineWire(0, 0, 8, 0),
692
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
693
- `<line x1="14" y1="0" x2="24" y2="0" ${BODY}/>`,
694
- `<polygon points="26,0 20,-4 20,4" ${FILL}/>`,
695
- lineWire(32, 0, 40, 0)
382
+ lineWire(0, 0, 14, 0),
383
+ `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
384
+ `<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
385
+ lineWire(32, -8, 40, -16),
386
+ `<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
387
+ lineWire(32, 8, 40, 16),
388
+ `<polygon points="10,0 14,-4 14,4" ${FILL}/>`
696
389
  ].join("")
697
390
  };
698
- var ac_source = {
699
- length: 40,
391
+ var opamp = {
392
+ length: 50,
393
+ netlistPins: ["plus", "minus", "out"],
700
394
  anchors: {
701
395
  start: { x: 0, y: 0 },
702
- end: { x: 40, y: 0 },
703
- minus: { x: 0, y: 0 },
704
- plus: { x: 40, y: 0 }
396
+ end: { x: 50, y: 0 },
397
+ plus: { x: 0, y: -10 },
398
+ minus: { x: 0, y: 10 },
399
+ out: { x: 50, y: 0 },
400
+ "supply+": { x: 25, y: -20 },
401
+ "supply-": { x: 25, y: 20 }
705
402
  },
706
403
  svg: () => [
707
- lineWire(0, 0, 8, 0),
708
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
709
- `<path d="M 14,0 Q 17,-6 20,0 Q 23,6 26,0" fill="none" ${BODY}/>`,
710
- lineWire(32, 0, 40, 0)
404
+ `<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
405
+ `<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
406
+ `<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`
711
407
  ].join("")
712
408
  };
713
- var battery = {
714
- length: 24,
409
+ var comparator = {
410
+ length: 50,
411
+ netlistPins: ["plus", "minus", "out"],
715
412
  anchors: {
716
413
  start: { x: 0, y: 0 },
717
- end: { x: 24, y: 0 },
718
- minus: { x: 0, y: 0 },
719
- plus: { x: 24, y: 0 }
414
+ end: { x: 50, y: 0 },
415
+ plus: { x: 0, y: -10 },
416
+ minus: { x: 0, y: 10 },
417
+ out: { x: 50, y: 0 }
720
418
  },
721
419
  svg: () => [
722
- lineWire(0, 0, 8, 0),
723
- `<line x1="8" y1="-8" x2="8" y2="8" ${BODY}/>`,
724
- `<line x1="12" y1="-4" x2="12" y2="4" ${BODY}/>`,
725
- `<line x1="14" y1="-8" x2="14" y2="8" ${BODY}/>`,
726
- `<line x1="18" y1="-4" x2="18" y2="4" ${BODY}/>`,
727
- lineWire(18, 0, 24, 0)
420
+ `<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
421
+ `<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
422
+ `<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`,
423
+ `<circle cx="48" cy="0" r="3" fill="white" ${BODY}/>`
728
424
  ].join("")
729
425
  };
730
- var ground = {
731
- length: 20,
732
- anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
733
- // Drawn as a "terminal" — vertical connection at start, earth lines below
426
+ var switch_spst = {
427
+ length: 40,
428
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
734
429
  svg: () => [
735
- `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
736
- `<line x1="10" y1="-8" x2="10" y2="8" ${BODY}/>`,
737
- `<line x1="6" y1="4" x2="14" y2="4" ${BODY}/>`,
738
- `<line x1="8" y1="8" x2="12" y2="8" ${BODY}/>`
430
+ lineWire(0, 0, 10, 0),
431
+ `<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
432
+ `<circle cx="10" cy="0" r="2" ${FILL}/>`,
433
+ `<circle cx="30" cy="0" r="2" ${FILL}/>`,
434
+ lineWire(30, 0, 40, 0)
739
435
  ].join("")
740
436
  };
741
- var gnd_signal = {
742
- length: 20,
743
- anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
437
+ var push_no = {
438
+ length: 40,
439
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
744
440
  svg: () => [
745
- `<line x1="0" y1="0" x2="8" y2="0" ${WIRE}/>`,
746
- `<polygon points="8,-6 8,6 16,0" ${FILL}/>`
441
+ lineWire(0, 0, 12, 0),
442
+ lineWire(28, 0, 40, 0),
443
+ `<circle cx="12" cy="0" r="2" ${FILL}/>`,
444
+ `<circle cx="28" cy="0" r="2" ${FILL}/>`,
445
+ `<line x1="12" y1="-4" x2="28" y2="-4" ${BODY}/>`,
446
+ `<line x1="20" y1="-4" x2="20" y2="-12" ${BODY}/>`,
447
+ `<line x1="14" y1="-12" x2="26" y2="-12" ${BODY}/>`
747
448
  ].join("")
748
449
  };
749
- var vcc = {
750
- length: 20,
751
- anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
450
+ var meterSvg = (letter) => () => [
451
+ lineWire(0, 0, 8, 0),
452
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
453
+ `<text x="20" y="4" text-anchor="middle" class="schematex-circuit-meter">${letter}</text>`,
454
+ lineWire(32, 0, 40, 0)
455
+ ].join("");
456
+ var ammeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("A") };
457
+ var voltmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("V") };
458
+ var wattmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("W") };
459
+ var motor = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("M") };
460
+ var lamp = {
461
+ length: 40,
462
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
752
463
  svg: () => [
753
- `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
754
- `<line x1="4" y1="-6" x2="16" y2="-6" ${BODY}/>`
464
+ lineWire(0, 0, 8, 0),
465
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
466
+ `<line x1="12" y1="-8" x2="28" y2="8" ${BODY}/>`,
467
+ `<line x1="12" y1="8" x2="28" y2="-8" ${BODY}/>`,
468
+ lineWire(32, 0, 40, 0)
755
469
  ].join("")
756
470
  };
757
- var diode = {
758
- length: 30,
759
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
471
+ var buzzer = {
472
+ length: 40,
473
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
760
474
  svg: () => [
761
475
  lineWire(0, 0, 8, 0),
762
- `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
763
- `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
764
- lineWire(22, 0, 30, 0)
476
+ `<path d="M 8,0 A 12,12 0 0 1 32,0 L 8,0 Z" fill="white" ${BODY}/>`,
477
+ lineWire(32, 0, 40, 0)
765
478
  ].join("")
766
479
  };
767
- var zener = {
768
- length: 30,
769
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
480
+ var speaker = {
481
+ length: 40,
482
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
770
483
  svg: () => [
771
- lineWire(0, 0, 8, 0),
772
- `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
773
- `<path d="M 18,-10 L 22,-8 L 22,8 L 26,10" fill="none" ${BODY}/>`,
774
- lineWire(22, 0, 30, 0)
484
+ lineWire(0, 0, 6, 0),
485
+ `<rect x="6" y="-8" width="10" height="16" fill="white" ${BODY}/>`,
486
+ `<path d="M 16,-8 L 28,-16 L 28,16 L 16,8 Z" fill="white" ${BODY}/>`,
487
+ lineWire(0, 8, 6, 8)
775
488
  ].join("")
776
489
  };
777
- var schottky = {
778
- length: 30,
779
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
490
+ var microphone = {
491
+ length: 40,
492
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
780
493
  svg: () => [
781
494
  lineWire(0, 0, 8, 0),
782
- `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
783
- `<path d="M 18,-4 L 18,-8 L 22,-8 L 22,8 L 26,8 L 26,4" fill="none" ${BODY}/>`,
784
- lineWire(22, 0, 30, 0)
495
+ `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
496
+ `<line x1="20" y1="-10" x2="20" y2="10" ${BODY}/>`,
497
+ lineWire(32, 0, 40, 0)
785
498
  ].join("")
786
499
  };
787
- var led = {
788
- length: 30,
789
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
500
+ var rheostat = {
501
+ length: 50,
502
+ anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
790
503
  svg: () => [
791
- lineWire(0, 0, 8, 0),
792
- `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
793
- `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
794
- lineWire(22, 0, 30, 0),
795
- // outward light arrows
796
- `<path d="M 12,-10 L 20,-18 M 18,-18 L 20,-18 L 20,-16" fill="none" ${BODY}/>`,
797
- `<path d="M 16,-10 L 24,-18 M 22,-18 L 24,-18 L 24,-16" fill="none" ${BODY}/>`
504
+ `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
505
+ `<line x1="5" y1="12" x2="45" y2="-12" ${BODY}/>`,
506
+ `<polygon points="45,-12 40,-9 44,-5" ${FILL}/>`
798
507
  ].join("")
799
508
  };
800
- var photodiode = {
801
- length: 30,
802
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
509
+ var thermistor_ntc = {
510
+ length: 50,
511
+ anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
803
512
  svg: () => [
804
- lineWire(0, 0, 8, 0),
805
- `<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
806
- `<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
807
- lineWire(22, 0, 30, 0),
808
- // inward light arrows
809
- `<path d="M 20,-18 L 12,-10 M 12,-12 L 12,-10 L 14,-10" fill="none" ${BODY}/>`,
810
- `<path d="M 24,-18 L 16,-10 M 16,-12 L 16,-10 L 18,-10" fill="none" ${BODY}/>`
513
+ `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
514
+ `<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
515
+ `<text x="40" y="-14" class="schematex-circuit-pol">-t\xB0</text>`
811
516
  ].join("")
812
517
  };
813
- var npn = {
814
- length: 40,
815
- // base at left, collector up-right, emitter down-right
816
- anchors: {
817
- start: { x: 0, y: 0 },
818
- end: { x: 40, y: -16 },
819
- base: { x: 0, y: 0 },
820
- collector: { x: 40, y: -16 },
821
- emitter: { x: 40, y: 16 },
822
- b: { x: 0, y: 0 },
823
- c: { x: 40, y: -16 },
824
- e: { x: 40, y: 16 }
825
- },
518
+ var thermistor_ptc = {
519
+ length: 50,
520
+ anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
521
+ svg: () => [
522
+ `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
523
+ `<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
524
+ `<text x="40" y="-14" class="schematex-circuit-pol">+t\xB0</text>`
525
+ ].join("")
526
+ };
527
+ var ldr = {
528
+ length: 50,
529
+ anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
530
+ svg: () => [
531
+ `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
532
+ `<circle cx="25" cy="-2" r="14" fill="none" ${BODY}/>`,
533
+ `<path d="M 10,-24 L 18,-16 M 14,-16 L 18,-16 L 18,-20" fill="none" ${BODY}/>`,
534
+ `<path d="M 20,-24 L 28,-16 M 24,-16 L 28,-16 L 28,-20" fill="none" ${BODY}/>`
535
+ ].join("")
536
+ };
537
+ var variable_cap = {
538
+ length: 24,
539
+ anchors: { start: { x: 0, y: 0 }, end: { x: 24, y: 0 } },
826
540
  svg: () => [
827
- `<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
541
+ lineWire(0, 0, 10, 0),
542
+ `<line x1="10" y1="-10" x2="10" y2="10" ${BODY}/>`,
828
543
  `<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
829
- lineWire(0, 0, 14, 0),
830
- `<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
831
- lineWire(30, -12, 40, -16),
832
- `<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
833
- lineWire(30, 12, 40, 16),
834
- // NPN arrow (outward on emitter)
835
- `<polygon points="30,12 24,10 26,16" ${FILL}/>`
544
+ lineWire(14, 0, 24, 0),
545
+ `<line x1="3" y1="10" x2="21" y2="-12" ${BODY}/>`,
546
+ `<polygon points="21,-12 15,-10 19,-6" ${FILL}/>`
836
547
  ].join("")
837
548
  };
838
- var pnp = {
549
+ var variable_inductor = {
839
550
  length: 40,
840
- anchors: {
841
- start: { x: 0, y: 0 },
842
- end: { x: 40, y: -16 },
843
- base: { x: 0, y: 0 },
844
- collector: { x: 40, y: 16 },
845
- emitter: { x: 40, y: -16 },
846
- b: { x: 0, y: 0 },
847
- c: { x: 40, y: 16 },
848
- e: { x: 40, y: -16 }
849
- },
551
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
850
552
  svg: () => [
851
- `<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
852
- `<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
853
- lineWire(0, 0, 14, 0),
854
- `<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
855
- lineWire(30, -12, 40, -16),
856
- `<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
857
- lineWire(30, 12, 40, 16),
858
- // PNP arrow (inward on emitter → toward base line)
859
- `<polygon points="14,-6 20,-4 18,-10" ${FILL}/>`
553
+ `<path d="M 0,0 L 5,0 A 5,5 0 0 1 15,0 A 5,5 0 0 1 25,0 A 5,5 0 0 1 35,0 L 40,0" fill="none" ${BODY}/>`,
554
+ `<line x1="0" y1="10" x2="38" y2="-14" ${BODY}/>`,
555
+ `<polygon points="38,-14 32,-12 36,-8" ${FILL}/>`
860
556
  ].join("")
861
557
  };
862
- var nmos = {
863
- length: 40,
558
+ var switch_spdt = {
559
+ length: 50,
560
+ netlistPins: ["common", "nc", "no"],
864
561
  anchors: {
865
562
  start: { x: 0, y: 0 },
866
- end: { x: 40, y: -16 },
867
- gate: { x: 0, y: 0 },
868
- drain: { x: 40, y: -16 },
869
- source: { x: 40, y: 16 },
870
- g: { x: 0, y: 0 },
871
- d: { x: 40, y: -16 },
872
- s: { x: 40, y: 16 }
563
+ end: { x: 50, y: 0 },
564
+ common: { x: 0, y: 0 },
565
+ nc: { x: 50, y: -12 },
566
+ no: { x: 50, y: 12 }
873
567
  },
874
568
  svg: () => [
875
- lineWire(0, 0, 14, 0),
876
- `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
877
- `<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
878
- `<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
879
- `<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
880
- `<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
881
- lineWire(32, -8, 40, -16),
882
- `<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
883
- lineWire(32, 8, 40, 16),
884
- `<polygon points="22,0 18,-4 18,4" ${FILL}/>`
569
+ lineWire(0, 0, 10, 0),
570
+ `<circle cx="10" cy="0" r="2" ${FILL}/>`,
571
+ `<line x1="10" y1="0" x2="40" y2="-12" ${BODY}/>`,
572
+ `<circle cx="42" cy="-12" r="2" ${FILL}/>`,
573
+ lineWire(42, -12, 50, -12),
574
+ `<circle cx="42" cy="12" r="2" ${FILL}/>`,
575
+ lineWire(42, 12, 50, 12)
885
576
  ].join("")
886
577
  };
887
- var pmos = {
578
+ var push_nc = {
888
579
  length: 40,
889
- anchors: {
890
- start: { x: 0, y: 0 },
891
- end: { x: 40, y: -16 },
892
- gate: { x: 0, y: 0 },
893
- source: { x: 40, y: -16 },
894
- drain: { x: 40, y: 16 },
895
- g: { x: 0, y: 0 },
896
- s: { x: 40, y: -16 },
897
- d: { x: 40, y: 16 }
898
- },
580
+ anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
899
581
  svg: () => [
900
- lineWire(0, 0, 14, 0),
901
- `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
902
- `<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
903
- `<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
904
- `<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
905
- `<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
906
- lineWire(32, -8, 40, -16),
907
- `<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
908
- lineWire(32, 8, 40, 16),
909
- `<polygon points="14,0 18,-4 18,4" ${FILL}/>`
582
+ lineWire(0, 0, 12, 0),
583
+ lineWire(28, 0, 40, 0),
584
+ `<circle cx="12" cy="0" r="2" ${FILL}/>`,
585
+ `<circle cx="28" cy="0" r="2" ${FILL}/>`,
586
+ `<line x1="10" y1="0" x2="30" y2="0" ${BODY}/>`,
587
+ `<line x1="20" y1="0" x2="20" y2="-10" ${BODY}/>`,
588
+ `<line x1="14" y1="-10" x2="26" y2="-10" ${BODY}/>`
910
589
  ].join("")
911
590
  };
912
- var jfet_n = {
913
- length: 40,
914
- anchors: {
915
- start: { x: 0, y: 0 },
916
- end: { x: 40, y: -16 },
917
- gate: { x: 0, y: 0 },
918
- drain: { x: 40, y: -16 },
919
- source: { x: 40, y: 16 }
920
- },
591
+ var gnd_chassis = {
592
+ length: 20,
593
+ anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
921
594
  svg: () => [
922
- lineWire(0, 0, 14, 0),
923
- `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
924
- `<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
925
- lineWire(32, -8, 40, -16),
926
- `<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
927
- lineWire(32, 8, 40, 16),
928
- `<polygon points="14,0 10,-4 10,4" ${FILL}/>`
595
+ `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
596
+ `<line x1="10" y1="-6" x2="10" y2="6" ${BODY}/>`,
597
+ `<line x1="10" y1="6" x2="14" y2="10" ${BODY}/>`,
598
+ `<line x1="10" y1="2" x2="14" y2="6" ${BODY}/>`,
599
+ `<line x1="10" y1="-2" x2="14" y2="2" ${BODY}/>`
929
600
  ].join("")
930
601
  };
931
- var jfet_p = {
932
- length: 40,
933
- anchors: {
934
- start: { x: 0, y: 0 },
935
- end: { x: 40, y: -16 },
936
- gate: { x: 0, y: 0 },
937
- drain: { x: 40, y: -16 },
938
- source: { x: 40, y: 16 }
939
- },
602
+ var gnd_digital = {
603
+ length: 20,
604
+ anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
940
605
  svg: () => [
941
- lineWire(0, 0, 14, 0),
942
- `<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
943
- `<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
944
- lineWire(32, -8, 40, -16),
945
- `<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
946
- lineWire(32, 8, 40, 16),
947
- `<polygon points="10,0 14,-4 14,4" ${FILL}/>`
606
+ `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
607
+ `<polygon points="8,-6 8,6 16,0" fill="none" ${BODY}/>`
948
608
  ].join("")
949
609
  };
950
- var opamp = {
951
- length: 50,
610
+ var test_point = {
611
+ length: 16,
612
+ anchors: { start: { x: 0, y: 0 }, end: { x: 16, y: 0 } },
613
+ svg: () => [
614
+ lineWire(0, 0, 6, 0),
615
+ `<circle cx="10" cy="0" r="4" fill="white" ${BODY}/>`
616
+ ].join("")
617
+ };
618
+ var no_connect = {
619
+ length: 0,
620
+ anchors: { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } },
621
+ svg: () => [
622
+ `<line x1="-5" y1="-5" x2="5" y2="5" ${BODY}/>`,
623
+ `<line x1="5" y1="-5" x2="-5" y2="5" ${BODY}/>`
624
+ ].join("")
625
+ };
626
+ var antenna = {
627
+ length: 30,
628
+ anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
629
+ svg: () => [
630
+ lineWire(0, 0, 0, -10),
631
+ `<line x1="0" y1="-10" x2="-10" y2="-24" ${BODY}/>`,
632
+ `<line x1="0" y1="-10" x2="10" y2="-24" ${BODY}/>`
633
+ ].join("")
634
+ };
635
+ function icSymbol(defaultLeft, defaultRight, bodyLabel) {
636
+ const BODY_W = 80;
637
+ return {
638
+ length: BODY_W,
639
+ netlistPins: [],
640
+ anchors: {
641
+ start: { x: 0, y: 0 },
642
+ end: { x: BODY_W, y: 0 }
643
+ },
644
+ svg: (_label, _value, attrs) => {
645
+ const left = attrs?.pins_left ? attrs.pins_left.split(",").map((s) => s.trim()) : defaultLeft;
646
+ const right = attrs?.pins_right ? attrs.pins_right.split(",").map((s) => s.trim()) : defaultRight;
647
+ const n = Math.max(left.length, right.length, 2);
648
+ const pitch = 16;
649
+ const bodyH = pitch * (n + 1);
650
+ const topY = -bodyH / 2;
651
+ const parts = [];
652
+ parts.push(`<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" fill="white" ${BODY}/>`);
653
+ const labelText = attrs?.ic_label ?? bodyLabel ?? "";
654
+ if (labelText) {
655
+ parts.push(`<text x="${BODY_W / 2}" y="3" text-anchor="middle" class="schematex-circuit-meter">${labelText}</text>`);
656
+ }
657
+ for (let i = 0; i < left.length; i++) {
658
+ const y = topY + pitch * (i + 1);
659
+ parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
660
+ parts.push(`<text x="4" y="${y + 3}" class="schematex-circuit-pol">${left[i]}</text>`);
661
+ }
662
+ for (let i = 0; i < right.length; i++) {
663
+ const y = topY + pitch * (i + 1);
664
+ parts.push(`<line x1="${BODY_W}" y1="${y}" x2="${BODY_W + 8}" y2="${y}" ${WIRE}/>`);
665
+ parts.push(`<text x="${BODY_W - 4}" y="${y + 3}" text-anchor="end" class="schematex-circuit-pol">${right[i]}</text>`);
666
+ }
667
+ return parts.join("");
668
+ }
669
+ };
670
+ }
671
+ var generic_ic = icSymbol(
672
+ ["1", "2", "3", "4"],
673
+ ["8", "7", "6", "5"],
674
+ "IC"
675
+ );
676
+ var timer_555 = (() => {
677
+ const left = ["GND", "TRG", "OUT", "RST"];
678
+ const right = ["VCC", "DIS", "THR", "CTL"];
679
+ const sym = icSymbol(left, right, "555");
680
+ const BODY_W = 80;
681
+ const pitch = 16;
682
+ const n = 4;
683
+ const topY = -80 / 2;
684
+ const anchors = {
685
+ start: { x: 0, y: 0 },
686
+ end: { x: BODY_W, y: 0 }
687
+ };
688
+ const leftNames = ["gnd", "trg", "out", "rst"];
689
+ const rightNames = ["vcc", "dis", "thr", "ctl"];
690
+ for (let i = 0; i < n; i++) {
691
+ const y = topY + pitch * (i + 1);
692
+ anchors[leftNames[i]] = { x: -8, y };
693
+ anchors[rightNames[i]] = { x: BODY_W + 8, y };
694
+ }
695
+ return { ...sym, anchors };
696
+ })();
697
+ var voltage_regulator = {
698
+ length: 60,
699
+ netlistPins: ["in", "gnd", "out"],
952
700
  anchors: {
953
701
  start: { x: 0, y: 0 },
954
- end: { x: 50, y: 0 },
955
- plus: { x: 0, y: -10 },
956
- minus: { x: 0, y: 10 },
957
- out: { x: 50, y: 0 },
958
- "supply+": { x: 25, y: -20 },
959
- "supply-": { x: 25, y: 20 }
702
+ end: { x: 60, y: 0 },
703
+ in: { x: 0, y: 0 },
704
+ out: { x: 60, y: 0 },
705
+ gnd: { x: 30, y: 20 }
960
706
  },
961
- svg: () => [
962
- `<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
963
- `<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
964
- `<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`
707
+ svg: (_l, _v, attrs) => [
708
+ lineWire(0, 0, 10, 0),
709
+ `<rect x="10" y="-15" width="40" height="30" fill="white" ${BODY}/>`,
710
+ `<text x="30" y="4" text-anchor="middle" class="schematex-circuit-meter">${attrs?.model ?? "REG"}</text>`,
711
+ lineWire(50, 0, 60, 0),
712
+ lineWire(30, 15, 30, 20)
965
713
  ].join("")
966
714
  };
967
- var comparator = {
715
+ var potentiometer = {
968
716
  length: 50,
717
+ netlistPins: ["start", "wiper", "end"],
969
718
  anchors: {
970
719
  start: { x: 0, y: 0 },
971
720
  end: { x: 50, y: 0 },
972
- plus: { x: 0, y: -10 },
973
- minus: { x: 0, y: 10 },
974
- out: { x: 50, y: 0 }
721
+ wiper: { x: 25, y: -22 }
975
722
  },
976
723
  svg: () => [
977
- `<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
978
- `<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
979
- `<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`,
980
- `<circle cx="48" cy="0" r="3" fill="white" ${BODY}/>`
981
- ].join("")
982
- };
983
- var switch_spst = {
984
- length: 40,
985
- anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
986
- svg: () => [
987
- lineWire(0, 0, 10, 0),
988
- `<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
989
- `<circle cx="10" cy="0" r="2" ${FILL}/>`,
990
- `<circle cx="30" cy="0" r="2" ${FILL}/>`,
991
- lineWire(30, 0, 40, 0)
992
- ].join("")
993
- };
994
- var push_no = {
995
- length: 40,
996
- anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
997
- svg: () => [
998
- lineWire(0, 0, 12, 0),
999
- lineWire(28, 0, 40, 0),
1000
- `<circle cx="12" cy="0" r="2" ${FILL}/>`,
1001
- `<circle cx="28" cy="0" r="2" ${FILL}/>`,
1002
- `<line x1="12" y1="-4" x2="28" y2="-4" ${BODY}/>`,
1003
- `<line x1="20" y1="-4" x2="20" y2="-12" ${BODY}/>`,
1004
- `<line x1="14" y1="-12" x2="26" y2="-12" ${BODY}/>`
724
+ `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
725
+ `<line x1="25" y1="-22" x2="25" y2="-10" ${BODY}/>`,
726
+ `<polygon points="25,-10 21,-16 29,-16" ${FILL}/>`
1005
727
  ].join("")
1006
728
  };
1007
- var meterSvg = (letter) => () => [
1008
- lineWire(0, 0, 8, 0),
1009
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
1010
- `<text x="20" y="4" text-anchor="middle" class="schematex-circuit-meter">${letter}</text>`,
1011
- lineWire(32, 0, 40, 0)
1012
- ].join("");
1013
- var ammeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("A") };
1014
- var voltmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("V") };
1015
- var wattmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("W") };
1016
- var motor = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("M") };
1017
- var lamp = {
1018
- length: 40,
1019
- anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1020
- svg: () => [
1021
- lineWire(0, 0, 8, 0),
1022
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
1023
- `<line x1="12" y1="-8" x2="28" y2="8" ${BODY}/>`,
1024
- `<line x1="12" y1="8" x2="28" y2="-8" ${BODY}/>`,
1025
- lineWire(32, 0, 40, 0)
1026
- ].join("")
729
+ var terminal_block = {
730
+ length: 80,
731
+ netlistPins: [],
732
+ anchors: { start: { x: 0, y: 0 }, end: { x: 80, y: 0 } },
733
+ svg: (label, _value, attrs) => {
734
+ const pinsAttr = attrs?.pins ?? attrs?.terminals ?? "1,2,3,4";
735
+ const pins = pinsAttr.split(",").map((s) => s.trim()).filter(Boolean);
736
+ const n = Math.max(pins.length, 1);
737
+ const BODY_W = 80;
738
+ const pitch = 18;
739
+ const bodyH = pitch * (n + 1);
740
+ const topY = -bodyH / 2;
741
+ const parts = [];
742
+ parts.push(
743
+ `<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" rx="3" fill="white" stroke-width="2" ${BODY}/>`
744
+ );
745
+ if (label) {
746
+ parts.push(
747
+ `<text x="${BODY_W / 2}" y="${topY + 14}" text-anchor="middle" class="schematex-circuit-meter">${label}</text>`
748
+ );
749
+ }
750
+ for (let i = 0; i < n; i++) {
751
+ const y = topY + pitch * (i + 1) + (label ? 8 : 0);
752
+ parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
753
+ parts.push(`<circle cx="6" cy="${y}" r="2" ${FILL}/>`);
754
+ parts.push(
755
+ `<text x="12" y="${y + 3}" class="schematex-circuit-pol">${pins[i] ?? `T${i + 1}`}</text>`
756
+ );
757
+ }
758
+ return parts.join("");
759
+ }
1027
760
  };
1028
- var buzzer = {
761
+ var relay_coil = {
1029
762
  length: 40,
1030
763
  anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1031
764
  svg: () => [
1032
765
  lineWire(0, 0, 8, 0),
1033
- `<path d="M 8,0 A 12,12 0 0 1 32,0 L 8,0 Z" fill="white" ${BODY}/>`,
766
+ `<rect x="8" y="-10" width="24" height="20" fill="white" ${BODY}/>`,
767
+ // Diagonal slash inside the box = coil winding indicator
768
+ `<line x1="8" y1="-10" x2="32" y2="10" ${BODY}/>`,
1034
769
  lineWire(32, 0, 40, 0)
1035
770
  ].join("")
1036
771
  };
1037
- var speaker = {
772
+ var relay_no = {
1038
773
  length: 40,
1039
774
  anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1040
775
  svg: () => [
1041
- lineWire(0, 0, 6, 0),
1042
- `<rect x="6" y="-8" width="10" height="16" fill="white" ${BODY}/>`,
1043
- `<path d="M 16,-8 L 28,-16 L 28,16 L 16,8 Z" fill="white" ${BODY}/>`,
1044
- lineWire(0, 8, 6, 8)
776
+ lineWire(0, 0, 10, 0),
777
+ `<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
778
+ `<circle cx="10" cy="0" r="2" ${FILL}/>`,
779
+ `<circle cx="30" cy="0" r="2" ${FILL}/>`,
780
+ // Small dashed bar above to denote actuator-driven (vs hand switch)
781
+ `<line x1="14" y1="-14" x2="26" y2="-14" stroke-dasharray="2,2" ${BODY}/>`,
782
+ lineWire(30, 0, 40, 0)
1045
783
  ].join("")
1046
784
  };
1047
- var microphone = {
785
+ var relay_nc = {
1048
786
  length: 40,
1049
787
  anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1050
788
  svg: () => [
1051
- lineWire(0, 0, 8, 0),
1052
- `<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
1053
- `<line x1="20" y1="-10" x2="20" y2="10" ${BODY}/>`,
1054
- lineWire(32, 0, 40, 0)
1055
- ].join("")
1056
- };
1057
- var rheostat = {
1058
- length: 50,
1059
- anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
1060
- svg: () => [
1061
- `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
1062
- `<line x1="5" y1="12" x2="45" y2="-12" ${BODY}/>`,
1063
- `<polygon points="45,-12 40,-9 44,-5" ${FILL}/>`
1064
- ].join("")
1065
- };
1066
- var thermistor_ntc = {
1067
- length: 50,
1068
- anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
1069
- svg: () => [
1070
- `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
1071
- `<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
1072
- `<text x="40" y="-14" class="schematex-circuit-pol">-t\xB0</text>`
789
+ lineWire(0, 0, 10, 0),
790
+ `<line x1="10" y1="-10" x2="30" y2="-10" ${BODY}/>`,
791
+ // NC slash: line crosses both contact endpoints (closed by default)
792
+ `<line x1="8" y1="2" x2="32" y2="-12" ${BODY}/>`,
793
+ `<circle cx="10" cy="0" r="2" ${FILL}/>`,
794
+ `<circle cx="30" cy="0" r="2" ${FILL}/>`,
795
+ `<line x1="14" y1="-14" x2="26" y2="-14" stroke-dasharray="2,2" ${BODY}/>`,
796
+ lineWire(30, 0, 40, 0)
1073
797
  ].join("")
1074
798
  };
1075
- var thermistor_ptc = {
1076
- length: 50,
1077
- anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
799
+ var contactor = {
800
+ length: 44,
801
+ anchors: { start: { x: 0, y: 0 }, end: { x: 44, y: 0 } },
1078
802
  svg: () => [
1079
- `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
1080
- `<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
1081
- `<text x="40" y="-14" class="schematex-circuit-pol">+t\xB0</text>`
803
+ lineWire(0, 0, 10, 0),
804
+ // Two parallel diagonal contacts = double-break (typical of contactors)
805
+ `<line x1="10" y1="0" x2="30" y2="-10" stroke-width="2.5" ${BODY}/>`,
806
+ `<line x1="14" y1="2" x2="34" y2="-8" stroke-width="2.5" ${BODY}/>`,
807
+ `<circle cx="10" cy="0" r="2" ${FILL}/>`,
808
+ `<circle cx="34" cy="0" r="2" ${FILL}/>`,
809
+ // Solid bar above = electromagnetic-driven actuator
810
+ `<line x1="14" y1="-14" x2="30" y2="-14" stroke-width="2" ${BODY}/>`,
811
+ lineWire(34, 0, 44, 0)
1082
812
  ].join("")
1083
813
  };
1084
- var ldr = {
814
+ var solenoid_valve = {
1085
815
  length: 50,
1086
816
  anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
1087
817
  svg: () => [
1088
- `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
1089
- `<circle cx="25" cy="-2" r="14" fill="none" ${BODY}/>`,
1090
- `<path d="M 10,-24 L 18,-16 M 14,-16 L 18,-16 L 18,-20" fill="none" ${BODY}/>`,
1091
- `<path d="M 20,-24 L 28,-16 M 24,-16 L 28,-16 L 28,-20" fill="none" ${BODY}/>`
1092
- ].join("")
1093
- };
1094
- var variable_cap = {
1095
- length: 24,
1096
- anchors: { start: { x: 0, y: 0 }, end: { x: 24, y: 0 } },
1097
- svg: () => [
1098
- lineWire(0, 0, 10, 0),
1099
- `<line x1="10" y1="-10" x2="10" y2="10" ${BODY}/>`,
1100
- `<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
1101
- lineWire(14, 0, 24, 0),
1102
- `<line x1="3" y1="10" x2="21" y2="-12" ${BODY}/>`,
1103
- `<polygon points="21,-12 15,-10 19,-6" ${FILL}/>`
818
+ lineWire(0, 0, 8, 0),
819
+ // Solenoid box on top
820
+ `<rect x="8" y="-22" width="14" height="12" fill="white" ${BODY}/>`,
821
+ `<line x1="8" y1="-22" x2="22" y2="-10" ${BODY}/>`,
822
+ // Valve body (triangle pair = IEC valve symbol)
823
+ `<polygon points="22,0 38,-8 38,8" fill="white" ${BODY}/>`,
824
+ `<polygon points="22,0 8,-8 8,8" fill="white" ${BODY}/>`,
825
+ // Connect solenoid to valve body (actuator line)
826
+ `<line x1="15" y1="-10" x2="22" y2="0" ${BODY}/>`,
827
+ lineWire(38, 0, 50, 0)
1104
828
  ].join("")
1105
829
  };
1106
- var variable_inductor = {
830
+ var thermal_overload = {
1107
831
  length: 40,
1108
832
  anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1109
833
  svg: () => [
1110
- `<path d="M 0,0 L 5,0 A 5,5 0 0 1 15,0 A 5,5 0 0 1 25,0 A 5,5 0 0 1 35,0 L 40,0" fill="none" ${BODY}/>`,
1111
- `<line x1="0" y1="10" x2="38" y2="-14" ${BODY}/>`,
1112
- `<polygon points="38,-14 32,-12 36,-8" ${FILL}/>`
834
+ lineWire(0, 0, 8, 0),
835
+ `<rect x="8" y="-12" width="24" height="24" fill="white" ${BODY}/>`,
836
+ // Bimetal element: bent line inside box
837
+ `<path d="M 12,-6 L 16,4 L 20,-6 L 24,4 L 28,-6" fill="none" ${BODY}/>`,
838
+ lineWire(32, 0, 40, 0)
1113
839
  ].join("")
1114
840
  };
1115
- var switch_spdt = {
1116
- length: 50,
1117
- anchors: {
1118
- start: { x: 0, y: 0 },
1119
- end: { x: 50, y: 0 },
1120
- common: { x: 0, y: 0 },
1121
- nc: { x: 50, y: -12 },
1122
- no: { x: 50, y: 12 }
1123
- },
841
+ var disconnect_switch = {
842
+ length: 48,
843
+ anchors: { start: { x: 0, y: 0 }, end: { x: 48, y: 0 } },
1124
844
  svg: () => [
1125
845
  lineWire(0, 0, 10, 0),
846
+ `<line x1="10" y1="0" x2="34" y2="-12" ${BODY}/>`,
1126
847
  `<circle cx="10" cy="0" r="2" ${FILL}/>`,
1127
- `<line x1="10" y1="0" x2="40" y2="-12" ${BODY}/>`,
1128
- `<circle cx="42" cy="-12" r="2" ${FILL}/>`,
1129
- lineWire(42, -12, 50, -12),
1130
- `<circle cx="42" cy="12" r="2" ${FILL}/>`,
1131
- lineWire(42, 12, 50, 12)
848
+ // Hollow square at top of arm = visible-isolation indicator
849
+ `<rect x="30" y="-16" width="8" height="8" fill="white" ${BODY}/>`,
850
+ `<circle cx="38" cy="0" r="2" ${FILL}/>`,
851
+ lineWire(38, 0, 48, 0)
1132
852
  ].join("")
1133
853
  };
1134
- var push_nc = {
1135
- length: 40,
1136
- anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
1137
- svg: () => [
1138
- lineWire(0, 0, 12, 0),
1139
- lineWire(28, 0, 40, 0),
1140
- `<circle cx="12" cy="0" r="2" ${FILL}/>`,
1141
- `<circle cx="28" cy="0" r="2" ${FILL}/>`,
1142
- `<line x1="10" y1="0" x2="30" y2="0" ${BODY}/>`,
1143
- `<line x1="20" y1="0" x2="20" y2="-10" ${BODY}/>`,
1144
- `<line x1="14" y1="-10" x2="26" y2="-10" ${BODY}/>`
1145
- ].join("")
854
+ var SYMBOLS = {
855
+ resistor,
856
+ capacitor,
857
+ electrolytic_cap,
858
+ inductor,
859
+ fuse,
860
+ crystal,
861
+ transformer,
862
+ voltage_source,
863
+ current_source,
864
+ ac_source,
865
+ battery,
866
+ ground,
867
+ gnd_signal,
868
+ vcc,
869
+ diode,
870
+ zener,
871
+ schottky,
872
+ led,
873
+ photodiode,
874
+ npn,
875
+ pnp,
876
+ nmos,
877
+ pmos,
878
+ jfet_n,
879
+ jfet_p,
880
+ opamp,
881
+ comparator,
882
+ switch_spst,
883
+ push_no,
884
+ ammeter,
885
+ voltmeter,
886
+ wattmeter,
887
+ motor,
888
+ speaker,
889
+ microphone,
890
+ buzzer,
891
+ potentiometer,
892
+ rheostat,
893
+ thermistor_ntc,
894
+ thermistor_ptc,
895
+ ldr,
896
+ variable_cap,
897
+ variable_inductor,
898
+ switch_spdt,
899
+ push_nc,
900
+ gnd_chassis,
901
+ gnd_digital,
902
+ test_point,
903
+ no_connect,
904
+ antenna,
905
+ generic_ic,
906
+ terminal_block,
907
+ "555_timer": timer_555,
908
+ voltage_regulator,
909
+ // Industrial control / power electrical (IEC 60617)
910
+ relay_coil,
911
+ relay_no,
912
+ relay_nc,
913
+ contactor,
914
+ solenoid_valve,
915
+ thermal_overload,
916
+ disconnect_switch
917
+ // Lamp reuses buzzer slot? No, needs its own entry but our CircuitComponentType
918
+ // doesn't have "lamp". We map it via parser alias to "buzzer" or add specifically.
1146
919
  };
1147
- var gnd_chassis = {
1148
- length: 20,
1149
- anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
1150
- svg: () => [
1151
- `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
1152
- `<line x1="10" y1="-6" x2="10" y2="6" ${BODY}/>`,
1153
- `<line x1="10" y1="6" x2="14" y2="10" ${BODY}/>`,
1154
- `<line x1="10" y1="2" x2="14" y2="6" ${BODY}/>`,
1155
- `<line x1="10" y1="-2" x2="14" y2="2" ${BODY}/>`
1156
- ].join("")
920
+ var EXTRA_SYMBOLS = {
921
+ lamp
922
+ };
923
+ function getSymbol(t) {
924
+ return SYMBOLS[t] ?? EXTRA_SYMBOLS[t];
925
+ }
926
+ function getNetlistPinOrder(t) {
927
+ const sym = getSymbol(t);
928
+ if (!sym) return void 0;
929
+ if (sym.netlistPins) return [...sym.netlistPins];
930
+ if (sym.anchors.start && sym.anchors.end) return ["start", "end"];
931
+ return Object.keys(sym.anchors);
932
+ }
933
+
934
+ // src/diagrams/circuit/netlist.ts
935
+ var NetlistParseError = class extends Error {
936
+ constructor(message, line) {
937
+ super(message);
938
+ this.line = line;
939
+ this.name = "NetlistParseError";
940
+ }
941
+ line;
1157
942
  };
1158
- var gnd_digital = {
1159
- length: 20,
1160
- anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
1161
- svg: () => [
1162
- `<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
1163
- `<polygon points="8,-6 8,6 16,0" fill="none" ${BODY}/>`
1164
- ].join("")
943
+ var PREFIX_MAP = {
944
+ R: { type: "resistor", pins: ["start", "end"] },
945
+ C: { type: "capacitor", pins: ["start", "end"] },
946
+ L: { type: "inductor", pins: ["start", "end"] },
947
+ D: { type: "diode", pins: ["start", "end"] },
948
+ // anode start, cathode → end
949
+ V: { type: "voltage_source", pins: ["plus", "minus"] },
950
+ I: { type: "current_source", pins: ["plus", "minus"] },
951
+ Q: { type: "npn", pins: ["c", "b", "e"] },
952
+ M: { type: "nmos", pins: ["d", "g", "s"] },
953
+ J: { type: "jfet_n", pins: ["d", "g", "s"] },
954
+ S: { type: "switch_spst", pins: ["start", "end"] },
955
+ F: { type: "fuse", pins: ["start", "end"] },
956
+ B: { type: "battery", pins: ["plus", "minus"] },
957
+ K: { type: "relay_coil", pins: ["start", "end"] },
958
+ U: { type: "generic_ic", pins: [] },
959
+ // pins declared via pins="..." attr
960
+ X: { type: "generic_ic", pins: [] },
961
+ W: { type: "wire", pins: ["start", "end"] },
962
+ // explicit wire (non-SPICE convention, common in EE textbooks)
963
+ T: { type: "terminal_block", pins: [] }
964
+ // pins via pins="..."
1165
965
  };
1166
- var test_point = {
1167
- length: 16,
1168
- anchors: { start: { x: 0, y: 0 }, end: { x: 16, y: 0 } },
1169
- svg: () => [
1170
- lineWire(0, 0, 6, 0),
1171
- `<circle cx="10" cy="0" r="4" fill="white" ${BODY}/>`
1172
- ].join("")
966
+ var TYPE_ALIASES = {
967
+ vsource: "voltage_source",
968
+ isource: "current_source",
969
+ acsource: "ac_source",
970
+ ecap: "electrolytic_cap",
971
+ pot: "potentiometer",
972
+ gnd: "ground",
973
+ ic: "generic_ic",
974
+ reg: "voltage_regulator",
975
+ timer555: "555_timer",
976
+ transistor: "npn",
977
+ tb: "terminal_block",
978
+ junction_box: "terminal_block",
979
+ jbox: "terminal_block",
980
+ enclosure: "terminal_block"
1173
981
  };
1174
- var no_connect = {
1175
- length: 0,
1176
- anchors: { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } },
1177
- svg: () => [
1178
- `<line x1="-5" y1="-5" x2="5" y2="5" ${BODY}/>`,
1179
- `<line x1="5" y1="-5" x2="-5" y2="5" ${BODY}/>`
1180
- ].join("")
982
+ var GROUND_REF = /^(0|gnd|ground|earth|pe|agnd|dgnd|gnda|gndd|vss|com)(_\w+|\d+)?$/i;
983
+ function isGroundRef(s) {
984
+ return GROUND_REF.test(s);
985
+ }
986
+ function tokenize(line) {
987
+ const tokens = [];
988
+ let i = 0;
989
+ while (i < line.length) {
990
+ const ch = line[i];
991
+ if (ch === " " || ch === " ") {
992
+ i++;
993
+ continue;
994
+ }
995
+ if (ch === '"') {
996
+ const end = line.indexOf('"', i + 1);
997
+ tokens.push(line.slice(i, end < 0 ? line.length : end + 1));
998
+ i = end < 0 ? line.length : end + 1;
999
+ continue;
1000
+ }
1001
+ let j = i;
1002
+ while (j < line.length && line[j] !== " " && line[j] !== " ") {
1003
+ if (line[j] === "=" && line[j + 1] === '"') {
1004
+ const end = line.indexOf('"', j + 2);
1005
+ j = end < 0 ? line.length : end + 1;
1006
+ break;
1007
+ }
1008
+ j++;
1009
+ }
1010
+ tokens.push(line.slice(i, j));
1011
+ i = j;
1012
+ }
1013
+ return tokens;
1014
+ }
1015
+ function isKeyEqVal(tok) {
1016
+ const eq = tok.indexOf("=");
1017
+ return eq > 0 && /^[a-zA-Z_][\w]*$/.test(tok.slice(0, eq));
1018
+ }
1019
+ function parseKV(tok) {
1020
+ const eq = tok.indexOf("=");
1021
+ const key = tok.slice(0, eq).trim();
1022
+ let val = tok.slice(eq + 1).trim();
1023
+ if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
1024
+ return [key, val];
1025
+ }
1026
+ function parseNetlist(body, title2) {
1027
+ const components = [];
1028
+ const netByName = /* @__PURE__ */ new Map();
1029
+ const pinMap = {};
1030
+ let autoGnd = 0;
1031
+ const ensureNet = (name) => {
1032
+ let n = netByName.get(name);
1033
+ if (!n) {
1034
+ n = { id: name, anchors: [] };
1035
+ netByName.set(name, n);
1036
+ }
1037
+ return n;
1038
+ };
1039
+ const lines = body.split("\n").map((l) => l.replace(/\r$/, ""));
1040
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
1041
+ const raw = lines[lineIdx];
1042
+ const stripped = raw.replace(/#.*$/, "").trim();
1043
+ if (!stripped) continue;
1044
+ const tokens = tokenize(stripped);
1045
+ if (tokens.length < 2) {
1046
+ throw new NetlistParseError(
1047
+ `Netlist line must have at least ID + one net: "${stripped}"`,
1048
+ lineIdx + 1
1049
+ );
1050
+ }
1051
+ const id = tokens[0];
1052
+ if (!/^[a-zA-Z_][\w]*$/.test(id)) {
1053
+ throw new NetlistParseError(`Invalid component id: "${id}"`, lineIdx + 1);
1054
+ }
1055
+ let cursor = 1;
1056
+ const netRefs = [];
1057
+ while (cursor < tokens.length && !isKeyEqVal(tokens[cursor])) {
1058
+ netRefs.push(tokens[cursor]);
1059
+ cursor++;
1060
+ }
1061
+ const kv = {};
1062
+ for (; cursor < tokens.length; cursor++) {
1063
+ if (!isKeyEqVal(tokens[cursor])) {
1064
+ throw new NetlistParseError(
1065
+ `Expected key=value after nets, got "${tokens[cursor]}"`,
1066
+ lineIdx + 1
1067
+ );
1068
+ }
1069
+ const [k, v] = parseKV(tokens[cursor]);
1070
+ kv[k] = v;
1071
+ }
1072
+ const prefix = id[0].toUpperCase();
1073
+ const defaults = PREFIX_MAP[prefix];
1074
+ let cType;
1075
+ let pinOrder;
1076
+ if (kv.type) {
1077
+ const t = kv.type.toLowerCase();
1078
+ cType = TYPE_ALIASES[t] ?? t;
1079
+ pinOrder = getNetlistPinOrder(cType) ?? defaults?.pins ?? ["start", "end"];
1080
+ } else if (defaults) {
1081
+ cType = defaults.type;
1082
+ pinOrder = defaults.pins;
1083
+ } else if (isGroundRef(id)) {
1084
+ cType = "ground";
1085
+ pinOrder = ["start"];
1086
+ } else {
1087
+ throw new NetlistParseError(
1088
+ `Cannot infer type from id "${id}". Either rename to a SPICE-prefix id (R*, C*, L*, D*, V*, I*, Q*, M*, J*, S*, F*, B*, K*, U*, X*, W*, T*) or pass an explicit \`type=<name>\` attribute (e.g. \`${id} ... type=resistor\`). Schematex circuit covers electrical schematics only \u2014 hydraulic/pneumatic prefixes (EV*, BOMBA*, TANK*, etc.) are not supported.`,
1089
+ lineIdx + 1
1090
+ );
1091
+ }
1092
+ const expectedPins = pinOrder.length;
1093
+ let valueFromTail;
1094
+ if (netRefs.length > expectedPins && expectedPins > 0) {
1095
+ const tail = netRefs.slice(expectedPins);
1096
+ netRefs.length = expectedPins;
1097
+ const first = tail[0].toLowerCase();
1098
+ if (TYPE_ALIASES[first]) {
1099
+ cType = TYPE_ALIASES[first];
1100
+ pinOrder = getNetlistPinOrder(cType) ?? pinOrder;
1101
+ } else if (first === "npn" || first === "pnp" || first === "nmos" || first === "pmos" || first === "jfet_n" || first === "jfet_p" || first === "zener" || first === "schottky" || first === "led" || first === "photodiode") {
1102
+ cType = first;
1103
+ pinOrder = getNetlistPinOrder(cType) ?? pinOrder;
1104
+ } else {
1105
+ valueFromTail = tail.join(" ");
1106
+ }
1107
+ if (tail.length > 1 && !valueFromTail) {
1108
+ valueFromTail = tail.slice(1).join(" ");
1109
+ }
1110
+ }
1111
+ if (cType === "ground" || cType === "gnd_signal" || cType === "gnd_chassis" || cType === "gnd_digital") {
1112
+ pinOrder = ["start"];
1113
+ }
1114
+ if (cType === "terminal_block") {
1115
+ const pinsAttr = kv.pins ?? kv.terminals;
1116
+ const labels = pinsAttr ? pinsAttr.split(",").map((s) => s.trim()).filter(Boolean) : Array.from({ length: Math.max(netRefs.length, 1) }, (_, i) => `t${i + 1}`);
1117
+ pinOrder = labels.map(
1118
+ (label, idx) => label.toLowerCase().replace(/[^a-z0-9]+/g, "_") || `t${idx + 1}`
1119
+ );
1120
+ }
1121
+ if (netRefs.length < pinOrder.length) {
1122
+ throw new NetlistParseError(
1123
+ `Component ${id} (${cType}) expects ${pinOrder.length} nets, got ${netRefs.length}`,
1124
+ lineIdx + 1
1125
+ );
1126
+ }
1127
+ const pins = {};
1128
+ for (let p = 0; p < pinOrder.length; p++) {
1129
+ let net = netRefs[p];
1130
+ if (isGroundRef(net)) net = "GND";
1131
+ pins[pinOrder[p]] = net;
1132
+ ensureNet(net).anchors.push(`${id}.${pinOrder[p]}`);
1133
+ }
1134
+ pinMap[id] = pins;
1135
+ const comp = {
1136
+ id,
1137
+ componentType: cType,
1138
+ direction: "right",
1139
+ label: kv.label ?? id,
1140
+ value: kv.value ?? valueFromTail,
1141
+ attrs: {}
1142
+ };
1143
+ for (const [k, v] of Object.entries(kv)) {
1144
+ if (k === "label" || k === "value" || k === "type") continue;
1145
+ comp.attrs[k] = v;
1146
+ }
1147
+ components.push(comp);
1148
+ }
1149
+ if (netByName.has("GND")) {
1150
+ const hasGroundSym = components.some(
1151
+ (c) => c.componentType === "ground" || c.componentType === "gnd_signal" || c.componentType === "gnd_chassis" || c.componentType === "gnd_digital"
1152
+ );
1153
+ if (!hasGroundSym) {
1154
+ const gId = `_GND${autoGnd++}`;
1155
+ components.push({
1156
+ id: gId,
1157
+ componentType: "ground",
1158
+ direction: "down",
1159
+ label: void 0,
1160
+ value: void 0,
1161
+ attrs: { auto: "true" }
1162
+ });
1163
+ pinMap[gId] = { start: "GND" };
1164
+ ensureNet("GND").anchors.push(`${gId}.start`);
1165
+ }
1166
+ }
1167
+ const nets = Array.from(netByName.values());
1168
+ return {
1169
+ type: "circuit",
1170
+ title: title2,
1171
+ components,
1172
+ nets,
1173
+ pinMap,
1174
+ mode: "netlist"
1175
+ };
1176
+ }
1177
+
1178
+ // src/diagrams/circuit/parser.ts
1179
+ var CircuitParseError = class extends Error {
1180
+ constructor(message) {
1181
+ super(message);
1182
+ this.name = "CircuitParseError";
1183
+ }
1181
1184
  };
1182
- var antenna = {
1183
- length: 30,
1184
- anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
1185
- svg: () => [
1186
- lineWire(0, 0, 0, -10),
1187
- `<line x1="0" y1="-10" x2="-10" y2="-24" ${BODY}/>`,
1188
- `<line x1="0" y1="-10" x2="10" y2="-24" ${BODY}/>`
1189
- ].join("")
1185
+ var COMPONENT_TYPES = /* @__PURE__ */ new Set([
1186
+ "resistor",
1187
+ "potentiometer",
1188
+ "rheostat",
1189
+ "thermistor_ntc",
1190
+ "thermistor_ptc",
1191
+ "ldr",
1192
+ "varistor",
1193
+ "fuse",
1194
+ "fuse_slow",
1195
+ "capacitor",
1196
+ "electrolytic_cap",
1197
+ "variable_cap",
1198
+ "inductor",
1199
+ "inductor_iron",
1200
+ "inductor_ferrite",
1201
+ "variable_inductor",
1202
+ "ferrite_bead",
1203
+ "crystal",
1204
+ "transformer",
1205
+ "diode",
1206
+ "zener",
1207
+ "schottky",
1208
+ "led",
1209
+ "photodiode",
1210
+ "varactor",
1211
+ "tvs_diode",
1212
+ "bridge_rectifier",
1213
+ "npn",
1214
+ "pnp",
1215
+ "darlington_npn",
1216
+ "darlington_pnp",
1217
+ "nmos",
1218
+ "pmos",
1219
+ "nmos_depletion",
1220
+ "jfet_n",
1221
+ "jfet_p",
1222
+ "igbt",
1223
+ "scr",
1224
+ "triac",
1225
+ "diac",
1226
+ "phototransistor",
1227
+ "optocoupler",
1228
+ "opamp",
1229
+ "comparator",
1230
+ "schmitt_buffer",
1231
+ "tri_state_buffer",
1232
+ "instrumentation_amp",
1233
+ "generic_ic",
1234
+ "voltage_regulator",
1235
+ "dc_dc_converter",
1236
+ "555_timer",
1237
+ "voltage_source",
1238
+ "current_source",
1239
+ "ac_source",
1240
+ "battery",
1241
+ "vcc",
1242
+ "ground",
1243
+ "gnd_signal",
1244
+ "gnd_chassis",
1245
+ "gnd_digital",
1246
+ "switch_spst",
1247
+ "switch_spdt",
1248
+ "switch_dpdt",
1249
+ "push_no",
1250
+ "push_nc",
1251
+ "relay_coil",
1252
+ "relay_no",
1253
+ "relay_nc",
1254
+ "contactor",
1255
+ "solenoid_valve",
1256
+ "thermal_overload",
1257
+ "disconnect_switch",
1258
+ "motor",
1259
+ "speaker",
1260
+ "microphone",
1261
+ "buzzer",
1262
+ "ammeter",
1263
+ "voltmeter",
1264
+ "wattmeter",
1265
+ "oscilloscope",
1266
+ "wire",
1267
+ "dot",
1268
+ "label",
1269
+ "port",
1270
+ "test_point",
1271
+ "no_connect",
1272
+ "antenna"
1273
+ ]);
1274
+ var ALIASES = {
1275
+ vsource: "voltage_source",
1276
+ isource: "current_source",
1277
+ acsource: "ac_source",
1278
+ ecap: "electrolytic_cap",
1279
+ pot: "potentiometer",
1280
+ xtal: "crystal",
1281
+ xfmr: "transformer",
1282
+ transistor: "npn",
1283
+ bjt_npn: "npn",
1284
+ bjt_pnp: "pnp",
1285
+ mosfet_n: "nmos",
1286
+ mosfet_p: "pmos",
1287
+ gnd: "ground",
1288
+ ic: "generic_ic",
1289
+ reg: "voltage_regulator",
1290
+ timer555: "555_timer",
1291
+ therm: "thermistor_ntc",
1292
+ ntc: "thermistor_ntc",
1293
+ ptc: "thermistor_ptc",
1294
+ ths: "thermistor_ntc",
1295
+ // Industrial control aliases (IEC letter codes)
1296
+ coil: "relay_coil",
1297
+ relay: "relay_coil",
1298
+ km: "contactor",
1299
+ solenoid: "solenoid_valve",
1300
+ ev: "solenoid_valve",
1301
+ overload: "thermal_overload",
1302
+ thermal: "thermal_overload",
1303
+ disconnect: "disconnect_switch",
1304
+ isolator: "disconnect_switch"
1190
1305
  };
1191
- function icSymbol(defaultLeft, defaultRight, bodyLabel) {
1192
- const BODY_W = 80;
1193
- return {
1194
- length: BODY_W,
1195
- anchors: {
1196
- start: { x: 0, y: 0 },
1197
- end: { x: BODY_W, y: 0 }
1198
- },
1199
- svg: (_label, _value, attrs) => {
1200
- const left = attrs?.pins_left ? attrs.pins_left.split(",").map((s) => s.trim()) : defaultLeft;
1201
- const right = attrs?.pins_right ? attrs.pins_right.split(",").map((s) => s.trim()) : defaultRight;
1202
- const n = Math.max(left.length, right.length, 2);
1203
- const pitch = 16;
1204
- const bodyH = pitch * (n + 1);
1205
- const topY = -bodyH / 2;
1206
- const parts = [];
1207
- parts.push(`<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" fill="white" ${BODY}/>`);
1208
- const labelText = attrs?.ic_label ?? bodyLabel ?? "";
1209
- if (labelText) {
1210
- parts.push(`<text x="${BODY_W / 2}" y="3" text-anchor="middle" class="schematex-circuit-meter">${labelText}</text>`);
1306
+ var EXTRA_TYPES = /* @__PURE__ */ new Set(["lamp"]);
1307
+ function normalizeType(raw) {
1308
+ const lower = raw.toLowerCase();
1309
+ if (ALIASES[lower]) return ALIASES[lower];
1310
+ if (COMPONENT_TYPES.has(lower)) {
1311
+ return lower;
1312
+ }
1313
+ if (EXTRA_TYPES.has(lower)) {
1314
+ return lower;
1315
+ }
1316
+ return null;
1317
+ }
1318
+ var DIRECTIONS = /* @__PURE__ */ new Set(["right", "left", "up", "down"]);
1319
+ function parseAttrs(rest) {
1320
+ const out = { attrs: {} };
1321
+ const tokens = [];
1322
+ let i = 0;
1323
+ while (i < rest.length) {
1324
+ const ch = rest[i];
1325
+ if (ch === " " || ch === " ") {
1326
+ i++;
1327
+ continue;
1328
+ }
1329
+ if (ch === '"') {
1330
+ const end = rest.indexOf('"', i + 1);
1331
+ const tok = rest.slice(i, end < 0 ? rest.length : end + 1);
1332
+ tokens.push(tok);
1333
+ i = end < 0 ? rest.length : end + 1;
1334
+ continue;
1335
+ }
1336
+ let j = i;
1337
+ while (j < rest.length && rest[j] !== " " && rest[j] !== " ") {
1338
+ if (rest[j] === "=" && rest[j + 1] === '"') {
1339
+ const end = rest.indexOf('"', j + 2);
1340
+ j = end < 0 ? rest.length : end + 1;
1341
+ break;
1211
1342
  }
1212
- for (let i = 0; i < left.length; i++) {
1213
- const y = topY + pitch * (i + 1);
1214
- parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
1215
- parts.push(`<text x="4" y="${y + 3}" class="schematex-circuit-pol">${left[i]}</text>`);
1343
+ j++;
1344
+ }
1345
+ tokens.push(rest.slice(i, j));
1346
+ i = j;
1347
+ }
1348
+ for (const tok of tokens) {
1349
+ if (!tok) continue;
1350
+ if (DIRECTIONS.has(tok.toLowerCase())) {
1351
+ out.direction = tok.toLowerCase();
1352
+ continue;
1353
+ }
1354
+ const eq = tok.indexOf("=");
1355
+ if (eq > 0) {
1356
+ const key = tok.slice(0, eq).trim();
1357
+ let val = tok.slice(eq + 1).trim();
1358
+ if (val.startsWith('"') && val.endsWith('"')) {
1359
+ val = val.slice(1, -1);
1360
+ }
1361
+ if (key === "label") out.label = val;
1362
+ else if (key === "value") out.value = val;
1363
+ else if (key === "at") out.at = val;
1364
+ else if (key === "length") out.length = val;
1365
+ else out.attrs[key] = val;
1366
+ continue;
1367
+ }
1368
+ out.attrs[tok] = "true";
1369
+ }
1370
+ return out;
1371
+ }
1372
+ function parseCircuit(text2) {
1373
+ const rawLines = text2.split("\n");
1374
+ const firstMeaningful = rawLines.map((l) => l.replace(/#.*$/, "").trim()).find((l) => l.length > 0) ?? "";
1375
+ if (/^circuit\b.*\bnetlist\s*$/i.test(firstMeaningful)) {
1376
+ const netlistTitle = chunkNAGUZFXX_cjs.matchQuotedTitle(firstMeaningful);
1377
+ let headerIdx = -1;
1378
+ for (let i = 0; i < rawLines.length; i++) {
1379
+ const s = rawLines[i].replace(/#.*$/, "").trim();
1380
+ if (s.length > 0) {
1381
+ headerIdx = i;
1382
+ break;
1383
+ }
1384
+ }
1385
+ const body = rawLines.slice(headerIdx + 1).join("\n");
1386
+ return parseNetlist(body, netlistTitle);
1387
+ }
1388
+ const lines = text2.split("\n").map((l) => l.replace(/\r$/, ""));
1389
+ let title2;
1390
+ const components = [];
1391
+ const nets = [];
1392
+ const netByName = /* @__PURE__ */ new Map();
1393
+ let autoId = 0;
1394
+ let pendingAt;
1395
+ const mkId = (prefix) => `${prefix}_${autoId++}`;
1396
+ for (const rawLine of lines) {
1397
+ const stripped = rawLine.replace(/#.*$/, "").trim();
1398
+ if (!stripped) continue;
1399
+ if (/^circuit\b/i.test(stripped)) {
1400
+ const t = chunkNAGUZFXX_cjs.matchQuotedTitle(stripped);
1401
+ if (t !== void 0) title2 = t;
1402
+ continue;
1403
+ }
1404
+ const atMatch = stripped.match(/^at:\s*(.+)$/i);
1405
+ if (atMatch) {
1406
+ pendingAt = atMatch[1].trim();
1407
+ continue;
1408
+ }
1409
+ const netDecl = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*$/i);
1410
+ if (netDecl) {
1411
+ const name = netDecl[1];
1412
+ if (!netByName.has(name)) {
1413
+ const n = { id: name, anchors: [] };
1414
+ netByName.set(name, n);
1415
+ nets.push(n);
1216
1416
  }
1217
- for (let i = 0; i < right.length; i++) {
1218
- const y = topY + pitch * (i + 1);
1219
- parts.push(`<line x1="${BODY_W}" y1="${y}" x2="${BODY_W + 8}" y2="${y}" ${WIRE}/>`);
1220
- parts.push(`<text x="${BODY_W - 4}" y="${y + 3}" text-anchor="end" class="schematex-circuit-pol">${right[i]}</text>`);
1417
+ continue;
1418
+ }
1419
+ const netDotMatch = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*:\s*dot\s*$/i);
1420
+ if (netDotMatch) {
1421
+ const name = netDotMatch[1];
1422
+ let n = netByName.get(name);
1423
+ if (!n) {
1424
+ n = { id: name, anchors: [] };
1425
+ netByName.set(name, n);
1426
+ nets.push(n);
1221
1427
  }
1222
- return parts.join("");
1428
+ const id = mkId("dot");
1429
+ components.push({
1430
+ id,
1431
+ componentType: "dot",
1432
+ direction: "right",
1433
+ at: pendingAt,
1434
+ attrs: { net: name }
1435
+ });
1436
+ n.anchors.push(`${id}.end`);
1437
+ pendingAt = `${id}.end`;
1438
+ continue;
1223
1439
  }
1224
- };
1225
- }
1226
- var generic_ic = icSymbol(
1227
- ["1", "2", "3", "4"],
1228
- ["8", "7", "6", "5"],
1229
- "IC"
1230
- );
1231
- var timer_555 = (() => {
1232
- const left = ["GND", "TRG", "OUT", "RST"];
1233
- const right = ["VCC", "DIS", "THR", "CTL"];
1234
- const sym = icSymbol(left, right, "555");
1235
- const BODY_W = 80;
1236
- const pitch = 16;
1237
- const n = 4;
1238
- const topY = -80 / 2;
1239
- const anchors = {
1240
- start: { x: 0, y: 0 },
1241
- end: { x: BODY_W, y: 0 }
1242
- };
1243
- const leftNames = ["gnd", "trg", "out", "rst"];
1244
- const rightNames = ["vcc", "dis", "thr", "ctl"];
1245
- for (let i = 0; i < n; i++) {
1246
- const y = topY + pitch * (i + 1);
1247
- anchors[leftNames[i]] = { x: -8, y };
1248
- anchors[rightNames[i]] = { x: BODY_W + 8, y };
1249
- }
1250
- return { ...sym, anchors };
1251
- })();
1252
- var voltage_regulator = {
1253
- length: 60,
1254
- anchors: {
1255
- start: { x: 0, y: 0 },
1256
- end: { x: 60, y: 0 },
1257
- in: { x: 0, y: 0 },
1258
- out: { x: 60, y: 0 },
1259
- gnd: { x: 30, y: 20 }
1260
- },
1261
- svg: (_l, _v, attrs) => [
1262
- lineWire(0, 0, 10, 0),
1263
- `<rect x="10" y="-15" width="40" height="30" fill="white" ${BODY}/>`,
1264
- `<text x="30" y="4" text-anchor="middle" class="schematex-circuit-meter">${attrs?.model ?? "REG"}</text>`,
1265
- lineWire(50, 0, 60, 0),
1266
- lineWire(30, 15, 30, 20)
1267
- ].join("")
1268
- };
1269
- var potentiometer = {
1270
- length: 50,
1271
- anchors: {
1272
- start: { x: 0, y: 0 },
1273
- end: { x: 50, y: 0 },
1274
- wiper: { x: 25, y: -22 }
1275
- },
1276
- svg: () => [
1277
- `<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
1278
- `<line x1="25" y1="-22" x2="25" y2="-10" ${BODY}/>`,
1279
- `<polygon points="25,-10 21,-16 29,-16" ${FILL}/>`
1280
- ].join("")
1281
- };
1282
- var terminal_block = {
1283
- length: 80,
1284
- anchors: { start: { x: 0, y: 0 }, end: { x: 80, y: 0 } },
1285
- svg: (label, _value, attrs) => {
1286
- const pinsAttr = attrs?.pins ?? attrs?.terminals ?? "1,2,3,4";
1287
- const pins = pinsAttr.split(",").map((s) => s.trim()).filter(Boolean);
1288
- const n = Math.max(pins.length, 1);
1289
- const BODY_W = 80;
1290
- const pitch = 18;
1291
- const bodyH = pitch * (n + 1);
1292
- const topY = -bodyH / 2;
1293
- const parts = [];
1294
- parts.push(
1295
- `<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" rx="3" fill="white" stroke-width="2" ${BODY}/>`
1296
- );
1297
- if (label) {
1298
- parts.push(
1299
- `<text x="${BODY_W / 2}" y="${topY + 14}" text-anchor="middle" class="schematex-circuit-meter">${label}</text>`
1300
- );
1440
+ const labelMatch = stripped.match(/^label\s+"([^"]*)"(?:\s+(right|left|up|down))?\s*$/i);
1441
+ if (labelMatch) {
1442
+ const id = mkId("lbl");
1443
+ components.push({
1444
+ id,
1445
+ componentType: "label",
1446
+ direction: labelMatch[2]?.toLowerCase() ?? "right",
1447
+ at: pendingAt,
1448
+ label: labelMatch[1]
1449
+ });
1450
+ continue;
1301
1451
  }
1302
- for (let i = 0; i < n; i++) {
1303
- const y = topY + pitch * (i + 1) + (label ? 8 : 0);
1304
- parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
1305
- parts.push(`<circle cx="6" cy="${y}" r="2" ${FILL}/>`);
1306
- parts.push(
1307
- `<text x="12" y="${y + 3}" class="schematex-circuit-pol">${pins[i] ?? `T${i + 1}`}</text>`
1308
- );
1452
+ const wireMatch = stripped.match(/^wire(?:\s+(right|left|up|down))?(?:\s+(\d+)(?:px)?)?\s*$/i);
1453
+ if (wireMatch) {
1454
+ const id = mkId("w");
1455
+ components.push({
1456
+ id,
1457
+ componentType: "wire",
1458
+ direction: wireMatch[1]?.toLowerCase() ?? "right",
1459
+ at: pendingAt,
1460
+ attrs: wireMatch[2] ? { length: wireMatch[2] } : {}
1461
+ });
1462
+ pendingAt = `${id}.end`;
1463
+ continue;
1464
+ }
1465
+ const bareMatch = stripped.match(/^([a-zA-Z_][\w]*)(\s+.*)?$/);
1466
+ const colonMatch = stripped.match(/^([a-zA-Z_][\w]*)\s*:\s*([a-zA-Z_][\w]*)(\s+.*)?$/);
1467
+ if (colonMatch) {
1468
+ const id = colonMatch[1];
1469
+ const typeStr = colonMatch[2];
1470
+ const norm = normalizeType(typeStr);
1471
+ if (!norm) {
1472
+ throw new CircuitParseError(`Unknown component type: ${typeStr}`);
1473
+ }
1474
+ const rest = colonMatch[3] ?? "";
1475
+ const parsed = parseAttrs(rest);
1476
+ const comp = {
1477
+ id,
1478
+ componentType: norm,
1479
+ direction: parsed.direction ?? "right",
1480
+ at: parsed.at ?? pendingAt,
1481
+ label: parsed.label,
1482
+ value: parsed.value,
1483
+ attrs: parsed.attrs
1484
+ };
1485
+ if (parsed.length) {
1486
+ comp.attrs = { ...comp.attrs, length: parsed.length };
1487
+ }
1488
+ components.push(comp);
1489
+ pendingAt = `${id}.end`;
1490
+ continue;
1491
+ }
1492
+ if (bareMatch) {
1493
+ const typeStr = bareMatch[1];
1494
+ const norm = normalizeType(typeStr);
1495
+ if (!norm) {
1496
+ continue;
1497
+ }
1498
+ const rest = bareMatch[2] ?? "";
1499
+ const parsed = parseAttrs(rest);
1500
+ const id = mkId(norm);
1501
+ const comp = {
1502
+ id,
1503
+ componentType: norm,
1504
+ direction: parsed.direction ?? "right",
1505
+ at: parsed.at ?? pendingAt,
1506
+ label: parsed.label,
1507
+ value: parsed.value,
1508
+ attrs: parsed.attrs
1509
+ };
1510
+ components.push(comp);
1511
+ pendingAt = `${id}.end`;
1512
+ continue;
1309
1513
  }
1310
- return parts.join("");
1311
1514
  }
1312
- };
1313
- var SYMBOLS = {
1314
- resistor,
1315
- capacitor,
1316
- electrolytic_cap,
1317
- inductor,
1318
- fuse,
1319
- crystal,
1320
- transformer,
1321
- voltage_source,
1322
- current_source,
1323
- ac_source,
1324
- battery,
1325
- ground,
1326
- gnd_signal,
1327
- vcc,
1328
- diode,
1329
- zener,
1330
- schottky,
1331
- led,
1332
- photodiode,
1333
- npn,
1334
- pnp,
1335
- nmos,
1336
- pmos,
1337
- jfet_n,
1338
- jfet_p,
1339
- opamp,
1340
- comparator,
1341
- switch_spst,
1342
- push_no,
1343
- ammeter,
1344
- voltmeter,
1345
- wattmeter,
1346
- motor,
1347
- speaker,
1348
- microphone,
1349
- buzzer,
1350
- potentiometer,
1351
- rheostat,
1352
- thermistor_ntc,
1353
- thermistor_ptc,
1354
- ldr,
1355
- variable_cap,
1356
- variable_inductor,
1357
- switch_spdt,
1358
- push_nc,
1359
- gnd_chassis,
1360
- gnd_digital,
1361
- test_point,
1362
- no_connect,
1363
- antenna,
1364
- generic_ic,
1365
- terminal_block,
1366
- "555_timer": timer_555,
1367
- voltage_regulator
1368
- // Lamp reuses buzzer slot? No, needs its own entry but our CircuitComponentType
1369
- // doesn't have "lamp". We map it via parser alias to "buzzer" or add specifically.
1370
- };
1371
- var EXTRA_SYMBOLS = {
1372
- lamp
1373
- };
1374
- function getSymbol(t) {
1375
- return SYMBOLS[t] ?? EXTRA_SYMBOLS[t];
1515
+ return {
1516
+ type: "circuit",
1517
+ title: title2,
1518
+ components,
1519
+ nets,
1520
+ mode: "positional"
1521
+ };
1376
1522
  }
1377
1523
 
1378
1524
  // src/diagrams/circuit/layout.ts
@@ -1902,5 +2048,5 @@ exports.layoutCircuitNetlist = layoutCircuitNetlist;
1902
2048
  exports.parseCircuit = parseCircuit;
1903
2049
  exports.parseNetlist = parseNetlist;
1904
2050
  exports.renderCircuit = renderCircuit;
1905
- //# sourceMappingURL=chunk-2Z543TC3.cjs.map
1906
- //# sourceMappingURL=chunk-2Z543TC3.cjs.map
2051
+ //# sourceMappingURL=chunk-QMTWG6JL.cjs.map
2052
+ //# sourceMappingURL=chunk-QMTWG6JL.cjs.map