@tscircuit/ngspice-spice-engine 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { SpiceEngine } from '@tscircuit/props';
2
1
  import { ResultType } from '@tscircuit/eecircuit-engine';
2
+ import { SpiceEngine } from '@tscircuit/props';
3
3
 
4
4
  interface TranParams {
5
5
  tstep?: number;
@@ -10,6 +10,8 @@ interface TranParams {
10
10
  }
11
11
  declare const parseTranParams: (spiceString: string) => TranParams | null;
12
12
 
13
+ declare const rewritePspiceCompatibilitySyntax: (spiceString: string) => string;
14
+
13
15
  interface VoltageGraph {
14
16
  netName: string;
15
17
  time: number[];
@@ -26,4 +28,4 @@ interface ProbeMetadata {
26
28
  declare const eecircuitResultToVGraphs: (result: ResultType, spiceString: string) => VoltageGraph[];
27
29
  declare const createNgspiceSpiceEngine: () => Promise<SpiceEngine>;
28
30
 
29
- export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToVGraphs, parseTranParams };
31
+ export { type TranParams, createNgspiceSpiceEngine, createNgspiceSpiceEngine as default, eecircuitResultToVGraphs, parseTranParams, rewritePspiceCompatibilitySyntax };
package/dist/index.js CHANGED
@@ -108,6 +108,71 @@ var parseTranParams = (spiceString) => {
108
108
  return null;
109
109
  };
110
110
 
111
+ // lib/rewrite-pspice-compatibility-syntax.ts
112
+ var pspiceNumberToken = String.raw`([+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:[eE][+-]?\d+)?)`;
113
+ var rewritePspiceResistorTcPairs = (spiceString) => spiceString.split(/\r?\n/).map((line) => {
114
+ if (!/^\s*r/i.test(line)) return line;
115
+ return line.replace(
116
+ new RegExp(
117
+ String.raw`\bTC\s*=\s*${pspiceNumberToken}\s*,\s*${pspiceNumberToken}\b`,
118
+ "gi"
119
+ ),
120
+ "TC1=$1 TC2=$2"
121
+ );
122
+ }).join("\n");
123
+ var pspiceComparisonOperator = "(?:<=|>=|==|!=|(?<![!<>=])=(?!=)|<|>)";
124
+ var pspiceComparisonOperand = String.raw`(?:V\s*\([^)]*\)|\{[^}\r\n]+\}|${pspiceNumberToken}(?:[a-zA-Z]+)?|[A-Za-z_][\w.$]*)`;
125
+ var pspiceComparisonExpression = String.raw`${pspiceComparisonOperand}\s*${pspiceComparisonOperator}\s*${pspiceComparisonOperand}`;
126
+ var pspiceComparisonBeforeCaretPattern = new RegExp(
127
+ String.raw`${pspiceComparisonExpression}\s*$`,
128
+ "i"
129
+ );
130
+ var pspiceComparisonAfterCaretPattern = new RegExp(
131
+ String.raw`^\s*\+?\s*${pspiceComparisonExpression}`,
132
+ "i"
133
+ );
134
+ var isPspiceBooleanCaret = (block, caretOffset, operatorLength) => pspiceComparisonBeforeCaretPattern.test(block.slice(0, caretOffset)) && pspiceComparisonAfterCaretPattern.test(
135
+ block.slice(caretOffset + operatorLength)
136
+ );
137
+ var rewritePspiceValueBooleanCarets = (spiceString) => {
138
+ let result = "";
139
+ let cursor = 0;
140
+ const valueStartPattern = /\bVALUE\s*\{/gi;
141
+ for (; ; ) {
142
+ valueStartPattern.lastIndex = cursor;
143
+ const match = valueStartPattern.exec(spiceString);
144
+ if (!match) break;
145
+ const blockStart = match.index;
146
+ const firstBraceIndex = spiceString.indexOf("{", blockStart);
147
+ let depth = 0;
148
+ let blockEnd = -1;
149
+ for (let i = firstBraceIndex; i < spiceString.length; i++) {
150
+ const char = spiceString[i];
151
+ if (char === "{") {
152
+ depth += 1;
153
+ } else if (char === "}") {
154
+ depth -= 1;
155
+ if (depth === 0) {
156
+ blockEnd = i + 1;
157
+ break;
158
+ }
159
+ }
160
+ }
161
+ if (blockEnd === -1) break;
162
+ result += spiceString.slice(cursor, blockStart);
163
+ const block = spiceString.slice(blockStart, blockEnd);
164
+ result += block.replace(/\s+\^\s+/g, (operator, offset, fullBlock) => {
165
+ if (isPspiceBooleanCaret(fullBlock, offset, operator.length)) {
166
+ return operator.replace("^", "!=");
167
+ }
168
+ return operator;
169
+ });
170
+ cursor = blockEnd;
171
+ }
172
+ return result + spiceString.slice(cursor);
173
+ };
174
+ var rewritePspiceCompatibilitySyntax = (spiceString) => rewritePspiceValueBooleanCarets(rewritePspiceResistorTcPairs(spiceString));
175
+
111
176
  // lib/index.ts
112
177
  var ensureSimulation = async () => {
113
178
  const { Simulation: SimulationCtor } = await import("@tscircuit/eecircuit-engine");
@@ -127,7 +192,7 @@ var getSimulation = async () => {
127
192
  };
128
193
  var extractRequestedPlots = (spiceString) => {
129
194
  const match = spiceString.match(/\.print\s+tran\s+(.*)/i);
130
- if (!match || !match[1]) {
195
+ if (!match?.[1]) {
131
196
  return null;
132
197
  }
133
198
  const tokens = match[1].match(/[VI]\s*\([^)]+\)/gi);
@@ -162,7 +227,6 @@ var extractProbeMetadata = (spiceString) => {
162
227
  reference_node_name: typeof parsed.reference_node_name === "string" ? parsed.reference_node_name : void 0
163
228
  });
164
229
  } catch {
165
- continue;
166
230
  }
167
231
  }
168
232
  return metadata;
@@ -179,7 +243,7 @@ var getNetName = (rawName) => {
179
243
  return match[1] ?? rawName;
180
244
  };
181
245
  var eecircuitResultToVGraphs = (result, spiceString) => {
182
- if (!result || !result.data || result.dataType !== "real") {
246
+ if (!result?.data || result.dataType !== "real") {
183
247
  return [];
184
248
  }
185
249
  const timeData = result.data.find((item) => item.type === "time");
@@ -281,7 +345,8 @@ var voltageGraphsToCircuitJson = (graphs, spiceString) => {
281
345
  };
282
346
  var simulate = async (spiceString) => {
283
347
  const simulation = await getSimulation();
284
- simulation.setNetList(spiceString);
348
+ const simulationSpiceString = rewritePspiceCompatibilitySyntax(spiceString);
349
+ simulation.setNetList(simulationSpiceString);
285
350
  let result;
286
351
  try {
287
352
  result = await simulation.runSim();
@@ -292,11 +357,11 @@ var simulate = async (spiceString) => {
292
357
  if (!result) {
293
358
  return { simulationResultCircuitJson: [] };
294
359
  }
295
- const graphs = eecircuitResultToVGraphs(result, spiceString);
360
+ const graphs = eecircuitResultToVGraphs(result, simulationSpiceString);
296
361
  return {
297
362
  simulationResultCircuitJson: voltageGraphsToCircuitJson(
298
363
  graphs,
299
- spiceString
364
+ simulationSpiceString
300
365
  )
301
366
  };
302
367
  };
@@ -310,5 +375,6 @@ export {
310
375
  createNgspiceSpiceEngine,
311
376
  index_default as default,
312
377
  eecircuitResultToVGraphs,
313
- parseTranParams
378
+ parseTranParams,
379
+ rewritePspiceCompatibilitySyntax
314
380
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/ngspice-spice-engine",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "A tscircuit-compatible SPICE engine using ngspice.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",