@intelligentelectron/universal-netlist 0.0.12

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 (105) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +4 -0
  4. package/README.md +246 -0
  5. package/dist/circuit-traversal.d.ts +73 -0
  6. package/dist/circuit-traversal.d.ts.map +1 -0
  7. package/dist/circuit-traversal.js +299 -0
  8. package/dist/circuit-traversal.js.map +1 -0
  9. package/dist/cli/commands.d.ts +23 -0
  10. package/dist/cli/commands.d.ts.map +1 -0
  11. package/dist/cli/commands.js +140 -0
  12. package/dist/cli/commands.js.map +1 -0
  13. package/dist/cli/prompts.d.ts +10 -0
  14. package/dist/cli/prompts.d.ts.map +1 -0
  15. package/dist/cli/prompts.js +22 -0
  16. package/dist/cli/prompts.js.map +1 -0
  17. package/dist/cli/shell.d.ts +15 -0
  18. package/dist/cli/shell.d.ts.map +1 -0
  19. package/dist/cli/shell.js +66 -0
  20. package/dist/cli/shell.js.map +1 -0
  21. package/dist/cli/updater.d.ts +46 -0
  22. package/dist/cli/updater.d.ts.map +1 -0
  23. package/dist/cli/updater.js +319 -0
  24. package/dist/cli/updater.js.map +1 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +63 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/parsers/altium/connectivity.d.ts +32 -0
  30. package/dist/parsers/altium/connectivity.d.ts.map +1 -0
  31. package/dist/parsers/altium/connectivity.js +308 -0
  32. package/dist/parsers/altium/connectivity.js.map +1 -0
  33. package/dist/parsers/altium/discovery.d.ts +30 -0
  34. package/dist/parsers/altium/discovery.d.ts.map +1 -0
  35. package/dist/parsers/altium/discovery.js +174 -0
  36. package/dist/parsers/altium/discovery.js.map +1 -0
  37. package/dist/parsers/altium/hierarchy.d.ts +29 -0
  38. package/dist/parsers/altium/hierarchy.d.ts.map +1 -0
  39. package/dist/parsers/altium/hierarchy.js +94 -0
  40. package/dist/parsers/altium/hierarchy.js.map +1 -0
  41. package/dist/parsers/altium/index.d.ts +53 -0
  42. package/dist/parsers/altium/index.d.ts.map +1 -0
  43. package/dist/parsers/altium/index.js +404 -0
  44. package/dist/parsers/altium/index.js.map +1 -0
  45. package/dist/parsers/altium/net-extractor.d.ts +24 -0
  46. package/dist/parsers/altium/net-extractor.d.ts.map +1 -0
  47. package/dist/parsers/altium/net-extractor.js +295 -0
  48. package/dist/parsers/altium/net-extractor.js.map +1 -0
  49. package/dist/parsers/altium/ole-reader.d.ts +91 -0
  50. package/dist/parsers/altium/ole-reader.d.ts.map +1 -0
  51. package/dist/parsers/altium/ole-reader.js +304 -0
  52. package/dist/parsers/altium/ole-reader.js.map +1 -0
  53. package/dist/parsers/altium/record-parser.d.ts +21 -0
  54. package/dist/parsers/altium/record-parser.d.ts.map +1 -0
  55. package/dist/parsers/altium/record-parser.js +117 -0
  56. package/dist/parsers/altium/record-parser.js.map +1 -0
  57. package/dist/parsers/altium/schemas.d.ts +277 -0
  58. package/dist/parsers/altium/schemas.d.ts.map +1 -0
  59. package/dist/parsers/altium/schemas.js +246 -0
  60. package/dist/parsers/altium/schemas.js.map +1 -0
  61. package/dist/parsers/altium/types.d.ts +213 -0
  62. package/dist/parsers/altium/types.d.ts.map +1 -0
  63. package/dist/parsers/altium/types.js +180 -0
  64. package/dist/parsers/altium/types.js.map +1 -0
  65. package/dist/parsers/cadence/discovery.d.ts +45 -0
  66. package/dist/parsers/cadence/discovery.d.ts.map +1 -0
  67. package/dist/parsers/cadence/discovery.js +277 -0
  68. package/dist/parsers/cadence/discovery.js.map +1 -0
  69. package/dist/parsers/cadence/index.d.ts +41 -0
  70. package/dist/parsers/cadence/index.d.ts.map +1 -0
  71. package/dist/parsers/cadence/index.js +139 -0
  72. package/dist/parsers/cadence/index.js.map +1 -0
  73. package/dist/parsers/cadence/pstchip-parser.d.ts +23 -0
  74. package/dist/parsers/cadence/pstchip-parser.d.ts.map +1 -0
  75. package/dist/parsers/cadence/pstchip-parser.js +82 -0
  76. package/dist/parsers/cadence/pstchip-parser.js.map +1 -0
  77. package/dist/parsers/cadence/pstxnet-parser.d.ts +15 -0
  78. package/dist/parsers/cadence/pstxnet-parser.d.ts.map +1 -0
  79. package/dist/parsers/cadence/pstxnet-parser.js +55 -0
  80. package/dist/parsers/cadence/pstxnet-parser.js.map +1 -0
  81. package/dist/parsers/cadence/pstxprt-parser.d.ts +24 -0
  82. package/dist/parsers/cadence/pstxprt-parser.d.ts.map +1 -0
  83. package/dist/parsers/cadence/pstxprt-parser.js +75 -0
  84. package/dist/parsers/cadence/pstxprt-parser.js.map +1 -0
  85. package/dist/parsers/index.d.ts +33 -0
  86. package/dist/parsers/index.d.ts.map +1 -0
  87. package/dist/parsers/index.js +49 -0
  88. package/dist/parsers/index.js.map +1 -0
  89. package/dist/server.d.ts +16 -0
  90. package/dist/server.d.ts.map +1 -0
  91. package/dist/server.js +277 -0
  92. package/dist/server.js.map +1 -0
  93. package/dist/service.d.ts +129 -0
  94. package/dist/service.d.ts.map +1 -0
  95. package/dist/service.js +759 -0
  96. package/dist/service.js.map +1 -0
  97. package/dist/types.d.ts +242 -0
  98. package/dist/types.d.ts.map +1 -0
  99. package/dist/types.js +27 -0
  100. package/dist/types.js.map +1 -0
  101. package/dist/version.d.ts +10 -0
  102. package/dist/version.d.ts.map +1 -0
  103. package/dist/version.js +25 -0
  104. package/dist/version.js.map +1 -0
  105. package/package.json +74 -0
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Altium Connectivity Detection
3
+ *
4
+ * Uses spatial indexing and Union-Find for O(n) connectivity detection
5
+ * instead of O(n²) pairwise comparisons.
6
+ */
7
+ import { RECORD_TYPES } from './types.js';
8
+ /**
9
+ * Union-Find data structure for efficient connected component detection
10
+ */
11
+ class UnionFind {
12
+ parent = new Map();
13
+ rank = new Map();
14
+ find(x) {
15
+ if (!this.parent.has(x)) {
16
+ this.parent.set(x, x);
17
+ this.rank.set(x, 0);
18
+ }
19
+ if (this.parent.get(x) !== x) {
20
+ this.parent.set(x, this.find(this.parent.get(x)));
21
+ }
22
+ return this.parent.get(x);
23
+ }
24
+ union(x, y) {
25
+ let rootX = this.find(x);
26
+ let rootY = this.find(y);
27
+ if (rootX === rootY)
28
+ return;
29
+ const rankX = this.rank.get(rootX);
30
+ const rankY = this.rank.get(rootY);
31
+ if (rankX < rankY) {
32
+ [rootX, rootY] = [rootY, rootX];
33
+ }
34
+ this.parent.set(rootY, rootX);
35
+ if (rankX === rankY) {
36
+ this.rank.set(rootX, rankX + 1);
37
+ }
38
+ }
39
+ }
40
+ /**
41
+ * Grid-based spatial index for fast neighbor lookup
42
+ */
43
+ class SpatialIndex {
44
+ cellSize;
45
+ grid = new Map();
46
+ pointToDevices = new Map();
47
+ segmentCells = new Map();
48
+ constructor(cellSize = 10000) {
49
+ this.cellSize = cellSize;
50
+ }
51
+ cellKey(x, y) {
52
+ const cx = Math.floor(x / this.cellSize);
53
+ const cy = Math.floor(y / this.cellSize);
54
+ return `${cx},${cy}`;
55
+ }
56
+ coordKey(x, y) {
57
+ return `${x},${y}`;
58
+ }
59
+ cellsForSegment(p1, p2) {
60
+ const cells = new Set();
61
+ const [x1, y1] = p1;
62
+ const [x2, y2] = p2;
63
+ const minCx = Math.floor(Math.min(x1, x2) / this.cellSize);
64
+ const maxCx = Math.floor(Math.max(x1, x2) / this.cellSize);
65
+ const minCy = Math.floor(Math.min(y1, y2) / this.cellSize);
66
+ const maxCy = Math.floor(Math.max(y1, y2) / this.cellSize);
67
+ for (let cx = minCx; cx <= maxCx; cx++) {
68
+ for (let cy = minCy; cy <= maxCy; cy++) {
69
+ cells.add(`${cx},${cy}`);
70
+ }
71
+ }
72
+ return cells;
73
+ }
74
+ addDevice(device) {
75
+ if (!device.coords || device.coords.length === 0)
76
+ return;
77
+ const deviceIdx = device.index;
78
+ const allCells = new Set();
79
+ for (const coord of device.coords) {
80
+ const coordKeyStr = this.coordKey(coord[0], coord[1]);
81
+ if (!this.pointToDevices.has(coordKeyStr)) {
82
+ this.pointToDevices.set(coordKeyStr, []);
83
+ }
84
+ this.pointToDevices.get(coordKeyStr).push(deviceIdx);
85
+ const cellKeyStr = this.cellKey(coord[0], coord[1]);
86
+ allCells.add(cellKeyStr);
87
+ }
88
+ const recordType = device.RECORD;
89
+ if ((recordType === RECORD_TYPES.WIRE || recordType === RECORD_TYPES.PIN) &&
90
+ device.coords.length > 1) {
91
+ for (let i = 0; i < device.coords.length - 1; i++) {
92
+ const segCells = this.cellsForSegment(device.coords[i], device.coords[i + 1]);
93
+ for (const cell of segCells) {
94
+ allCells.add(cell);
95
+ }
96
+ }
97
+ }
98
+ this.segmentCells.set(deviceIdx, allCells);
99
+ for (const cell of allCells) {
100
+ if (!this.grid.has(cell)) {
101
+ this.grid.set(cell, []);
102
+ }
103
+ this.grid.get(cell).push(deviceIdx);
104
+ }
105
+ }
106
+ getCandidates(device) {
107
+ const cells = this.segmentCells.get(device.index);
108
+ if (!cells)
109
+ return new Set();
110
+ const candidates = new Set();
111
+ for (const cell of cells) {
112
+ const devicesInCell = this.grid.get(cell);
113
+ if (devicesInCell) {
114
+ for (const idx of devicesInCell) {
115
+ candidates.add(idx);
116
+ }
117
+ }
118
+ }
119
+ candidates.delete(device.index);
120
+ return candidates;
121
+ }
122
+ getPointToDevices() {
123
+ return this.pointToDevices;
124
+ }
125
+ }
126
+ /**
127
+ * Get line segments for a device.
128
+ */
129
+ const getLineSegments = (device) => {
130
+ if (!device.coords || device.coords.length === 0) {
131
+ return [];
132
+ }
133
+ if (device.RECORD === RECORD_TYPES.WIRE && device.coords.length > 1) {
134
+ const segments = [];
135
+ for (let i = 0; i < device.coords.length - 1; i++) {
136
+ segments.push([device.coords[i], device.coords[i + 1]]);
137
+ }
138
+ return segments;
139
+ }
140
+ if (device.RECORD === RECORD_TYPES.PIN && device.coords.length > 1) {
141
+ return [[device.coords[0], device.coords[1]]];
142
+ }
143
+ const point = device.coords[0];
144
+ return [[point, point]];
145
+ };
146
+ /**
147
+ * Check if a point lies on a line segment.
148
+ */
149
+ const pointOnSegment = (point, segment) => {
150
+ const [p1, p2] = segment;
151
+ const [px, py] = point;
152
+ const minX = Math.min(p1[0], p2[0]);
153
+ const maxX = Math.max(p1[0], p2[0]);
154
+ const minY = Math.min(p1[1], p2[1]);
155
+ const maxY = Math.max(p1[1], p2[1]);
156
+ return px >= minX && px <= maxX && py >= minY && py <= maxY;
157
+ };
158
+ /**
159
+ * Check if a point lies on any of the given line segments.
160
+ */
161
+ const pointOnAnySegment = (point, segments) => {
162
+ for (const segment of segments) {
163
+ if (pointOnSegment(point, segment)) {
164
+ return true;
165
+ }
166
+ }
167
+ return false;
168
+ };
169
+ /**
170
+ * Check if two devices are connected.
171
+ *
172
+ * Connectivity is determined by:
173
+ * 1. For wires: line segment intersection
174
+ * 2. For other devices: point overlap on wire segment
175
+ * 3. Special case: power ports/net labels with same TEXT value
176
+ */
177
+ export const isConnected = (deviceA, deviceB) => {
178
+ const segmentsA = getLineSegments(deviceA);
179
+ const segmentsB = getLineSegments(deviceB);
180
+ for (const segment of segmentsA) {
181
+ for (const vertex of segment) {
182
+ if (pointOnAnySegment(vertex, segmentsB)) {
183
+ return true;
184
+ }
185
+ }
186
+ }
187
+ for (const segment of segmentsB) {
188
+ for (const vertex of segment) {
189
+ if (pointOnAnySegment(vertex, segmentsA)) {
190
+ return true;
191
+ }
192
+ }
193
+ }
194
+ // Special case: power ports AND net labels with same Text are connected globally
195
+ const isGloballyNamedDevice = (d) => d.RECORD === RECORD_TYPES.POWER_PORT || d.RECORD === RECORD_TYPES.NET_LABEL;
196
+ const deviceAText = deviceA.Text ?? deviceA.TEXT;
197
+ const deviceBText = deviceB.Text ?? deviceB.TEXT;
198
+ if (isGloballyNamedDevice(deviceA) &&
199
+ isGloballyNamedDevice(deviceB) &&
200
+ deviceAText &&
201
+ deviceBText &&
202
+ deviceAText === deviceBText) {
203
+ return true;
204
+ }
205
+ return false;
206
+ };
207
+ /**
208
+ * Find all connected components using spatial indexing and Union-Find.
209
+ * This is O(n) average case instead of O(n²).
210
+ */
211
+ export const findAllConnectedComponents = (devices) => {
212
+ if (devices.length === 0)
213
+ return [];
214
+ const spatialIndex = new SpatialIndex();
215
+ for (const device of devices) {
216
+ spatialIndex.addDevice(device);
217
+ }
218
+ const uf = new UnionFind();
219
+ const deviceByIndex = new Map();
220
+ for (const d of devices) {
221
+ deviceByIndex.set(d.index, d);
222
+ uf.find(d.index); // Initialize
223
+ }
224
+ // Collect globally-named devices (power ports and net labels)
225
+ const globalLabels = new Map();
226
+ for (const device of devices) {
227
+ if (device.RECORD === RECORD_TYPES.POWER_PORT || device.RECORD === RECORD_TYPES.NET_LABEL) {
228
+ const text = (device.Text ?? device.TEXT);
229
+ if (text) {
230
+ if (!globalLabels.has(text)) {
231
+ globalLabels.set(text, []);
232
+ }
233
+ globalLabels.get(text).push(device.index);
234
+ }
235
+ }
236
+ }
237
+ // Union devices sharing exact coordinates
238
+ for (const deviceIndices of spatialIndex.getPointToDevices().values()) {
239
+ if (deviceIndices.length > 1) {
240
+ const first = deviceIndices[0];
241
+ for (let i = 1; i < deviceIndices.length; i++) {
242
+ uf.union(first, deviceIndices[i]);
243
+ }
244
+ }
245
+ }
246
+ // Union geometrically connected devices (only check candidates in same cells)
247
+ for (const device of devices) {
248
+ const candidates = spatialIndex.getCandidates(device);
249
+ for (const candidateIdx of candidates) {
250
+ const candidate = deviceByIndex.get(candidateIdx);
251
+ if (isConnected(device, candidate)) {
252
+ uf.union(device.index, candidateIdx);
253
+ }
254
+ }
255
+ }
256
+ // Union globally-named devices (power ports/net labels with same text)
257
+ for (const indices of globalLabels.values()) {
258
+ if (indices.length > 1) {
259
+ const first = indices[0];
260
+ for (let i = 1; i < indices.length; i++) {
261
+ uf.union(first, indices[i]);
262
+ }
263
+ }
264
+ }
265
+ // Group devices by their root
266
+ const components = new Map();
267
+ for (const device of devices) {
268
+ const root = uf.find(device.index);
269
+ if (!components.has(root)) {
270
+ components.set(root, []);
271
+ }
272
+ components.get(root).push(device);
273
+ }
274
+ return Array.from(components.values());
275
+ };
276
+ /**
277
+ * Find all devices directly connected to the given device.
278
+ */
279
+ export const findNeighbors = (device, allDevices) => {
280
+ const neighbors = [];
281
+ for (const other of allDevices) {
282
+ if (other.index === device.index) {
283
+ continue;
284
+ }
285
+ if (isConnected(device, other)) {
286
+ neighbors.push(other);
287
+ }
288
+ }
289
+ return neighbors;
290
+ };
291
+ /**
292
+ * Find all devices connected to a starting device using DFS.
293
+ * Note: This is kept for backwards compatibility but the new
294
+ * findAllConnectedComponents() is preferred for performance.
295
+ */
296
+ export const findConnectedDevices = (startDevice, allDevices, visited = []) => {
297
+ const alreadyVisited = visited.some((v) => v.index === startDevice.index);
298
+ if (alreadyVisited) {
299
+ return visited;
300
+ }
301
+ visited.push(startDevice);
302
+ const neighbors = findNeighbors(startDevice, allDevices);
303
+ for (const neighbor of neighbors) {
304
+ findConnectedDevices(neighbor, allDevices, visited);
305
+ }
306
+ return visited;
307
+ };
308
+ //# sourceMappingURL=connectivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectivity.js","sourceRoot":"","sources":["../../../src/parsers/altium/connectivity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK1C;;GAEG;AACH,MAAM,SAAS;IACL,MAAM,GAAwB,IAAI,GAAG,EAAE,CAAC;IACxC,IAAI,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE9C,IAAI,CAAC,CAAS;QACZ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,CAAS,EAAE,CAAS;QACxB,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,KAAK;YAAE,OAAO;QAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;QAEpC,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;YAClB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9B,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,YAAY;IACR,QAAQ,CAAS;IACjB,IAAI,GAA0B,IAAI,GAAG,EAAE,CAAC;IACxC,cAAc,GAA0B,IAAI,GAAG,EAAE,CAAC;IAClD,YAAY,GAA6B,IAAI,GAAG,EAAE,CAAC;IAE3D,YAAY,QAAQ,GAAG,KAAK;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEO,OAAO,CAAC,CAAS,EAAE,CAAS;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;IACvB,CAAC;IAEO,QAAQ,CAAC,CAAS,EAAE,CAAS;QACnC,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;IACrB,CAAC;IAEO,eAAe,CAAC,EAAc,EAAE,EAAc;QACpD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;QACpB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;QAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE3D,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;YACvC,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;gBACvC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,SAAS,CAAC,MAAoB;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEzD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;QAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACtD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,IACE,CAAC,UAAU,KAAK,YAAY,CAAC,IAAI,IAAI,UAAU,KAAK,YAAY,CAAC,GAAG,CAAC;YACrE,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EACxB,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC9E,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,aAAa,CAAC,MAAoB;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAE7B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,aAAa,EAAE,CAAC;gBAClB,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;oBAChC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QACD,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,eAAe,GAAG,CAAC,MAAoB,EAAiB,EAAE;IAC9D,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAkB,EAAE,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,cAAc,GAAG,CAAC,KAAiB,EAAE,OAAoB,EAAW,EAAE;IAC1E,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;IAEvB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpC,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC;AAC9D,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAAiB,EAAE,QAAuB,EAAW,EAAE;IAChF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAqB,EAAE,OAAqB,EAAW,EAAE;IACnF,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAE3C,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;gBACzC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;gBACzC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,iFAAiF;IACjF,MAAM,qBAAqB,GAAG,CAAC,CAAe,EAAW,EAAE,CACzD,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,SAAS,CAAC;IAE9E,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IACjD,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAEjD,IACE,qBAAqB,CAAC,OAAO,CAAC;QAC9B,qBAAqB,CAAC,OAAO,CAAC;QAC9B,WAAW;QACX,WAAW;QACX,WAAW,KAAK,WAAW,EAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAuB,EAAoB,EAAE;IACtF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;IACxC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,SAAS,EAAE,CAAC;IAC3B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9B,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa;IACjC,CAAC;IAED,8DAA8D;IAC9D,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;IACjD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,CAAC,SAAS,EAAE,CAAC;YAC1F,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAuB,CAAC;YAChE,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5B,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC7B,CAAC;gBACD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,KAAK,MAAM,aAAa,IAAI,YAAY,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;QACtE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9C,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACtD,KAAK,MAAM,YAAY,IAAI,UAAU,EAAE,CAAC;YACtC,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC;YACnD,IAAI,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;gBACnC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,KAAK,MAAM,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;IACrD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3B,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAoB,EAAE,UAA0B,EAAkB,EAAE;IAChG,MAAM,SAAS,GAAmB,EAAE,CAAC;IAErC,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,WAAyB,EACzB,UAA0B,EAC1B,UAA0B,EAAE,EACZ,EAAE;IAClB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1E,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1B,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAEzD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,oBAAoB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Altium design discovery module.
3
+ * Finds Altium Designer projects (.PrjPcb) and their schematic files (.SchDoc).
4
+ */
5
+ declare const ALTIUM_EXTENSIONS: readonly [".prjpcb"];
6
+ /**
7
+ * Altium-specific discovered design with schematic document paths.
8
+ */
9
+ export interface AltiumDiscoveredDesign {
10
+ name: string;
11
+ sourcePath: string;
12
+ format: "altium";
13
+ schdocPaths: string[];
14
+ error?: string;
15
+ }
16
+ /**
17
+ * Discover Altium designs in a directory.
18
+ */
19
+ export declare const discoverAltiumDesigns: (rootDir: string) => Promise<AltiumDiscoveredDesign[]>;
20
+ /**
21
+ * Find SchDoc files for a specific Altium project file.
22
+ */
23
+ export declare const findAltiumSchDocs: (projectPath: string) => Promise<string[]>;
24
+ /**
25
+ * Check if a file path is an Altium project file.
26
+ */
27
+ export declare const isAltiumFile: (filePath: string) => boolean;
28
+ /** Altium file extensions */
29
+ export { ALTIUM_EXTENSIONS };
30
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/parsers/altium/discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,QAAA,MAAM,iBAAiB,sBAAuB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2ID;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,KACd,OAAO,CAAC,sBAAsB,EAAE,CA8BlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,KAClB,OAAO,CAAC,MAAM,EAAE,CAWlB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,KAAG,OAG/C,CAAC;AAEF,6BAA6B;AAC7B,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Altium design discovery module.
3
+ * Finds Altium Designer projects (.PrjPcb) and their schematic files (.SchDoc).
4
+ */
5
+ import { open, readFile, readdir } from "fs/promises";
6
+ import path from "path";
7
+ const ALTIUM_EXTENSIONS = [".prjpcb"];
8
+ const OLE_MAGIC = Buffer.from([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]);
9
+ /**
10
+ * Check if a file is an OLE-format SchDoc file.
11
+ */
12
+ const isOleSchDoc = async (filePath) => {
13
+ let handle;
14
+ try {
15
+ handle = await open(filePath, "r");
16
+ const buffer = Buffer.alloc(OLE_MAGIC.length);
17
+ const { bytesRead } = await handle.read(buffer, 0, OLE_MAGIC.length, 0);
18
+ if (bytesRead < OLE_MAGIC.length) {
19
+ return false;
20
+ }
21
+ return buffer.equals(OLE_MAGIC);
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ finally {
27
+ if (handle) {
28
+ await handle.close();
29
+ }
30
+ }
31
+ };
32
+ /**
33
+ * Read SchDoc paths from an Altium project file.
34
+ * Returns absolute paths to valid SchDoc files.
35
+ */
36
+ const readProjectSchDocs = async (projectPath) => {
37
+ let content;
38
+ try {
39
+ content = await readFile(projectPath, "utf-8");
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ const projectDir = path.dirname(projectPath);
45
+ const schdocs = new Set();
46
+ for (const line of content.split(/\r?\n/)) {
47
+ const match = line.match(/^\s*DocumentPath=(.+)$/i);
48
+ if (!match)
49
+ continue;
50
+ const rawPath = match[1].trim();
51
+ if (!rawPath)
52
+ continue;
53
+ const trimmed = rawPath.replace(/^"+|"+$/g, "");
54
+ const pathPart = trimmed.split("|")[0]?.trim();
55
+ if (!pathPart)
56
+ continue;
57
+ const normalized = pathPart.replace(/\\/g, "/");
58
+ if (!normalized.toLowerCase().endsWith(".schdoc")) {
59
+ continue;
60
+ }
61
+ // Skip absolute paths from the project file
62
+ if (path.win32.isAbsolute(normalized) ||
63
+ path.posix.isAbsolute(normalized)) {
64
+ continue;
65
+ }
66
+ // Resolve to absolute path
67
+ const absolutePath = path.resolve(projectDir, normalized);
68
+ if (await isOleSchDoc(absolutePath)) {
69
+ schdocs.add(absolutePath);
70
+ }
71
+ }
72
+ return Array.from(schdocs.values()).sort((a, b) => a.localeCompare(b));
73
+ };
74
+ /**
75
+ * Walk directory tree to find Altium-related files.
76
+ */
77
+ const walkForAltiumFiles = async (rootDir) => {
78
+ const projects = [];
79
+ const schdocs = [];
80
+ const walk = async (currentDir) => {
81
+ let entries;
82
+ try {
83
+ entries = await readdir(currentDir, { withFileTypes: true });
84
+ }
85
+ catch (error) {
86
+ if (!(error instanceof Error) ||
87
+ !("code" in error) ||
88
+ error.code !== "EACCES") {
89
+ throw error;
90
+ }
91
+ return;
92
+ }
93
+ for (const entry of entries) {
94
+ const fullPath = path.join(currentDir, entry.name);
95
+ if (entry.isDirectory()) {
96
+ await walk(fullPath);
97
+ continue;
98
+ }
99
+ if (!entry.isFile())
100
+ continue;
101
+ const ext = path.extname(entry.name).toLowerCase();
102
+ if (ext === ".prjpcb") {
103
+ projects.push(fullPath);
104
+ }
105
+ else if (ext === ".schdoc") {
106
+ if (await isOleSchDoc(fullPath)) {
107
+ schdocs.push(fullPath);
108
+ }
109
+ }
110
+ }
111
+ };
112
+ await walk(rootDir);
113
+ return { projects, schdocs };
114
+ };
115
+ /**
116
+ * Fallback: find SchDoc files in the project directory if none found in project file.
117
+ */
118
+ const fallbackProjectSchDocs = (projectDir, schdocs) => {
119
+ const candidates = schdocs.filter((schdoc) => {
120
+ const schdocDir = path.dirname(schdoc);
121
+ return schdocDir === projectDir || schdoc.startsWith(projectDir + path.sep);
122
+ });
123
+ return candidates.length === 1 ? candidates : [];
124
+ };
125
+ /**
126
+ * Discover Altium designs in a directory.
127
+ */
128
+ export const discoverAltiumDesigns = async (rootDir) => {
129
+ const absoluteRootDir = path.resolve(rootDir);
130
+ const { projects, schdocs } = await walkForAltiumFiles(absoluteRootDir);
131
+ const designs = [];
132
+ for (const projectPath of projects) {
133
+ const name = path.basename(projectPath, path.extname(projectPath));
134
+ let schdocPaths = await readProjectSchDocs(projectPath);
135
+ if (schdocPaths.length === 0) {
136
+ const projectDir = path.dirname(projectPath);
137
+ schdocPaths = fallbackProjectSchDocs(projectDir, schdocs);
138
+ }
139
+ const design = {
140
+ name,
141
+ format: "altium",
142
+ sourcePath: projectPath,
143
+ schdocPaths,
144
+ };
145
+ if (schdocPaths.length === 0) {
146
+ design.error = `No schematic documents found for project '${name}'.`;
147
+ }
148
+ designs.push(design);
149
+ }
150
+ return designs;
151
+ };
152
+ /**
153
+ * Find SchDoc files for a specific Altium project file.
154
+ */
155
+ export const findAltiumSchDocs = async (projectPath) => {
156
+ const schdocPaths = await readProjectSchDocs(projectPath);
157
+ if (schdocPaths.length === 0) {
158
+ // Fallback: scan project directory
159
+ const projectDir = path.dirname(projectPath);
160
+ const { schdocs } = await walkForAltiumFiles(projectDir);
161
+ return fallbackProjectSchDocs(projectDir, schdocs);
162
+ }
163
+ return schdocPaths;
164
+ };
165
+ /**
166
+ * Check if a file path is an Altium project file.
167
+ */
168
+ export const isAltiumFile = (filePath) => {
169
+ const ext = path.extname(filePath).toLowerCase();
170
+ return ALTIUM_EXTENSIONS.includes(ext);
171
+ };
172
+ /** Altium file extensions */
173
+ export { ALTIUM_EXTENSIONS };
174
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/parsers/altium/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Altium Hierarchy Builder
3
+ *
4
+ * Converts a flat list of records into a hierarchical structure
5
+ * using the OwnerIndex property to establish parent-child relationships.
6
+ */
7
+ import type { AltiumRecord, AltiumSchematic } from './types.js';
8
+ /**
9
+ * Build hierarchy from flat record list.
10
+ *
11
+ * Records with no OwnerIndex become root nodes.
12
+ * Records with OwnerIndex are added as children to their owner.
13
+ */
14
+ export declare const buildHierarchy: (schematic: AltiumSchematic) => AltiumSchematic;
15
+ /**
16
+ * Flatten a hierarchical schematic back to a list.
17
+ */
18
+ export declare const flattenHierarchy: (schematic: AltiumSchematic) => AltiumRecord[];
19
+ /**
20
+ * Get parts list (components only).
21
+ *
22
+ * Filters for RECORD="1" which represents components/parts.
23
+ */
24
+ export declare const getPartsList: (schematic: AltiumSchematic) => AltiumRecord[];
25
+ /**
26
+ * Find a record by its index.
27
+ */
28
+ export declare const findRecordByIndex: (schematic: AltiumSchematic, index: number) => AltiumRecord | undefined;
29
+ //# sourceMappingURL=hierarchy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../src/parsers/altium/hierarchy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,eAAe,KAAG,eAwC3D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,eAAe,KAAG,YAAY,EAiBzE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,eAAe,KAAG,YAAY,EAErE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,eAAe,EAC1B,OAAO,MAAM,KACZ,YAAY,GAAG,SAejB,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Altium Hierarchy Builder
3
+ *
4
+ * Converts a flat list of records into a hierarchical structure
5
+ * using the OwnerIndex property to establish parent-child relationships.
6
+ */
7
+ /**
8
+ * Build hierarchy from flat record list.
9
+ *
10
+ * Records with no OwnerIndex become root nodes.
11
+ * Records with OwnerIndex are added as children to their owner.
12
+ */
13
+ export const buildHierarchy = (schematic) => {
14
+ // Deep clone the records to avoid mutating the original
15
+ const recordsCopy = schematic.records.map((r) => JSON.parse(JSON.stringify(r)));
16
+ const hierarchy = [];
17
+ // First pass: ensure all records have their index set
18
+ for (let i = 0; i < recordsCopy.length; i++) {
19
+ recordsCopy[i].index = i;
20
+ }
21
+ // Second pass: build parent-child relationships
22
+ for (const current of recordsCopy) {
23
+ const ownerIndexStr = current.OwnerIndex ?? current.OWNERINDEX;
24
+ if (ownerIndexStr === undefined || ownerIndexStr === null || ownerIndexStr === '') {
25
+ // No owner - this is a root record
26
+ hierarchy.push(current);
27
+ }
28
+ else {
29
+ // Has an owner - add as child
30
+ const ownerIndex = parseInt(ownerIndexStr, 10);
31
+ if (ownerIndex >= 0 && ownerIndex < recordsCopy.length) {
32
+ const owner = recordsCopy[ownerIndex];
33
+ if (!owner.children) {
34
+ owner.children = [];
35
+ }
36
+ owner.children.push(current);
37
+ }
38
+ else {
39
+ // Invalid owner index - treat as root
40
+ hierarchy.push(current);
41
+ }
42
+ }
43
+ }
44
+ return {
45
+ header: schematic.header,
46
+ records: hierarchy,
47
+ };
48
+ };
49
+ /**
50
+ * Flatten a hierarchical schematic back to a list.
51
+ */
52
+ export const flattenHierarchy = (schematic) => {
53
+ const flat = [];
54
+ const traverse = (record) => {
55
+ flat.push(record);
56
+ if (record.children) {
57
+ for (const child of record.children) {
58
+ traverse(child);
59
+ }
60
+ }
61
+ };
62
+ for (const record of schematic.records) {
63
+ traverse(record);
64
+ }
65
+ return flat;
66
+ };
67
+ /**
68
+ * Get parts list (components only).
69
+ *
70
+ * Filters for RECORD="1" which represents components/parts.
71
+ */
72
+ export const getPartsList = (schematic) => {
73
+ return schematic.records.filter((r) => r.RECORD === '1');
74
+ };
75
+ /**
76
+ * Find a record by its index.
77
+ */
78
+ export const findRecordByIndex = (schematic, index) => {
79
+ const search = (records) => {
80
+ for (const record of records) {
81
+ if (record.index === index) {
82
+ return record;
83
+ }
84
+ if (record.children) {
85
+ const found = search(record.children);
86
+ if (found)
87
+ return found;
88
+ }
89
+ }
90
+ return undefined;
91
+ };
92
+ return search(schematic.records);
93
+ };
94
+ //# sourceMappingURL=hierarchy.js.map