diff --git a/lib/components/primitive-components/Port/Port.ts b/lib/components/primitive-components/Port/Port.ts index 85dbb54b6..3db5d8edf 100644 --- a/lib/components/primitive-components/Port/Port.ts +++ b/lib/components/primitive-components/Port/Port.ts @@ -9,12 +9,13 @@ import { applyToPoint, compose, translate } from "transformation-matrix" import { z } from "zod" import { PrimitiveComponent } from "../../base-components/PrimitiveComponent" import type { Trace } from "../Trace/Trace" -import type { LayerRef, SchematicPort } from "circuit-json" +import type { LayerRef, SchematicPort, SourcePort } from "circuit-json" import { areAllPcbPrimitivesOverlapping } from "./areAllPcbPrimitivesOverlapping" import { getCenterOfPcbPrimitives } from "./getCenterOfPcbPrimitives" import { type PinAttributeMap, portProps } from "@tscircuit/props" import type { INormalComponent } from "lib/components/base-components/NormalComponent/INormalComponent" import { applyPinAttributesToSourcePort } from "./apply-pin-attributes-to-source-port" +import { applyDefaultDecouplingRequirementToSourcePort } from "./apply-default-decoupling-requirement-to-source-port" import { Port_doInitialCreateTracesFromProps } from "./Port_doInitialCreateTracesFromProps" import { Port_tryRenderGroupPcbPort } from "./Port_tryRenderGroupPcbPort" import { getSourcePortNetLabelText } from "lib/utils/schematic/getSourcePortNetLabelText" @@ -393,11 +394,16 @@ export class Port extends PrimitiveComponent { // Get pin attributes from parent component and apply them to this port const pinAttributes = this._getMatchingPinAttributes() - const portAttributesFromParent: Record = {} + const sourcePortAttributes: Partial = {} for (const attributes of pinAttributes) { - applyPinAttributesToSourcePort(portAttributesFromParent, attributes) + applyPinAttributesToSourcePort(sourcePortAttributes, attributes) } + applyDefaultDecouplingRequirementToSourcePort({ + sourcePortAttributes, + sourcePortLabels: port_hints, + parentNormalComponentName: parentNormalComponent?.config.componentName, + }) const source_port = db.source_port.insert({ name: props.name!, @@ -405,7 +411,7 @@ export class Port extends PrimitiveComponent { port_hints, source_component_id: source_component_id!, subcircuit_id: this.getSubcircuit()?.subcircuit_id!, - ...portAttributesFromParent, + ...sourcePortAttributes, }) this.source_port_id = source_port.source_port_id diff --git a/lib/components/primitive-components/Port/apply-default-decoupling-requirement-to-source-port.ts b/lib/components/primitive-components/Port/apply-default-decoupling-requirement-to-source-port.ts new file mode 100644 index 000000000..19f2674e8 --- /dev/null +++ b/lib/components/primitive-components/Port/apply-default-decoupling-requirement-to-source-port.ts @@ -0,0 +1,36 @@ +import type { SourcePort } from "circuit-json" +import { POWER_NET_REGEX } from "lib/utils/gnd-power-net-regex" + +export const applyDefaultDecouplingRequirementToSourcePort = ({ + sourcePortAttributes, + sourcePortLabels, + parentNormalComponentName, +}: { + sourcePortAttributes: Partial + sourcePortLabels: string[] + parentNormalComponentName: string | undefined +}): void => { + if (parentNormalComponentName !== "Chip") return + if (sourcePortAttributes.should_have_decoupling_capacitor !== undefined) { + return + } + + if (sourcePortAttributes.provides_power === true) { + sourcePortAttributes.should_have_decoupling_capacitor = false + return + } + + if (sourcePortAttributes.requires_power !== undefined) { + sourcePortAttributes.should_have_decoupling_capacitor = + sourcePortAttributes.requires_power + return + } + + if ( + sourcePortLabels.some((sourcePortLabel) => + POWER_NET_REGEX.test(sourcePortLabel), + ) + ) { + sourcePortAttributes.should_have_decoupling_capacitor = true + } +} diff --git a/lib/components/primitive-components/Port/apply-pin-attributes-to-source-port.ts b/lib/components/primitive-components/Port/apply-pin-attributes-to-source-port.ts index 76234e551..c4db3efdb 100644 --- a/lib/components/primitive-components/Port/apply-pin-attributes-to-source-port.ts +++ b/lib/components/primitive-components/Port/apply-pin-attributes-to-source-port.ts @@ -1,7 +1,8 @@ import type { PinAttributeMap } from "@tscircuit/props" +import type { SourcePort } from "circuit-json" export const applyPinAttributesToSourcePort = ( - sourcePortProps: Record, + sourcePortProps: Partial, attributes: PinAttributeMap, ): void => { if (attributes.mustBeConnected !== undefined) { diff --git a/tests/components/normal-components/chip-decoupling-metadata.test.tsx b/tests/components/normal-components/chip-decoupling-metadata.test.tsx new file mode 100644 index 000000000..3e5c8f4a2 --- /dev/null +++ b/tests/components/normal-components/chip-decoupling-metadata.test.tsx @@ -0,0 +1,97 @@ +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("emits chip decoupling metadata for external checks", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + + + + + + + + + + + + + + + , + ) + + await circuit.renderUntilSettled() + + const sourceComponentsByName = new Map( + circuit.db.source_component + .list() + .map((sourceComponent) => [sourceComponent.name, sourceComponent]), + ) + const getSourcePortByHint = (sourceComponentName: string, portHint: string) => + circuit.db.source_port + .list() + .find( + (sourcePort) => + sourcePort.source_component_id === + sourceComponentsByName.get(sourceComponentName) + ?.source_component_id && + sourcePort.port_hints?.includes(portHint), + ) + + expect(getSourcePortByHint("U_MISSING", "VCC")).toMatchObject({ + requires_power: true, + should_have_decoupling_capacitor: true, + recommended_decoupling_capacitor_capacitance: "100nF", + }) + expect(getSourcePortByHint("U_MISSING", "GND")).toMatchObject({ + requires_ground: true, + }) + expect(getSourcePortByHint("U_WITH_CAP", "VDD")).toMatchObject({ + should_have_decoupling_capacitor: true, + }) + expect(getSourcePortByHint("U_OPT_OUT", "VBAT")).toMatchObject({ + requires_power: true, + should_have_decoupling_capacitor: false, + }) + expect(getSourcePortByHint("U_POWER_SOURCE", "VCC")).toMatchObject({ + provides_power: true, + should_have_decoupling_capacitor: false, + }) +})