circuitscript 0.0.25 → 0.0.27

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 (51) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cjs/BaseVisitor.js +16 -12
  3. package/dist/cjs/SemanticTokenVisitor.js +3 -3
  4. package/dist/cjs/antlr/CircuitScriptLexer.js +189 -166
  5. package/dist/cjs/antlr/CircuitScriptParser.js +1295 -719
  6. package/dist/cjs/draw_symbols.js +42 -14
  7. package/dist/cjs/execute.js +91 -30
  8. package/dist/cjs/export.js +91 -5
  9. package/dist/cjs/geometry.js +45 -26
  10. package/dist/cjs/globals.js +1 -2
  11. package/dist/cjs/helpers.js +6 -2
  12. package/dist/cjs/layout.js +37 -17
  13. package/dist/cjs/main.js +21 -9
  14. package/dist/cjs/objects/ClassComponent.js +8 -0
  15. package/dist/cjs/objects/types.js +8 -1
  16. package/dist/cjs/render.js +1 -1
  17. package/dist/cjs/visitor.js +131 -23
  18. package/dist/esm/BaseVisitor.mjs +17 -13
  19. package/dist/esm/SemanticTokenVisitor.mjs +3 -3
  20. package/dist/esm/antlr/CircuitScriptLexer.mjs +189 -166
  21. package/dist/esm/antlr/CircuitScriptParser.mjs +1287 -716
  22. package/dist/esm/antlr/CircuitScriptVisitor.mjs +6 -1
  23. package/dist/esm/draw_symbols.mjs +44 -16
  24. package/dist/esm/execute.mjs +90 -26
  25. package/dist/esm/export.mjs +89 -6
  26. package/dist/esm/geometry.mjs +44 -25
  27. package/dist/esm/globals.mjs +1 -2
  28. package/dist/esm/helpers.mjs +7 -3
  29. package/dist/esm/layout.mjs +35 -16
  30. package/dist/esm/main.mjs +21 -9
  31. package/dist/esm/objects/ClassComponent.mjs +8 -0
  32. package/dist/esm/objects/types.mjs +7 -0
  33. package/dist/esm/render.mjs +2 -2
  34. package/dist/esm/visitor.mjs +133 -25
  35. package/dist/types/BaseVisitor.d.ts +2 -5
  36. package/dist/types/SemanticTokenVisitor.d.ts +2 -2
  37. package/dist/types/antlr/CircuitScriptLexer.d.ts +29 -22
  38. package/dist/types/antlr/CircuitScriptParser.d.ts +121 -44
  39. package/dist/types/antlr/CircuitScriptVisitor.d.ts +12 -2
  40. package/dist/types/draw_symbols.d.ts +11 -6
  41. package/dist/types/execute.d.ts +6 -4
  42. package/dist/types/export.d.ts +27 -1
  43. package/dist/types/geometry.d.ts +12 -9
  44. package/dist/types/globals.d.ts +2 -3
  45. package/dist/types/layout.d.ts +5 -0
  46. package/dist/types/objects/ClassComponent.d.ts +5 -0
  47. package/dist/types/objects/Wire.d.ts +2 -1
  48. package/dist/types/objects/types.d.ts +6 -0
  49. package/dist/types/visitor.d.ts +7 -3
  50. package/libs/lib.cst +28 -10
  51. package/package.json +1 -1
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SymbolDrawingCommands = exports.SymbolDrawing = exports.SymbolCustom = exports.PlaceHolderCommands = exports.SymbolPlaceholder = exports.SymbolText = exports.SymbolPointHidden = exports.SymbolFactory = exports.SymbolGraphic = void 0;
4
4
  const globals_js_1 = require("./globals.js");
5
5
  const geometry_js_1 = require("./geometry.js");
6
+ const PinTypes_js_1 = require("./objects/PinTypes.js");
6
7
  const defaultSymbolLineWidth = 2;
