circuitscript 0.1.23 → 0.1.25

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 (57) hide show
  1. package/dist/cjs/BaseVisitor.js +35 -23
  2. package/dist/cjs/BomGeneration.js +167 -0
  3. package/dist/cjs/ComponentMatchConditions.js +116 -0
  4. package/dist/cjs/antlr/CircuitScriptLexer.js +247 -244
  5. package/dist/cjs/antlr/CircuitScriptParser.js +1476 -825
  6. package/dist/cjs/builtinMethods.js +6 -1
  7. package/dist/cjs/execute.js +27 -16
  8. package/dist/cjs/graph.js +10 -9
  9. package/dist/cjs/helpers.js +43 -18
  10. package/dist/cjs/layout.js +14 -13
  11. package/dist/cjs/main.js +17 -1
  12. package/dist/cjs/objects/ExecutionScope.js +3 -0
  13. package/dist/cjs/objects/PinDefinition.js +11 -1
  14. package/dist/cjs/objects/types.js +6 -4
  15. package/dist/cjs/rules-check/no-connect-on-connected-pin.js +81 -0
  16. package/dist/cjs/rules-check/rules.js +74 -0
  17. package/dist/cjs/rules-check/unconnected-pins.js +52 -0
  18. package/dist/cjs/visitor.js +121 -5
  19. package/dist/esm/BaseVisitor.js +35 -23
  20. package/dist/esm/BomGeneration.js +137 -0
  21. package/dist/esm/ComponentMatchConditions.js +109 -0
  22. package/dist/esm/antlr/CircuitScriptLexer.js +247 -244
  23. package/dist/esm/antlr/CircuitScriptParser.js +1471 -824
  24. package/dist/esm/antlr/CircuitScriptVisitor.js +7 -0
  25. package/dist/esm/builtinMethods.js +6 -1
  26. package/dist/esm/execute.js +27 -16
  27. package/dist/esm/graph.js +11 -10
  28. package/dist/esm/helpers.js +43 -18
  29. package/dist/esm/layout.js +15 -13
  30. package/dist/esm/main.js +17 -1
  31. package/dist/esm/objects/ExecutionScope.js +3 -0
  32. package/dist/esm/objects/PinDefinition.js +11 -1
  33. package/dist/esm/objects/types.js +7 -5
  34. package/dist/esm/rules-check/no-connect-on-connected-pin.js +77 -0
  35. package/dist/esm/rules-check/rules.js +70 -0
  36. package/dist/esm/rules-check/unconnected-pins.js +48 -0
  37. package/dist/esm/visitor.js +121 -5
  38. package/dist/libs/std.cst +7 -3
  39. package/dist/types/BomGeneration.d.ts +13 -0
  40. package/dist/types/ComponentMatchConditions.d.ts +19 -0
  41. package/dist/types/antlr/CircuitScriptLexer.d.ts +60 -59
  42. package/dist/types/antlr/CircuitScriptParser.d.ts +146 -62
  43. package/dist/types/antlr/CircuitScriptVisitor.d.ts +14 -0
  44. package/dist/types/execute.d.ts +2 -1
  45. package/dist/types/graph.d.ts +6 -1
  46. package/dist/types/helpers.d.ts +7 -2
  47. package/dist/types/layout.d.ts +3 -2
  48. package/dist/types/objects/ExecutionScope.d.ts +8 -2
  49. package/dist/types/objects/ParamDefinition.d.ts +1 -1
  50. package/dist/types/objects/PinDefinition.d.ts +1 -0
  51. package/dist/types/objects/types.d.ts +4 -2
  52. package/dist/types/rules-check/no-connect-on-connected-pin.d.ts +3 -0
  53. package/dist/types/rules-check/rules.d.ts +15 -0
  54. package/dist/types/rules-check/unconnected-pins.d.ts +2 -0
  55. package/dist/types/visitor.d.ts +10 -1
  56. package/libs/std.cst +7 -3
  57. package/package.json +2 -1
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RuleCheck_UnconnectedPinsWires = void 0;
4
+ const graph_js_1 = require("../graph.js");
5
+ const rules_js_1 = require("./rules.js");
6
+ function RuleCheck_UnconnectedPinsWires(graph) {
7
+ const items = [];
8
+ const allNodes = graph.nodes();
9
+ allNodes.forEach(node => {
10
+ const nodeInfo = graph.node(node);
11
+ if (nodeInfo[0] === graph_js_1.RenderItemType.Component) {
12
+ const { component } = nodeInfo[1];
13
+ const edges = graph.nodeEdges(node);
14
+ const instanceName = component.instanceName;
15
+ const connectedPins = [];
16
+ edges.forEach(edge => {
17
+ const edgeInfo = graph.edge(edge.v, edge.w);
18
+ let pin;
19
+ if (edge.v === instanceName) {
20
+ pin = edgeInfo[1];
21
+ }
22
+ else if (edge.w === instanceName) {
23
+ pin = edgeInfo[3];
24
+ }
25
+ connectedPins.push(pin.getHashValue());
26
+ });
27
+ const pinIds = Array.from(component.pins.keys());
28
+ pinIds.forEach(pinId => {
29
+ const hashValue = pinId.getHashValue();
30
+ if (connectedPins.indexOf(hashValue) === -1) {
31
+ items.push({
32
+ type: rules_js_1.ERC_Rules.UnconnectedPin,
33
+ instance: component,
34
+ pin: pinId,
35
+ });
36
+ }
37
+ });
38
+ }
39
+ else if (nodeInfo[0] === graph_js_1.RenderItemType.Wire) {
40
+ const renderWire = nodeInfo[1];
41
+ const edges = graph.nodeEdges(node);
42
+ if (edges.length < 2) {
43
+ items.push({
44
+ type: rules_js_1.ERC_Rules.UnconnectedWire,
45
+ wire: renderWire.wire,
46
+ });
47
+ }
48
+ }
49
+ });
50
+ return items;
51
+ }
52
+ exports.RuleCheck_UnconnectedPinsWires = RuleCheck_UnconnectedPinsWires;
@@ -14,10 +14,12 @@ const utils_js_2 = require("./utils.js");
14
14
  const helpers_js_1 = require("./helpers.js");
