circuit-json-to-tscircuit 0.0.93 → 0.0.95

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 (32) hide show
  1. package/dist/{chunk-B7377FUZ.js → chunk-KYTTH2AG.js} +717 -147
  2. package/dist/cli/main.js +3 -3
  3. package/dist/lib/index.js +1 -1
  4. package/lib/board-converter/get-pin-labels.ts +6 -1
  5. package/lib/generate-board-schematic-tsx/convert-components.ts +67 -12
  6. package/lib/generate-board-schematic-tsx/convert-native-symbol-pin-numbers.ts +81 -0
  7. package/lib/generate-board-schematic-tsx/convert-primitives.ts +28 -5
  8. package/lib/generate-board-schematic-tsx/convert-symbol-primitives.ts +65 -22
  9. package/lib/generate-board-schematic-tsx/get-native-symbol-port-matching-inputs.ts +131 -0
  10. package/lib/generate-board-schematic-tsx/get-native-symbol-text-replacement-candidate.ts +153 -0
  11. package/lib/generate-board-schematic-tsx/get-native-symbol-text-replacements.ts +82 -0
  12. package/lib/generate-board-schematic-tsx/get-nearest-schematic-text.ts +104 -0
  13. package/lib/generate-board-schematic-tsx/get-replaced-schematic-component-ids.ts +21 -0
  14. package/lib/generate-board-schematic-tsx/get-schematic-primitive-paint.ts +2 -2
  15. package/lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts +9 -2
  16. package/lib/generate-board-schematic-tsx/get-symbol-to-schematic-transform.ts +8 -1
  17. package/lib/generate-board-schematic-tsx/has-multiple-native-symbol-units.ts +23 -0
  18. package/lib/generate-board-schematic-tsx/has-preserved-package-value-text.ts +32 -0
  19. package/lib/generate-board-schematic-tsx/is-pin-designator-for-port.ts +32 -0
  20. package/lib/generate-board-schematic-tsx/match-symbol-ports-by-pin-identity.ts +9 -1
  21. package/lib/generate-board-schematic-tsx/resolve-native-schematic-symbol-name.ts +114 -0
  22. package/package.json +2 -2
  23. package/tests/__snapshots__/board-imported-bga-pin-labels-orangecrab-bga-pin-labels.snap.svg +1 -0
  24. package/tests/board-imported-bga-pin-labels.test.ts +145 -0
  25. package/tests/explicit-native-symbol-content.test.ts +60 -0
  26. package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-schematic-comparison.snap.svg +2 -2
  27. package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip.test.tsx.snap +16 -20
  28. package/tests/ti-evms/__snapshots__/ti-lm5155evm-fly-roundtrip-schematic-comparison.snap.svg +1 -1
  29. package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip-schematic-comparison.snap.svg +1 -1
  30. package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip.test.tsx.snap +80 -128
  31. package/tests/ti-evms/ti-lm5155evm-fly-roundtrip.test.tsx +42 -81
  32. package/tests/ti-native-symbols.test.ts +528 -0
@@ -1126,55 +1126,6 @@ ${schematicElements.join("\n")}
1126
1126
  // lib/generate-board-schematic-tsx/convert-primitives.ts
1127
1127
  import { schematic_text } from "circuit-json";
1128
1128
 
1129
- // lib/generate-board-schematic-tsx/convert-rect.ts
1130
- import {
1131
- applyToPoint,
1132
- compose,
1133
- rotateDEG,
1134
- translate
1135
- } from "transformation-matrix";
1136
-
1137
- // lib/generate-board-schematic-tsx/format-attributes.ts
1138
- var formatAttributes = (attributes) => Object.entries(attributes).filter(([, attribute]) => attribute !== void 0 && attribute !== null).map(([name, attribute]) => `${name}={${JSON.stringify(attribute)}}`).join(" ");
1139
- var formatElement = (tagName, attributes) => `<${tagName} ${formatAttributes(attributes)} />`;
1140
-
1141
- // lib/generate-board-schematic-tsx/convert-rect.ts
1142
- var DEFAULT_SCHEMATIC_STROKE_WIDTH = 0.02;
1143
- var DASH_LENGTH_TO_STROKE_WIDTH_RATIO = 3;
1144
- var convertRect = ({
1145
- center,
1146
- width,
1147
- height,
1148
- ccwRotationDegrees,
1149
- strokeWidth,
1150
- color,
1151
- fillColor,
1152
- isFilled,
1153
- isDashed
1154
- }) => {
1155
- const rectToSchematicTransform = compose(
1156
- translate(center.x, center.y),
1157
- rotateDEG(ccwRotationDegrees ?? 0)
1158
- );
1159
- const points = [
1160
- { x: -width / 2, y: -height / 2 },
1161
- { x: width / 2, y: -height / 2 },
1162
- { x: width / 2, y: height / 2 },
1163
- { x: -width / 2, y: height / 2 },
1164
- { x: -width / 2, y: -height / 2 }
1165
- ].map((point) => applyToPoint(rectToSchematicTransform, point));
1166
- const dashLength = isDashed ? (strokeWidth ?? DEFAULT_SCHEMATIC_STROKE_WIDTH) * DASH_LENGTH_TO_STROKE_WIDTH_RATIO : void 0;
1167
- return formatElement("schematicpath", {
1168
- points,
1169
- strokeWidth,
1170
- strokeColor: color,
1171
- fillColor,
1172
- isFilled,
1173
- dashLength,
1174
- dashGap: dashLength
1175
- });
1176
- };
1177
-
1178
1129
  // lib/generate-symbol-tsx.ts
1179
1130
  import { su } from "@tscircuit/soup-util";