7
8
  class SymbolGraphic {
8
9
  constructor() {
@@ -255,7 +256,7 @@ class SymbolText extends SymbolGraphic {
255
256
  }
256
257
  generateDrawing() {
257
258
  const drawing = new SymbolDrawing();
258
- drawing.addLabel(0, 0, this.text, {
259
+ drawing.addTextbox(0, 0, this.text, {
259
260
  fontSize: this.fontSize,
260
261
  anchor: geometry_js_1.HorizontalAlign.Middle,
261
262
  fontWeight: this.fontWeight,
@@ -321,13 +322,7 @@ class SymbolPlaceholder extends SymbolGraphic {
321
322
  break;
322
323
  }
323
324
  case PlaceHolderCommands.label: {
324
- const keywords = ['fontSize', 'anchor', 'vanchor', 'angle'];
325
- const style = {};
326
- keywords.forEach(item => {
327
- if (keywordParams.has(item)) {
328
- style[item] = keywordParams.get(item);
329
- }
330
- });
325
+ const style = this.parseLabelStyle(keywordParams);
331
326
  positionParams = [...positionParams];
332
327
  positionParams.push(style);
333
328
  const labelId = positionParams[0];
@@ -340,10 +335,33 @@ class SymbolPlaceholder extends SymbolGraphic {
340
335
  drawing.addLabelId(...tmpPositionParams);
341
336
  break;
342
337
  }
338
+ case PlaceHolderCommands.text: {
339
+ const style = this.parseLabelStyle(keywordParams);
340
+ const content = keywordParams.get('content');
341
+ let offsetX = 0;
342
+ let offsetY = 0;
343
+ if (keywordParams.has('offset')) {
344
+ const offset = keywordParams.get('offset');
345
+ offsetX = offset[0];
346
+ offsetY = offset[1];
347
+ }
348
+ drawing.addTextbox(offsetX, offsetY, content, style);
349
+ break;
350
+ }
343
351
  }
344
352
  });
345
353
  drawing.log("=== end generate drawing ===");
346
354
  }
355
+ parseLabelStyle(keywordParams) {
356
+ const keywords = ['fontSize', 'anchor', 'vanchor', 'angle'];
357
+ const style = {};
358
+ keywords.forEach(item => {
359
+ if (keywordParams.has(item)) {
360
+ style[item] = keywordParams.get(item);
361
+ }
362
+ });
363
+ return style;
364
+ }
347
365
  drawPinParams(drawing, commandName, keywordParams, positionParams) {
348
366
  drawing.log('add pin', ...positionParams);
349
367
  const keywordDisplayPinId = 'display_pin_id';
@@ -353,6 +371,11 @@ class SymbolPlaceholder extends SymbolGraphic {
353
371
  displayPinId = false;
354
372
  }
355
373
  let pinNameParam = null;
374
+ let pinType = PinTypes_js_1.PinTypes.Any;
375
+ if (positionParams[1].type && positionParams[1].type === globals_js_1.ReferenceTypes.pinType) {
376
+ pinType = positionParams[1].value;
377
+ positionParams = [positionParams[0], ...positionParams.slice(2)];
378
+ }
356
379
  if (typeof positionParams[1] === 'string') {
357
380
  pinNameParam = positionParams[1];
358
381
  positionParams = [positionParams[0], ...positionParams.slice(2)];
@@ -449,6 +472,7 @@ var PlaceHolderCommands;
449
472
  PlaceHolderCommands["lineWidth"] = "lineWidth";
450
473
  PlaceHolderCommands["fill"] = "fill";
451
474
  PlaceHolderCommands["lineColor"] = "lineColor";
475
+ PlaceHolderCommands["text"] = "text";
452
476
  })(PlaceHolderCommands || (exports.PlaceHolderCommands = PlaceHolderCommands = {}));
453
477
  class SymbolCustom extends SymbolGraphic {
454
478
  constructor(pinDefinition) {
@@ -637,6 +661,10 @@ class SymbolDrawing {
637
661
  this.items.push(geometry_js_1.Geometry.label(id, x, y, textValue, style));
638
662
  return this;
639
663
  }
664
+ addTextbox(x, y, textValue, style) {
665
+ this.items.push(geometry_js_1.Geometry.textbox(null, x, y, textValue, style));
666
+ return this;
667
+ }
640
668
  addPath(...pathParts) {
641
669
  const parts = pathParts.reduce((accum, tmp) => {
642
670
  if (typeof tmp === "string") {
@@ -711,7 +739,7 @@ class SymbolDrawing {
711
739
  let currentLineColor = '#333';
712
740
  const pathItems = [];
713
741
  this.items.forEach(item => {
714
- if (!(item instanceof geometry_js_1.Label)) {
742
+ if (!(item instanceof geometry_js_1.Textbox)) {
715
743
  if (item instanceof geometry_js_1.GeometryProp) {
716
744
  if (item.name === 'lineWidth') {
717
745
  currentLineWidth = item.value;
@@ -726,7 +754,7 @@ class SymbolDrawing {
726
754
  else {
727
755
  let tmpResult = geometry_js_1.Geometry.groupFlip([item], this.flipX, this.flipY);
728
756
  tmpResult = geometry_js_1.Geometry.groupRotate(tmpResult, this.angle, this.mainOrigin);
729
- const { path, isClosedPolygon } = this.featuresToPath(tmpResult);
757
+ const { path, isClosedPolygon } = this.featuresToPath(tmpResult, this.flipX, this.flipY);
730
758
  pathItems.push({
731
759
  path: path,
732
760
  lineWidth: currentLineWidth,
@@ -742,14 +770,14 @@ class SymbolDrawing {
742
770
  let features = this.pins.map(item => item[1]);
743
771
  features = geometry_js_1.Geometry.groupFlip(features, this.flipX, this.flipY);
744
772
  features = geometry_js_1.Geometry.groupRotate(features, this.angle, this.mainOrigin);
745
- const { path } = this.featuresToPath(features);
773
+ const { path } = this.featuresToPath(features, this.flipX, this.flipY);
746
774
  return path;
747
775
  }
748
776
  getLabels() {
749
- return this.items.filter(item => item instanceof geometry_js_1.Label);
777
+ return this.items.filter(item => item instanceof geometry_js_1.Textbox);
750
778
  }
751
- featuresToPath(items) {
752
- return geometry_js_1.Geometry.featuresToPath(items);
779
+ featuresToPath(items, flipX, flipY) {
780
+ return geometry_js_1.Geometry.featuresToPath(items, flipX, flipY);
753
781
  }
754
782
  getBoundingBox(excludeLabels = false) {
755
783
  const pinFeatures = this.pins.map(pin => {
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPortSide = exports.isNetOnlyComponent = exports.isLabelComponent = exports.isNetComponent = exports.ExecutionContext = void 0;
3
+ exports.getPortSide = exports.ExecutionContext = void 0;
4
4
  const globals_js_1 = require("./globals.js");
5
5
  const ClassComponent_js_1 = require("./objects/ClassComponent.js");
6
6
  const ExecutionScope_js_1 = require("./objects/ExecutionScope.js");
7
7
  const Net_js_1 = require("./objects/Net.js");
8
8
  const PinDefinition_js_1 = require("./objects/PinDefinition.js");
9
+ const types_js_1 = require("./objects/types.js");
9
10
  const Wire_js_1 = require("./objects/Wire.js");
10
11
  const Frame_js_1 = require("./objects/Frame.js");
12
+ const layout_js_1 = require("./layout.js");
11
13
  class ExecutionContext {
12
14
  constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger, parent) {
13
15
  this.tmpPointId = 0;
@@ -16,6 +18,7 @@ class ExecutionContext {
16
18
  this.returnValue = null;
17
19
  this.silent = false;
18
20
  this.__functionCache = {};
21
+ this.componentAngleFollowsWire = true;
19
22
  this.name = name;
20
23
  this.namespace = namespace;
21
24
  this.netNamespace = netNamespace;
@@ -140,12 +143,27 @@ class ExecutionContext {
140
143
  pins.forEach((pin) => {
141
144
  component.pins.set(pin.id, pin);
142
145
  });
146
+ component.arrangeProps = props.arrange ?? null;
147
+ component.displayProp = props.display ?? null;
148
+ component.widthProp = props.width ?? null;
149
+ component.typeProp = props.type ?? null;
150
+ component.copyProp = props.copy ?? false;
151
+ let useAngle = null;
152
+ if (props.angle) {
153
+ useAngle = props.angle % 360;
154
+ if (useAngle < 0) {
155
+ useAngle += 360;
156
+ }
157
+ }
158
+ component.angleProp = useAngle ?? 0;
159
+ component.followWireOrientationProp = props.followWireOrientation;
143
160
  const paramsMap = new Map();
144
161
  params.forEach((param) => {
145
162
  component.parameters.set(param.paramName, param.paramValue);
146
163
  paramsMap.set(param.paramName, param.paramValue);
147
164
  });
148
- if (paramsMap.has(globals_js_1.ParamKeys.__is_net)) {
165
+ if (component.typeProp === globals_js_1.ComponentTypes.net
166
+ || component.typeProp === globals_js_1.ComponentTypes.label) {
149
167
  const netName = paramsMap.get(globals_js_1.ParamKeys.net_name);
150
168
  const priority = paramsMap.get(globals_js_1.ParamKeys.priority);
151
169
  const result = this.resolveNet(netName, this.netNamespace);
@@ -161,12 +179,7 @@ class ExecutionContext {
161
179
  this.scope.setNet(component, 1, tmpNet);
162
180
  this.log('set net', netName, 'component', component);
163
181
  }
164
- const { arrange = null } = props;
165
- component.arrangeProps = arrange;
166
- component.displayProp = props.display ?? null;
167
- component.widthProp = props.width ?? null;
168
- component.typeProp = props.type ?? null;
169
- const portSides = getPortSide(component.pins, arrange);
182
+ const portSides = getPortSide(component.pins, component.arrangeProps);
170
183
  portSides.forEach(({ pinId, side, position }) => {
171
184
  if (component.pins.has(pinId)) {
172
185
  const tmpPin = component.pins.get(pinId);
@@ -183,6 +196,10 @@ class ExecutionContext {
183
196
  }
184
197
  printPoint(extra = '') {
185
198
  let netName = globals_js_1.NoNetText;
199
+ if (this.scope.currentComponent === null || this.scope.currentPin === null) {
200
+ this.log((extra !== '' ? (extra + ' ') : '') + 'point is null');
201
+ return;
202
+ }
186
203
  if (this.scope.hasNet(this.scope.currentComponent, this.scope.currentPin)) {
187
204
  netName = this.scope
188
205
  .getNet(this.scope.currentComponent, this.scope.currentPin)
@@ -196,6 +213,7 @@ class ExecutionContext {
196
213
  addComponentExisting(component, pin) {
197
214
  const startPin = pin;
198
215
  const nextPin = component.getNextPinAfter(startPin);
216
+ this.applyComponentAngleFromWire(component, pin);
199
217
  this.toComponent(component, startPin, { addSequence: true });
200
218
  this.log('move to next pin: ' + nextPin);
201
219
  this.atComponent(component, nextPin, {
@@ -231,6 +249,7 @@ class ExecutionContext {
231
249
  .toString());
232
250
  }
233
251
  const linkedNet = this.linkComponentPinNet(this.scope.currentComponent, this.scope.currentPin, component, pinId);
252
+ this.applyComponentAngleFromWire(component, pinId);
234
253
  this.scope.currentComponent = component;
235
254
  this.scope.currentPin = pinId;
236
255
  this.scope.clearActive();
@@ -279,22 +298,22 @@ class ExecutionContext {
279
298
  this.printPoint();
280
299
  return this.getCurrentPoint();
281
300
  }
282
- cloneComponent(component) {
283
- let clonedComponent = null;
301
+ copyComponent(component) {
302
+ let componentCopy = null;
284
303
  if (!this.scope.copyIDs.has(component.instanceName)) {
285
304
  this.scope.copyIDs.set(component.instanceName, 0);
286
305
  }
287
306
  const idNum = this.scope.copyIDs.get(component.instanceName);
288
- clonedComponent = component.clone();
289
- clonedComponent._copyID = idNum;
290
- clonedComponent._copyFrom = component;
307
+ componentCopy = component.clone();
308
+ componentCopy._copyID = idNum;
309
+ componentCopy._copyFrom = component;
291
310
  this.scope.copyIDs.set(component.instanceName, idNum + 1);
292
311
  const cloneInstanceName = component.instanceName + ':' + idNum;
293
- this.scope.instances.set(cloneInstanceName, clonedComponent);
294
- clonedComponent.instanceName = cloneInstanceName;
295
- this.linkComponentPinNet(component, 1, clonedComponent, 1);
312
+ this.scope.instances.set(cloneInstanceName, componentCopy);
313
+ componentCopy.instanceName = cloneInstanceName;
314
+ this.linkComponentPinNet(component, 1, componentCopy, 1);
296
315
  this.log('created clone of net component:', cloneInstanceName);
297
- return clonedComponent;
316
+ return componentCopy;
298
317
  }
299
318
  enterBlocks(blockType) {
300
319
  if (blockType === globals_js_1.BlockTypes.Point) {
@@ -561,7 +580,8 @@ class ExecutionContext {
561
580
  }
562
581
  else if (action === ExecutionScope_js_1.SequenceAction.At || action === ExecutionScope_js_1.SequenceAction.To) {
563
582
  const tmpComponent = sequenceAction[1];
564
- if (isNetComponent(tmpComponent) && tmpComponent.parameters.get(globals_js_1.ParamKeys.net_name) === 'gnd') {
583
+ if (tmpComponent.typeProp === globals_js_1.ComponentTypes.net
584
+ && tmpComponent.parameters.get(globals_js_1.ParamKeys.net_name) === 'gnd') {
565
585
  tmpComponent._copyID = gndCopyIdOffset + incrementGndLinkId;
566
586
  incrementGndLinkId += 1;
567
587
  }
@@ -678,6 +698,59 @@ class ExecutionContext {
678
698
  this.scope.currentComponent.styles[key] = styles[key];
679
699
  }
680
700
  }
701
+ applyComponentAngleFromWire(component, pin) {
702
+ if (this.componentAngleFollowsWire
703
+ && component.followWireOrientationProp
704
+ && component.useWireOrientationAngle
705
+ && this.scope.currentWireId !== -1) {
706
+ const currentWire = this.scope.wires[this.scope.currentWireId];
707
+ const lastSegment = currentWire.path[currentWire.path.length - 1];
708
+ const pinPositions = (0, layout_js_1.CalculatePinPositions)(component);
709
+ if (pinPositions.has(pin)) {
710
+ const connectedPinPos = pinPositions.get(pin);
711
+ let targetAngle = null;
712
+ switch (lastSegment.direction) {
713
+ case types_js_1.Direction.Down:
714
+ targetAngle = 90;
715
+ break;
716
+ case types_js_1.Direction.Up:
717
+ targetAngle = 270;
718
+ break;
719
+ case types_js_1.Direction.Right:
720
+ targetAngle = 0;
721
+ break;
722
+ case types_js_1.Direction.Left:
723
+ targetAngle = 180;
724
+ break;
725
+ default:
726
+ targetAngle = null;
727
+ }
728
+ if (targetAngle === null) {
729
+ return;
730
+ }
731
+ this.log('set component angle from wire, target angle:', targetAngle, ', component angle:', component.angleProp, 'pin angle:', connectedPinPos.angle);
732
+ let useAngle = (targetAngle - connectedPinPos.angle) % 360;
733
+ if (useAngle < 0) {
734
+ useAngle += 360;
735
+ }
736
+ if (useAngle === 90) {
737
+ component.setParam('angle', 90);
738
+ }
739
+ else if (useAngle === 180) {
740
+ if (component.angleProp === 0 || component.angleProp === 180) {
741
+ component.setParam('flipX', 1);
742
+ }
743
+ else if (component.angleProp === 90 || component.angleProp === 270) {
744
+ component.setParam('flipY', 1);
745
+ }
746
+ }
747
+ else if (useAngle === 270) {
748
+ component.setParam('angle', 270);
749
+ }
750
+ component.wireOrientationAngle = useAngle;
751
+ }
752
+ }
753
+ }
681
754
  enterFrame() {
682
755
  const frameId = this.scope.frames.length + 1;
683
756
  const frameObject = new Frame_js_1.Frame(frameId);
@@ -703,18 +776,6 @@ function isWireSegmentsEndAuto(segments) {
703
776
  }
704
777
  return false;
705
778
  }
706
- function isNetComponent(component) {
707
- return component.parameters.has(globals_js_1.ParamKeys.__is_net);
708
- }
709
- exports.isNetComponent = isNetComponent;
710
- function isLabelComponent(component) {
711
- return component.parameters.has(globals_js_1.ParamKeys.__is_label);
712
- }
713
- exports.isLabelComponent = isLabelComponent;
714
- function isNetOnlyComponent(component) {
715
- return isNetComponent(component) && !isLabelComponent(component);
716
- }
717
- exports.isNetOnlyComponent = isNetOnlyComponent;
718
779
  function getPortSide(pins, arrangeProps) {
719
780
  const result = [];
720
781
  if (arrangeProps === null) {
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateKiCADNetList = void 0;
3
+ exports.SExpObject = exports._id = exports.IdObject = exports.printTree = exports.generateKiCADNetList = void 0;
4
4
  const globals_js_1 = require("./globals.js");
5
5
  const ParamDefinition_js_1 = require("./objects/ParamDefinition.js");
6
6
  function generateKiCADNetList(netlist) {
7
7
  const componentsList = [];
8
8
  const nets = {};
9
+ const missingFootprints = [];
9
10
  netlist.forEach(entry => {
10
11
  const { instance, pins } = entry;
11
12
  if (instance.assignedRefDes !== null) {
@@ -25,7 +26,10 @@ function generateKiCADNetList(netlist) {
25
26
  instance.parameters.get('footprint')]);
26
27
  }
27
28
  else {
28
- console.log(instance.assignedRefDes, instance.instanceName, 'does not have footprint');
29
+ missingFootprints.push({
30
+ refdes: instance.assignedRefDes,
31
+ instanceName: instance.instanceName
32
+ });
29
33
  }
30
34
  componentsList.push(instanceDetails);
31
35
  for (const key in pins) {
@@ -66,18 +70,22 @@ function generateKiCADNetList(netlist) {
66
70
  ]);
67
71
  counter++;
68
72
  }
73
+ const dateString = new Date().toISOString().slice(0, 10);
69
74
  const tree = [
70
75
  Id("export"),
71
76
  [Id("version"), "E"],
72
77
  [Id("design"),
73
- [Id("source"), "/somefile"],
74
- [Id("date"), "2023-11-19"],
78
+ [Id("source"), "/unknown-file"],
79
+ [Id("date"), dateString],
75
80
  [Id("tool"), "circuitscript-to-kicad"]
76
81
  ],
77
82
  [Id('components'), ...componentsList],
78
83
  [Id('nets'), ...netItems]
79
84
  ];
80
- return printTree(tree);
85
+ return {
86
+ tree,
87
+ missingFootprints
88
+ };
81
89
  }
82
90
  exports.generateKiCADNetList = generateKiCADNetList;
83
91
  function printTree(tree, level = 0) {
@@ -99,6 +107,7 @@ function printTree(tree, level = 0) {
99
107
  }
100
108
  return "(" + output.join(" ") + ")";
101
109
  }
110
+ exports.printTree = printTree;
102
111
  function Id(name) {
103
112
  return new IdObject(name);
104
113
  }
@@ -107,3 +116,80 @@ class IdObject {
107
116
  this.keyName = keyName;
108
117
  }
109
118
  }
119
+ exports.IdObject = IdObject;
120
+ function _id(key) {
121
+ return new IdObject(key);
122
+ }
123
+ exports._id = _id;
124
+ class SExpObject {
125
+ constructor(object) {
126
+ this.object = object;
127
+ }
128
+ getKey(object = null) {
129
+ object = object ?? this.object;
130
+ return object[0];
131
+ }
132
+ getValue(object = null) {
133
+ object = object ?? this.object;
134
+ return object.slice(1);
135
+ }
136
+ getJSON(object = null) {
137
+ object = object ?? this.object;
138
+ if (!Array.isArray(object)) {
139
+ return object;
140
+ }
141
+ const properties = {};
142
+ const keyName = object[0].keyName;
143
+ if (object.length === 2) {
144
+ properties[keyName] = this.getJSON(object[1]);
145
+ }
146
+ else {
147
+ const innerProps = {};
148
+ this.getValue(object).forEach(item => {
149
+ const tmpValue = this.getJSON(item);
150
+ if (typeof tmpValue === "object") {
151
+ for (const key in tmpValue) {
152
+ if (innerProps[key]) {
153
+ if (!Array.isArray(innerProps[key])) {
154
+ innerProps[key] = [innerProps[key]];
155
+ }
156
+ innerProps[key].push(tmpValue[key]);
157
+ }
158
+ else {
159
+ innerProps[key] = tmpValue[key];
160
+ }
161
+ }
162
+ }
163
+ else {
164
+ innerProps[item[0].keyName] = tmpValue;
165
+ }
166
+ });
167
+ properties[keyName] = innerProps;
168
+ }
169
+ return properties;
170
+ }
171
+ getWithId(id, object = null) {
172
+ object = object ?? this.object;
173
+ let result = null;
174
+ const key = object[0];
175
+ if (key.keyName === id) {
176
+ return object;
177
+ }
178
+ else {
179
+ this.getValue(object).some(item => {
180
+ if (Array.isArray(item)) {
181
+ result = this.getWithId(id, item);
182
+ if (result !== null) {
183
+ return true;
184
+ }
185
+ }
186
+ return false;
187
+ });
188
+ }
189
+ return result;
190
+ }
191
+ print() {
192
+ console.log(printTree(this.object));
193
+ }
194
+ }
195
+ exports.SExpObject = SExpObject;
@@ -3,16 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.VerticalAlign = exports.HorizontalAlign = exports.Geometry = exports.GeometryProp = exports.Label = void 0;
6
+ exports.VerticalAlign = exports.HorizontalAlign = exports.Geometry = exports.GeometryProp = exports.Label = exports.Textbox = void 0;
7
7
  const core_1 = __importDefault(require("@flatten-js/core"));
8
8
  const sizing_js_1 = require("./sizing.js");
9
9
  const globals_js_1 = require("./globals.js");
10
10
  const ParamDefinition_js_1 = require("./objects/ParamDefinition.js");
11
- class Label extends core_1.default.Polygon {
11
+ class Textbox extends core_1.default.Polygon {
12
12
  get box() {
13
13
  return this.polygon.box;
14
14
  }
15
- constructor(id, text, anchorPoint, polygon, style, bounds) {
15
+ constructor(id, text, anchorPoint, polygon, style, bounds, label) {
16
16
  super(polygon.vertices);
17
17
  this.anchorPoint = [0, 0];
18
18
  this.boundingBox = { width: -1, height: -1 };
@@ -24,8 +24,9 @@ class Label extends core_1.default.Polygon {
24
24
  this.boundingBox = polygon.box;
25
25
  this.polygon = polygon;
26
26
  this.textMeasurementBounds = bounds;
27
+ this.label = label;
27
28
  }
28
- static fromPoint(id, x, y, text, style) {
29
+ static fromPoint(id, x, y, text, style, label) {
29
30
  let useText;
30
31
  if (typeof text === 'number') {
31
32
  useText = text.toString();
@@ -38,7 +39,7 @@ class Label extends core_1.default.Polygon {
38
39
  useText = text;
39
40
  }
40
41
  else {
41
- throw 'Invalid string passed into label';
42
+ throw 'Invalid string passed into textbox';
42
43
  }
43
44
  const { fontSize = 10, anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', } = style ?? {};
44
45
  const { width, height, box } = (0, sizing_js_1.measureTextSize2)(useText, globals_js_1.defaultFont, fontSize, fontWeight, anchor, vanchor);
@@ -50,20 +51,23 @@ class Label extends core_1.default.Polygon {
50
51
  [box.x, box.y],
51
52
  ];
52
53
  const polygon = new core_1.default.Polygon(polygonCoords);
53
- return new Label(id, useText, [x, y], polygon, style, box);
54
+ return new Textbox(id, useText, [x, y], polygon, style, box, label);
54
55
  }
55
56
  rotate(angle, origin) {
56
57
  const feature = super.rotate(angle, origin);
57
- return new Label(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds);
58
+ return new Textbox(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds, this.label);
58
59
  }
59
60
  transform(matrix) {
60
61
  const feature = super.transform(matrix);
61
- return new Label(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds);
62
+ return new Textbox(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds, this.label);
62
63
  }
63
64
  getLabelPosition() {
64
65
  return this.anchorPoint;
65
66
  }
66
67
  }
68
+ exports.Textbox = Textbox;
69
+ class Label extends Textbox {
70
+ }
67
71
  exports.Label = Label;
68
72
  class GeometryProp {
69
73
  constructor(name, value) {
@@ -80,7 +84,10 @@ class Geometry {
80
84
  return new core_1.default.Line(Geometry.point(x1, y1), Geometry.point(x2, y2));
81
85
  }
82
86
  static label(id, x, y, text, style) {
83
- return Label.fromPoint(id, x, y, text, style);
87
+ return Textbox.fromPoint(id, x, y, text, style, true);
88
+ }
89
+ static textbox(id, x, y, text, style) {
90
+ return Textbox.fromPoint(id, x, y, text, style, false);
84
91
  }
85
92
  static segment(start, end) {
86
93
  return new core_1.default.Segment(Geometry.point(start[0], start[1]), Geometry.point(end[0], end[1]));
@@ -131,12 +138,28 @@ class Geometry {
131
138
  let maxX = Number.NEGATIVE_INFINITY;
132
139
  let maxY = Number.NEGATIVE_INFINITY;
133
140
  features.forEach(feature => {
134
- const box = feature.box;
135
- if (feature instanceof Label
141
+ const tmpBox = feature.box;
142
+ let box = {
143
+ xmin: tmpBox.xmin,
144
+ ymin: tmpBox.ymin,
145
+ xmax: tmpBox.xmax,
146
+ ymax: tmpBox.ymax
147
+ };
148
+ if (feature instanceof Textbox
149
+ && feature.label
136
150
  && typeof feature.text === 'string'
137
151
  && feature.text.trim().length === 0) {
138
152
  return;
139
153
  }
154
+ if (feature instanceof Textbox && !feature.label) {
155
+ const [x, y] = feature.anchorPoint;
156
+ box = {
157
+ xmin: box.xmin + x,
158
+ ymin: box.ymin + y,
159
+ xmax: box.xmax + x,
160
+ ymax: box.ymax + y
161
+ };
162
+ }
140
163
  if (box.xmin === undefined) {
141
164
  throw "Invalid box!";
142
165
  }
@@ -152,23 +175,11 @@ class Geometry {
152
175
  height: maxY - minY,
153
176
  };
154
177
  }
155
- static getType(feature) {
156
- if (feature instanceof Label) {
157
- return 'label';
158
- }
159
- else if (feature instanceof core_1.default.Polygon) {
160
- return 'polygon';
161
- }
162
- else if (feature instanceof core_1.default.Segment) {
163
- return 'segment';
164
- }
165
- console.log('unknown type', feature);
166
- }
167
- static featuresToPath(items) {
178
+ static featuresToPath(items, flipX, flipY) {
168
179
  const paths = [];
169
180
  let isClosedPolygon = false;
170
181
  items.forEach(item => {
171
- if (item instanceof Label) {
182
+ if (item instanceof Textbox) {
172
183
  return;
173
184
  }
174
185
  const path = [];
@@ -185,7 +196,15 @@ class Geometry {
185
196
  }
186
197
  const startPoint = getArcPointRadians(x, y, radius, item.startAngle);
187
198
  const endPoint = getArcPointRadians(x, y, radius, useEndAngle);
188
- paths.push('M', startPoint[0], startPoint[1], 'A', radius, radius, 0, 1, 1, endPoint[0], endPoint[1], extraEnd);
199
+ let largeArcSweepFlag = 0;
200
+ if (useEndAngle - item.startAngle > Math.PI) {
201
+ largeArcSweepFlag = 1;
202
+ }
203
+ let sweepFlag = 1;
204
+ if (flipX === 1 && flipY === 0) {
205
+ sweepFlag = 0;
206
+ }
207
+ paths.push('M', startPoint[0], startPoint[1], 'A', radius, radius, 0, largeArcSweepFlag, sweepFlag, endPoint[0], endPoint[1], extraEnd);
189
208
  }
190
209
  else {
191
210
  const coords = Geometry.getCoords(item);
@@ -13,8 +13,6 @@ var GlobalNames;
13
13
  exports.NoNetText = 'NO_NET';
14
14
  var ParamKeys;
15
15
  (function (ParamKeys) {
16
- ParamKeys["__is_net"] = "__is_net";
17
- ParamKeys["__is_label"] = "__is_label";
18
16
  ParamKeys["priority"] = "priority";
19
17
  ParamKeys["net_name"] = "net_name";
20
18
  })(ParamKeys || (exports.ParamKeys = ParamKeys = {}));
@@ -50,6 +48,7 @@ var ReferenceTypes;
50
48
  ReferenceTypes["value"] = "value";
51
49
  ReferenceTypes["variable"] = "variable";
52
50
  ReferenceTypes["instance"] = "instance";
51
+ ReferenceTypes["pinType"] = "pinType";
53
52
  })(ReferenceTypes || (exports.ReferenceTypes = ReferenceTypes = {}));
54
53
  var BlockTypes;
55
54
  (function (BlockTypes) {
@@ -188,8 +188,11 @@ function renderScript(scriptData, outputPath, options) {
188
188
  console.log('Error during annotation: ', err);
189
189
  }
190
190
  if (kicadNetlistPath) {
191
- const kicadNetList = (0, export_js_1.generateKiCADNetList)(visitor.getNetList());
192
- (0, fs_1.writeFileSync)(kicadNetlistPath, kicadNetList);
191
+ const { tree: kicadNetList, missingFootprints } = (0, export_js_1.generateKiCADNetList)(visitor.getNetList());
192
+ missingFootprints.forEach(entry => {
193
+ console.log(`${entry.refdes} (${entry.instanceName}) does not have footprint`);
194
+ });
195
+ (0, fs_1.writeFileSync)(kicadNetlistPath, (0, export_js_1.printTree)(kicadNetList));
193
196
  console.log('Generated KiCad netlist file');
194
197
  }
195
198
  const { sequence, nets } = visitor.getGraph();
@@ -223,6 +226,7 @@ function renderScript(scriptData, outputPath, options) {
223
226
  showStats && console.log('Render took:', generateSvgTimer.lap());
224
227
  if (outputPath) {
225
228
  (0, fs_1.writeFileSync)(outputPath, svgOutput);
229
+ console.log('Generated file', outputPath);
226
230
  }
227
231
  }
228
232
  catch (err) {