15
15
  const Frame_js_1 = require("./objects/Frame.js");
16
16
  const ComponentAnnotater_js_1 = require("./ComponentAnnotater.js");
17
+ const ComponentMatchConditions_js_1 = require("./ComponentMatchConditions.js");
17
18
  class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
18
19
  constructor() {
19
20
  super(...arguments);
20
21
  this.componentCreationIndex = 0;
22
+ this.creationCtx = new Map();
21
23
  this.visitKeyword_assignment_expr = (ctx) => {
22
24
  const id = ctx.ID().getText();
23
25
  const value = this.visitResult(ctx.data_expr());
@@ -542,7 +544,7 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
542
544
  scope.triggerPropertyHandler(this, value, ctxValue);
543
545
  this.getScope().exitContext();
544
546
  this.getScope().exitContext();
545
- if (value instanceof types_js_1.UndeclaredReference && (value.reference.parentValue === undefined
547
+ if (value instanceof types_js_1.UndeclaredReference && (value.reference.rootValue === undefined
546
548
  && value.reference.value === undefined)) {
547
549
  throw value.throwMessage();
548
550
  }
@@ -611,11 +613,11 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
611
613
  componentCtx = ctxAssignmentExpr;
612
614
  }
613
615
  if (dataResult instanceof types_js_1.AnyReference) {
614
- const { trailers = [], parentValue = null } = dataResult;
615
- if (parentValue instanceof ClassComponent_js_1.ClassComponent
616
+ const { trailers = [], rootValue = null } = dataResult;
617
+ if (rootValue instanceof ClassComponent_js_1.ClassComponent
616
618
  && trailers.length > 0
617
619
  && trailers[0] === globals_js_1.ModuleContainsKeyword) {
618
- dataResult = parentValue;
620
+ dataResult = rootValue;
619
621
  this.placeModuleContains(dataResult);
620
622
  }
621
623
  }
@@ -1011,7 +1013,8 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1011
1013
  const segments = wireAtomExpr.map(wireSegment => {
1012
1014
  return this.visitResult(wireSegment);
1013
1015
  });
1014
- this.getExecutor().addWire(segments);
1016
+ const newWire = this.getExecutor().addWire(segments);
1017
+ this.creationCtx.set(newWire, ctx);
1015
1018
  };
1016
1019
  this.visitPoint_expr = (ctx) => {
1017
1020
  const ID = ctx.ID();
@@ -1199,6 +1202,119 @@ class ParserVisitor extends BaseVisitor_js_1.BaseVisitor {
1199
1202
  }
1200
1203
  }
1201
1204
  };
1205
+ this.visitPart_set_expr = (ctx) => {
1206
+ const paramKeys = ctx.data_expr().map(ctx => {
1207
+ return this.visitResult(ctx);
1208
+ });
1209
+ const partConditionTree = this.visitResult(ctx.part_match_block());
1210
+ const flattenedTree = (0, ComponentMatchConditions_js_1.flattenConditionNodes)(partConditionTree);
1211
+ const partConditions = (0, ComponentMatchConditions_js_1.extractPartConditions)(flattenedTree);
1212
+ const instances = this.getScope().getInstances();
1213
+ (0, ComponentMatchConditions_js_1.applyPartConditions)(instances, paramKeys, partConditions);
1214
+ };
1215
+ this.visitPart_match_block = (ctx) => {
1216
+ const results = ctx.part_sub_expr().map(ctxExpr => {
1217
+ return this.visitResult(ctxExpr);
1218
+ });
1219
+ this.setResult(ctx, results);
1220
+ };
1221
+ this.visitPart_sub_expr = (ctx) => {
1222
+ const ctxForm1 = ctx.part_condition_expr();
1223
+ const ctxForm2 = ctx.part_condition_key_only_expr();
1224
+ const ctxForm3 = ctx.part_value_expr();
1225
+ let result;
1226
+ if (ctxForm1) {
1227
+ result = this.visitResult(ctxForm1);
1228
+ }
1229
+ else if (ctxForm2) {
1230
+ result = this.visitResult(ctxForm2);
1231
+ }
1232
+ else if (ctxForm3) {
1233
+ result = this.visitResult(ctxForm3);
1234
+ }
1235
+ this.setResult(ctx, result);
1236
+ };
1237
+ this.visitPart_set_key = (ctx) => {
1238
+ const ctxID = ctx.ID();
1239
+ const ctxIntegerValue = ctx.INTEGER_VALUE();
1240
+ const ctxNumericValue = ctx.NUMERIC_VALUE();
1241
+ const ctxStringValue = ctx.STRING_VALUE();
1242
+ let useType = '';
1243
+ let useValue;
1244
+ if (ctxID) {
1245
+ useType = 'ID';
1246
+ useValue = ctxID.getText();
1247
+ }
1248
+ else if (ctxIntegerValue) {
1249
+ useType = 'number',
1250
+ useValue = Number(ctxIntegerValue.getText());
1251
+ }
1252
+ else if (ctxNumericValue) {
1253
+ useType = 'NUMERIC_VALUE';
1254
+ useValue = (0, ParamDefinition_js_1.numeric)(ctxNumericValue.getText());
1255
+ }
1256
+ else if (ctxStringValue) {
1257
+ useType = 'STRING_VALUE';
1258
+ useValue = this.prepareStringValue(ctxStringValue.getText());
1259
+ }
1260
+ this.setResult(ctx, {
1261
+ type: useType,
1262
+ value: useValue
1263
+ });
1264
+ };
1265
+ this.visitPart_value_expr = (ctx) => {
1266
+ const key = this.visitResult(ctx.part_set_key());
1267
+ const values = ctx.data_expr().map(ctxData => {
1268
+ return this.visitResult(ctxData);
1269
+ });
1270
+ this.setResult(ctx, { key, endValue: values });
1271
+ };
1272
+ this.visitPart_condition_expr = (ctx) => {
1273
+ const allKeys = ctx._key_id.map(ctx => {
1274
+ return this.visitResult(ctx);
1275
+ });
1276
+ const allValues = ctx._values.map(ctx => {
1277
+ return this.visitResult(ctx);
1278
+ });
1279
+ let deepestChildren = [];
1280
+ const ctxPartMatchBlock = ctx.part_match_block();
1281
+ if (ctxPartMatchBlock) {
1282
+ deepestChildren = this.visitResult(ctxPartMatchBlock);
1283
+ }
1284
+ let lastValue = undefined;
1285
+ if (ctx._last_data.length > 0) {
1286
+ lastValue = ctx._last_data.map(ctxData => {
1287
+ return this.visitResult(ctxData);
1288
+ });
1289
+ }
1290
+ if (ctx._id_only) {
1291
+ allKeys.push(this.visitResult(ctx._id_only));
1292
+ allValues.push(undefined);
1293
+ }
1294
+ const reversedKeys = [...allKeys].reverse();
1295
+ const reversedValues = [...allValues].reverse();
1296
+ let tmpKeyValues;
1297
+ reversedKeys.forEach((key, index) => {
1298
+ const node = {
1299
+ key,
1300
+ values: (reversedValues[index] !== undefined) ? [reversedValues[index]] : undefined,
1301
+ children: (index === 0) ? deepestChildren : [tmpKeyValues],
1302
+ };
1303
+ if (index === 0 && lastValue !== undefined) {
1304
+ node.endValue = lastValue;
1305
+ }
1306
+ tmpKeyValues = node;
1307
+ });
1308
+ this.setResult(ctx, tmpKeyValues);
1309
+ };
1310
+ this.visitPart_condition_key_only_expr = (ctx) => {
1311
+ const key = this.visitResult(ctx.part_set_key());
1312
+ const children = this.visitResult(ctx.part_match_block());
1313
+ this.setResult(ctx, {
1314
+ key,
1315
+ children,
1316
+ });
1317
+ };
1202
1318
  this.pinTypes = [
1203
1319
  PinTypes_js_1.PinTypes.Any,
1204
1320
  PinTypes_js_1.PinTypes.IO,
@@ -48,7 +48,9 @@ export class BaseVisitor extends CircuitScriptVisitor {
48
48
  scope.sequence.push([
49
49
  SequenceAction.At, scope.componentRoot, scope.currentPin
50
50
  ]);
51
- scope.setVariable(GlobalDocumentName, {});
51
+ scope.setVariable(GlobalDocumentName, {
52
+ 'bom': {},
53
+ });
52
54
  this.setupBuiltInFunctions(this.startingContext);
53
55
  this.executionStack = [this.startingContext];
54
56
  this.startingContext.resolveNet =
@@ -168,34 +170,39 @@ export class BaseVisitor extends CircuitScriptVisitor {
168
170
  sequenceParts.push(...[itemType, leftSideReference.name, rhsValue]);
169
171
  }
170
172
  else {
171
- if (leftSideReference.parentValue instanceof ClassComponent) {
172
- this.setInstanceParam(leftSideReference.parentValue, trailers, rhsValue);
173
- this.log2(`assigned component param ${leftSideReference.parentValue} trailers: ${trailers} value: ${rhsValue}`);
174
- sequenceParts.push(...['instance', [leftSideReference.parentValue, trailers], rhsValue]);
175
- if (leftSideReference.parentValue.typeProp === ComponentTypes.net) {
176
- const net = this.getScope().getNet(leftSideReference.parentValue, new PinId(1));
173
+ if (leftSideReference.rootValue instanceof ClassComponent) {
174
+ this.setInstanceParam(leftSideReference.rootValue, trailers, rhsValue);
175
+ this.log2(`assigned component param ${leftSideReference.rootValue} trailers: ${trailers} value: ${rhsValue}`);
176
+ sequenceParts.push(...['instance', [leftSideReference.rootValue, trailers], rhsValue]);
177
+ if (leftSideReference.rootValue.typeProp === ComponentTypes.net) {
178
+ const net = this.getScope().getNet(leftSideReference.rootValue, new PinId(1));
177
179
  if (net) {
178
180
  const trailerValue = trailers.join(".");
179
181
  net.params.set(trailerValue, rhsValue);
180
182
  }
181
183
  }
182
184
  }
183
- else if (leftSideReference.parentValue instanceof Object) {
185
+ else if (leftSideReference.rootValue instanceof Object) {
184
186
  if (Array.isArray(trailers[0]) && trailers[0][0] === TrailerArrayIndex) {
185
- if (Array.isArray(leftSideReference.parentValue)) {
187
+ if (Array.isArray(leftSideReference.rootValue)) {
186
188
  const arrayIndexValue = trailers[0][1];
187
- leftSideReference.parentValue[arrayIndexValue] = rhsValue;
188
- this.log2(`assigned array index ${leftSideReference.parentValue} index: ${arrayIndexValue} value: ${rhsValue}`);
189
+ leftSideReference.rootValue[arrayIndexValue] = rhsValue;
190
+ this.log2(`assigned array index ${leftSideReference.rootValue} index: ${arrayIndexValue} value: ${rhsValue}`);
189
191
  }
190
192
  else {
191
193
  this.throwWithContext(lhsCtx, "Invalid array");
192
194
  }
193
195
  }
194
196
  else {
195
- leftSideReference.parentValue[trailers.join('.')] = rhsValue;
196
- this.log2(`assigned object ${leftSideReference.parentValue} trailers: ${trailers} value: ${rhsValue}`);
197
+ let expandedValue = leftSideReference.rootValue;
198
+ trailers.slice(0, -1).forEach(trailer => {
199
+ expandedValue = expandedValue[trailer];
200
+ });
201
+ const lastTrailer = trailers.slice(-1)[0];
202
+ expandedValue[lastTrailer] = rhsValue;
203
+ this.log2(`assigned object ${leftSideReference.rootValue} trailers: ${trailers} value: ${rhsValue}`);
197
204
  }
198
- sequenceParts.push(...['variable', [leftSideReference.parentValue, trailers], rhsValue]);
205
+ sequenceParts.push(...['variable', [leftSideReference.rootValue, trailers], rhsValue]);
199
206
  }
200
207
  }
201
208
  if (sequenceParts.length > 0) {
@@ -268,7 +275,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
268
275
  const reference = this.visitResult(ctx);
269
276
  const { trailers = [] } = reference;
270
277
  const undefinedParentWithTrailers = trailers.length > 0
271
- && reference.parentValue === undefined;
278
+ && reference.rootValue === undefined;
272
279
  if (undefinedParentWithTrailers) {
273
280
  this.throwWithContext(ctx, 'Undefined reference: ' + reference.name + '.' + trailers.join('.'));
274
281
  }
@@ -282,7 +289,12 @@ export class BaseVisitor extends CircuitScriptVisitor {
282
289
  let nextReference;
283
290
  if (ctxID) {
284
291
  reference.trailers.push(ctxID.getText());
285
- nextReference = this.getExecutor().resolveTrailers(reference.type, useValue, reference.trailers);
292
+ const useRootValue = reference.rootValue ?? reference.value;
293
+ const useTrailerIndex = reference.trailerIndex ?? 0;
294
+ nextReference = this.getExecutor().resolveTrailers(reference.type, useRootValue, reference.trailers);
295
+ nextReference.name =
296
+ [reference.name,
297
+ ...reference.trailers.slice(useTrailerIndex)].join('.');
286
298
  }
287
299
  else if (ctxDataExpr) {
288
300
  const arrayIndex = this.visitResult(ctxDataExpr);
@@ -296,7 +308,7 @@ export class BaseVisitor extends CircuitScriptVisitor {
296
308
  type: refType,
297
309
  value: foundValue,
298
310
  trailers: [[TrailerArrayIndex, arrayIndexValue]],
299
- parentValue: useValue
311
+ rootValue: useValue
300
312
  });
301
313
  }
302
314
  }
@@ -315,15 +327,15 @@ export class BaseVisitor extends CircuitScriptVisitor {
315
327
  });
316
328
  }
317
329
  else {
330
+ this.log('resolve variable ctx: ' + ctx.getText(), 'atomId', atomId);
318
331
  currentReference = executor.resolveVariable(this.executionStack, atomId);
332
+ this.log('reference:', currentReference.name, 'found:', currentReference.found);
319
333
  }
320
334
  if (currentReference !== undefined && currentReference.found) {
321
- const trailersLength = ctx.trailer_expr2().length;
322
- for (let i = 0; i < trailersLength; i++) {
323
- const trailerCtx = ctx.trailer_expr2(i);
324
- this.setResult(trailerCtx, currentReference);
325
- currentReference = this.visitResult(trailerCtx);
326
- }
335
+ ctx.trailer_expr2().forEach(ctxTrailer => {
336
+ this.setResult(ctxTrailer, currentReference);
337
+ currentReference = this.visitResult(ctxTrailer);
338
+ });
327
339
  }
328
340
  this.setResult(ctx, currentReference);
329
341
  this.log2('atom resolved: ' + ctx.getText() + ' -> ' + currentReference);
@@ -0,0 +1,137 @@
1
+ import * as csv from '@fast-csv/format';
2
+ import * as fs from 'fs';
3
+ import { NumericValue } from "./objects/ParamDefinition.js";
4
+ const TypeSortOrder = {
5
+ "res": 1,
6
+ "cap": 2,
7
+ "ind": 3,
8
+ "diode": 9,
9
+ "ic": 10,
10
+ "conn": 20,
11
+ };
12
+ export function generateBom(bomConfig, instances) {
13
+ const bomComponents = extractComponentValuesForBom(bomConfig, instances);
14
+ const tmpGroupedComponents = groupComponents(bomConfig, bomComponents);
15
+ const groupedBom = [];
16
+ tmpGroupedComponents.forEach(value => {
17
+ groupedBom.push({
18
+ ...value.items[0],
19
+ refdes: value.allRefdes.join(', ')
20
+ });
21
+ });
22
+ const sortedGroupedBom = groupedBom.toSorted((a, b) => {
23
+ const typeSortA = TypeSortOrder[a['.type']] ?? 100;
24
+ const typeSortB = TypeSortOrder[b['.type']] ?? 100;
25
+ return typeSortA - typeSortB;
26
+ });
27
+ return sortedGroupedBom;
28
+ }
29
+ export function groupComponents(bomConfig, bomComponents) {
30
+ const { group_by } = bomConfig;
31
+ const grouped = new Map();
32
+ bomComponents.forEach(row => {
33
+ const groupKeyParts = {};
34
+ group_by.forEach(paramKey => {
35
+ groupKeyParts[paramKey] = row[paramKey];
36
+ });
37
+ const groupKey = JSON.stringify(groupKeyParts);
38
+ if (!grouped.has(groupKey)) {
39
+ grouped.set(groupKey, {
40
+ allRefdes: [],
41
+ items: [],
42
+ });
43
+ }
44
+ const entry = grouped.get(groupKey);
45
+ entry.items.push(row);
46
+ entry.allRefdes.push(row.refdes);
47
+ grouped.set(groupKey, entry);
48
+ });
49
+ return grouped;
50
+ }
51
+ function extractComponentValuesForBom(bomConfig, instances) {
52
+ const { columns = [] } = bomConfig;
53
+ const resultRows = [];
54
+ instances.forEach(instance => {
55
+ if (instance.assignedRefDes !== null) {
56
+ const row = {
57
+ '.type': instance.typeProp,
58
+ };
59
+ columns.forEach(paramKey => {
60
+ let useValue = '';
61
+ if (paramKey === 'refdes') {
62
+ useValue = instance.assignedRefDes;
63
+ }
64
+ else {
65
+ if (instance.hasParam(paramKey)) {
66
+ useValue = instance.getParam(paramKey);
67
+ if (typeof useValue === 'string') {
68
+ useValue = resolveValuesInTemplate(instance, useValue);
69
+ }
70
+ else if (useValue instanceof NumericValue) {
71
+ useValue = useValue.toDisplayString();
72
+ }
73
+ }
74
+ }
75
+ row[paramKey] = useValue;
76
+ });
77
+ resultRows.push(row);
78
+ }
79
+ });
80
+ return resultRows;
81
+ }
82
+ function resolveValuesInTemplate(instance, templateString) {
83
+ return templateString.replace(/\{(\w+)\}/g, (match, paramName) => {
84
+ if (instance.hasParam(paramName)) {
85
+ const paramValue = instance.getParam(paramName);
86
+ if (paramValue instanceof NumericValue) {
87
+ return paramValue.toDisplayString();
88
+ }
89
+ return instance.getParam(paramName);
90
+ }
91
+ return match;
92
+ });
93
+ }
94
+ export function generateBomCSV(bomData) {
95
+ const useHeaders = [];
96
+ const rows = [];
97
+ if (bomData.length > 0) {
98
+ const [firstRow] = bomData;
99
+ for (const key in firstRow) {
100
+ if (key.startsWith('.')) {
101
+ continue;
102
+ }
103
+ const useKey = key[0].toUpperCase() + key.substring(1);
104
+ useHeaders.push(useKey);
105
+ }
106
+ }
107
+ rows.push(useHeaders);
108
+ const keys = [];
109
+ if (bomData.length > 0) {
110
+ for (const key in bomData[0]) {
111
+ if (key.startsWith('.')) {
112
+ continue;
113
+ }
114
+ keys.push(key);
115
+ }
116
+ }
117
+ bomData.forEach(row => {
118
+ const result = keys.map(key => {
119
+ return row[key];
120
+ });
121
+ rows.push(result);
122
+ });
123
+ return rows;
124
+ }
125
+ export async function saveBomOutputCsv(bomCsvOutput, filePath) {
126
+ return new Promise(resolve => {
127
+ const outputStream = fs.createWriteStream(filePath);
128
+ const csvStream = csv.format();
129
+ csvStream.pipe(outputStream).on("finish", () => {
130
+ resolve();
131
+ });
132
+ bomCsvOutput.forEach(row => {
133
+ csvStream.write(row);
134
+ });
135
+ csvStream.end();
136
+ });
137
+ }
@@ -0,0 +1,109 @@
1
+ import { NumericValue } from "./objects/ParamDefinition.js";
2
+ import { TypeProps } from "./objects/types.js";
3
+ export function flattenConditionNodes(conditionNodes, level = 0) {
4
+ const conditionBranches = [];
5
+ conditionNodes.forEach(node => {
6
+ const { key, values, children = [], endValue = [] } = node;
7
+ const firstCondition = {
8
+ key, values, endValue
9
+ };
10
+ if (children.length > 0) {
11
+ const nestedBranches = flattenConditionNodes(children, level + 1);
12
+ nestedBranches.forEach(tmpCondition => {
13
+ if (values === undefined) {
14
+ const modifiedCondition = {
15
+ ...firstCondition,
16
+ values: [tmpCondition[0].key.value],
17
+ endValue: tmpCondition[0].endValue
18
+ };
19
+ conditionBranches.push([
20
+ modifiedCondition,
21
+ ...tmpCondition.slice(1)
22
+ ]);
23
+ }
24
+ else {
25
+ conditionBranches.push([
26
+ firstCondition,
27
+ ...tmpCondition
28
+ ]);
29
+ }
30
+ });
31
+ }
32
+ else {
33
+ conditionBranches.push([firstCondition]);
34
+ }
35
+ });
36
+ return conditionBranches;
37
+ }
38
+ export function extractPartConditions(conditionBranches) {
39
+ const partConditions = conditionBranches.map(branch => {
40
+ const lastNode = branch[branch.length - 1];
41
+ const { endValue } = lastNode;
42
+ const conditions = [];
43
+ branch.forEach((node, index) => {
44
+ conditions.push({
45
+ key: node.key,
46
+ values: node.values
47
+ });
48
+ });
49
+ return {
50
+ endValue,
51
+ conditions
52
+ };
53
+ });
54
+ return partConditions;
55
+ }
56
+ export function partMatchesConditions(instance, partConditions) {
57
+ for (let i = 0; i < partConditions.length; i++) {
58
+ const { endValue, conditions } = partConditions[i];
59
+ const didNotMatch = conditions.some(condition => {
60
+ const { key, values } = condition;
61
+ let useKey = '';
62
+ if (key.type === 'ID') {
63
+ useKey = key.value;
64
+ }
65
+ else {
66
+ console.log('key type not supported', key);
67
+ return true;
68
+ }
69
+ if (useKey === 'type') {
70
+ return (instance.typeProp !== values[0]);
71
+ }
72
+ else {
73
+ if (!instance.hasParam(useKey)) {
74
+ return true;
75
+ }
76
+ else {
77
+ const paramValue = instance.getParam(useKey);
78
+ const compareValue = values[0];
79
+ if (typeof compareValue === "string") {
80
+ return (compareValue !== paramValue);
81
+ }
82
+ else if (compareValue instanceof NumericValue) {
83
+ return !compareValue.eq(paramValue);
84
+ }
85
+ else if (typeof compareValue === 'number') {
86
+ return compareValue !== paramValue;
87
+ }
88
+ }
89
+ }
90
+ });
91
+ if (didNotMatch === false) {
92
+ return endValue;
93
+ }
94
+ }
95
+ }
96
+ export function applyPartConditions(instances, paramKeys, partConditions) {
97
+ instances.forEach(item => {
98
+ if (item.typeProp !== TypeProps.Graphic) {
99
+ const matchedResult = partMatchesConditions(item, partConditions);
100
+ if (matchedResult !== undefined) {
101
+ paramKeys.forEach((paramKey, index) => {
102
+ if (matchedResult[index] !== undefined) {
103
+ item.setParam(paramKey, matchedResult[index]);
104
+ }
105
+ });
106
+ }
107
+ }
108
+ });
109
+ }