1180
1131
  var escapeJsxText = (text) => text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -1394,46 +1345,381 @@ var generateSymbolTsx = (circuitJson) => {
1394
1345
  `.trim();
1395
1346
  };
1396
1347
 
1397
- // lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts
1398
- var isSchematicPrimitive = (element) => element.type === "schematic_text" || element.type === "schematic_path" || element.type === "schematic_rect" || element.type === "schematic_line" || element.type === "schematic_circle" || element.type === "schematic_arc" || element.type === "schematic_box";
1399
- var isCustomComponentBody = ({
1400
- component,
1401
- rect
1402
- }) => component.is_box_with_pins === false && rect.is_filled && rect.center.x === component.center.x && rect.center.y === component.center.y && rect.width === component.size.width && rect.height === component.size.height;
1403
- var getSchematicPrimitivesInRenderOrder = (circuitJson) => {
1404
- const customComponentById = /* @__PURE__ */ new Map();
1405
- for (const element of circuitJson) {
1406
- if (element.type === "schematic_component" && element.is_box_with_pins === false) {
1407
- customComponentById.set(element.schematic_component_id, element);
1408
- }
1348
+ // lib/generate-board-schematic-tsx/convert-rect.ts
1349
+ import {
1350
+ applyToPoint,
1351
+ compose,
1352
+ rotateDEG,
1353
+ translate
1354
+ } from "transformation-matrix";
1355
+
1356
+ // lib/generate-board-schematic-tsx/format-attributes.ts
1357
+ var formatAttributes = (attributes) => Object.entries(attributes).filter(([, attribute]) => attribute !== void 0 && attribute !== null).map(([name, attribute]) => `${name}={${JSON.stringify(attribute)}}`).join(" ");
1358
+ var formatElement = (tagName, attributes) => `<${tagName} ${formatAttributes(attributes)} />`;
1359
+
1360
+ // lib/generate-board-schematic-tsx/convert-rect.ts
1361
+ var DEFAULT_SCHEMATIC_STROKE_WIDTH = 0.02;
1362
+ var DASH_LENGTH_TO_STROKE_WIDTH_RATIO = 3;
1363
+ var convertRect = ({
1364
+ center,
1365
+ width,
1366
+ height,
1367
+ ccwRotationDegrees,
1368
+ strokeWidth,
1369
+ color,
1370
+ fillColor,
1371
+ isFilled,
1372
+ isDashed
1373
+ }) => {
1374
+ const rectToSchematicTransform = compose(
1375
+ translate(center.x, center.y),
1376
+ rotateDEG(ccwRotationDegrees ?? 0)
1377
+ );
1378
+ const points = [
1379
+ { x: -width / 2, y: -height / 2 },
1380
+ { x: width / 2, y: -height / 2 },
1381
+ { x: width / 2, y: height / 2 },
1382
+ { x: -width / 2, y: height / 2 },
1383
+ { x: -width / 2, y: -height / 2 }
1384
+ ].map((point) => applyToPoint(rectToSchematicTransform, point));
1385
+ const dashLength = isDashed ? (strokeWidth ?? DEFAULT_SCHEMATIC_STROKE_WIDTH) * DASH_LENGTH_TO_STROKE_WIDTH_RATIO : void 0;
1386
+ return formatElement("schematicpath", {
1387
+ points,
1388
+ strokeWidth,
1389
+ strokeColor: color,
1390
+ fillColor,
1391
+ isFilled,
1392
+ dashLength,
1393
+ dashGap: dashLength
1394
+ });
1395
+ };
1396
+
1397
+ // lib/generate-board-schematic-tsx/get-nearest-schematic-text.ts
1398
+ var DEGREES_TO_RADIANS = Math.PI / 180;
1399
+ var distanceFromComponentCenter = ({
1400
+ schematicText,
1401
+ schematicComponent
1402
+ }) => Math.hypot(
1403
+ schematicText.position.x - schematicComponent.center.x,
1404
+ schematicText.position.y - schematicComponent.center.y
1405
+ );
1406
+ var getNearestSchematicText = ({
1407
+ schematicTexts,
1408
+ schematicComponent
1409
+ }) => schematicTexts.toSorted(
1410
+ (firstText, secondText) => distanceFromComponentCenter({
1411
+ schematicText: firstText,
1412
+ schematicComponent
1413
+ }) - distanceFromComponentCenter({
1414
+ schematicText: secondText,
1415
+ schematicComponent
1416
+ })
1417
+ )[0];
1418
+ var getSchematicTextAxisDistances = ({
1419
+ schematicText,
1420
+ schematicComponent
1421
+ }) => {
1422
+ const rotationRadians = schematicText.rotation * DEGREES_TO_RADIANS;
1423
+ const deltaX = schematicComponent.center.x - schematicText.position.x;
1424
+ const deltaY = schematicComponent.center.y - schematicText.position.y;
1425
+ return {
1426
+ alongAxis: deltaX * Math.cos(rotationRadians) + deltaY * Math.sin(rotationRadians),
1427
+ acrossAxis: Math.abs(
1428
+ -deltaX * Math.sin(rotationRadians) + deltaY * Math.cos(rotationRadians)
1429
+ )
1430
+ };
1431
+ };
1432
+ var getSchematicTextAxisRange = ({
1433
+ schematicText,
1434
+ maximumDistance
1435
+ }) => {
1436
+ const maximumTextAdvance = Array.from(schematicText.text).length * schematicText.font_size;
1437
+ if (schematicText.anchor.includes("left")) {
1438
+ return {
1439
+ minimum: -maximumDistance,
1440
+ maximum: maximumTextAdvance + maximumDistance
1441
+ };
1409
1442
  }
1410
- const primitives = circuitJson.filter(isSchematicPrimitive);
1411
- const componentBodyById = /* @__PURE__ */ new Map();
1412
- for (const primitive of primitives) {
1413
- if (primitive.type !== "schematic_rect" || !primitive.schematic_component_id) {
1414
- continue;
1415
- }
1416
- const component = customComponentById.get(primitive.schematic_component_id);
1417
- if (component && isCustomComponentBody({ component, rect: primitive })) {
1418
- componentBodyById.set(primitive.schematic_component_id, primitive);
1419
- }
1443
+ if (schematicText.anchor.includes("right")) {
1444
+ return {
1445
+ minimum: -maximumTextAdvance - maximumDistance,
1446
+ maximum: maximumDistance
1447
+ };
1420
1448
  }
1421
- const emittedComponentBodies = /* @__PURE__ */ new Set();
1422
- const result = [];
1423
- for (const primitive of primitives) {
1424
- const componentId = primitive.schematic_component_id;
1425
- const componentBody = componentId ? componentBodyById.get(componentId) : void 0;
1426
- if (!componentId || !componentBody) {
1427
- result.push(primitive);
1428
- continue;
1429
- }
1430
- if (!emittedComponentBodies.has(componentId)) {
1431
- result.push(componentBody);
1432
- emittedComponentBodies.add(componentId);
1449
+ return {
1450
+ minimum: -maximumTextAdvance / 2 - maximumDistance,
1451
+ maximum: maximumTextAdvance / 2 + maximumDistance
1452
+ };
1453
+ };
1454
+ var isSchematicTextWithinComponentLabelRange = ({
1455
+ schematicText,
1456
+ schematicComponent,
1457
+ maximumDistance
1458
+ }) => {
1459
+ const distance = getSchematicTextAxisDistances({
1460
+ schematicText,
1461
+ schematicComponent
1462
+ });
1463
+ const textAxisRange = getSchematicTextAxisRange({
1464
+ schematicText,
1465
+ maximumDistance
1466
+ });
1467
+ return distance.alongAxis >= textAxisRange.minimum && distance.alongAxis <= textAxisRange.maximum && distance.acrossAxis <= maximumDistance;
1468
+ };
1469
+
1470
+ // lib/generate-board-schematic-tsx/resolve-native-schematic-symbol-name.ts
1471
+ var normalizePortName = (portName) => portName.toLowerCase().replace(/[^a-z0-9]/gu, "");
1472
+ var hasExactPortNames = (sourcePortNames, expectedPortNames) => sourcePortNames.size === expectedPortNames.length && expectedPortNames.every((portName) => sourcePortNames.has(portName));
1473
+ var resolveNativeSchematicSymbolName = ({
1474
+ circuitJson,
1475
+ schematicComponent
1476
+ }) => {
1477
+ if (schematicComponent.symbol_name) return schematicComponent.symbol_name;
1478
+ const sourceComponent = circuitJson.find(
1479
+ (element) => element.type === "source_component" && element.source_component_id === schematicComponent.source_component_id
1480
+ );
1481
+ if (sourceComponent?.type !== "source_component") return void 0;
1482
+ const sourcePorts = circuitJson.filter(
1483
+ (element) => element.type === "source_port" && element.source_component_id === sourceComponent.source_component_id
1484
+ );
1485
+ const sourcePortNames = new Set(
1486
+ sourcePorts.map((sourcePort) => normalizePortName(sourcePort.name))
1487
+ );
1488
+ const schematicPorts = circuitJson.filter(
1489
+ (element) => element.type === "schematic_port" && element.schematic_component_id === schematicComponent.schematic_component_id
1490
+ );
1491
+ const schematicSourcePortNames = new Set(
1492
+ schematicPorts.flatMap((schematicPort) => {
1493
+ const sourcePort = sourcePorts.find(
1494
+ (candidate) => candidate.source_port_id === schematicPort.source_port_id
1495
+ );
1496
+ return sourcePort ? [normalizePortName(sourcePort.name)] : [];
1497
+ })
1498
+ );
1499
+ const logicPortNames = new Set(
1500
+ [...schematicSourcePortNames].map(
1501
+ (portName) => portName.replace(/^\d+([aby])$/u, "$1")
1502
+ )
1503
+ );
1504
+ const designator = sourceComponent.display_name ?? "";
1505
+ const componentValue = sourceComponent.display_value?.toUpperCase() ?? "";
1506
+ if (componentValue.startsWith("SN74LVC2G08") && hasExactPortNames(logicPortNames, ["a", "b", "y"])) {
1507
+ return "and_gate_right";
1508
+ }
1509
+ if (/^SN74LVC[23]G14/u.test(componentValue) && hasExactPortNames(logicPortNames, ["a", "y"])) {
1510
+ return "schmitt_trigger_inverter_right";
1511
+ }
1512
+ if (designator.startsWith("U") && hasExactPortNames(sourcePortNames, ["a", "k", "c", "e"])) {
1513
+ return "phototransistor_optocoupler_right";
1514
+ }
1515
+ if (designator.startsWith("T") && hasExactPortNames(sourcePortNames, [
1516
+ "1",
1517
+ "2",
1518
+ "3",
1519
+ "5",
1520
+ "6",
1521
+ "7",
1522
+ "9",
1523
+ "10"
1524
+ ])) {
1525
+ return "transformer_4_winding_right";
1526
+ }
1527
+ if (designator.startsWith("D") && hasExactPortNames(sourcePortNames, ["1anode", "2cathode", "1cathode2anode"])) {
1528
+ return "dual_series_schottky_diode_right";
1529
+ }
1530
+ return void 0;
1531
+ };
1532
+
1533
+ // lib/generate-board-schematic-tsx/has-multiple-native-symbol-units.ts
1534
+ var hasMultipleNativeSymbolUnits = ({
1535
+ circuitJson,
1536
+ schematicComponent,
1537
+ symbolName
1538
+ }) => circuitJson.filter(
1539
+ (candidate) => candidate.type === "schematic_component" && candidate.source_component_id === schematicComponent.source_component_id && !candidate.symbol_name && resolveNativeSchematicSymbolName({
1540
+ circuitJson,
1541
+ schematicComponent: candidate
1542
+ }) === symbolName
1543
+ ).length > 1;
1544
+
1545
+ // lib/generate-board-schematic-tsx/has-preserved-package-value-text.ts
1546
+ var hasPreservedPackageValueText = ({
1547
+ circuitJson,
1548
+ schematicComponent,
1549
+ schematicComponents,
1550
+ replacedSchematicComponentIds,
1551
+ displayTexts
1552
+ }) => circuitJson.some((candidate) => {
1553
+ if (candidate.type !== "schematic_text" || !candidate.schematic_component_id || !displayTexts.has(candidate.text) || replacedSchematicComponentIds.has(candidate.schematic_component_id)) {
1554
+ return false;
1555
+ }
1556
+ return schematicComponents.some(
1557
+ (component) => component.schematic_component_id === candidate.schematic_component_id && component.source_component_id === schematicComponent.source_component_id
1558
+ );
1559
+ });
1560
+
1561
+ // lib/generate-board-schematic-tsx/is-pin-designator-for-port.ts
1562
+ var isPinDesignatorForPort = ({
1563
+ schematicText,
1564
+ schematicPort,
1565
+ schematicComponent
1566
+ }) => {
1567
+ if (schematicText.text !== String(schematicPort.pin_number)) return false;
1568
+ const portToCenter = {
1569
+ x: schematicComponent.center.x - schematicPort.center.x,
1570
+ y: schematicComponent.center.y - schematicPort.center.y
1571
+ };
1572
+ const portToText = {
1573
+ x: schematicText.position.x - schematicPort.center.x,
1574
+ y: schematicText.position.y - schematicPort.center.y
1575
+ };
1576
+ const portDistance = Math.hypot(portToCenter.x, portToCenter.y);
1577
+ const textDistance = Math.hypot(portToText.x, portToText.y);
1578
+ const pointsTowardComponent = portToCenter.x * portToText.x + portToCenter.y * portToText.y >= 0;
1579
+ return pointsTowardComponent && textDistance <= Math.min(0.3, portDistance * 0.6);
1580
+ };
1581
+
1582
+ // lib/generate-board-schematic-tsx/get-native-symbol-text-replacement-candidate.ts
1583
+ var distanceBetween = (firstPoint, secondPoint) => Math.hypot(firstPoint.x - secondPoint.x, firstPoint.y - secondPoint.y);
1584
+ var getNativeSymbolTextReplacementCandidate = (context) => {
1585
+ const { circuitJson, schematicComponent, unownedSchematicTexts } = context;
1586
+ if (schematicComponent.symbol_name) return void 0;
1587
+ const symbolName = resolveNativeSchematicSymbolName({
1588
+ circuitJson,
1589
+ schematicComponent
1590
+ });
1591
+ if (!symbolName) return void 0;
1592
+ const sourceComponent = circuitJson.find(
1593
+ (candidate) => candidate.type === "source_component" && candidate.source_component_id === schematicComponent.source_component_id
1594
+ );
1595
+ const reference = sourceComponent?.display_name ?? sourceComponent?.name;
1596
+ const displayTexts = new Set(
1597
+ [
1598
+ sourceComponent?.display_value,
1599
+ schematicComponent.symbol_display_value
1600
+ ].filter((displayText) => Boolean(displayText))
1601
+ );
1602
+ const labelSearchDistance = Math.max(schematicComponent.size.width, schematicComponent.size.height) / 2 + 0.3;
1603
+ const referenceTexts = unownedSchematicTexts.filter(
1604
+ (schematicText) => schematicText.text === reference && distanceBetween(schematicText.position, schematicComponent.center) <= labelSearchDistance
1605
+ );
1606
+ const displayValueTextsInRange = unownedSchematicTexts.filter(
1607
+ (schematicText) => displayTexts.has(schematicText.text) && isSchematicTextWithinComponentLabelRange({
1608
+ schematicText,
1609
+ schematicComponent,
1610
+ maximumDistance: labelSearchDistance
1611
+ })
1612
+ );
1613
+ const nearestDisplayValueText = getNearestSchematicText({
1614
+ schematicTexts: displayValueTextsInRange,
1615
+ schematicComponent
1616
+ });
1617
+ const displayValueTexts = nearestDisplayValueText ? [nearestDisplayValueText] : [];
1618
+ const schematicPorts = circuitJson.filter(
1619
+ (candidate) => candidate.type === "schematic_port" && candidate.schematic_component_id === schematicComponent.schematic_component_id
1620
+ );
1621
+ const replacedPinPortIds = /* @__PURE__ */ new Set();
1622
+ const pinDesignatorTexts = schematicPorts.flatMap((schematicPort) => {
1623
+ const matches = unownedSchematicTexts.filter(
1624
+ (schematicText) => isPinDesignatorForPort({
1625
+ schematicText,
1626
+ schematicPort,
1627
+ schematicComponent
1628
+ })
1629
+ );
1630
+ if (matches.length > 0)
1631
+ replacedPinPortIds.add(schematicPort.schematic_port_id);
1632
+ return matches;
1633
+ });
1634
+ return {
1635
+ schematicComponentId: schematicComponent.schematic_component_id,
1636
+ importedTextIds: new Set(
1637
+ [...referenceTexts, ...displayValueTexts, ...pinDesignatorTexts].map(
1638
+ (schematicText) => schematicText.schematic_text_id
1639
+ )
1640
+ ),
1641
+ replacedPinPortIds,
1642
+ replacesReference: referenceTexts.length > 0,
1643
+ includeNativeDisplayText: false,
1644
+ referenceFontSize: getNearestSchematicText({
1645
+ schematicTexts: referenceTexts,
1646
+ schematicComponent
1647
+ })?.font_size,
1648
+ displayTextFontSize: nearestDisplayValueText?.font_size,
1649
+ sourceComponentId: schematicComponent.source_component_id,
1650
+ symbolName,
1651
+ displayValueTextIds: new Set(
1652
+ displayValueTexts.map((schematicText) => schematicText.schematic_text_id)
1653
+ ),
1654
+ isMultiUnitSymbol: hasMultipleNativeSymbolUnits({
1655
+ circuitJson,
1656
+ schematicComponent,
1657
+ symbolName
1658
+ }),
1659
+ hasPreservedPackageValueText: hasPreservedPackageValueText({
1660
+ circuitJson,
1661
+ schematicComponent,
1662
+ schematicComponents: context.schematicComponents,
1663
+ replacedSchematicComponentIds: context.replacedSchematicComponentIds,
1664
+ displayTexts
1665
+ })
1666
+ };
1667
+ };
1668
+
1669
+ // lib/generate-board-schematic-tsx/get-replaced-schematic-component-ids.ts
1670
+ import { symbols } from "schematic-symbols";
1671
+ var getReplacedSchematicComponentIds = (circuitJson) => {
1672
+ const replacedSchematicComponentIds = /* @__PURE__ */ new Set();
1673
+ for (const element of circuitJson) {
1674
+ if (element.type !== "schematic_component" || element.symbol_name) continue;
1675
+ const inferredSymbolName = resolveNativeSchematicSymbolName({
1676
+ circuitJson,
1677
+ schematicComponent: element
1678
+ });
1679
+ if (inferredSymbolName && inferredSymbolName in symbols) {
1680
+ replacedSchematicComponentIds.add(element.schematic_component_id);
1433
1681
  }
1434
- if (primitive !== componentBody) result.push(primitive);
1435
1682
  }
1436
- return result;
1683
+ return replacedSchematicComponentIds;
1684
+ };
1685
+
1686
+ // lib/generate-board-schematic-tsx/get-native-symbol-text-replacements.ts
1687
+ var isFirstUnitWithDisplayValue = ({
1688
+ candidate,
1689
+ allCandidates
1690
+ }) => allCandidates.find(
1691
+ (otherCandidate) => otherCandidate.sourceComponentId === candidate.sourceComponentId && otherCandidate.symbolName === candidate.symbolName && otherCandidate.displayValueTextIds.size > 0
1692
+ )?.schematicComponentId === candidate.schematicComponentId;
1693
+ var getNativeSymbolTextReplacements = (circuitJson) => {
1694
+ const unownedSchematicTexts = circuitJson.filter(
1695
+ (element) => element.type === "schematic_text" && element.schematic_component_id === void 0
1696
+ );
1697
+ const replacedSchematicComponentIds = getReplacedSchematicComponentIds(circuitJson);
1698
+ const schematicComponents = circuitJson.filter(
1699
+ (element) => element.type === "schematic_component"
1700
+ );
1701
+ const candidates = schematicComponents.flatMap((schematicComponent) => {
1702
+ const candidate = getNativeSymbolTextReplacementCandidate({
1703
+ circuitJson,
1704
+ schematicComponent,
1705
+ unownedSchematicTexts,
1706
+ replacedSchematicComponentIds,
1707
+ schematicComponents
1708
+ });
1709
+ return candidate ? [candidate] : [];
1710
+ });
1711
+ return candidates.map((candidate) => ({
1712
+ schematicComponentId: candidate.schematicComponentId,
1713
+ importedTextIds: candidate.importedTextIds,
1714
+ replacedPinPortIds: candidate.replacedPinPortIds,
1715
+ replacesReference: candidate.replacesReference,
1716
+ includeNativeDisplayText: candidate.displayValueTextIds.size > 0 && (!candidate.isMultiUnitSymbol || !candidate.hasPreservedPackageValueText && isFirstUnitWithDisplayValue({
1717
+ candidate,
1718
+ allCandidates: candidates
1719
+ })),
1720
+ referenceFontSize: candidate.referenceFontSize,
1721
+ displayTextFontSize: candidate.displayTextFontSize
1722
+ }));
1437
1723
  };
1438
1724
 
1439
1725
  // lib/generate-board-schematic-tsx/get-schematic-primitive-paint.ts
@@ -1518,14 +1804,71 @@ var getSchematicPrimitivePaint = (primitive) => {
1518
1804
  };
1519
1805
  };
1520
1806
 
1807
+ // lib/generate-board-schematic-tsx/get-schematic-primitives-in-render-order.ts
1808
+ var isSchematicPrimitive = (element) => element.type === "schematic_text" || element.type === "schematic_path" || element.type === "schematic_rect" || element.type === "schematic_line" || element.type === "schematic_circle" || element.type === "schematic_arc" || element.type === "schematic_box";
1809
+ var isCustomComponentBody = ({
1810
+ component,
1811
+ rect
1812
+ }) => component.is_box_with_pins === false && rect.is_filled && rect.center.x === component.center.x && rect.center.y === component.center.y && rect.width === component.size.width && rect.height === component.size.height;
1813
+ var getSchematicPrimitivesInRenderOrder = (circuitJson, nativeComponentIds = /* @__PURE__ */ new Set()) => {
1814
+ const customComponentById = /* @__PURE__ */ new Map();
1815
+ for (const element of circuitJson) {
1816
+ if (element.type === "schematic_component" && element.is_box_with_pins === false) {
1817
+ customComponentById.set(element.schematic_component_id, element);
1818
+ }
1819
+ }
1820
+ const primitives = circuitJson.filter(isSchematicPrimitive).filter(
1821
+ (primitive) => !primitive.schematic_component_id || !nativeComponentIds.has(primitive.schematic_component_id)
1822
+ );
1823
+ const componentBodyById = /* @__PURE__ */ new Map();
1824
+ for (const primitive of primitives) {
1825
+ if (primitive.type !== "schematic_rect" || !primitive.schematic_component_id) {
1826
+ continue;
1827
+ }
1828
+ const component = customComponentById.get(primitive.schematic_component_id);
1829
+ if (component && isCustomComponentBody({ component, rect: primitive })) {
1830
+ componentBodyById.set(primitive.schematic_component_id, primitive);
1831
+ }
1832
+ }
1833
+ const emittedComponentBodies = /* @__PURE__ */ new Set();
1834
+ const result = [];
1835
+ for (const primitive of primitives) {
1836
+ const componentId = primitive.schematic_component_id;
1837
+ const componentBody = componentId ? componentBodyById.get(componentId) : void 0;
1838
+ if (!componentId || !componentBody) {
1839
+ result.push(primitive);
1840
+ continue;
1841
+ }
1842
+ if (!emittedComponentBodies.has(componentId)) {
1843
+ result.push(componentBody);
1844
+ emittedComponentBodies.add(componentId);
1845
+ }
1846
+ if (primitive !== componentBody) result.push(primitive);
1847
+ }
1848
+ return result;
1849
+ };
1850
+
1521
1851
  // lib/generate-board-schematic-tsx/convert-primitives.ts
1852
+ var getRenderablePrimitives = (circuitJson) => {
1853
+ const replacedTextIds = new Set(
1854
+ getNativeSymbolTextReplacements(circuitJson).flatMap((replacement) => [
1855
+ ...replacement.importedTextIds
1856
+ ])
1857
+ );
1858
+ return getSchematicPrimitivesInRenderOrder(
1859
+ circuitJson,
1860
+ getReplacedSchematicComponentIds(circuitJson)
1861
+ ).filter(
1862
+ (primitive) => primitive.type !== "schematic_text" || !replacedTextIds.has(primitive.schematic_text_id)
1863
+ );
1864
+ };
1522
1865
  var convertPrimitives = (circuitJson) => [
1523
1866
  ...generateSymbolElements(
1524
1867
  circuitJson.filter(
1525
1868
  (element) => element.type === "schematic_table" || element.type === "schematic_table_cell"
1526
1869
  )
1527
1870
  ),
1528
- ...getSchematicPrimitivesInRenderOrder(circuitJson).flatMap((element) => {
1871
+ ...getRenderablePrimitives(circuitJson).flatMap((element) => {
1529
1872
  const paint = getSchematicPrimitivePaint(element);
1530
1873
  switch (element.type) {
1531
1874
  case "schematic_text":
@@ -1623,7 +1966,7 @@ var convertPrimitives = (circuitJson) => [
1623
1966
 
1624
1967
  // lib/generate-board-schematic-tsx/convert-components.ts
1625
1968
  import { su as su3 } from "@tscircuit/soup-util";
1626
- import { symbols } from "schematic-symbols";
1969
+ import { symbols as symbols2 } from "schematic-symbols";
1627
1970
 
1628
1971
  // lib/generate-board-schematic-tsx/get-symbol-to-schematic-transform.ts
1629
1972
  import { fromTriangles as fromTriangles2 } from "transformation-matrix";
@@ -1801,18 +2144,21 @@ var isRigidUniformTransform = (transform) => {
1801
2144
  };
1802
2145
 
1803
2146
  // lib/generate-board-schematic-tsx/match-symbol-ports-by-pin-identity.ts
2147
+ var getLogicUnitPortAlias = (portName) => portName?.match(/^\d*([aby])$/iu)?.[1]?.toLowerCase();
1804
2148
  var matchSymbolPortsByPinIdentity = ({
1805
2149
  schematicPorts,
1806
2150
  sourcePorts,
1807
- symbol
2151
+ symbol,
2152
+ includeSchematicPinNumbers = true
1808
2153
  }) => symbol.ports.flatMap((symbolPort) => {
1809
2154
  const candidates = schematicPorts.filter((schematicPort) => {
1810
2155
  const sourcePort = sourcePorts.find(
1811
2156
  (port) => port.source_port_id === schematicPort.source_port_id
1812
2157
  );
1813
- const pinNumber = schematicPort.pin_number ?? sourcePort?.pin_number;
2158
+ const pinNumber = includeSchematicPinNumbers ? schematicPort.pin_number ?? sourcePort?.pin_number : sourcePort?.pin_number;
1814
2159
  const portIdentities = [
1815
2160
  sourcePort?.name,
2161
+ getLogicUnitPortAlias(sourcePort?.name),
1816
2162
  ...sourcePort?.port_hints ?? [],
1817
2163
  ...pinNumber === void 0 ? [] : [String(pinNumber), `pin${pinNumber}`]
1818
2164
  ];
@@ -1828,12 +2174,17 @@ var getSymbolToSchematicTransform = ({
1828
2174
  symbol,
1829
2175
  schematicComponent,
1830
2176
  schematicPorts,
1831
- sourcePorts
2177
+ sourcePorts,
2178
+ includeSchematicPinNumbers
1832
2179
  }) => {
2180
+ const componentSourcePorts = sourcePorts.filter(
2181
+ (sourcePort) => sourcePort.source_component_id === schematicComponent.source_component_id
2182
+ );
1833
2183
  const pinIdentityMatches = matchSymbolPortsByPinIdentity({
1834
2184
  schematicPorts,
1835
- sourcePorts,
1836
- symbol
2185
+ sourcePorts: componentSourcePorts,
2186
+ symbol,
2187
+ includeSchematicPinNumbers
1837
2188
  });
1838
2189
  const rigidPinIdentityTransform = getRigidPinIdentityTransform(pinIdentityMatches);
1839
2190
  if (rigidPinIdentityTransform) return rigidPinIdentityTransform;
@@ -1869,6 +2220,17 @@ var getSymbolToSchematicTransform = ({
1869
2220
  import { schematic_text as schematic_text2 } from "circuit-json";
1870
2221
  import { applyToPoint as applyToPoint4 } from "transformation-matrix";
1871
2222
  var SYMBOL_OUTLINE_STROKE_WIDTH = 0.02;
2223
+ var MINIMUM_FILL_AREA = 1e-12;
2224
+ var pathHasFillArea = (points) => {
2225
+ if (points.length < 3) return false;
2226
+ let doubledArea = 0;
2227
+ for (const [pointIndex, point] of points.entries()) {
2228
+ const nextPoint = points[(pointIndex + 1) % points.length];
2229
+ if (!nextPoint) continue;
2230
+ doubledArea += point.x * nextPoint.y - nextPoint.x * point.y;
2231
+ }
2232
+ return Math.abs(doubledArea) > MINIMUM_FILL_AREA;
2233
+ };
1872
2234
  var anchors = {
1873
2235
  middle_top: "top_center",
1874
2236
  middle_bottom: "bottom_center",
@@ -1884,8 +2246,13 @@ var convertSymbolPrimitives = ({
1884
2246
  symbol,
1885
2247
  symbolToSchematicTransform,
1886
2248
  reference,
1887
- displayText
1888
- }) => symbol.primitives.map((primitive) => {
2249
+ displayText,
2250
+ includeReference = true,
2251
+ includeDisplayText = true,
2252
+ referenceFontSize,
2253
+ displayTextFontSize,
2254
+ filledPrimitiveColor
2255
+ }) => symbol.primitives.flatMap((primitive) => {
1889
2256
  if (primitive.type === "path") {
1890
2257
  const points = primitive.points.map(
1891
2258
  (point) => applyToPoint4(symbolToSchematicTransform, point)
@@ -1894,19 +2261,25 @@ var convertSymbolPrimitives = ({
1894
2261
  return formatElement("schematicpath", {
1895
2262
  points,
1896
2263
  strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
2264
+ fillColor: primitive.fill && pathHasFillArea(points) ? filledPrimitiveColor : void 0,
1897
2265
  isFilled: primitive.fill
1898
2266
  });
1899
2267
  }
1900
2268
  const center = applyToPoint4(symbolToSchematicTransform, primitive);
1901
2269
  if (primitive.type === "text") {
2270
+ if (!includeReference && primitive.text === "{REF}") return [];
2271
+ if (!includeDisplayText && primitive.text === "{VAL}") return [];
1902
2272
  const text = primitive.text === "{REF}" ? reference : primitive.text === "{VAL}" ? displayText : primitive.text;
1903
- return formatElement("schematictext", {
1904
- text,
1905
- schX: center.x,
1906
- schY: center.y,
1907
- anchor: anchors[primitive.anchor],
1908
- fontSize: primitive.fontSize ?? schematic_text2.shape.font_size.parse(void 0)
1909
- });
2273
+ const importedFontSize = primitive.text === "{REF}" ? referenceFontSize : primitive.text === "{VAL}" ? displayTextFontSize : void 0;
2274
+ return [
2275
+ formatElement("schematictext", {
2276
+ text,
2277
+ schX: center.x,
2278
+ schY: center.y,
2279
+ anchor: anchors[primitive.anchor],
2280
+ fontSize: importedFontSize ?? primitive.fontSize ?? schematic_text2.shape.font_size.parse(void 0)
2281
+ })
2282
+ ];
1910
2283
  }
1911
2284
  const symbolToSchematicVectorTransform = {
1912
2285
  ...symbolToSchematicTransform,
@@ -1918,12 +2291,15 @@ var convertSymbolPrimitives = ({
1918
2291
  x: primitive.radius,
1919
2292
  y: 0
1920
2293
  });
1921
- return formatElement("schematiccircle", {
1922
- center,
1923
- radius: Math.hypot(radiusVector.x, radiusVector.y),
1924
- strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
1925
- isFilled: primitive.fill
1926
- });
2294
+ return [
2295
+ formatElement("schematiccircle", {
2296
+ center,
2297
+ radius: Math.hypot(radiusVector.x, radiusVector.y),
2298
+ strokeWidth: SYMBOL_OUTLINE_STROKE_WIDTH,
2299
+ fillColor: primitive.fill ? filledPrimitiveColor : void 0,
2300
+ isFilled: primitive.fill
2301
+ })
2302
+ ];
1927
2303
  }
1928
2304
  const widthVector = applyToPoint4(symbolToSchematicVectorTransform, {
1929
2305
  x: primitive.width,
@@ -1934,13 +2310,15 @@ var convertSymbolPrimitives = ({
1934
2310
  y: primitive.height
1935
2311
  });
1936
2312
  const ccwRotationDegrees = Math.atan2(widthVector.y, widthVector.x) * 180 / Math.PI;
1937
- return formatElement("schematicrect", {
1938
- schX: center.x,
1939
- schY: center.y,
1940
- width: Math.hypot(widthVector.x, widthVector.y),
1941
- height: Math.hypot(heightVector.x, heightVector.y),
1942
- rotation: ccwRotationDegrees
1943
- });
2313
+ return [
2314
+ formatElement("schematicrect", {
2315
+ schX: center.x,
2316
+ schY: center.y,
2317
+ width: Math.hypot(widthVector.x, widthVector.y),
2318
+ height: Math.hypot(heightVector.x, heightVector.y),
2319
+ rotation: ccwRotationDegrees
2320
+ })
2321
+ ];
1944
2322
  });
1945
2323
 
1946
2324
  // lib/generate-board-schematic-tsx/convert-box-components.ts
@@ -2171,33 +2549,222 @@ var convertBoxComponent = ({
2171
2549
  return primitives;
2172
2550
  };
2173
2551
 
2174
- // lib/generate-board-schematic-tsx/convert-components.ts
2175
- var convertComponents = (circuitJson) => su3(circuitJson).schematic_component.list().flatMap((schematicComponent) => {
2176
- const symbolName = schematicComponent.symbol_name;
2177
- if (symbolName && symbolName in symbols) {
2178
- const symbol = symbols[symbolName];
2179
- if (!symbol) return [];
2180
- const sourceComponent = su3(circuitJson).source_component.get(
2181
- schematicComponent.source_component_id ?? ""
2182
- );
2183
- const symbolToSchematicTransform = getSymbolToSchematicTransform({
2184
- symbol,
2185
- schematicComponent,
2186
- schematicPorts: su3(circuitJson).schematic_port.list({
2187
- schematic_component_id: schematicComponent.schematic_component_id
2188
- }),
2189
- sourcePorts: su3(circuitJson).source_port.list()
2190
- });
2191
- return convertSymbolPrimitives({
2192
- symbol,
2193
- symbolToSchematicTransform,
2194
- reference: sourceComponent?.display_name ?? sourceComponent?.name ?? "",
2195
- displayText: schematicComponent.symbol_display_value ?? ""
2196
- });
2552
+ // lib/generate-board-schematic-tsx/convert-native-symbol-pin-numbers.ts
2553
+ import { applyToPoint as applyToPoint5 } from "transformation-matrix";
2554
+ var PIN_TEXT_FONT_SIZE = 0.15;
2555
+ var PIN_TEXT_COLOR = "#a90000";
2556
+ var PIN_NUMBER_BASELINE_OFFSET = 0.02;
2557
+ var SYMBOL_POINT_TOLERANCE = 1e-6;
2558
+ var pointsMatch = (firstPoint, secondPoint) => Math.hypot(firstPoint.x - secondPoint.x, firstPoint.y - secondPoint.y) < SYMBOL_POINT_TOLERANCE;
2559
+ var getPortLeadInnerPoint = ({
2560
+ symbol,
2561
+ symbolPort
2562
+ }) => {
2563
+ for (const primitive of symbol.primitives) {
2564
+ if (primitive.type !== "path" || primitive.points.length < 2) continue;
2565
+ const firstPoint = primitive.points[0];
2566
+ const lastPoint = primitive.points.at(-1);
2567
+ if (pointsMatch(firstPoint, symbolPort)) return primitive.points[1];
2568
+ if (pointsMatch(lastPoint, symbolPort)) return primitive.points.at(-2);
2197
2569
  }
2198
- return schematicComponent.is_box_with_pins ? convertBoxComponent({ circuitJson, schematicComponent }) : [];
2570
+ return void 0;
2571
+ };
2572
+ var convertNativeSymbolPinNumbers = ({
2573
+ symbol,
2574
+ symbolToSchematicTransform,
2575
+ portMatches,
2576
+ replacedPinPortIds
2577
+ }) => portMatches.flatMap(({ schematicPort, symbolPort }) => {
2578
+ if (schematicPort.pin_number === void 0 || !replacedPinPortIds.has(schematicPort.schematic_port_id)) {
2579
+ return [];
2580
+ }
2581
+ const leadInnerPoint = getPortLeadInnerPoint({ symbol, symbolPort });
2582
+ if (!leadInnerPoint) return [];
2583
+ const portCenter = applyToPoint5(symbolToSchematicTransform, symbolPort);
2584
+ const leadInnerCenter = applyToPoint5(
2585
+ symbolToSchematicTransform,
2586
+ leadInnerPoint
2587
+ );
2588
+ const pinNumberPosition = {
2589
+ x: (portCenter.x + leadInnerCenter.x) / 2,
2590
+ y: (portCenter.y + leadInnerCenter.y) / 2
2591
+ };
2592
+ const isVerticalLead = Math.abs(leadInnerCenter.y - portCenter.y) > Math.abs(leadInnerCenter.x - portCenter.x);
2593
+ if (isVerticalLead) pinNumberPosition.x -= PIN_NUMBER_BASELINE_OFFSET;
2594
+ else pinNumberPosition.y += PIN_NUMBER_BASELINE_OFFSET;
2595
+ return [
2596
+ formatElement("schematictext", {
2597
+ text: String(schematicPort.pin_number),
2598
+ schX: pinNumberPosition.x,
2599
+ schY: pinNumberPosition.y,
2600
+ anchor: "bottom_center",
2601
+ fontSize: PIN_TEXT_FONT_SIZE,
2602
+ color: PIN_TEXT_COLOR,
2603
+ schRotation: isVerticalLead ? -90 : void 0
2604
+ })
2605
+ ];
2199
2606
  });
2200
2607
 
2608
+ // lib/generate-board-schematic-tsx/get-native-symbol-port-matching-inputs.ts
2609
+ var getNumericPortHint = (sourcePort) => {
2610
+ const numericPortHint = sourcePort.port_hints?.find(
2611
+ (portHint) => /^(?:pin)?\d+$/.test(portHint)
2612
+ );
2613
+ return numericPortHint?.replace(/^pin/, "");
2614
+ };
2615
+ var getNumericPortName = (sourcePort) => /^\d+$/.test(sourcePort.name) ? sourcePort.name : void 0;
2616
+ var getSourcePinNumber = ({
2617
+ sourcePort,
2618
+ schematicPorts
2619
+ }) => {
2620
+ const linkedSchematicPort = schematicPorts.find(
2621
+ (schematicPort) => schematicPort.source_port_id === sourcePort.source_port_id
2622
+ );
2623
+ const sourcePinNumber = sourcePort.pin_number ?? linkedSchematicPort?.pin_number ?? getNumericPortHint(sourcePort) ?? getNumericPortName(sourcePort);
2624
+ return sourcePinNumber === void 0 ? void 0 : String(sourcePinNumber);
2625
+ };
2626
+ var getFourWindingTransformerAlias = (sourcePinNumber) => {
2627
+ switch (sourcePinNumber) {
2628
+ case "1":
2629
+ return "primary_end";
2630
+ case "2":
2631
+ return "primary_start";
2632
+ case "5":
2633
+ return "auxiliary_end";
2634
+ case "3":
2635
+ return "auxiliary_start";
2636
+ case "9":
2637
+ return "secondary1_end";
2638
+ case "10":
2639
+ return "secondary1_start";
2640
+ case "6":
2641
+ return "secondary2_end";
2642
+ case "7":
2643
+ return "secondary2_start";
2644
+ default:
2645
+ return void 0;
2646
+ }
2647
+ };
2648
+ var getDualSeriesSchottkyAlias = (sourcePinNumber) => {
2649
+ switch (sourcePinNumber) {
2650
+ case "1":
2651
+ return "anode";
2652
+ case "2":
2653
+ return "cathode";
2654
+ case "3":
2655
+ return "common";
2656
+ default:
2657
+ return void 0;
2658
+ }
2659
+ };
2660
+ var getInferredPortAlias = ({
2661
+ symbolName,
2662
+ sourcePinNumber
2663
+ }) => {
2664
+ if (symbolName === "transformer_4_winding_right") {
2665
+ return getFourWindingTransformerAlias(sourcePinNumber);
2666
+ }
2667
+ if (symbolName === "dual_series_schottky_diode_right") {
2668
+ return getDualSeriesSchottkyAlias(sourcePinNumber);
2669
+ }
2670
+ return void 0;
2671
+ };
2672
+ var getNativeSymbolPortMatchingInputs = ({
2673
+ symbolName,
2674
+ sourcePorts,
2675
+ schematicPorts,
2676
+ isInferredSymbol
2677
+ }) => {
2678
+ const usesInferredPortAliases = symbolName === "transformer_4_winding_right" || symbolName === "dual_series_schottky_diode_right";
2679
+ if (!isInferredSymbol || !usesInferredPortAliases) {
2680
+ return { sourcePorts, includeSchematicPinNumbers: true };
2681
+ }
2682
+ const aliasedSourcePorts = sourcePorts.map((sourcePort) => {
2683
+ const sourcePinNumber = getSourcePinNumber({ sourcePort, schematicPorts });
2684
+ if (!sourcePinNumber) return sourcePort;
2685
+ const inferredPortAlias = getInferredPortAlias({
2686
+ symbolName,
2687
+ sourcePinNumber
2688
+ });
2689
+ if (!inferredPortAlias) return sourcePort;
2690
+ return {
2691
+ ...sourcePort,
2692
+ name: inferredPortAlias,
2693
+ port_hints: [inferredPortAlias],
2694
+ pin_number: void 0
2695
+ };
2696
+ });
2697
+ return {
2698
+ sourcePorts: aliasedSourcePorts,
2699
+ includeSchematicPinNumbers: false
2700
+ };
2701
+ };
2702
+
2703
+ // lib/generate-board-schematic-tsx/convert-components.ts
2704
+ var convertComponents = (circuitJson) => {
2705
+ const textReplacements = getNativeSymbolTextReplacements(circuitJson);
2706
+ return su3(circuitJson).schematic_component.list().flatMap((schematicComponent) => {
2707
+ const symbolName = resolveNativeSchematicSymbolName({
2708
+ circuitJson,
2709
+ schematicComponent
2710
+ });
2711
+ if (symbolName && symbolName in symbols2) {
2712
+ const symbol = symbols2[symbolName];
2713
+ if (!symbol) return [];
2714
+ const isInferredSymbol = !schematicComponent.symbol_name;
2715
+ const sourceComponent = su3(circuitJson).source_component.get(
2716
+ schematicComponent.source_component_id ?? ""
2717
+ );
2718
+ const schematicPorts = su3(circuitJson).schematic_port.list({
2719
+ schematic_component_id: schematicComponent.schematic_component_id
2720
+ });
2721
+ const sourcePorts = su3(circuitJson).source_port.list({
2722
+ source_component_id: schematicComponent.source_component_id
2723
+ });
2724
+ const portMatchingInputs = getNativeSymbolPortMatchingInputs({
2725
+ symbolName,
2726
+ sourcePorts,
2727
+ schematicPorts,
2728
+ isInferredSymbol
2729
+ });
2730
+ const symbolToSchematicTransform = getSymbolToSchematicTransform({
2731
+ symbol,
2732
+ schematicComponent,
2733
+ schematicPorts,
2734
+ ...portMatchingInputs
2735
+ });
2736
+ const textReplacement = textReplacements.find(
2737
+ (replacement) => replacement.schematicComponentId === schematicComponent.schematic_component_id
2738
+ );
2739
+ const portMatches = matchSymbolPortsByPinIdentity({
2740
+ schematicPorts,
2741
+ symbol,
2742
+ ...portMatchingInputs
2743
+ });
2744
+ return [
2745
+ ...convertSymbolPrimitives({
2746
+ symbol,
2747
+ symbolToSchematicTransform,
2748
+ reference: sourceComponent?.display_name ?? sourceComponent?.name ?? "",
2749
+ displayText: isInferredSymbol ? sourceComponent?.display_value ?? schematicComponent.symbol_display_value ?? "" : schematicComponent.symbol_display_value ?? "",
2750
+ includeReference: !isInferredSymbol || textReplacement?.replacesReference,
2751
+ includeDisplayText: !isInferredSymbol || textReplacement?.includeNativeDisplayText,
2752
+ referenceFontSize: textReplacement?.referenceFontSize,
2753
+ displayTextFontSize: textReplacement?.displayTextFontSize,
2754
+ filledPrimitiveColor: isInferredSymbol ? COMPONENT_OUTLINE_COLOR : void 0
2755
+ }),
2756
+ ...isInferredSymbol && textReplacement ? convertNativeSymbolPinNumbers({
2757
+ symbol,
2758
+ symbolToSchematicTransform,
2759
+ portMatches,
2760
+ replacedPinPortIds: textReplacement.replacedPinPortIds
2761
+ }) : []
2762
+ ];
2763
+ }
2764
+ return schematicComponent.is_box_with_pins ? convertBoxComponent({ circuitJson, schematicComponent }) : [];
2765
+ });
2766
+ };
2767
+
2201
2768
  // lib/generate-board-schematic-tsx/convert-schematic-graphics.ts
2202
2769
  var convertSchematicGraphics = (circuitJson) => circuitJson.flatMap((element) => {
2203
2770
  if (element.type !== "schematic_graphic") return [];
@@ -2214,7 +2781,7 @@ var convertSchematicGraphics = (circuitJson) => circuitJson.flatMap((element) =>
2214
2781
  // lib/generate-board-schematic-tsx/convert-net-labels.ts
2215
2782
  import { su as su4 } from "@tscircuit/soup-util";
2216
2783
  import { schematic_text as schematic_text3 } from "circuit-json";
2217
- import { symbols as symbols2 } from "schematic-symbols";
2784
+ import { symbols as symbols3 } from "schematic-symbols";
2218
2785
 
2219
2786
  // lib/generate-board-schematic-tsx/get-net-label-symbol-to-schematic-transform.ts
2220
2787
  import {
@@ -2243,8 +2810,8 @@ function canRenderNativeNetLabel(name) {
2243
2810
  var convertNetLabels = (circuitJson) => su4(circuitJson).schematic_net_label.list().flatMap((schematicNetLabel) => {
2244
2811
  const anchorPosition = schematicNetLabel.anchor_position ?? schematicNetLabel.center;
2245
2812
  const symbolName = schematicNetLabel.symbol_name;
2246
- if (symbolName && symbolName in symbols2) {
2247
- const symbol = symbols2[symbolName];
2813
+ if (symbolName && symbolName in symbols3) {
2814
+ const symbol = symbols3[symbolName];
2248
2815
  if (symbol)
2249
2816
  return convertSymbolPrimitives({
2250
2817
  symbol,
@@ -3453,7 +4020,7 @@ var generateFootprintTsx = (circuitJson, context) => {
3453
4020
 
3454
4021
  // lib/board-converter/get-pcb-component-render-placement.ts
3455
4022
  import { getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
3456
- import { applyToPoint as applyToPoint5, inverse, translate as translate5 } from "transformation-matrix";
4023
+ import { applyToPoint as applyToPoint6, inverse, translate as translate5 } from "transformation-matrix";
3457
4024
  var physicalPcbElementTypes = /* @__PURE__ */ new Set([
3458
4025
  "pcb_copper_text",
3459
4026
  "pcb_cutout",
@@ -3479,7 +4046,7 @@ var getPcbComponentRenderPlacement = ({
3479
4046
  pcbBoard,
3480
4047
  pcbComponent
3481
4048
  }) => {
3482
- const componentPosition = applyToPoint5(
4049
+ const componentPosition = applyToPoint6(
3483
4050
  inverse(translate5(pcbBoard.center.x, pcbBoard.center.y)),
3484
4051
  pcbComponent.center
3485
4052
  );
@@ -3508,7 +4075,10 @@ var getPcbComponentRenderPlacement = ({
3508
4075
 
3509
4076
  // lib/board-converter/get-pin-labels.ts
3510
4077
  var getCompoundPinNumber = (sourcePort) => {
3511
- if (sourcePort.pin_number !== void 0) return sourcePort.pin_number;
4078
+ if (sourcePort.pin_number !== void 0) {
4079
+ const pinNumber = Number(sourcePort.pin_number);
4080
+ return Number.isSafeInteger(pinNumber) && pinNumber >= 0 ? pinNumber : void 0;
4081
+ }
3512
4082
  const firstPinNumber = /^\d+/u.exec(sourcePort.name)?.[0];
3513
4083
  return firstPinNumber ? Number.parseInt(firstPinNumber, 10) : void 0;
3514
4084
  };
@@ -3594,7 +4164,7 @@ var getSchematicComponentsForPcbComponent = ({
3594
4164
  // lib/board-converter/localize-pcb-component-elements.ts
3595
4165
  import { transformPCBElements } from "@tscircuit/circuit-json-util";
3596
4166
  import {
3597
- applyToPoint as applyToPoint6,
4167
+ applyToPoint as applyToPoint7,
3598
4168
  compose as compose4,
3599
4169
  decomposeTSR,
3600
4170
  flipY,
@@ -3636,13 +4206,13 @@ var transformSilkscreenGraphic = ({
3636
4206
  }) => {
3637
4207
  if (graphic.shape !== "brep") return;
3638
4208
  graphic.brep_shape.outer_ring.vertices = graphic.brep_shape.outer_ring.vertices.map(
3639
- (vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
4209
+ (vertex) => applyToPoint7(absoluteToComponentLocalTransform, vertex)
3640
4210
  );
3641
4211
  graphic.brep_shape.inner_rings = graphic.brep_shape.inner_rings.map(
3642
4212
  (ring) => ({
3643
4213
  ...ring,
3644
4214
  vertices: ring.vertices.map(
3645
- (vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
4215
+ (vertex) => applyToPoint7(absoluteToComponentLocalTransform, vertex)
3646
4216
  )
3647
4217
  })
3648
4218
  );