From c36eb7f4866484bf971dc3e58d96b970d2b70e22 Mon Sep 17 00:00:00 2001 From: Manish chaudhary <125847751+techmannih@users.noreply.github.com> Date: Tue, 28 Jan 2025 03:26:20 +0530 Subject: [PATCH 01/33] add support polarized capacitor symbol (#579) * add support polarized capacitor symbol * format code --- lib/components/normal-components/Capacitor.ts | 5 +-- .../capacitor-polarized-schematic.snap.svg | 17 ++++++++++ .../capacitor-polarized.test.tsx | 32 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 tests/components/normal-components/__snapshots__/capacitor-polarized-schematic.snap.svg create mode 100644 tests/components/normal-components/capacitor-polarized.test.tsx diff --git a/lib/components/normal-components/Capacitor.ts b/lib/components/normal-components/Capacitor.ts index 51fc7773..24ef226e 100644 --- a/lib/components/normal-components/Capacitor.ts +++ b/lib/components/normal-components/Capacitor.ts @@ -18,8 +18,9 @@ export class Capacitor extends NormalComponent< get config() { return { componentName: "Capacitor", - schematicSymbolName: - this.props.symbolName ?? ("capacitor" as BaseSymbolName), + schematicSymbolName: this.props.polarized + ? "capacitor_polarized" + : (this.props.symbolName ?? ("capacitor" as BaseSymbolName)), zodProps: capacitorProps, sourceFtype: FTYPE.simple_capacitor, } diff --git a/tests/components/normal-components/__snapshots__/capacitor-polarized-schematic.snap.svg b/tests/components/normal-components/__snapshots__/capacitor-polarized-schematic.snap.svg new file mode 100644 index 00000000..b91f2abd --- /dev/null +++ b/tests/components/normal-components/__snapshots__/capacitor-polarized-schematic.snap.svg @@ -0,0 +1,17 @@ +-2,-1-2,0-2,1-1,-1-1,0-1,10,-10,00,11,-11,01,12,-12,02,1C110µF \ No newline at end of file diff --git a/tests/components/normal-components/capacitor-polarized.test.tsx b/tests/components/normal-components/capacitor-polarized.test.tsx new file mode 100644 index 00000000..331417fc --- /dev/null +++ b/tests/components/normal-components/capacitor-polarized.test.tsx @@ -0,0 +1,32 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("capacitor polarized", () => { + const { project } = getTestFixture() + + project.add( + + + , + ) + + project.render() + + const capacitors = project.db.source_component.list({ + ftype: "simple_capacitor", + }) as Array<{ + ftype: "simple_capacitor" + display_capacitance?: string + }> + + expect(capacitors).toHaveLength(1) + expect(capacitors[0].display_capacitance).toBe("10µF") + expect(project).toMatchSchematicSnapshot(import.meta.path) +}) From 1ec3f17d9bc90d687bd5ef320f153eb819d053dd Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 27 Jan 2025 21:56:48 +0000 Subject: [PATCH 02/33] v0.0.293 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b86ac269..3e13f3ea 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.291", + "version": "0.0.293", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From b02f0cc1302cdf0e5596b89d76a236c1ede7b75d Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Wed, 29 Jan 2025 01:31:43 +0530 Subject: [PATCH 03/33] fix: missing subcircuit_id for chip and jumper --- lib/components/normal-components/Chip.ts | 1 + lib/components/normal-components/Jumper.ts | 1 + .../subcircuit-for-chip-and-jumper.test.tsx | 65 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx diff --git a/lib/components/normal-components/Chip.ts b/lib/components/normal-components/Chip.ts index 55c64c14..f407e073 100644 --- a/lib/components/normal-components/Chip.ts +++ b/lib/components/normal-components/Chip.ts @@ -58,6 +58,7 @@ export class Chip extends NormalComponent< layer: props.layer ?? "top", rotation: props.pcbRotation ?? 0, source_component_id: this.source_component_id!, + subcircuit_id: this.getSubcircuit().subcircuit_id ?? undefined, }) this.pcb_component_id = pcb_component.pcb_component_id diff --git a/lib/components/normal-components/Jumper.ts b/lib/components/normal-components/Jumper.ts index 603e5ea4..375c712d 100644 --- a/lib/components/normal-components/Jumper.ts +++ b/lib/components/normal-components/Jumper.ts @@ -48,6 +48,7 @@ export class Jumper extends NormalComponent< layer: props.layer ?? "top", rotation: props.pcbRotation ?? 0, source_component_id: this.source_component_id!, + subcircuit_id: this.getSubcircuit().subcircuit_id ?? undefined, }) this.pcb_component_id = pcb_component.pcb_component_id diff --git a/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx b/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx new file mode 100644 index 00000000..6802d4e6 --- /dev/null +++ b/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx @@ -0,0 +1,65 @@ +import { test, expect } from "bun:test" +import { getTestAutoroutingServer } from "tests/fixtures/get-test-autorouting-server" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("subcircuit-id property for chip", async () => { + const { circuit } = await getTestFixture() + const { autoroutingServerUrl } = getTestAutoroutingServer() + + circuit.add( + + + + ) + + circuit.render() + + expect(circuit.db.pcb_component.list()[0]).toMatchInlineSnapshot(` +{ + "center": { + "x": 0, + "y": 0, + }, + "height": 3, + "layer": "top", + "pcb_component_id": "pcb_component_0", + "rotation": 0, + "source_component_id": "source_component_0", + "subcircuit_id": "subcircuit_source_group_0", + "type": "pcb_component", + "width": 2, +} +`) +}) + +test("subcircuit-id property for jumper", async () => { + const { circuit } = await getTestFixture() + const { autoroutingServerUrl } = getTestAutoroutingServer() + + circuit.add( + + + + ) + + circuit.render() + + expect(circuit.db.pcb_component.list()[0]).toMatchInlineSnapshot(` +{ + "center": { + "x": 0, + "y": 0, + }, + "height": 3, + "layer": "top", + "pcb_component_id": "pcb_component_0", + "rotation": 0, + "source_component_id": "source_component_0", + "subcircuit_id": "subcircuit_source_group_0", + "type": "pcb_component", + "width": 2, +} +`) +}) \ No newline at end of file From 1e51a8b58d6e0d3fea5c9bf741c12076af686dd8 Mon Sep 17 00:00:00 2001 From: tscircuitbot Date: Tue, 28 Jan 2025 20:02:26 +0000 Subject: [PATCH 04/33] formatbot: Automatically format code --- .../subcircuit-for-chip-and-jumper.test.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx b/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx index 6802d4e6..2c98024a 100644 --- a/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx +++ b/tests/subcircuits/subcircuit-for-chip-and-jumper.test.tsx @@ -8,10 +8,8 @@ test("subcircuit-id property for chip", async () => { circuit.add( - - + + , ) circuit.render() @@ -41,7 +39,7 @@ test("subcircuit-id property for jumper", async () => { circuit.add( - + , ) circuit.render() @@ -62,4 +60,4 @@ test("subcircuit-id property for jumper", async () => { "width": 2, } `) -}) \ No newline at end of file +}) From 7fe32b39dc45b52f7a99f01f536cc91f0a5fa41a Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 28 Jan 2025 20:03:47 +0000 Subject: [PATCH 05/33] v0.0.294 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e13f3ea..7f38c662 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.293", + "version": "0.0.294", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From ecf147e244639c277a5a5ec81bda179f60c5ea09 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 31 Jan 2025 01:41:20 +0530 Subject: [PATCH 06/33] fix: schematic x and y props using parsed value in mm --- .../base-components/PrimitiveComponent.ts | 3 +- .../repo8-resistor-schX-schematic.snap.svg | 17 +++++ tests/repros/repo8-resistor-schX.test.tsx | 62 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/repros/__snapshots__/repo8-resistor-schX-schematic.snap.svg create mode 100644 tests/repros/repo8-resistor-schX.test.tsx diff --git a/lib/components/base-components/PrimitiveComponent.ts b/lib/components/base-components/PrimitiveComponent.ts index a27e6376..17ea9008 100644 --- a/lib/components/base-components/PrimitiveComponent.ts +++ b/lib/components/base-components/PrimitiveComponent.ts @@ -280,7 +280,8 @@ export abstract class PrimitiveComponent< * schematic components */ computeSchematicPropsTransform(): Matrix { - return compose(translate(this.props.schX ?? 0, this.props.schY ?? 0)) + const { _parsedProps: props } = this + return compose(translate(props.schX ?? 0, props.schY ?? 0)) } /** diff --git a/tests/repros/__snapshots__/repo8-resistor-schX-schematic.snap.svg b/tests/repros/__snapshots__/repo8-resistor-schX-schematic.snap.svg new file mode 100644 index 00000000..52314c39 --- /dev/null +++ b/tests/repros/__snapshots__/repo8-resistor-schX-schematic.snap.svg @@ -0,0 +1,17 @@ +0,-10,00,11,-11,01,12,-12,02,13,-13,03,14,-14,04,1R11kΩ \ No newline at end of file diff --git a/tests/repros/repo8-resistor-schX.test.tsx b/tests/repros/repo8-resistor-schX.test.tsx new file mode 100644 index 00000000..5417748b --- /dev/null +++ b/tests/repros/repo8-resistor-schX.test.tsx @@ -0,0 +1,62 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("board with resistor being passed schX and pcbX in mm", () => { + const { circuit } = getTestFixture() + + circuit.add( + + + , + ) + + circuit.render() + + expect(circuit.db.schematic_component.list()).toMatchInlineSnapshot(` + [ + { + "center": { + "x": 2, + "y": 0, + }, + "rotation": 0, + "schematic_component_id": "schematic_component_0", + "size": { + "height": 0.388910699999999, + "width": 1.0583332999999997, + }, + "source_component_id": "source_component_0", + "symbol_display_value": "1kΩ", + "symbol_name": "boxresistor_right", + "type": "schematic_component", + }, + ] + `) + + expect(circuit.db.pcb_component.list()).toMatchInlineSnapshot(` + [ + { + "center": { + "x": -2, + "y": 0, + }, + "height": 0.6000000000000001, + "layer": "top", + "pcb_component_id": "pcb_component_0", + "rotation": 0, + "source_component_id": "source_component_0", + "subcircuit_id": "subcircuit_source_group_0", + "type": "pcb_component", + "width": 1.5999999999999999, + }, + ] + `) + + expect(circuit).toMatchSchematicSnapshot(import.meta.path) +}) From 52fb57b339e49037fdff3a68a01e15df77f2722e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 30 Jan 2025 20:13:43 +0000 Subject: [PATCH 07/33] v0.0.295 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f38c662..fbb1ac9d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.294", + "version": "0.0.295", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 077060a4754051ed05f86a4ee0e3b5f7311e17b1 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta Date: Fri, 31 Jan 2025 02:13:45 +0530 Subject: [PATCH 08/33] fix: parse negative value pcb props --- bun.lockb | Bin 224896 -> 225282 bytes package.json | 2 +- .../repro9-platedhole-pcbX-pcbY-pcb.snap.svg | 13 ++++ .../repro9-platedhole-pcbX-pcbY.test.tsx | 58 ++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/repros/__snapshots__/repro9-platedhole-pcbX-pcbY-pcb.snap.svg create mode 100644 tests/repros/repro9-platedhole-pcbX-pcbY.test.tsx diff --git a/bun.lockb b/bun.lockb index 2271bf94cde5d14f87ba277042e0e644956a4089..fe86198380ca42f8e6044b95c92903625c648d58 100755 GIT binary patch delta 38627 zcmeI5d7O=9AOFueOdOi*%ouBk!C)|3W9E?ESVIh12E)uShM7^uHbV)?ddEe!gfhyO zWJ~*|(*6{cN~@_9+Njj;{kiY^;OXhevpEARN`p{+~W=jN31=##Q+P+i}K zPRpjgUbxrm@m%fk6tzdL1kdw(JhkDea0NK7oW~OiFN3dvFS>Tm@*YnW>^rat7L_BD zitsNO;;&()|CIQeZ~>Vp{a9G(!ZC2UzGx7F9DBmb=vN{L7JUI%gP$W(6?+H{ho_Ny zWq7T1!P~fLd4lq;OEV~`C_it?B(-oFWzd46NwD;Ys#XtQox*|SSXFXnZd!hNo+o>n zoIRel)t$ogGtwt!jxF%ia_z>jvhPGXRbt$PoKf=sxrWC>RMD5PTKhJj3r{GPnhH|ClFI~4Vtck~iQ1nA% zhu?t7p=c*e4n<4gdhjHeniutRxwXqxVVYX>({&CXbNLWV(~H)-JO`!=i^jU#!{NfB zmIPGqYOtp4Z;hPxjLl2GC4FLk-gnsQ_};Wb9h?aBUs0=8PCrE3?ei36aY#XPUKel%KPr{mnufb~mA=@tW6m21(S+yKi#xr4c+<3S$JP2084zT>9 zT)R4~0r0r`>1ZeYaajH@z?I=WuDuRc`a5BjGX<`uE=qG9Qe1~P*KQPTJslG3Z-BFA zmnCy6Fh#OI>GAANc2c(rIHli(O^+6hg5|%Y zy_4T8xDxiC{WH*2>xwtH^EhYX=yVUCTXWMUO)Bts2IHW`_!|z&pqp#Qz-nd=1*w(2 zVRg$PDyZgs*2zitGOQhDO74WHtenh=Ph)F-KMHHS$98f2Z-&c}V^KE(%4jDU$>Dx0 zx=h!8N4q=O?SZ9k>EZNGep+tS*gWQPiZlCX!|I>UU{&KCmoq13q~~U`kzp%+hIOP& z-NL(jIhC0-CEMQMx{|9>jn2rqbz-i^v!2q*VVCaX^yb;#PNO$s%P)5{J;kSKUq{!j zlbxBD57~NM^z!&k%o&p&l{P9fFFpH~bn+cYIdp1aQCkA)#YV8Iy_Eu$;0ag-1e=%G z->K-RwA}QloIH=swEIVN`RC>5rl)03^?c>p^9MN19Mv|>uE;EGHDn6xhn?n&=v^*qfam8Z%|mg!HND zxp|W&Wag7uenxK2lyMoJro_vy9;|}K=H_Ip=@m$?0-FtYI4?gfe@b3@UOu+sX`Ytu%LPM?&Y=UHymFIPA6DzfwAHDyZX7-c_dbZ)_< z{H(kk^s`dm2df(QTbbqR7M@~$s8JKsCd%0}&b3ovH7>>F0837bt39?VdmLN2WadTL z7ssJvo!n!IS1Ankm@%2TlY+B-@;Il{g0tOS9fd{dL^v6x<>sapc&cG5gVao?H#75c zMrEas&fkHp?II=1+0-)9@>l^L&k1blF|f9Y6#P{2XU99;kmTB_6CA&-u;y_Je2s_s z6^(-`a2>3c)q+(4hQRKTUl}CrqEm7+r%G5(p(p6$*$KDRB zg;%@wU^m~GDUN?RSbpl+LUrwa1hv@fMl^LDtGM>5Tbv%Mg{_tcGYF;&R^Z!Pos7>i z>ouqL(_iY@ov;e5LeGk)vT3Wl-1L04AH$8v&xy)SAD2Egm|>G?jw3T8YE0(Xv8-Qv zvh|qmv~UBg3*e~Sw9%aEJfmkg`hJ%O!m4l&SUuGqR>8++I{M2qNv+9~HnAW(Eq`=I zaMqu)R)^N@5K`nMyFe|~4&&PC=}}`dbMx{SW2-$=CQizn#AM0N$sMO<^xSNxm_ycu z(7Ms@&-wS%!DYVbHb=j5xvR2^t?t+K@h-GhUlSMI`wpi;0hf2rckJL9a#C*2=%@)f z0PlkZ8u@7^ud&-!RoWj*`FC(JHOF+ zdHDr&Uk7xx|7}+Q^~%{fVv4f$M2F0<{yCj81@^i?BQZPMp)R&| zhS1Fl`R0XMSytH+eE*mHsC*4 z&Etu+y>>T^^PaIv+6H`q>Q>X3Wd8zsT~Vd1-PgtWpTJ7S@>-Ld$Aw(PqCpR~^VYDM z#wL4LTbZ!|Uuc-MEjHPo#xQoX6XNQB0!s-?Ta%l_`7gRw8H@5ldNA-^tnKlM{&j>n zp{ua?IR8gj@wRm~Ce9yS)1#Z1BA?xo(N=MMz`MdK;qT8@WJ18#I>O3INcLt~#R&ob z9_AD$aGZC?#`(+C@_0C?Q)@cGpMs?>DP=_`#Ch+timwm&KXbLRR`m4vvfK&Cf!a}v z(^&1WuClXgQ^&DFWO;L}lEi@j4YZr=4CUXruG7-8cItH3qW{;&m&H)?>{@w$vm%oM z{`h)MVP)-($;DD(Wo&DQYh7hqUtzT;j-pq_d+S?S$;tj1^_{}}*4fr^{)4WCf73Ys zc`Rq>C#S}HueGuQ$=>Iz;y}RHtbz4aAlW~&0h7nO4*d zi6L7qg|3O@Bx!3?2&LPh_Xwrgp~R*h&j@RKmv*J?Kz7G=-lo>Jj)Bt6Jf2~;$KFe! z%FTmX4xyoT>`RwIjiNXv+1jj2p?5EZTD8yyp_FU1^%N+-X`xC6*#M#rsm(a>;+AZ0i*UITSCLA+&CstcrO3CtmYn5~hgw$-q zl(bHFOAHxKsEZxiOsJb3`sPw>D-xphYFC;-PdoBiLJU;zcBNyqc_@zogq++~5pweQ zn2?j8IqTQa@(J~}qDV@>iM%E*So{D&j@w#7PIez((wZ==PKta&PK6H=awwr3XaaMunmExpk zr;4C56zHy|RIFCk>FW~x3kYdKIrTh@MWIDy)u$n$9X*~7*7k%%e{Vw4oxNlcR%a}F zl3DvERw|a?-YJ^VHM+()n{zIf(^uL%e;}xB+-pVmjq|r7iy>I{_UB)TrP0A6&sVWD z3eL7!mhD%ogq?|=%Exl^#B)EEdXYY&l|Nvqk33fNfH;3AD&njzjnwT}mq+$-EX^LS zKJ46QtjM7OU%hTt*3e|{Agg$2z_M)9!rJ!?Hzl(ReWN1VgD!L}x|eYfr9EC+iSyd$lW5rL3(XtCOry>D5WBLn_W z_8PVm?Ilf^L%pr9Mka^MMr>h1@<+MZ&8`_im_qnt~QRGf6RgRUwtp480 z92M{<(f!)P?CVmF+?C|16d|$L=a$%YN3j(aGK^R>|mqzqns; zl2EIVvsk^&8#}yhta~5ym%Y*HDHb^sXfBpBrDZ*XrOG%LxHA2n{^sgW?{~t|&^w#M zEG%sf^ddd=$R%rc>o}ihfR!~i*_S-P+BP=XfA@f331_MFn^;bNYt2<2Xl0E{4rxD- zUb6dU1|esDF;%>eT9FxnkaK9Qt<#B#zE(F`+cJ{Cr_tlw^-( zNO!CotkWYC{R;^>-O0T19=9U10=~$>R#sNBf9haoGB{WJ7qFbk$9(pcNwu1ePxg0V zU24AA3pHdGRy!^FkQWJ2ZtFxHVkZQ=i>yrkeqt3*2>5#ry|jdq;=F6E$n1dsV>D&X z4CScS`DSg}*^$(akn;Cv5&56N(vo6OyTpsmB>JBxq!DHcvDC|raLRV(!VOr;%U;g@ zTrABDd!zC0vLYwzjG8%_Gwetw6*1KDW-QgwnUrg>+F?<-(Q)2mR%R{-`!v>(eV&XZ zOC?`7>^3XW%SSvC=5b`KmH+yycPRQ|9 z?5$P_vAag2*-br9$k{1b+P?Nv-astb#p!To2*GsfID6YZ zLS1ljHrI=;ld~W@WYY}$x;~qbGqu=|xssR6WFwvE>}~d;EF=+&QwxjtUP8_U*Mxl? zOWovLo2uqG`8XB45lbEFRB$_%(oqwxO((39!hk<~l9Sr$@?ltNGyXAgAseu|SW*2F z{hwdbqch@sjVD`8XD9oYPrfv-8J|~Oi_zkWRxa1+N@sQ?W2pd^!F1{_`kI8p(v@7bLj-_$1XJ5!(ENAO% zKPA|yx{}Spaz=}CL!QRs64E5m{|g~!eMTq6`D1T!yyy__`zB$rdoVe6T-J5uz|#D4 z=6l;)gF~RJ=~OId!&a#eV<~s1?LTA1VmU{gsHwqv%X1vorNtTYELMBFXFJc^|hT7X(61qa|9W^Ar88rv+!de6z4r_Eq*(?p`b>rQ$wtJ)L@0o$h!# zQ#KXLnZW9wN3m`q7pLd1o^ff(FzUHjj;B`a3$Dd(63d})CVgaYQT+(HQ=O8RV5uHX z$zR9|%h@@a&bqV&$Hs+Bz>2r`%*})@dwC0;1E0NrhYZDvwW9ha`j-*X&Wg@4_ZjI} z%pz_FD;5REwKpMWCt>D=+-K`NH1U5-NIQnJ`-II7j)8jXMy$4Woc5bLtjwhW|7&P! zhcn~L&v7j0xY8Aio6q>fkXs40wGYS-O0)eLxsWfh+UpGEZ+x56J8bp?;zH78*(rAt za^}N#gj6$U$u_>-=?lA+A>*;GxBF-dA+^`mz3*Ek7LPsVT21dx_9e}=vhGgyXV1M< z1J>L+tQPollgM0r8Ov#*YFGXa)jFGNV2`-by_>sxa!3#%)+m$UbSC*3&aakn_%RST@F zRmuJi3occFAt|s*Rt3C|S&^#)Ayx0x#M7~&kdO+aXs)V9u{2=LRkiLyXMmlZG8O9v zCyvX@8Z0eLXHWeW%bmW-To>-Lnyz6lyz9~|>K_;KCRPV4YE5EDl|^ogv^LiU{E>^D zKIevq{!7Jj+PjF*^%Oz>(MRuMxpR{9c*7-5oPBrTAC8rXXF2;Cxf(0Mu9{Zdn^+yN z7<1-$?WHu(iem3dCDg((z+Qhna14)H)vAPh)RK;^Yma13Hik=m( z$KcM4(dvx8+gYnTkz#ipjn&Gj6DMg4s}mMCk5l8zVknt2wJNL#j>XxTasFOdN>;{- zzB|r86HCjV@x|KdTHLr$lapA=l3`#B8?CgOZcg?twK6vcydPM_n*+W&#`+3rloh!p z;N5Cv^0&k)-V*TDUS)l?CE0tE6?uQaZ&n5Sn=`)uXRN+<)hL4Jm?ifIygRMP2Lj&T zt;`1kAxZa8J^ON+tq`8h8d!(b)=sD0_1{@Mmc*%%(`IiTHRByZnE=xnUJP79murzuXpmZ z9}|RhmSvreNer1yh@FUMp-&NV_EhZ|z70-lr_L$=W-Y*SMjOwNr?9wVWS9M!kUL0L zeA#;)!|9fxSWW||q<;lgGF9V(%j4g-tjHY!f3=Ol2J6{OKP+`B&uzxUm&V`$P)wr# z1%+%mnlTE!FIbOg4mh2$*czH7hAbe&LvCvH79kbnoHHwJy29Vz9ZOZB7db)PrZ}w& z{~>m)?;b01Z-Dbt=H5WaFI)A*F?(-fNdICzQ&eaxp?-Gg0wHoi>$WWz zGK6~B+Gm7P6!Nuva8K4gpSRHGu@}APDwq}E@q&J!6c_*$&zZsI!Lan9Kp(N};Xvs| z0DZ)=M}pE|43M1;l;1d@4_p`w*coNn7XR-ER>mBx?T=U)aZa`Me3v)J|fc)=uc_XaPU$J_a zfwezkm0Rqzp8$q3dP zf&AYB`drD1f7@0au12`Twf~*z|9=<$AKM!LzpFq9@!z^N|0@nBu8f-df5`Uy`@hNH z|FmE?T~qPDwLpz2>$d1h_FAV9=nEyN- z^ylB$ZodiUUQp%mBtJ5~?eh+kQF2z)g>b^rmT9j8AoE5q^FnyQmv z6`1G7ixtdw?JHT*6#kU5LZ7H>Ux#M6URSbmD|B_Sf<>+^R_V99_TRBw=DL1=!A{5i zMTA|z0un0ioo)tVRcw)~FNRf-+idy82(SqF!_3#hTFX!z$netf&w5=P%h^ zd2*1?N3Nq-8Ju)&v4Wqt_LZ#u{Ty9A^o<)YR`9fI{}pS%e$nQpf_`%y#Xc+h>ALp7 zc!^SkPcAMiSlZP?T)xVUzmk=%47wJ21vg%-^<34p|Aw88xza%yR&x`IWmktKh4Dx2 zuPei41?#)ESpL_#wpasu9W1E{f7Fl7VEHxoxdYQ&v9@rT{RCss6~+I@u@hboD`BF< zKd}l5po=@Yew|$I46ER7F#maaxO$3qE@jx$jp*&#eO&JA>NmP}e^?)Jd3ZRi0!O*} zU$KTJi+J_iWY7Q5y+(tbAdFJYm%L>lpkJ8O|b+POPt}Ryj zMXoJYMec_2EA*^zBmRmtiSBXZ#mab%YhTG)j1RcFSbke!rQh!Af6a{lUq?8)((ZIK z5G&(dt}RvpdtqI754rJ=xqKMbN37rzuKjPU`FEwDu6hPX74)o|;7XSMoU4mf@XN5I zqb|P&%kOoGE-Uz^Yl~IRJFq?f6;RwU{%9_|536M#!^-HSBLBq7;BzB-SFETwH~vaiIfe0V#Feaw1axJb=*Eksw{tnk)x`?7cex`h zzfLZ9RwSSQ!i9E(cBo!%g5GWdu`=r8a$i>$t7130dViM(xI7TnM=ZZVu0Gi1RF{Xq z_WV~s1r3FjV3=zUw;kAGVGY43S04>m#-8Hp1+W@08`kH4i?z&Vm$L5J_hzBW?g6x< z|9O`3&$E<&o~8WVqYW0x-#+^I-;URn;O`35O8u*6C@M($KhIMBd6x3`&s21M&@&W$ z#JZ^b-7^&VDPAX^f1af{{q@hYlz*P3Xk9oDTeO(|d6r^#2aiykdzpWprTp_O<)3FM zdZwc5>p#y@{&|-2&$E>OKc1y%z0cm0@IlY3+AnUlaNXpO#y>dp?Jiw25-XRqZRcxt zw&xcQd@(4e;peyfQu(QYzbVa5 zxlfw-tht}0Sn;2STBkot@kUq)pAWK5VXgZ-#ar7d!CLi2sMYI>6mMN?^%sMzZeNC4 z7qRMF-M<`UoyXe#Ws0|fbpdPZsZeX!sT6M`tN7F)Yj8=Z61&E zinRP+4YKxQWq+08ZDt+7%J@3es{M6}H_FQVdXN?NO{jGgtECnG%^>SVteM}Wc%!W& zSW{1jT2ZG{c&(-2^dPIrx1rVvtQafu+dVA&)VQoK`;_YZ%z}osf z?fX8(+u17qp7#Af`+i9AcC}J}pnX5mKCJGR|3}(~mHlIiH^n-DmGKkp`zgiS%gX$T z_Wexzu=-fxKhr*}nLnp^`&mb@rkt%CEk?*i?^8fZmcpnX`2E~N0D)p4x( zztFy4QoO0wf?sIgue1+qsFm<5?ZaC4Yl?T6Rf4tZH`@1Gig$#y`ZwBlk@jJwS=}$v zKCJB*Q@o?C3s_r!r+vStc+;)o-)Y|;wC|4;UU*LZW6+ASUfPG1xx()qv|_(EbVar| z#XEk*0q-D_;q``^+FtBzlj%hW^C29SkYmDq2ro*Q=|h-oj!2kV3L&Z#LY^roh0vrl z!U+jeOk`>AAnz?^w&+%K95VAmh)xP2y1*<5L7!$$il&={tDqTXnP{dd5zR6k%0Pu? zwW!FP70ou?%aYM~8e+DWC8OKS1qAQyrXMZx&NaoNJB+s+G|!}p=9}H31;$^Vr2EU0 zG`l=W7n%bSGOk9beKo=&lX*2lSSZ3#2}?|PC@Ghk$)aWEh-kT~e+^`r0@2;(4bch{ zSpiyUW{ZqDE?Q-xD?+Qy0?|F@q-c#vs06Jw%S7u;iDK?Fj4Erin&4w-~n2&W{htA%jblt@@r8=+TigeT1E+6dk1AY7F2 zl<8gv;k<gp6wuYF~?R)MQ?Z5Y_`C)X_Fa+5Y__WsD$rKcngFVCCqGraMm1=FtsH@ zR7-^KO+ib9Can-oNcho2wn8{2VNolDpUrUz^P>@xq7g2b1^Ow-=75BZc!b*V2%#o39w97&&`}8$On3sqixOrg zAXG9(Buu>?A?kXBDyHCigeHjyCnQuek%0tgo+)HmG&2FtZavv^gSSYG;I~&IoNxL1%;}T@X%4h%u2}5ROS$)CD2V9G5V^D?(CN zgaosoD?)rXgwqldO+q(>Qxev7Lr5|u5>|Cb=+zw|U{-f$2W)T7iaMC?J%~QvgXrx& zi0)`ENZ6_o9maLt+u0OzDK>+9B82ut=xS1XB9!fga9Bcj}9FZ_}C_>awggjF)6rst@ z2qz>=F_AYT9FwraS2Nv#wD!4EEt9mKOB$K!|<4H5{4t3lCW+#!c0>l zVbutPULz0+&FT>d-9{o@lrYSY$HCAcUnO9F?%dgr_6CC}Czg!ZLG2 z!ql+{QDYG-Q!o~x$vA`)5>}YVaR|pGEESo`~?EIUpe;2cdQj!giCHgAg_e;i!b2CVUdY zixOr|LfCDNNSHbqA!;(h9#b$Gp-C>n2?={mWG=!n35#+O_L<`n=I0?K--k1K0m=X!AiV%7gA$(+37a??;jc`%INz;8c z!g&eXXCr)SE=brq2VvM8gwIX!9E8EQA%xzB@TEz;4WaDq2!|z<82{}E`z2)Gj_|cP zAR%KeLhZQ-r%mQugs?jhj!O8>gx`ViqJ)`uAe=QvBut%$5H%0sds8qEp~-xN6B2$j zk@FFbNmw)=;b(JP!u$mYNed7zm<00mZh`$%% zw1h;Ha4*6s3G41fNHQf7R&7M+wGkm;R&PY;b|1n;2^~!L`#6T&U^a?6nhT;%rr##0 zvndvJG2YEkSCcC0W_F9Z8~+xl$G)^J-g%|1R*kBzyx&{ed{gYL>YcXFyUknI%XO#z zgI*I_qo(tZ!PSQ=?&F^dDep69?&qI$8QG|`KR0K>1pQOp5AHjZ#JueE zh@8x>J>Ie*BX||8+~pWMxq0kSVtRMu+hzJUNczj$dvss@ecm`q$p%sO}mE=Co&iwU5WN|Q+f8pY5B`g(`}ajZ?tQCN$bC7N>b8#tocHPP zemiqN|NQRQw0yo&XWn?xyU_dazF|kao4g@)7L!C}HM4W{WAf$7q8Iihz3jEhc+c&7 z<4x}ylhhs28i}henUt_-CoK+TEt2EIW>>51 zY8BD$bG0h2RtasZ>Cl-hiU=xKeX&?xRlp=_rtfjpaJ8z0Z$?w)^~GcP=~bYiW|^|+ z>b9|_8&!j-Zmt&LYGG(q(e#bITCS$=iIg@cmBj@lwY3h+fBLruJ-@nIJy^Nb0tXez zrva>5)CLDkbQiLC6I)%=$c?H?_;pv)x1Qx*54_`Qja{ui+Ph}9vd}klufdFTqZ$yt zldwKbVb!7`Fs>Hm`ZYpZY2Hv4kCD52x1}4^nDA4s)(TBs-2~`c4EnTn{UQmcn)+SI zBKW#ZtQ*ygsBqU^-@aC`IWRzP8l~x=~$S_c)?* zU9Fp|#iM=ZHm-bY06>@QRQ?by@8bm&1A zQADYC$GK7c2{%JahBI7k0O8;ZlbL9mKLbHWvrJiN8mSAjUH3tRRk}VCVFlUf?XK+t zPjda(=skVSNo5i4x@$U7xcvrgZC6wF(ryNNpGqIiQU!;B921>F7J8XX?YhN{8bSCG zpvr6J%6%l*3-piXe6-mq3$B*-3m>Y@Lf3r~VeO+Td6DZknQ&wC6j{{No+)#Q z8&y$Dkx$>j=G&gW=L=`ichkWPPz3Z{VSVL$CYT0Bg5LORw(5Jw`Yy7*psX*%>nq=l zz;&Q8C=1GgtAVbV=fL;i2k;~K36!B7&%w`w7xaygT?BT6hru532-t*^uAv)2F?bL> z0CWxA2JQt90bM`00(}RqC+G$GfWDv~r~)d3P*4$E11f|;6vf1XT-oCo} zM>sqS!Bn6f(B6w+eet>{&=pl*6YmasfG!{f=&BkCnu3;~6^I7SKywfU^u72NKwr2I z2Q@(r@G|Xv1@Hy`Li;rUy&CWf!Z+YFI0lY`_rP1=O`sPpo&ryTr-9z^I0*KG1K?4x z5B!Tpz6Fj0y%VO1q=|DE*bW{>+XEf}d-amuqXhN=y&tz7=moTw!7Jb>FeK7%khJ>+MZoFi5?cKLf!4Fvw)~^)+Zw zi(qZg33LWs!1W*zv;zUKoDs5s-)j!`^$jl!LAwf+pq&KA!7=a-cn`b_J_lcb55Xtk zOK=K&20jAsgAc%`;A3zCybWFhE5J%%z$&mB+ymACE=Ps-o~pe@F97JJf%$YmGOWwL z-eQOWu|Tgzv;lghq7H}vujBg$I0{|`C7>$M8!sP#55Y&^8QC;aZ}@44nF6$BPWE+W z5fjJ<(}4C&ZO0$u_!(GCcn7=_>;ig~@NTqi;31%Q8D9j(47<@6QJ6+>6qo^Kf>~f5 zm=Ep%+i2&5pcv>qUtRGV0A1d%1C2o)&=vFm9l#BsBY1-}uY)(iOWF*)`Imw|5$@|W^JvyYzzf@!$R+kB!KHdZP1LiJWbq}@E71D_!yj^;4|O?_!gW8 zItBa)bmiAJTm-c9m(kmIYk;mEY2Xx&pM$S~F5X{()nGa(0=EIZxY!&l1a|>_ zG1LNggB9Q*Dz_c9AlwwZMffP#3ibe9sds5}+5kp@ksu9>2D;`X(#l^*=%YfqP7elQ zARN>Ly721YUIA1Bl|dD7Be;ij<3To90+s?@QTG8|7I%YmP&kf1y0qx6n%{7`2uhPd zHfRo703E8ML2J+kv<26KMxZX3LYgDwkp;#BUG+TZJwY$f1vCaz@hbrNMC-<^iLMW2 zC|I{-KjUyeViA!#)U*Lj!C2zPfh>>%bd#i;BHh)5fD5G4Ez5cE8+eaA-UP1$-E+JP z-UbVZTM4#+$FOyGP*z)_3aLg$dV@-@_ULsV*-xQ+;6F(41i>ePuJ4Di4}&{E9{7li z^jhr^un2n@SPJd|(uAkMGvHb999Rj)03Oykr{axdtU}v^!-R!T$lz0O8Xp~TzXNly z%K|^R8cYWr!3gjr@hWT_$O273TMz}Bx%N)--2wEjl3tW5oJvBqq7)bnZUU*GFNgrj zuo_$u$Vd1FEyvAJ$2k=wJVM5gg8e{mU#YTLV7!}7X&ZogK&Pk4dM#QBUnIemUHm+@ zdf*wL~ ztwFRoJ;=AIP{o7;xsuYp0Tv5Y0HxTs-VtzhAiXxY#tqkp>wrd}uFKNufrg*~xE9oN zp=llo8iVV!@yekI5I1+Z8LS&rE_0qJ&=M#!B~qNi!8BLKl}3*NUeMNMRaE*eplPSQ zPs>ty*7nr}bO!A~0B8s42s(id z;0D*e5!Mx^Kjqu+xOIcMqT27hb%%R{ULXbZ1bu)K^#cRIKrk5S5~U4Pm#NV}8}=xW z3Pu3w(scO}4+q1*NRS3PXYfZEDDfDVwHc2E6Tt*99%Q>=-3R1>T%ZGgKDg67H^kRJ zY!Sgf_0b>2Xr|Rr-^juT3GD#d@|S|E!ByY{co(Rf-vLL#0ier-R&WoX%f+MM74SHC z85{;$lm~$proxJQ2^;}0fM>u{;7LuiCkQ+Zo&(PUMLh5Fi?HH@2^3Za@=^H8%%!~v z-T<$I*MJwi>hizfx4~QB18^K1(?omU4mhoSk8lL3YJlpX8mI~?gO7;22L289!RKI= za8d++?Am|8zk~DO47dn>1>b?6fYN;mlYw#5)0jI#{E`JGs0X_lh zt#3du{#(MQU0rE^aKqojKZ0Mt1)xg(4AcmfR~Smob!09DO1oSZz6z89I+d3PejvS^ z3+ajjfNeQN`B8EOS|oofkn=+bqsxvuc73CJM^#DOHx z4kUu>K{B`>=+LwU+y~U{z2Kgp8|VT$gHE75=m>&m-L8atfbJj#3;^nx-k`s(@XD+o zd?V-!G{${kX)4r!yMc}cIzlc7OTZW~8jJ$N!OdVG7zAztL&0E>3Wm5m3{C?hz(^1& zM`1FE1vwxa$Z-M~3(~=OvwMWEO5sF;lRz-7ouR0*a8+955U72P#CGDyc+jhr(*;9YCF= zg5>WAGuc9~=bHK$$!W z_JT)1FfXlv1K9H22c7`h37&#q2d{vaHU8STp22tt90AXR7r_hQS@0Z?7G(LqhJ6(1 zlJF}01}Fg^faBmT;3KXyc$e_o;2rQUm(`QU!225i_Xu2t;~o$Ue~G59J^?-lCqWnD zKZZX9AA!%nr{EKyO6j=p1!3*VN_z^Zps&Gc@RiH5zX893Y8w9w;5_&V#FO|t_($*q z_#WJhb`CxZ&VW>GoiU{UjQtB3LHIXVw(e}N0#(p-Z>O#Z_Q)T^{|?kM*8r98(Lvn{ zd@hH;y4xrR$^hMgsE2eH61;s@x)@Lu)B;V3)7hJwJp1NBH-OiIT0l1z)q&3Ex@!$K zguB>6`)P=7V|AMw25Nxd?XK=Nb<0~1)Canoke@PZ=(23xnd$~Xcdc8fSu0p~vQa<} z4mzVPppv@7RlM$Sh0fm5|9+eMAx`QVjgg?cibN3Xp(MhJS8uc@9B}Pe>^7h^kk$cI zC#)g(!_-grHLF}xL9$d*h<}mC3`zIZDYxIfL3#73eRrh$GD~@5_MOS_RV-~@9Pevu zJ{j+;Y$|8_+Igp%KH0u-?>v*4?d#=>D`)m+`+7#)QO>@lD7vv+jqK#!H@xQawrZNX6jDF|5Lue;|q@n{u=cg6Q)GO9Djbe&pS(wt(d}&!+&NJbm(a|Dxh{@0| zCUlZ7+*j^ub7rD1%f%M#@*3M4UX`W6`#%-r;dA+K{_vjVYDy8|RCt zY9{3S!fFM7h;HD>Z~pjYY1&UXwy8H`M!n%}8&)&-;^9lIW)9~2TJz{&Me7{B# z-0odVy`x)1^PlHS6OcpjhrhR7{m$=ybo^Ia+o6>vT(Q|O+gH6bp-0T3TbRp<;pT%| z82_c_$6I`z8@$a*;lE2i`+erwnUmJO`^sC&L4DK8v)Meciz0%*`#q@N+r5UJJ96@J z5p&J5TdC`E^B@!x{CUBP6TG`7UEAqB{9;-}w_vSysLf_YQRjb|p7HeHySMnfO;Ku~ z^fQG86fp^tZL(-g>N8KTuW)aO&pQ;Q8pw+w4vd$Pfk{%a3V2~81tA+nCyg$G|SowpPv0`h4t-U-h`~4SvozcxD*yGzwg1BA{9iUCZuF%L~r# zJ@$U!v01iXn-;Cxda5=seW$Tbmf;bB$AwDi<9}~^bTuB)E!wt-Zp;60yltAVO~lHE zPTOAHd2QnA0lS~Vp>2ye_0lHu1`d3UEM&T`O>FQN#{*^hjm@2ZWK3yq+ZL@8)Ca-e zB%hPAVf@#{<$7L@X?dNQIGswkKVx3B_m6MRm8AocG3MkA7zI3@S0nEQBJ0zvUj+czb;7UtjNX*>9(L0*Bb(kH4QEzIs;M zwJ-f~*&+Dz@WYNw?%b)z%r`H`gf%hO%w(yzYQ?t?eMK>i=(oxY%ZDF6vF^dvhZ9PB z8DBbu+b3c)nO`i^*K|3R{q*IS6mw!G^-FUd!hZQB`o@=H(=R(rF_mV~jyp{=C?fbv z>Y+6{m8{=!%L|wN_Lvbk!~}nOJ@Y`jt!=N${^GJj@WTtoiOsgKi*k(pu=U4 zL8fIP^$Px^{Ff{9&ut9+bm+1}@JHvHkFQbY`)9HknqaRjH#12Z5&V_<)|F=7bn@Vh zqb@rfGP`l$JEAYk?<94wJNc)gx-&Kpv@ZMoX#T*#SGJ9*S>)@Q-gqJqEVK4wvw%#4>` zt0ZR~zIEq!--cHHg@1XQg=+iRyLWg@@Hgy-U;X&hqbE)!;n0fn1Q`W?<-XfDk8Ha6 zs|VT>)0U(hYST(lP;8bFwTer}qag;es4!)T7ro~)#)^6skG8}Bm z-v(uvVYl1a2e2Y$wYR@XRFqY%aB1$Nb#x(XZC_+OOUyF-e60dz@ooH`X2lzvlUCQF zGY`$_mNdb3w5z?_RKU^vaGS3tl~y?7H=HXmM9(*QwQ;3Ex9!I{!RbFI*UOcVJ6|SO zQB?3j(Qc!fxnjisax2|rkD9c(q<-2=pUZyvvWedAt8Si~>#Obk%zTOz5&Ze>6SLR1 z`8am^yVR|fHeqfkO!OTj9cxnV@U7vsv@h@Qwehv;Zfec*wf0@#-SmYcg1;8O>6Wh^ zYxYKsqjo*o1p^BP>;`Q)I?NHR@p=o3DdN5A)7^3hdg$x%@m{uHUe0o3*@X*EgmG$L)cp!2;hn zr@-oF;{w{~mbJwkUqI`-n$SCG!nG;phC9hABgL83jlG+@Oxv4$j-2ev54YK7368u= z@C+0Y{K@r0Z+z;_kuMIs( zSKMv3FXV`oVSbhSSySyUE?TAgIK{v6X|1>crBW){+1fK`BQZK=9Qy6SN`bbU$JrU# zeOkA#nRS=1r>|*W^NN_J)Lg`9B=$GG;fTck&R(#5am@~$cCX(_N*xBM!dGU^BFg^J z>|MkvnlixgyX~EuuKRRKC#P(#&HNu=VstbuIQqgj)u;C>a%;tS%r~_clfzdgZZU0{ zV&*O;qyK*TXn2!zU_2PIadYV-5A3!xV%F_T>hzKuR9BrNsKe8y z{t`;sWD=J!3cE}WR>YyfPJX|=+r!s+z^n6Zce_(|nN3T4uhqJWn_%sOH6{)E=EIZA zBYa*qAp72@!Vt4~sV^+HCLTJ&ez&jv<3B!9mMXPjlWNP|QDZI`I=9`p;GG?H2KOlE z^G)D~qx15)j~rq?AZT&O`PJjQaSGpBs-qDM@ z6?RwkRnwcz$IBSt*qcq&<-S*IRUhtnw&Z=1;V-BCVBgm;7vntjhMV7)vrd`~H(?f6 zhkWzYHeVGp)ndn+W0qOI`Vs#nahtZD<>shGSKnv6chm7ZOvK#`@%<+AZr@&C>}XSO zg)c0oJvYZ{#`-%Bb=-RKn)?|5bug7oAx0zFslu)Y@)x~+r#;m6tV=c7E68x1nYV(K zdCGi;nax1y3{=oD-9KGF;k3hO|5d7&dl+Bbn~#G zXMW&rn2o@`>#CAzny;c$Yh{{iHpACtnvvMGqDi5d^k)5subnj4-+&al-Z6KRGR^vp zba{%|zKRl3P2KyT9p>aJc9NJZ=i>Ex)QSb~jJ?~rRNL3l6w`7w18~BO7Cmd$+(W7q zvwO9j$KkcmR`dC4_R~~TejS}iIZtk)9LF`{Kkq21P)v(ho-3Kx?qM*y@kM)jX5K_+ z5Vvow)3oK>T_4#Mr@MLTZ2GOC=v1?FgL6B!!)#EB|4E&7nK~`MQInmVkKO!x^?@(X z9pZKg4~4Q#ebqnJB(9}^Stdu;e6v7SsNysL1Z7 zHW52{N~G;`W3Pj?noTGgaJlCDO`nbU*VdxB3j`!=!`|NBaCroJZX6$`@GWSW_H zA9Zn8lJDPFSZf-u1rtoA=wzmO%+vyBlX!gWb64HG|JnEL+SvpDcNJj5h1cpa-RYh? zZvQN7`=tIe?C#-0f4Lu>wfd*3^mOOarIoh9EZI!W{#0QTb`M`6sJMlvLG5Rl=36dr z7Tz9a#1`h?f3KiDJk>*-T|=umV&DvCf=!$@A^z~^Av!{6DMjxShT#K zlT2_T*drMp@$yXPD)!aD9eH!6_RF(V$7*pOGrR96wc}Uozx&xcZdgpJyP?mxYS@~j zyS7YpyNrxZ&2nz)ZyhowJ@9_T;Gu<>p{CaZ)a-(p4f#Tf%%czZifSz`a%R;dTR)jr zA#R7RS6X~D$h}_i*5mlC9G(u%b_V#FapikOj+*$PePOe=#^=oGt<>H2)0SPo*ta+K zKl2T)(f_>2*_V?xF)H!uZFF)ouAy3^y;eUS_i4GicG#`6Hw0q>+bHUNle&$|m3;+m z!!hK?ZM297Voe|95o_QMXF9cOKIh?|YPPgbgCu4@>1~!h=zEQqMbjSg?Ty$y-|-vL z_^H_0O9#A3Dee;<`w*_dNZHQxcxZvMJw;qwYD2$!+kS2jT6A0PkOrH=?eu7l*|VM6 z>@g8Ln9a}J>Gad$x6ZwtcIGb5Fs(UbverHRg{JQgwxH?@oi6`j)SK^>OzBvP4Bc~; z>tWXJ@YRg?6gTz4R+G0Nx>sEuRRyQo6yCp~7iOEUcW~jbNoVKmomX6T2AhqTyia#X zs(-P0XD5rg+G0~~m#=3`jU~=RoZj@&$I?D+oA2XZ*uMOF6013td*_;jiIuCRbXTcP z@4aOf?xMBM!#rP=rRKd|^2>iIqSo__DuPkw~XjYay<}=j`s91OLkL} z4$I88-M)Jwb}e^WSFT0X!fxH|MIYTFUQ6MS8SyYRcb=!3k%3{!_0n!ddxFx9%0g?n(=#?3^P_b)n3+e$fE1^ zCM9SU&~>d_#IH3Q{@S4_L$A+T^VVLD7{^vQIjqb6$m;Y_v9@vhb}pVL`}H5Cz^*3o zQC~Cvz|~F*)|#A0d2H-F$qqAT9_7O6{J#a$a3A5JCa{lGStfNKhmVKM`&fVVEK$!5 zX#RdvVL!9exqZ3Qe1sHpu#WS5_Mx2UM<#qbdi~|3fAKVvn_5-zXA^aR_1u1g8FhdWnq_t# zxRiN43g-VYF}j)uS3DthPr9F&i#Y#H`|UdF)+Oa2nVvK02Ys_6{`2H)pI6xgQ;hcz zeyJwn5LMz}-1m^L^?y9Ow_9Z&(s;VR{*Zkf(z!aKJ(r7eny}wLx%;JxF&Q|zH_yk+ z*UI=?6Y>}p*tf+Q?9RCZ>fS$?$0^?6teIyvK4w=y)6Y9&-@hL7o%Kb;ZgtM7pI>M* z{<8+9c$694BEh~<>S<0sf#WFiD-=FqKeCAy;tYE%YMsD%O@G1VjT1g`0zvB z0<{LkZ@BF6G%e1gt;P6r+|v6a?+ML7xUC*0pWZ^c|}-AX3)YczJqf)5^Ej;;TN@Z;BCZR-&;Cu}gb z_T5c&?s&Fd-rK%wi%s;?zPcQv`$07avj?e5x9)xGY>)UJMQ5IIx*;oP-fC7wO~c*NIy-zzWs9=Y#-03+la AUH||9 delta 38561 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 ZdWC&ckLizUYW(ODW%u \ No newline at end of file diff --git a/tests/repros/repro9-platedhole-pcbX-pcbY.test.tsx b/tests/repros/repro9-platedhole-pcbX-pcbY.test.tsx new file mode 100644 index 00000000..04699418 --- /dev/null +++ b/tests/repros/repro9-platedhole-pcbX-pcbY.test.tsx @@ -0,0 +1,58 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("board with resistor being passed schX and pcbX in mm", () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + + } + /> + , + ) + + circuit.render() + + expect(circuit.db.pcb_component.list()).toMatchInlineSnapshot(` + [ + { + "center": { + "x": -0.25, + "y": 0, + }, + "height": 2.2, + "layer": "top", + "pcb_component_id": "pcb_component_0", + "rotation": 0, + "source_component_id": "source_component_0", + "subcircuit_id": "subcircuit_source_group_0", + "type": "pcb_component", + "width": 8.7, + }, + ] + `) + + expect(circuit).toMatchPcbSnapshot(import.meta.path) +}) From c51a5ee526d9c52c048585b37062b62e757e4731 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 30 Jan 2025 20:46:06 +0000 Subject: [PATCH 09/33] v0.0.296 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 949beb21..9e5e171e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.295", + "version": "0.0.296", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 0390dc3c1d024ad359f300a020b82b70f238477b Mon Sep 17 00:00:00 2001 From: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Date: Fri, 31 Jan 2025 21:17:30 +0530 Subject: [PATCH 10/33] fix: display value for units of 100 (#592) * fix: display value for 100uF * formatbot: Automatically format code * test update --------- Co-authored-by: tscircuitbot --- bun.lockb | Bin 225282 -> 225622 bytes package.json | 2 +- ...without-portarrangement-schematic.snap.svg | 2 +- ...matic-trace-obstacles-1-schematic.snap.svg | 2 +- ...ulator-with-connections-schematic.snap.svg | 2 +- ...ample17-display-capacitance-value.test.tsx | 35 ++++++++++++++++++ 6 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 tests/examples/example17-display-capacitance-value.test.tsx diff --git a/bun.lockb b/bun.lockb index fe86198380ca42f8e6044b95c92903625c648d58..cf08495096fd270a00434cefd7f657f811dff691 100755 GIT binary patch delta 2842 zcmb`Jc}!GS6vp3s42UQyAj&F?EP~1=h#)%*>i`N0I9L}HQ8rm@6{!ngZEdxRnbZ^8 z#$rW_tuZAOM_aLuwk9QA#71o*rb2AerfQ3t7;BsMJ94alH|fngIp6zzch0+Y-CyFP zy_??MG|9PONL7>xiqg`EJPFwyKA-E4D~dO=9kM6#-7ZCe*K!rv4Y^P9G32Q@Z%3Yj z+}tzZJki;{>2sQWy~-o1=azqv&b(`3cu!2QVUPLGpm_C>d2?@)meghbv^UW<5#>$h zzfQ&LAd1X=y>Yg8pbDO(cAQ>yEf?B1Kmi>mbZR1x$m0vF#qx# z>P-91cqq(p`qIeV)h@fgZH!(y^jT2M{qo2ktiS3zpQQI6?C~D{{k-|+kdc-gQ60(g zh-y^R$aF+4Q4Q41DV@f4B4tn+r%XD-DT|zrB4tx0ryR0!GFse^shdK~$pMqi^#MAE zRh4zMYtXgmF3X|sRkeY9KTsnaZl!BriZYl_#|>H{-7#nZBmOoZ+f=0f@ml$b1* z6Ra+=T)}WC&WIKSf5lXp=K{?S051zSYTy#?Vz~k>l^gL8hQ+L83iA|(g|1`?^CByk z@D_`o8=Y9wgn58Hh8~aXgN%cpCFO}QJvn8fgg;LC`ti6aXLt@qfUs%MS736V0)_cN zUlull%D6<3SbA93#R?WS9qe^zZtF~8e$a0~^O!~5Tq0Dg0H6cV-0?7BfzW4BmRlVz zYzDMdSOlqAC^1*8U|1$tJfelogmx1)PuMIlcVRJ9z$IeE3V}5R?c`r(zOYc}1Zi=c zurM%QJlyJdI?N>!#EJkKgyxZm%yJH5r?6yXt`>>d0L^VpqY*A)5Nj?_vrNxK=4*{c zY!a3wY#vynuxv`nMu{A;Vqv`r?T2g>HXphiwYX2YU^tXGL@XHhDWCRpi3Kt}0mx6< zv`|4A2=m;>rNnWK~Vg=$8#9~Afm2rv9u=qyG5U0f2 zBGXsl+=Ae-RoH6i(+DoHjk>wSc33zR{=eY9@V&Om^a|)|VQs?Jf<-~|*g^X!f_MS>Rbkc8=MXCquTcS)*aeF}S&KM}C`a(d#wFGxGT6k}Evycj zw<*4wJ#-i)=I<4&0ceIy-zTgQjQ3IY+J)KkbBU2_qI-GTCGYKM^0mw{YK_IUSc}sfn)qqLXj#jjoo>tjPidB&OEhxSr^4bt9sZyC8`qDwF(n0T z0y1y^cI0HzrqaR+ZSqXsNqC3JM(`%Yn-kw^I)XQ^k9lEZ+`d42E3`lwuF_m7tVXl7 zT&d7XY}81qKc#tDGOD!2#pF?=dC=SEwRN7&@)Gyc0N&$ByD9ahcF|JnOx(Z1xi zlR3kF&u4^R9KH6-U(ldcOSSl3&^lBH<;zieuHMprQERrNhh;Xt6kcj$Z>j0m3J;TS WzhNQ1=hsv8yov delta 2710 zcmb`JTToSH6vy}8927A^j)3aXNf4%R)QD*Hy$DO>p_3wuEZrT<6$h+y#zPqQ|4$RqH<6+S9n@U2h z!&#@djj-o#HVtEhVYq_8pGLgVW*8xe-H2lmPa-1cYC;S|+^%sI;%Iy?Kny@kX#d6T zYj3|laf+?^=NZ%6osn5@G+#cOVm&$0?A?*-`8VpynteKEc`i6<7>oK;8&q+hdJI+6 zr<@;B6?UZ9APW0XFH}C28Ph(jGt-`9!&tXtDqe_<{Zsl6u|2udZqNQ-dbK~kp5-ak z$IblqS8v_EC|^KH=W)|VLR!pxGgCISm?dVGbTMR0&<6-PQpezsOAJm4YemSF?F@PD zE3M|%sAgA$P0D{Ty*&RqVHm@t?u_}pd(MyMv|8^wSr#U57`=tknr)@Zui4gVKTm*R z@Flt?HaVJOjhyX?Qe0(YIQ&8XX~qy`Pk}vxCLW3pE{6}i6(_LEaCyKMep>De)WTjc zyE5z^>>y?CRQ`GYM3^sA$ zsj6^wJrCQ7Um zEh01(iqyBL;c`t)BEnRGphOeCW4EXcVT-FRNkAr?e z%QLku9;{wjj`-!Fg+t3{BDGmlPGyN;y*jyEWl3OfLWd*f$x61!$5$N2EO-*iry>?= zc?$FdZ82BbY_M=;MRJ-g=4mPosR*RFti{UaK)1kY^TBW!>F@=dIc%Yr`Dn37%QJ!g zK#OM)7i)PI^dn`ZT9*xW4~$kO#cZ)e%N;-uHMLC3onXAlY0H)6LVH1Tsh^XhY_UR9 z`9MBeUaqVFj8`H7aiy|CXr9C6UnLLNVzs7cYA(e`_UfDwEGjQ4lFs|YvcqT*!;zns=i)t+|0phRIHX%}$!nw3Lh_#6P z@iI8CBG;}?Zn6cp6H`m!A<#7LQnF?6Dhe2PDdlo_4Fo5?MPdul;zdoZ0Qv~d!EaSo z4t*9*+Xlvotb}*KS+_$P*!JC;TY~tKvJKFD($V%x*j%)DSyNR&ys^vS`;={j{us{DyaL8EtKpw0drj)t zf)6_`Qw=;GnxlDL%WI+e9OWK;|E2!H z2>9pbYsl0JYeF&~Ze&9cIk-I3@{z(vjRT$o&xZ4_nfFNNI()#s>yrHy)+9M{!5ZiO zs=_MqkP8>BneNgmD|xY;>ay04O=#NiIQ3kF`u(xOg!RbCtS=U}Eu8gOdDz#H7Br<`fQC5eXz3kKft&cC-d(D6=X z&tT?8n_TX;0=>s~_fO$skKF6FGThNU)-lujeosHGtZ`ra+^QdPFx(@|z2$4G?5Mb^ NJcheNsy&iy{{pOleAWN} diff --git a/package.json b/package.json index 9e5e171e..c0965223 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@tscircuit/soup-util": "^0.0.41", "circuit-json": "^0.0.135", "circuit-json-to-connectivity-map": "^0.0.17", - "format-si-unit": "^0.0.2", + "format-si-unit": "^0.0.3", "nanoid": "^5.0.7", "performance-now": "^2.1.0", "react-reconciler": "^0.31.0", diff --git a/tests/components/normal-components/__snapshots__/chip-port-without-portarrangement-schematic.snap.svg b/tests/components/normal-components/__snapshots__/chip-port-without-portarrangement-schematic.snap.svg index 8e1d1496..0fb481eb 100644 --- a/tests/components/normal-components/__snapshots__/chip-port-without-portarrangement-schematic.snap.svg +++ b/tests/components/normal-components/__snapshots__/chip-port-without-portarrangement-schematic.snap.svg @@ -14,7 +14,7 @@ .pin-number { fill: rgb(169, 0, 0); } .port-label { fill: rgb(0, 100, 100); } .component-name { fill: rgb(0, 100, 100); } - -8,-2-8,-1-8,0-8,1-8,2-8,3-7,-2-7,-1-7,0-7,1-7,2-7,3-6,-2-6,-1-6,0-6,1-6,2-6,3-5,-2-5,-1-5,0-5,1-5,2-5,3-4,-2-4,-1-4,0-4,1-4,2-4,3-3,-2-3,-1-3,0-3,1-3,2-3,3-2,-2-2,-1-2,0-2,1-2,2-2,3-1,-2-1,-1-1,0-1,1-1,2-1,30,-20,-10,00,10,20,31,-21,-11,01,11,21,32,-22,-12,02,12,22,33,-23,-13,03,13,23,34,-24,-14,04,14,24,3U11OUT12OUT23OUT34OUT45VCC6IN17IN28GNDD1D2C11nFC21nF-8,-2-8,-1-8,0-8,1-8,2-8,3-7,-2-7,-1-7,0-7,1-7,2-7,3-6,-2-6,-1-6,0-6,1-6,2-6,3-5,-2-5,-1-5,0-5,1-5,2-5,3-4,-2-4,-1-4,0-4,1-4,2-4,3-3,-2-3,-1-3,0-3,1-3,2-3,3-2,-2-2,-1-2,0-2,1-2,2-2,3-1,-2-1,-1-1,0-1,1-1,2-1,30,-20,-10,00,10,20,31,-21,-11,01,11,21,32,-22,-12,02,12,22,33,-23,-13,03,13,23,34,-24,-14,04,14,24,3U11OUT12OUT23OUT34OUT45VCC6IN17IN28GNDD1D2C1100nFC2100nF-2,-2-2,-1.5-2,-1-2,-0.5-2,0-2,0.5-2,1-2,1.5-2,2-1.5,-2-1.5,-1.5-1.5,-1-1.5,-0.5-1.5,0-1.5,0.5-1.5,1-1.5,1.5-1.5,2-1,-2-1,-1.5-1,-1-1,-0.5-1,0-1,0.5-1,1-1,1.5-1,2-0.5,-2-0.5,-1.5-0.5,-1-0.5,-0.5-0.5,0-0.5,0.5-0.5,1-0.5,1.5-0.5,20,-20,-1.50,-10,-0.50,00,0.50,10,1.50,20.5,-20.5,-1.50.5,-10.5,-0.50.5,00.5,0.50.5,10.5,1.50.5,21,-21,-1.51,-11,-0.51,01,0.51,11,1.51,21.5,-21.5,-1.51.5,-11.5,-0.51.5,01.5,0.51.5,11.5,1.51.5,22,-22,-1.52,-12,-0.52,02,0.52,12,1.52,22.5,-22.5,-1.52.5,-12.5,-0.52.5,02.5,0.52.5,12.5,1.52.5,23,-23,-1.53,-13,-0.53,03,0.53,13,1.53,23.5,-23.5,-1.53.5,-13.5,-0.53.5,03.5,0.53.5,13.5,1.53.5,24,-24,-1.54,-14,-0.54,04,0.54,14,1.54,24.5,-24.5,-1.54.5,-14.5,-0.54.5,04.5,0.54.5,14.5,1.54.5,25,-25,-1.55,-15,-0.55,05,0.55,15,1.55,25.5,-25.5,-1.55.5,-15.5,-0.55.5,05.5,0.55.5,15.5,1.55.5,26,-26,-1.56,-16,-0.56,06,0.56,16,1.56,26.5,-26.5,-1.56.5,-16.5,-0.56.5,06.5,0.56.5,16.5,1.56.5,27,-27,-1.57,-17,-0.57,07,0.57,17,1.57,2U112345678910111213141516R1 \ No newline at end of file + -2,-2-2,-1.5-2,-1-2,-0.5-2,0-2,0.5-2,1-2,1.5-2,2-1.5,-2-1.5,-1.5-1.5,-1-1.5,-0.5-1.5,0-1.5,0.5-1.5,1-1.5,1.5-1.5,2-1,-2-1,-1.5-1,-1-1,-0.5-1,0-1,0.5-1,1-1,1.5-1,2-0.5,-2-0.5,-1.5-0.5,-1-0.5,-0.5-0.5,0-0.5,0.5-0.5,1-0.5,1.5-0.5,20,-20,-1.50,-10,-0.50,00,0.50,10,1.50,20.5,-20.5,-1.50.5,-10.5,-0.50.5,00.5,0.50.5,10.5,1.50.5,21,-21,-1.51,-11,-0.51,01,0.51,11,1.51,21.5,-21.5,-1.51.5,-11.5,-0.51.5,01.5,0.51.5,11.5,1.51.5,22,-22,-1.52,-12,-0.52,02,0.52,12,1.52,22.5,-22.5,-1.52.5,-12.5,-0.52.5,02.5,0.52.5,12.5,1.52.5,23,-23,-1.53,-13,-0.53,03,0.53,13,1.53,23.5,-23.5,-1.53.5,-13.5,-0.53.5,03.5,0.53.5,13.5,1.53.5,24,-24,-1.54,-14,-0.54,04,0.54,14,1.54,24.5,-24.5,-1.54.5,-14.5,-0.54.5,04.5,0.54.5,14.5,1.54.5,25,-25,-1.55,-15,-0.55,05,0.55,15,1.55,25.5,-25.5,-1.55.5,-15.5,-0.55.5,05.5,0.55.5,15.5,1.55.5,26,-26,-1.56,-16,-0.56,06,0.56,16,1.56,26.5,-26.5,-1.56.5,-16.5,-0.56.5,06.5,0.56.5,16.5,1.56.5,27,-27,-1.57,-17,-0.57,07,0.57,17,1.57,2U112345678910111213141516R1100Ω \ No newline at end of file diff --git a/tests/examples/__snapshots__/example7-voltage-regulator-with-connections-schematic.snap.svg b/tests/examples/__snapshots__/example7-voltage-regulator-with-connections-schematic.snap.svg index f7a91b5f..aa61f69a 100644 --- a/tests/examples/__snapshots__/example7-voltage-regulator-with-connections-schematic.snap.svg +++ b/tests/examples/__snapshots__/example7-voltage-regulator-with-connections-schematic.snap.svg @@ -14,7 +14,7 @@ .pin-number { fill: rgb(169, 0, 0); } .port-label { fill: rgb(0, 100, 100); } .component-name { fill: rgb(0, 100, 100); } - -5,-3-5,-2-5,-1-5,0-5,1-5,2-5,3-5,4-4,-3-4,-2-4,-1-4,0-4,1-4,2-4,3-4,4-3,-3-3,-2-3,-1-3,0-3,1-3,2-3,3-3,4-2,-3-2,-2-2,-1-2,0-2,1-2,2-2,3-2,4-1,-3-1,-2-1,-1-1,0-1,1-1,2-1,3-1,40,-30,-20,-10,00,10,20,30,41,-31,-21,-11,01,11,21,31,42,-32,-22,-12,02,12,22,32,43,-33,-23,-13,03,13,23,33,44,-34,-24,-14,04,14,24,34,45,-35,-25,-15,05,15,25,35,46,-36,-26,-16,06,16,26,36,4PWR17EP6IN5PG4EN3GND2FB1OUTR61MΩR72kΩR81kΩC610µFC710µFLED1-5,-3-5,-2-5,-1-5,0-5,1-5,2-5,3-5,4-4,-3-4,-2-4,-1-4,0-4,1-4,2-4,3-4,4-3,-3-3,-2-3,-1-3,0-3,1-3,2-3,3-3,4-2,-3-2,-2-2,-1-2,0-2,1-2,2-2,3-2,4-1,-3-1,-2-1,-1-1,0-1,1-1,2-1,3-1,40,-30,-20,-10,00,10,20,30,41,-31,-21,-11,01,11,21,31,42,-32,-22,-12,02,12,22,32,43,-33,-23,-13,03,13,23,33,44,-34,-24,-14,04,14,24,34,45,-35,-25,-15,05,15,25,35,46,-36,-26,-16,06,16,26,36,4PWR17EP6IN5PG4EN3GND2FB1OUTR61MΩR7200kΩR81kΩC610µFC710µFLED1 { + const { circuit } = getTestFixture() + + circuit.add( + + + , + ) + + circuit.render() + + expect(circuit.db.source_component.list()[0]).toMatchInlineSnapshot(` + { + "capacitance": 0.0001, + "display_capacitance": "100µF", + "ftype": "simple_capacitor", + "manufacturer_part_number": undefined, + "max_decoupling_trace_length": undefined, + "name": "C1", + "source_component_id": "source_component_0", + "supplier_part_numbers": undefined, + "type": "source_component", + } + `) +}) From 6119a13e55e68617374f53a20dd001fcccf6529f Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 31 Jan 2025 15:47:55 +0000 Subject: [PATCH 11/33] v0.0.297 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c0965223..3228ce33 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.296", + "version": "0.0.297", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From de530cbe78acf83299932731e918b3f3536f6bfc Mon Sep 17 00:00:00 2001 From: Mustafa Mulla <97171641+MustafaMulla29@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:16:41 +0530 Subject: [PATCH 12/33] Modified bundle-size.yml to post if gt 10kb (#584) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Modified bundle-size.yml to post if gt 10kb * Fix workflow condition syntax in bundle-size.yml --------- Co-authored-by: “mustafa” <“mustafamulla765@gmail.com”> --- .github/workflows/bundle-size.yml | 53 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index 06a81b1b..90b88972 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -36,12 +36,12 @@ jobs: - name: Get base bundle size id: base-bundle-size run: | - echo "base=$(du -sh dist | cut -f1)" >> $GITHUB_OUTPUT + echo "base=$(du -sk dist | cut -f1)" >> $GITHUB_OUTPUT - name: Get base install size id: base-install-size run: | - echo "base=$(bunx howfat -r simple . | grep 'Size:' | awk '{print $2}')" >> $GITHUB_OUTPUT + echo "base=$(bunx howfat -r simple . | grep 'Size:' | awk '{print $2}' | sed 's/K//')" >> $GITHUB_OUTPUT - name: Checkout PR branch uses: actions/checkout@v3 @@ -55,12 +55,12 @@ jobs: - name: Get PR bundle size id: pr-bundle-size run: | - echo "pr=$(du -sh dist | cut -f1)" >> $GITHUB_OUTPUT + echo "pr=$(du -sk dist | cut -f1)" >> $GITHUB_OUTPUT - name: Get PR install size and full howfat output id: pr-install-size run: | - echo "pr=$(bunx howfat -r simple . | grep 'Size:' | awk '{print $2}')" >> $GITHUB_OUTPUT + echo "pr=$(bunx howfat -r simple . | grep 'Size:' | awk '{print $2}' | sed 's/K//')" >> $GITHUB_OUTPUT echo "full_output<> $GITHUB_OUTPUT bunx howfat -r table . >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT @@ -68,28 +68,25 @@ jobs: - name: Calculate bundle size difference id: bundle-size-diff run: | - base_size=$(echo ${{ steps.base-bundle-size.outputs.base }} | sed 's/[^0-9.]*//g') - pr_size=$(echo ${{ steps.pr-bundle-size.outputs.pr }} | sed 's/[^0-9.]*//g') - diff=$(echo "$pr_size - $base_size" | bc) - if (( $(echo "$diff > 0" | bc -l) )); then - echo "diff=+$diff" >> $GITHUB_OUTPUT - else - echo "diff=$diff" >> $GITHUB_OUTPUT - fi + base_size=${{ steps.base-bundle-size.outputs.base }} + pr_size=${{ steps.pr-bundle-size.outputs.pr }} + diff=$((pr_size - base_size)) + echo "diff=$diff" >> $GITHUB_OUTPUT - name: Calculate install size difference id: install-size-diff run: | - base_size=$(echo ${{ steps.base-install-size.outputs.base }} | sed 's/[^0-9.]*//g') - pr_size=$(echo ${{ steps.pr-install-size.outputs.pr }} | sed 's/[^0-9.]*//g') + base_size=${{ steps.base-install-size.outputs.base }} + pr_size=${{ steps.pr-install-size.outputs.pr }} diff=$(echo "$pr_size - $base_size" | bc) - if (( $(echo "$diff > 0" | bc -l) )); then - echo "diff=+$diff" >> $GITHUB_OUTPUT - else - echo "diff=$diff" >> $GITHUB_OUTPUT - fi - - - name: Update comment + echo "diff=$diff" >> $GITHUB_OUTPUT + + - name: Conditionally Update PR Comment + if: | + steps.bundle-size-diff.outputs.diff | tonumber >= 10 + or steps.bundle-size-diff.outputs.diff | tonumber <= -10 + or steps.install-size-diff.outputs.diff | tonumber >= 10 + or steps.install-size-diff.outputs.diff | tonumber <= -10 uses: mshick/add-pr-comment@v2 env: GITHUB_TOKEN: ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }} @@ -98,14 +95,14 @@ jobs: message: | ## Size Report ### Bundle Size - - Base branch size: ${{ steps.base-bundle-size.outputs.base }} - - PR branch size: ${{ steps.pr-bundle-size.outputs.pr }} - - Difference: ${{ steps.bundle-size-diff.outputs.diff }} + - Base branch size: ${{ steps.base-bundle-size.outputs.base }} KB + - PR branch size: ${{ steps.pr-bundle-size.outputs.pr }} KB + - Difference: ${{ steps.bundle-size-diff.outputs.diff }} KB ### Install Size - - Base branch size: ${{ steps.base-install-size.outputs.base }} - - PR branch size: ${{ steps.pr-install-size.outputs.pr }} - - Difference: ${{ steps.install-size-diff.outputs.diff }} + - Base branch size: ${{ steps.base-install-size.outputs.base }} KB + - PR branch size: ${{ steps.pr-install-size.outputs.pr }} KB + - Difference: ${{ steps.install-size-diff.outputs.diff }} KB ### Full Howfat Output (PR Branch) ``` @@ -114,4 +111,4 @@ jobs: (aside) ``` proxy-url: https://add-pr-comment-proxy-tscircuit.vercel.app/api - allow-repeats: false + allow-repeats: false \ No newline at end of file From 660028f60e2d97c962c00ef4d83427fd153f3d29 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 2 Feb 2025 14:47:05 +0000 Subject: [PATCH 13/33] v0.0.298 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3228ce33..d1339885 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.297", + "version": "0.0.298", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From aeae98dc827b747490d112461e7bd019543ac0a9 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:17:53 +0530 Subject: [PATCH 14/33] fix: breakup the function to create function for one port and not in pair (#590) * fix: refactor the function to create function for one port and not in pair * formatbot: Automatically format code --------- Co-authored-by: tscircuitbot --- .../primitive-components/Trace/Trace.ts | 69 +++++++---- ...create-downward-net-label-ground-symbol.ts | 117 ++++-------------- .../example11-net-symbol-schematic.snap.svg | 32 +---- 3 files changed, 72 insertions(+), 146 deletions(-) diff --git a/lib/components/primitive-components/Trace/Trace.ts b/lib/components/primitive-components/Trace/Trace.ts index 09a02401..3e71d75b 100644 --- a/lib/components/primitive-components/Trace/Trace.ts +++ b/lib/components/primitive-components/Trace/Trace.ts @@ -12,7 +12,6 @@ import { import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map" import { DirectLineRouter } from "lib/utils/autorouting/DirectLineRouter" import type { - Obstacle, SimpleRouteConnection, SimpleRouteJson, SimplifiedPcbTrace, @@ -21,10 +20,10 @@ import { computeObstacleBounds } from "lib/utils/autorouting/computeObstacleBoun import { findPossibleTraceLayerCombinations } from "lib/utils/autorouting/findPossibleTraceLayerCombinations" import { getDominantDirection } from "lib/utils/autorouting/getDominantDirection" import { mergeRoutes } from "lib/utils/autorouting/mergeRoutes" -import { getTraceLength } from "./compute-trace-length" import { createNetsFromProps } from "lib/utils/components/createNetsFromProps" import { getClosest } from "lib/utils/getClosest" import { pairs } from "lib/utils/pairs" +import { countComplexElements } from "lib/utils/schematic/countComplexElements" import { getEnteringEdgeFromDirection } from "lib/utils/schematic/getEnteringEdgeFromDirection" import { getStubEdges } from "lib/utils/schematic/getStubEdges" import { tryNow } from "lib/utils/try-now" @@ -34,15 +33,15 @@ import { Net } from "../Net" import type { Port } from "../Port" import type { TraceHint } from "../TraceHint" import type { TraceI } from "./TraceI" +import { getTraceLength } from "./compute-trace-length" +import { createDownwardNetLabelGroundSymbol } from "./create-downward-net-label-ground-symbol" import { createSchematicTraceCrossingSegments } from "./create-schematic-trace-crossing-segments" import { createSchematicTraceJunctions } from "./create-schematic-trace-junctions" -import { pushEdgesOfSchematicTraceToPreventOverlap } from "./push-edges-of-schematic-trace-to-prevent-overlap" -import { countComplexElements } from "lib/utils/schematic/countComplexElements" -import { createDownwardNetLabelGroundSymbol } from "./create-downward-net-label-ground-symbol" import { getMaxLengthFromConnectedCapacitors } from "./get-max-length-from-conn ected-capacitors" -import { getTraceDisplayName } from "./get-trace-display-name" import { getSchematicObstaclesForTrace } from "./get-obstacles-for-trace" import { getOtherSchematicTraces } from "./get-other-schematic-traces" +import { getTraceDisplayName } from "./get-trace-display-name" +import { pushEdgesOfSchematicTraceToPreventOverlap } from "./push-edges-of-schematic-trace-to-prevent-overlap" type PcbRouteObjective = | RouteHintPoint | { @@ -693,22 +692,50 @@ export class Trace } if ( - !existingFromNetLabel && - !existingToNetLabel && - (netLabelText?.toLocaleLowerCase().includes("gnd") || - netLabelText?.toLocaleLowerCase().includes("ground")) + netLabelText?.toLocaleLowerCase().includes("gnd") || + netLabelText?.toLocaleLowerCase().includes("ground") ) { - createDownwardNetLabelGroundSymbol( - { - fromPort, - toPort, - fromAnchorPos, - toAnchorPos, - schDisplayLabel: this.props.schDisplayLabel!, - source_trace_id: this.source_trace_id!, - }, - { db }, - ) + if (!existingFromNetLabel && !existingToNetLabel) { + createDownwardNetLabelGroundSymbol( + { + port: fromPort, + anchorPos: fromAnchorPos, + schDisplayLabel: this.props.schDisplayLabel!, + source_trace_id: this.source_trace_id!, + }, + { db }, + ) + + createDownwardNetLabelGroundSymbol( + { + port: toPort, + anchorPos: toAnchorPos, + schDisplayLabel: this.props.schDisplayLabel!, + source_trace_id: this.source_trace_id!, + }, + { db }, + ) + } else if (!existingFromNetLabel) { + createDownwardNetLabelGroundSymbol( + { + port: fromPort, + anchorPos: fromAnchorPos, + schDisplayLabel: this.props.schDisplayLabel!, + source_trace_id: this.source_trace_id!, + }, + { db }, + ) + } else if (!existingToNetLabel) { + createDownwardNetLabelGroundSymbol( + { + port: toPort, + anchorPos: toAnchorPos, + schDisplayLabel: this.props.schDisplayLabel!, + source_trace_id: this.source_trace_id!, + }, + { db }, + ) + } return } diff --git a/lib/components/primitive-components/Trace/create-downward-net-label-ground-symbol.ts b/lib/components/primitive-components/Trace/create-downward-net-label-ground-symbol.ts index 94066205..84a1313e 100644 --- a/lib/components/primitive-components/Trace/create-downward-net-label-ground-symbol.ts +++ b/lib/components/primitive-components/Trace/create-downward-net-label-ground-symbol.ts @@ -2,10 +2,8 @@ import type { SoupUtilObjects } from "@tscircuit/soup-util" import type { Port } from "../Port" interface CreateDownwardNetLabelSymbolParams { - fromPort: Port - toPort: Port - fromAnchorPos: { x: number; y: number } - toAnchorPos: { x: number; y: number } + port: Port + anchorPos: { x: number; y: number } schDisplayLabel: string source_trace_id: string } @@ -42,35 +40,29 @@ const calculateOffsets = (port: Port) => { export const createDownwardNetLabelGroundSymbol = ( { - fromPort, - toPort, - fromAnchorPos, - toAnchorPos, + port, + anchorPos, schDisplayLabel, source_trace_id, }: CreateDownwardNetLabelSymbolParams, { db }: { db: SoupUtilObjects }, ): void => { - const fromOffsets = calculateOffsets(fromPort) + const offsets = calculateOffsets(port) db.schematic_net_label.insert({ anchor_side: "top", center: { - x: - fromAnchorPos.x + - fromOffsets.horzPortDirection * fromOffsets.schBoxHorzOffset, + x: anchorPos.x + offsets.horzPortDirection * offsets.schBoxHorzOffset, y: - fromAnchorPos.y + - fromOffsets.vertPortDirectionOffset * fromOffsets.schBoxVertOffset, + anchorPos.y + + offsets.vertPortDirectionOffset * offsets.schBoxVertOffset, }, - source_net_id: fromPort.source_port_id!, + source_net_id: port.source_port_id!, text: schDisplayLabel!, anchor_position: { - x: - fromAnchorPos.x + - fromOffsets.horzPortDirection * fromOffsets.schBoxHorzOffset, + x: anchorPos.x + offsets.horzPortDirection * offsets.schBoxHorzOffset, y: - fromAnchorPos.y + - fromOffsets.vertPortDirectionOffset * fromOffsets.schBoxVertOffset, + anchorPos.y + + offsets.vertPortDirectionOffset * offsets.schBoxVertOffset, }, symbol_name: "ground_horz", }) @@ -78,93 +70,28 @@ export const createDownwardNetLabelGroundSymbol = ( db.schematic_trace.insert({ edges: [ { - from: { x: fromAnchorPos.x, y: fromAnchorPos.y }, + from: { x: anchorPos.x, y: anchorPos.y }, to: { - x: fromAnchorPos.x, - y: - fromAnchorPos.y + - fromOffsets.handleUp * fromOffsets.schBoxVertOffset, - }, - }, - { - from: { x: fromAnchorPos.x, y: fromAnchorPos.y }, - to: { - x: - fromAnchorPos.x + - fromOffsets.horzPortDirection * fromOffsets.schBoxHorzOffset, - y: - fromAnchorPos.y + - fromOffsets.vertPortDirectionOffset * fromOffsets.schBoxVertOffset, - }, - }, - ], - junctions: [ - { - x: - fromAnchorPos.x + - fromOffsets.horzPortDirection * fromOffsets.schBoxHorzOffset, - y: - fromAnchorPos.y + - fromOffsets.vertPortDirectionOffset * fromOffsets.schBoxVertOffset, - }, - ], - source_trace_id: source_trace_id!, - }) - - const toOffsets = calculateOffsets(toPort) - db.schematic_net_label.insert({ - anchor_side: "top", - center: { - x: - toAnchorPos.x + - toOffsets.horzPortDirection * toOffsets.schBoxHorzOffset, - y: - toAnchorPos.y + - toOffsets.vertPortDirectionOffset * toOffsets.schBoxVertOffset, - }, - source_net_id: toPort.source_port_id!, - text: schDisplayLabel!, - anchor_position: { - x: - toAnchorPos.x + - toOffsets.horzPortDirection * toOffsets.schBoxHorzOffset, - y: - toAnchorPos.y + - toOffsets.vertPortDirectionOffset * toOffsets.schBoxVertOffset, - }, - symbol_name: "ground_horz", - }) - - const toHandleUp = toPort.facingDirection === "up" ? 0.5 : 0 - db.schematic_trace.insert({ - edges: [ - { - from: { x: toAnchorPos.x, y: toAnchorPos.y }, - to: { - x: toAnchorPos.x, - y: toAnchorPos.y + toHandleUp * toOffsets.schBoxVertOffset, + x: anchorPos.x, + y: anchorPos.y + offsets.handleUp * offsets.schBoxVertOffset, }, }, { - from: { x: toAnchorPos.x, y: toAnchorPos.y }, + from: { x: anchorPos.x, y: anchorPos.y }, to: { - x: - toAnchorPos.x + - toOffsets.horzPortDirection * toOffsets.schBoxHorzOffset, + x: anchorPos.x + offsets.horzPortDirection * offsets.schBoxHorzOffset, y: - toAnchorPos.y + - toOffsets.vertPortDirectionOffset * toOffsets.schBoxVertOffset, + anchorPos.y + + offsets.vertPortDirectionOffset * offsets.schBoxVertOffset, }, }, ], junctions: [ { - x: - toAnchorPos.x + - toOffsets.horzPortDirection * toOffsets.schBoxHorzOffset, + x: anchorPos.x + offsets.horzPortDirection * offsets.schBoxHorzOffset, y: - toAnchorPos.y + - toOffsets.vertPortDirectionOffset * toOffsets.schBoxVertOffset, + anchorPos.y + + offsets.vertPortDirectionOffset * offsets.schBoxVertOffset, }, ], source_trace_id: source_trace_id!, diff --git a/tests/examples/__snapshots__/example11-net-symbol-schematic.snap.svg b/tests/examples/__snapshots__/example11-net-symbol-schematic.snap.svg index e13ce87b..b6699420 100644 --- a/tests/examples/__snapshots__/example11-net-symbol-schematic.snap.svg +++ b/tests/examples/__snapshots__/example11-net-symbol-schematic.snap.svg @@ -1,4 +1,4 @@ --4,-1-4,0-4,1-4,2-4,3-4,4-4,5-4,6-4,7-3,-1-3,0-3,1-3,2-3,3-3,4-3,5-3,6-3,7-2,-1-2,0-2,1-2,2-2,3-2,4-2,5-2,6-2,7-1,-1-1,0-1,1-1,2-1,3-1,4-1,5-1,6-1,70,-10,00,10,20,30,40,50,60,71,-11,01,11,21,31,41,51,61,72,-12,02,12,22,32,42,52,62,73,-13,03,13,23,33,43,53,63,74,-14,04,14,24,34,44,54,64,75,-15,05,15,25,35,45,55,65,76,-16,06,16,26,36,46,56,66,77,-17,07,17,27,37,47,57,67,78,-18,08,18,28,38,48,58,68,79,-19,09,19,29,39,49,59,69,7R110kΩR210kΩR310kΩU11718192021222324252627282930313212345678910111213141516GND3GND3GND1GND1GND1GND2GND2GND2GND2GND2 \ No newline at end of file From e13712c95c5368c59236ecbf8a754a92859e38c0 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 3 Feb 2025 04:48:19 +0000 Subject: [PATCH 15/33] v0.0.299 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d1339885..8409c1e5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.298", + "version": "0.0.299", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 0a9a733016632467d336be59ef171e437e878c1e Mon Sep 17 00:00:00 2001 From: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:26:36 +0530 Subject: [PATCH 16/33] test: subcircuit caching test for maximum traces (#596) * test: subcircuit caching test * formatbot: Automatically format code --------- Co-authored-by: tscircuitbot --- ...ple18-subcircuit-caching-test-pcb.snap.svg | 13 +++ ...example18-subcircuit-caching-test.test.tsx | 96 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 tests/examples/__snapshots__/example18-subcircuit-caching-test-pcb.snap.svg create mode 100644 tests/examples/example18-subcircuit-caching-test.test.tsx diff --git a/tests/examples/__snapshots__/example18-subcircuit-caching-test-pcb.snap.svg b/tests/examples/__snapshots__/example18-subcircuit-caching-test-pcb.snap.svg new file mode 100644 index 00000000..196c861a --- /dev/null +++ b/tests/examples/__snapshots__/example18-subcircuit-caching-test-pcb.snap.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/tests/examples/example18-subcircuit-caching-test.test.tsx b/tests/examples/example18-subcircuit-caching-test.test.tsx new file mode 100644 index 00000000..11f43042 --- /dev/null +++ b/tests/examples/example18-subcircuit-caching-test.test.tsx @@ -0,0 +1,96 @@ +import { grid } from "@tscircuit/math-utils" +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +const LedColumns = (props: { + numXLeds?: number + numYLeds?: number + pcbX?: number + pcbY?: number + autorouter?: any + name: string +}) => { + const numXLeds = props.numXLeds ?? 3 + const numYLeds = props.numYLeds ?? 3 + return ( + + {grid({ rows: numYLeds, cols: numXLeds, xSpacing: 8, ySpacing: 4 }).map( + ({ index, center: { x, y } }) => ( + <> + + {index > 0 && ( + + )} + + ), + )} + + ) +} + +test.skip("subcircuit autorouting max traces test", async () => { + const { circuit } = getTestFixture() + const totalLEDSubcircuits = 25 // Total number of LED column groups + const gridSize = Math.ceil(Math.sqrt(totalLEDSubcircuits)) // Calculate grid dimensions (3x3 for 9 columns) + const spacing = 30 + + const totalWidth = (gridSize - 1) * spacing + const totalHeight = (gridSize - 1) * spacing + const startX = -totalWidth / 2 + const startY = -totalHeight / 2 + const boardWidth = totalWidth + spacing + const boardHeight = totalHeight + spacing + + circuit.add( + + {Array.from({ length: totalLEDSubcircuits }, (_, index) => { + const row = Math.floor(index / gridSize) + const col = index % gridSize + const columnName = `S${index + 1}` + const pcbX = startX + col * spacing + const pcbY = startY + row * spacing + const prevColumnName = index > 0 ? `S${index}` : null + + return ( + <> + + {prevColumnName && ( + + )} + + ) + })} + , + ) + + await circuit.renderUntilSettled() + + console.log( + circuit.getCircuitJson().filter(({ type }) => type === "source_trace") + .length, + ) + + expect(circuit.getCircuitJson()).toMatchPcbSnapshot(import.meta.path) +}) From e191db817f8ade170144faa8ef515d776448506c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 5 Feb 2025 14:57:02 +0000 Subject: [PATCH 17/33] v0.0.300 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8409c1e5..265e271c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.299", + "version": "0.0.300", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From e01c1438f85af00eaac97a5bfff59b0f8caedb34 Mon Sep 17 00:00:00 2001 From: Ayush Jhawar <111112495+Ayushjhawar8@users.noreply.github.com> Date: Wed, 5 Feb 2025 22:27:42 +0530 Subject: [PATCH 18/33] Fix: Improve error handling for components with no PCB connection and missing footprint (#580) * Fix: Improve error message for components with missing footprint or PCB connection * fix: improve error message for missing footprint on components * Adding test * format * Chore: fix test msg * format * add new test and if condition for footprint checking * Add .toLowerCase() --- .../primitive-components/Port/Port.ts | 10 +++++++- .../led-error-messages.test.tsx | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/components/normal-components/led-error-messages.test.tsx diff --git a/lib/components/primitive-components/Port/Port.ts b/lib/components/primitive-components/Port/Port.ts index 9060065f..cf7a53ab 100644 --- a/lib/components/primitive-components/Port/Port.ts +++ b/lib/components/primitive-components/Port/Port.ts @@ -57,10 +57,18 @@ export class Port extends PrimitiveComponent { _getGlobalPcbPositionBeforeLayout(): { x: number; y: number } { const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive) + const parentComponent = this.parent + + // First check if parent component has a footprint + if (parentComponent && !parentComponent.props.footprint) { + throw new Error( + `${parentComponent.componentName} "${parentComponent.props.name}" does not have a footprint. Add a footprint prop, e.g. <${parentComponent.componentName.toLowerCase()} footprint="..." />`, + ) + } if (!matchedPcbElm) { throw new Error( - `Port ${this} has no matched pcb component, can't get global pcb position`, + `Port ${this} has no matching PCB primitives. This often means the footprint's pads lack matching port hints.`, ) } diff --git a/tests/components/normal-components/led-error-messages.test.tsx b/tests/components/normal-components/led-error-messages.test.tsx new file mode 100644 index 00000000..cd5106f4 --- /dev/null +++ b/tests/components/normal-components/led-error-messages.test.tsx @@ -0,0 +1,23 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "../../../tests/fixtures/get-test-fixture" + +test("LED without footprint should throw appropriate error", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + , + ) + + try { + circuit.render() + } catch (err) { + if (!(err instanceof Error)) { + throw new Error("Expected err to be an Error instance") + } + expect(err.message).toBe( + 'Led "LED1" does not have a footprint. Add a footprint prop, e.g. ', + ) + } +}) From 0ff80bcf90164581eceafd4a2a0a315f6be3032f Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 5 Feb 2025 16:58:19 +0000 Subject: [PATCH 19/33] v0.0.301 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 265e271c..6d5ea432 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.300", + "version": "0.0.301", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 588d8853cfbd64eb63d66cc8d914decef34d0042 Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Sat, 8 Feb 2025 10:08:18 -0800 Subject: [PATCH 20/33] add server_cache_enabled to autorouting requests (#608) * add server_cache_enabled to autorouting requests * change transistorType to type --- bun.lockb | Bin 225622 -> 225252 bytes .../normal-components/Transistor.ts | 4 +- .../primitive-components/Group/Group.ts | 21 +++++++--- package.json | 2 +- .../normal-components/transistor.test.tsx | 16 ++++---- ...uting-6-autorouting-cache-enabled.test.tsx | 38 ++++++++++++++++++ .../fixtures/get-test-autorouting-server.tsx | 11 +++++ 7 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 tests/features/remote-autorouting-6-autorouting-cache-enabled.test.tsx diff --git a/bun.lockb b/bun.lockb index cf08495096fd270a00434cefd7f657f811dff691..04fc5d6ff883dc2a6b0a0049bfc37a6a05e2f88f 100755 GIT binary patch delta 39061 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 delta 38421 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 { get config() { const baseSymbolName: BaseSymbolName = - this.props.transistorType === "npn" + this.props.type === "npn" ? "npn_bipolar_transistor" : "pnp_bipolar_transistor" @@ -23,7 +23,7 @@ export class Transistor extends NormalComponent { const source_component = db.source_component.insert({ ftype: "simple_transistor", name: props.name, - transistor_type: props.transistorType, + transistor_type: props.type, } as any) this.source_component_id = source_component.source_component_id } diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index acf78605..9890c66a 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -1,4 +1,8 @@ -import { type SubcircuitGroupProps, groupProps } from "@tscircuit/props" +import { + type AutorouterConfig, + type SubcircuitGroupProps, + groupProps, +} from "@tscircuit/props" import * as SAL from "@tscircuit/schematic-autolayout" import { type PcbTrace, @@ -175,10 +179,16 @@ export class Group = typeof groupProps> const debug = Debug("tscircuit:core:_runEffectMakeHttpAutoroutingRequest") const props = this._parsedProps as SubcircuitGroupProps - const serverUrl = - (props.autorouter as any)?.serverUrl ?? - "https://registry-api.tscircuit.com" - const serverMode = (props.autorouter as any)?.serverMode ?? "job" + const autoroutingOptions: AutorouterConfig = { + serverUrl: "https://registry-api.tscircuit.com", + serverMode: "job", + serverCacheEnabled: + (props.autorouter as any)?.serverCachingEnabled ?? false, + ...(typeof props.autorouter === "object" ? props.autorouter : {}), + } + + const serverUrl = autoroutingOptions.serverUrl! + const serverMode = autoroutingOptions.serverMode! const fetchWithDebug = (url: string, options: RequestInit) => { debug("fetching", url) @@ -239,6 +249,7 @@ export class Group = typeof groupProps> autostart: true, display_name: this.root?.name, subcircuit_id: this.subcircuit_id, + server_cache_enabled: autoroutingOptions.serverCacheEnabled, }), headers: { "Content-Type": "application/json" }, }, diff --git a/package.json b/package.json index 6d5ea432..c8f2f079 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@tscircuit/footprinter": "^0.0.97", "@tscircuit/infgrid-ijump-astar": "^0.0.33", "@tscircuit/math-utils": "^0.0.9", - "@tscircuit/props": "^0.0.137", + "@tscircuit/props": "^0.0.142", "@tscircuit/schematic-autolayout": "^0.0.6", "@tscircuit/soup-util": "^0.0.41", "circuit-json": "^0.0.135", diff --git a/tests/components/normal-components/transistor.test.tsx b/tests/components/normal-components/transistor.test.tsx index b3348721..e4e2148e 100644 --- a/tests/components/normal-components/transistor.test.tsx +++ b/tests/components/normal-components/transistor.test.tsx @@ -5,7 +5,7 @@ it("should render an NPN transistor with 0° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -16,7 +16,7 @@ it("should render an NPN transistor with 90° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -27,7 +27,7 @@ it("should render an NPN transistor with 180° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -38,7 +38,7 @@ it("should render an NPN transistor with 270° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -49,7 +49,7 @@ it("should render a PNP transistor with 0° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -60,7 +60,7 @@ it("should render a PNP transistor with 90° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -71,7 +71,7 @@ it("should render a PNP transistor with 180° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() @@ -82,7 +82,7 @@ it("should render a PNP transistor with 270° rotation", async () => { const { circuit } = getTestFixture() circuit.add( - + , ) circuit.render() diff --git a/tests/features/remote-autorouting-6-autorouting-cache-enabled.test.tsx b/tests/features/remote-autorouting-6-autorouting-cache-enabled.test.tsx new file mode 100644 index 00000000..89e92f56 --- /dev/null +++ b/tests/features/remote-autorouting-6-autorouting-cache-enabled.test.tsx @@ -0,0 +1,38 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "../fixtures/get-test-fixture" +import { getTestAutoroutingServer } from "tests/fixtures/get-test-autorouting-server" + +test("remote-autorouting-6 with caching enabled", async () => { + const { autoroutingServerUrl } = getTestAutoroutingServer({ + requireServerCacheEnabled: true, + }) + + const { circuit } = getTestFixture() + + // Create a basic circuit that needs routing + circuit.add( + + + + + , + ) + + await circuit.renderUntilSettled() + + // Verify routing request was made + expect(circuit.db.pcb_trace.list().length).toBeGreaterThan(0) +}) diff --git a/tests/fixtures/get-test-autorouting-server.tsx b/tests/fixtures/get-test-autorouting-server.tsx index 82e43e96..3075b1f9 100644 --- a/tests/fixtures/get-test-autorouting-server.tsx +++ b/tests/fixtures/get-test-autorouting-server.tsx @@ -6,8 +6,10 @@ import { getSimpleRouteJsonFromCircuitJson } from "lib/utils/autorouting/getSimp export const getTestAutoroutingServer = ({ requireDisplayName = false, + requireServerCacheEnabled = false, }: { requireDisplayName?: boolean + requireServerCacheEnabled?: boolean } = {}) => { let currentJobId = 0 const jobResults = new Map() @@ -78,6 +80,15 @@ export const getTestAutoroutingServer = ({ ) } + if (requireServerCacheEnabled && !body.server_cache_enabled) { + return new Response( + JSON.stringify({ + error: { message: "Missing server_cache_enabled" }, + }), + { status: 400 }, + ) + } + const simpleRouteJson = getSimpleRouteJsonFromCircuitJson({ circuitJson: body.input_circuit_json, }) From 1e3150d51ab08ec74436db8c817bad112c17a77a Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 8 Feb 2025 18:09:10 +0000 Subject: [PATCH 21/33] v0.0.302 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c8f2f079..27ddb592 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.301", + "version": "0.0.302", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 3c4ccacd8e8da708b59432dbb5b4dcacf3e102c5 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Date: Mon, 10 Feb 2025 00:12:36 +0530 Subject: [PATCH 22/33] test: repro subcircuit overlap traces issues (#601) --- ...e19-subcircuit-overlap-traces-pcb.snap.svg | 13 + ...ample19-subcircuit-overlap-traces.test.tsx | 237 ++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg create mode 100644 tests/examples/example19-subcircuit-overlap-traces.test.tsx diff --git a/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg new file mode 100644 index 00000000..c7715ed1 --- /dev/null +++ b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/tests/examples/example19-subcircuit-overlap-traces.test.tsx b/tests/examples/example19-subcircuit-overlap-traces.test.tsx new file mode 100644 index 00000000..2a97d155 --- /dev/null +++ b/tests/examples/example19-subcircuit-overlap-traces.test.tsx @@ -0,0 +1,237 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" +import { su } from "@tscircuit/soup-util" + +test("If the subcircuit is routing disabled, it should not have traces from the autorouter but it does have", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + + + , + ) + + await circuit.renderUntilSettled() + + const pcb_traces = su(circuit.getCircuitJson()).pcb_trace.list() + expect(pcb_traces).toMatchInlineSnapshot(` + [ + { + "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.9483, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 0.5517, + "type": "pcb_trace", + }, + { + "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.9483, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.3966, + "y": -0.5517, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -1.9483, + "y": -0.5517, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.5, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 3.9053, + "type": "pcb_trace", + }, + ] + `) +}) + +test("It is having traces from both autorouter and freerouting (Not in the final circuit json)", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + + + , + ) + + await circuit.renderUntilSettled() + + const pcb_traces = su(circuit.getCircuitJson()).pcb_trace.list() + expect(pcb_traces).toMatchInlineSnapshot(` + [ + { + "pcb_trace_id": "pcb_trace_0", + "route": [ + { + "layer": "top", + "route_type": "wire", + "start_pcb_port_id": "pcb_port_0", + "width": 0.16, + "x": -2.5, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 1.3, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 1.3, + }, + { + "end_pcb_port_id": "pcb_port_2", + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 6.6, + "type": "pcb_trace", + }, + { + "pcb_trace_id": "pcb_trace_source_trace_0--Pad1_R1_source_component_0--Pad1_R2_source_component_1", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.5, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 1.3, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 1.3, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 6.6, + "type": "pcb_trace", + }, + { + "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.5, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.12, + "y": 1.3, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 1.3, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 6.6, + "type": "pcb_trace", + }, + ] + `) + expect(circuit.getCircuitJson()).toMatchPcbSnapshot(import.meta.path) +}) From 0b88964ccd7b84781b6758641c90180094b870e3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 9 Feb 2025 18:43:07 +0000 Subject: [PATCH 23/33] v0.0.303 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 27ddb592..747e539e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.302", + "version": "0.0.303", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From b0c8b57803c79d6de6118699c679efdd56c7c9c4 Mon Sep 17 00:00:00 2001 From: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Date: Mon, 10 Feb 2025 01:37:25 +0530 Subject: [PATCH 24/33] fix: autorouter is inhertited by the subcircuit child (#610) * fix: autorouter is inhertited by the subcircuit child * formatbot: Automatically format code * use the fake auto cloud * using the subcircuit prop * inherit from parent * formatbot: Automatically format code --------- Co-authored-by: tscircuitbot --- .../primitive-components/Group/Group.ts | 10 +- ...e19-subcircuit-overlap-traces-pcb.snap.svg | 2 +- ...ample19-subcircuit-overlap-traces.test.tsx | 209 ++++++------------ ...ircuit3-dependent-autorouting-pcb.snap.svg | 2 +- ...subcircuit3-dependent-autorouting.test.tsx | 31 +-- 5 files changed, 98 insertions(+), 156 deletions(-) diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index 9890c66a..6b590fa7 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -469,10 +469,12 @@ export class Group = typeof groupProps> * or if using a "fullview" or "rip and replace" autorouting mode */ _shouldUseTraceByTraceRouting(): boolean { - const props = this._parsedProps as SubcircuitGroupProps - if (props.autorouter === "auto-local") return true - if (props.autorouter === "sequential-trace") return true - if (props.autorouter) return false + // Inherit from parent if not set by props + const autorouter = + this._parsedProps.autorouter ?? this.getInheritedProperty("autorouter") + if (autorouter === "auto-local") return true + if (autorouter === "sequential-trace") return true + if (autorouter) return false return true } } diff --git a/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg index c7715ed1..18e3a18a 100644 --- a/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg +++ b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg @@ -10,4 +10,4 @@ .pcb-silkscreen-top { stroke: #f2eda1; } .pcb-silkscreen-bottom { stroke: #f2eda1; } .pcb-silkscreen-text { fill: #f2eda1; } - \ No newline at end of file + \ No newline at end of file diff --git a/tests/examples/example19-subcircuit-overlap-traces.test.tsx b/tests/examples/example19-subcircuit-overlap-traces.test.tsx index 2a97d155..3a11d15f 100644 --- a/tests/examples/example19-subcircuit-overlap-traces.test.tsx +++ b/tests/examples/example19-subcircuit-overlap-traces.test.tsx @@ -1,8 +1,9 @@ import { test, expect } from "bun:test" import { getTestFixture } from "tests/fixtures/get-test-fixture" import { su } from "@tscircuit/soup-util" +import { getTestAutoroutingServer } from "tests/fixtures/get-test-autorouting-server" -test("If the subcircuit is routing disabled, it should not have traces from the autorouter but it does have", async () => { +test.skip("If the subcircuit is routing disabled, it should not have traces from the autorouter but it does have", async () => { const { circuit } = getTestFixture() circuit.add( @@ -82,11 +83,18 @@ test("If the subcircuit is routing disabled, it should not have traces from the `) }) -test("It is having traces from both autorouter and freerouting (Not in the final circuit json)", async () => { +test("Autorouter should not create traces if the parent subcircuit has async autorouter enabled", async () => { const { circuit } = getTestFixture() + const { autoroutingServerUrl } = getTestAutoroutingServer() + + const cloudAutorouterConfig = { + serverUrl: autoroutingServerUrl, + serverMode: "solve-endpoint", + inputFormat: "simplified", + } as const circuit.add( - + @@ -99,139 +107,66 @@ test("It is having traces from both autorouter and freerouting (Not in the final const pcb_traces = su(circuit.getCircuitJson()).pcb_trace.list() expect(pcb_traces).toMatchInlineSnapshot(` - [ - { - "pcb_trace_id": "pcb_trace_0", - "route": [ - { - "layer": "top", - "route_type": "wire", - "start_pcb_port_id": "pcb_port_0", - "width": 0.16, - "x": -2.5, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 1.3, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 1.3, - }, - { - "end_pcb_port_id": "pcb_port_2", - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 0, - }, - ], - "source_trace_id": "source_trace_0", - "trace_length": 6.6, - "type": "pcb_trace", - }, - { - "pcb_trace_id": "pcb_trace_source_trace_0--Pad1_R1_source_component_0--Pad1_R2_source_component_1", - "route": [ - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.5, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 1.3, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 1.3, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 0, - }, - ], - "source_trace_id": "source_trace_0", - "trace_length": 6.6, - "type": "pcb_trace", - }, - { - "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", - "route": [ - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.5, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 0, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -2.12, - "y": 1.3, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 1.3, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": 1.5, - "y": 0, - }, - ], - "source_trace_id": "source_trace_0", - "trace_length": 6.6, - "type": "pcb_trace", - }, - ] - `) + [ + { + "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 1.5, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.9483, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 0.5517, + "type": "pcb_trace", + }, + { + "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "route": [ + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.9483, + "y": 0, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": 0.3966, + "y": -0.5517, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -1.9483, + "y": -0.5517, + }, + { + "layer": "top", + "route_type": "wire", + "width": 0.16, + "x": -2.5, + "y": 0, + }, + ], + "source_trace_id": "source_trace_0", + "trace_length": 3.9053, + "type": "pcb_trace", + }, + ] + `) expect(circuit.getCircuitJson()).toMatchPcbSnapshot(import.meta.path) }) diff --git a/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg b/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg index 4c071f04..12831a8d 100644 --- a/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg +++ b/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg @@ -10,4 +10,4 @@ .pcb-silkscreen-top { stroke: #f2eda1; } .pcb-silkscreen-bottom { stroke: #f2eda1; } .pcb-silkscreen-text { fill: #f2eda1; } - \ No newline at end of file + \ No newline at end of file diff --git a/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx b/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx index ec5b9152..590f2842 100644 --- a/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx +++ b/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx @@ -60,19 +60,24 @@ test("subcircuit3-dependent-autorouting", async () => { // Check the order of the async effect, should be S1 then board, and S2 is // synchronously routed so has no effect expect(asyncEffectEndEvents).toMatchInlineSnapshot(` -[ - { - "componentDisplayName": "", - "effectName": "make-http-autorouting-request", - "phase": "PcbTraceRender", - }, - { - "componentDisplayName": "", - "effectName": "make-http-autorouting-request", - "phase": "PcbTraceRender", - }, -] -`) + [ + { + "componentDisplayName": "", + "effectName": "make-http-autorouting-request", + "phase": "PcbTraceRender", + }, + { + "componentDisplayName": "", + "effectName": "make-http-autorouting-request", + "phase": "PcbTraceRender", + }, + { + "componentDisplayName": "", + "effectName": "make-http-autorouting-request", + "phase": "PcbTraceRender", + }, + ] + `) // Check if the circuit matches the expected PCB snapshot expect(circuit).toMatchPcbSnapshot(import.meta.path) From 9a0c62c721ba9bd42bada0bc577995304e6f14ba Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 9 Feb 2025 20:07:54 +0000 Subject: [PATCH 25/33] v0.0.304 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 747e539e..22314121 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.303", + "version": "0.0.304", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 925be9e90f877db6e192c4f223a3dfd8807b0c32 Mon Sep 17 00:00:00 2001 From: Arnav K Date: Mon, 10 Feb 2025 03:31:38 +0530 Subject: [PATCH 26/33] patch: improve error message (#609) * improve error message that occurs when you put something that is not a react component inside the jsx * add test * Update PrimitiveComponent.ts --- .../base-components/PrimitiveComponent.ts | 5 +++++ .../primitive-components/invalid-jsx.test.tsx | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/components/primitive-components/invalid-jsx.test.tsx diff --git a/lib/components/base-components/PrimitiveComponent.ts b/lib/components/base-components/PrimitiveComponent.ts index 17ea9008..39e60558 100644 --- a/lib/components/base-components/PrimitiveComponent.ts +++ b/lib/components/base-components/PrimitiveComponent.ts @@ -466,6 +466,11 @@ export abstract class PrimitiveComponent< } add(component: PrimitiveComponent) { + if (!component.onAddToParent) { + throw new Error( + `Invalid JSX Element: Expected a React component but received "${JSON.stringify(component)}"`, + ) + } component.onAddToParent(this) component.parent = this this.children.push(component) diff --git a/tests/components/primitive-components/invalid-jsx.test.tsx b/tests/components/primitive-components/invalid-jsx.test.tsx new file mode 100644 index 00000000..53475200 --- /dev/null +++ b/tests/components/primitive-components/invalid-jsx.test.tsx @@ -0,0 +1,14 @@ +import { test, expect } from "bun:test" +import { Circuit } from "lib" + +test("snippet-import1-contribution-board", async () => { + const circuit = new Circuit() + + expect(() => { + circuit.add( + + {1} + , + ) + }).toThrowError("Invalid JSX Element") +}) From 02d2bf121998c27fed5a6d05f22e1d0b2c3e5dbd Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 9 Feb 2025 22:02:08 +0000 Subject: [PATCH 27/33] v0.0.305 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22314121..83a4230b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.304", + "version": "0.0.305", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From 932241d1513572df81331988e3e147e3de031ed7 Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Sun, 9 Feb 2025 19:06:59 -0800 Subject: [PATCH 28/33] fix typo in autoroutingCacheEnabled, add subcircuit_id to output source_trace and source_port (#611) * fix typo in autoroutingCacheEnabled * add subcircuit_id to source_port and source_trace --- bun.lockb | Bin 225252 -> 225622 bytes .../primitive-components/Group/Group.ts | 2 +- .../primitive-components/Port/Port.ts | 1 + .../primitive-components/Trace/Trace.ts | 2 ++ package.json | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bun.lockb b/bun.lockb index 04fc5d6ff883dc2a6b0a0049bfc37a6a05e2f88f..443565b49c4d34c45856660e84c377cb5c5c66d9 100755 GIT binary patch delta 38322 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 Xp^8~}h-Xf94*A;c`tDWV*$4kGst#r~ delta 38997 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 diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index 6b590fa7..f7c3d76e 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -183,7 +183,7 @@ export class Group = typeof groupProps> serverUrl: "https://registry-api.tscircuit.com", serverMode: "job", serverCacheEnabled: - (props.autorouter as any)?.serverCachingEnabled ?? false, + (props.autorouter as AutorouterConfig)?.serverCacheEnabled ?? false, ...(typeof props.autorouter === "object" ? props.autorouter : {}), } diff --git a/lib/components/primitive-components/Port/Port.ts b/lib/components/primitive-components/Port/Port.ts index cf7a53ab..453b56f7 100644 --- a/lib/components/primitive-components/Port/Port.ts +++ b/lib/components/primitive-components/Port/Port.ts @@ -266,6 +266,7 @@ export class Port extends PrimitiveComponent { pin_number: props.pinNumber, port_hints, source_component_id: this.parent?.source_component_id!, + subcircuit_id: this.getSubcircuit()?.subcircuit_id!, }) this.source_port_id = source_port.source_port_id diff --git a/lib/components/primitive-components/Trace/Trace.ts b/lib/components/primitive-components/Trace/Trace.ts index 3e71d75b..3697a42f 100644 --- a/lib/components/primitive-components/Trace/Trace.ts +++ b/lib/components/primitive-components/Trace/Trace.ts @@ -253,6 +253,7 @@ export class Trace const trace = db.source_trace.insert({ connected_source_port_ids: ports.map((p) => p.port.source_port_id!), connected_source_net_ids: nets.map((n) => n.source_net_id!), + subcircuit_id: this.getSubcircuit()?.subcircuit_id!, max_length: getMaxLengthFromConnectedCapacitors( ports.map((p) => p.port), @@ -589,6 +590,7 @@ export class Trace const pcb_trace = db.pcb_trace.insert({ route: mergedRoute, source_trace_id: this.source_trace_id!, + subcircuit_id: this.getSubcircuit()?.subcircuit_id!, trace_length: traceLength, }) this._portsRoutedOnPcb = ports diff --git a/package.json b/package.json index 83a4230b..79480fa8 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@tscircuit/props": "^0.0.142", "@tscircuit/schematic-autolayout": "^0.0.6", "@tscircuit/soup-util": "^0.0.41", - "circuit-json": "^0.0.135", + "circuit-json": "^0.0.136", "circuit-json-to-connectivity-map": "^0.0.17", "format-si-unit": "^0.0.3", "nanoid": "^5.0.7", From b333af2bd1570116decf8684d2daaeab0eb70581 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 10 Feb 2025 03:07:22 +0000 Subject: [PATCH 29/33] v0.0.306 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79480fa8..ba8f0e0e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.305", + "version": "0.0.306", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From ff5d626bcdcb7711f9b2f1db19210ffc0c4a462d Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Sun, 9 Feb 2025 20:33:33 -0800 Subject: [PATCH 30/33] speculative fix for undefined overshadowing (#612) --- lib/components/primitive-components/Group/Group.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index f7c3d76e..b1146a65 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -179,12 +179,15 @@ export class Group = typeof groupProps> const debug = Debug("tscircuit:core:_runEffectMakeHttpAutoroutingRequest") const props = this._parsedProps as SubcircuitGroupProps + const autorouterPropObj = + typeof props.autorouter === "object" ? props.autorouter : {} + const autoroutingOptions: AutorouterConfig = { - serverUrl: "https://registry-api.tscircuit.com", - serverMode: "job", - serverCacheEnabled: - (props.autorouter as AutorouterConfig)?.serverCacheEnabled ?? false, - ...(typeof props.autorouter === "object" ? props.autorouter : {}), + ...autorouterPropObj, + serverUrl: + autorouterPropObj.serverUrl ?? "https://registry-api.tscircuit.com", + serverMode: autorouterPropObj.serverMode ?? "job", + serverCacheEnabled: autorouterPropObj.serverCacheEnabled ?? false, } const serverUrl = autoroutingOptions.serverUrl! From 0db9834edbd61dbabb5b20c1d7562a468ef50cc6 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 10 Feb 2025 04:33:59 +0000 Subject: [PATCH 31/33] v0.0.307 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ba8f0e0e..ba8d73a7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.306", + "version": "0.0.307", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js", From b09a3c0ca497de85bc100b373e02e8a8290c0d2d Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Mon, 10 Feb 2025 22:41:32 -0800 Subject: [PATCH 32/33] fix non-subcircuits triggering autorouting, fix autorouting running when no traces need to be routed (#615) * fix non-subcircuits routing boards * lots of fixes for unnecessary circuit routing * mark test with bug fixed in http request ordering * update to include local autorouter for subcircuit --- bun.lockb | Bin 225622 -> 225252 bytes .../primitive-components/Group/Group.ts | 87 ++++++++++++------ package.json | 2 +- ...e19-subcircuit-overlap-traces-pcb.snap.svg | 2 +- ...ample19-subcircuit-overlap-traces.test.tsx | 45 +++------ ...ircuit3-dependent-autorouting-pcb.snap.svg | 2 +- ...subcircuit3-dependent-autorouting.test.tsx | 10 +- ...bcircuit4-nested-group-autorouter.test.tsx | 59 ++++++++++++ 8 files changed, 141 insertions(+), 66 deletions(-) create mode 100644 tests/subcircuits/subcircuit4-nested-group-autorouter.test.tsx diff --git a/bun.lockb b/bun.lockb index 443565b49c4d34c45856660e84c377cb5c5c66d9..97db4981fe12d10d531865bd7e52dd6df7ceed83 100755 GIT binary patch delta 39058 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 diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index b1146a65..e478f3a0 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -167,31 +167,27 @@ export class Group = typeof groupProps> } _shouldRouteAsync(): boolean { - const props = this._parsedProps as SubcircuitGroupProps - if (props.autorouter === "auto-local") return true - if (props.autorouter === "auto-cloud") return true - if (props.autorouter === "sequential-trace") return false - if (typeof props.autorouter === "object") return true - return false + const autorouter = this._getAutorouterConfig() + if (autorouter.local) return false + if (autorouter.groupMode === "sequential-trace") return false + return true + } + + _hasTracesToRoute(): boolean { + const debug = Debug("tscircuit:core:_hasTracesToRoute") + const traces = this.selectAll("trace") as Trace[] + debug(`[${this.getString()}] has ${traces.length} traces to route`) + return traces.length > 0 } async _runEffectMakeHttpAutoroutingRequest() { const debug = Debug("tscircuit:core:_runEffectMakeHttpAutoroutingRequest") const props = this._parsedProps as SubcircuitGroupProps - const autorouterPropObj = - typeof props.autorouter === "object" ? props.autorouter : {} - - const autoroutingOptions: AutorouterConfig = { - ...autorouterPropObj, - serverUrl: - autorouterPropObj.serverUrl ?? "https://registry-api.tscircuit.com", - serverMode: autorouterPropObj.serverMode ?? "job", - serverCacheEnabled: autorouterPropObj.serverCacheEnabled ?? false, - } + const autorouterConfig = this._getAutorouterConfig() - const serverUrl = autoroutingOptions.serverUrl! - const serverMode = autoroutingOptions.serverMode! + const serverUrl = autorouterConfig.serverUrl! + const serverMode = autorouterConfig.serverMode! const fetchWithDebug = (url: string, options: RequestInit) => { debug("fetching", url) @@ -252,7 +248,7 @@ export class Group = typeof groupProps> autostart: true, display_name: this.root?.name, subcircuit_id: this.subcircuit_id, - server_cache_enabled: autoroutingOptions.serverCacheEnabled, + server_cache_enabled: autorouterConfig.serverCacheEnabled, }), headers: { "Content-Type": "application/json" }, }, @@ -321,6 +317,7 @@ export class Group = typeof groupProps> doInitialPcbTraceRender() { const debug = Debug("tscircuit:core:doInitialPcbTraceRender") + if (!this.isSubcircuit) return if (this.root?.pcbDisabled) return if (this._shouldUseTraceByTraceRouting()) return @@ -334,12 +331,18 @@ export class Group = typeof groupProps> debug( `[${this.getString()}] no child subcircuits to wait for, initiating async routing`, ) + if (!this._hasTracesToRoute()) return this._startAsyncAutorouting() } updatePcbTraceRender() { const debug = Debug("tscircuit:core:updatePcbTraceRender") - if (this._shouldRouteAsync() && !this._hasStartedAsyncAutorouting) { + if (!this.isSubcircuit) return + if ( + this._shouldRouteAsync() && + this._hasTracesToRoute() && + !this._hasStartedAsyncAutorouting + ) { if (this._areChildSubcircuitsRouted()) { debug( `[${this.getString()}] child subcircuits are now routed, starting async autorouting`, @@ -463,6 +466,42 @@ export class Group = typeof groupProps> SAL.mutateSoupForScene(db.toArray(), laidOutScene) } + _getAutorouterConfig(): AutorouterConfig { + const defaults = { + serverUrl: "https://registry-api.tscircuit.com", + serverMode: "job", + serverCacheEnabled: false, + } + // Inherit from parent if not set by props + const autorouter = + this._parsedProps.autorouter ?? this.getInheritedProperty("autorouter") + + if (typeof autorouter === "object") { + return { + local: !( + autorouter.serverUrl || + autorouter.serverMode || + autorouter.serverCacheEnabled + ), + ...defaults, + ...autorouter, + } + } + + if (autorouter === "auto-local") + return { + local: true, + } + if (autorouter === "sequential-trace") + return { + local: true, + groupMode: "sequential-trace", + } + return { + local: true, + groupMode: "sequential-trace", + } + } /** * Trace-by-trace autorouting is where each trace routes itself in a well-known * order. It's the most deterministic way to autoroute, because a new trace @@ -473,11 +512,7 @@ export class Group = typeof groupProps> */ _shouldUseTraceByTraceRouting(): boolean { // Inherit from parent if not set by props - const autorouter = - this._parsedProps.autorouter ?? this.getInheritedProperty("autorouter") - if (autorouter === "auto-local") return true - if (autorouter === "sequential-trace") return true - if (autorouter) return false - return true + const autorouter = this._getAutorouterConfig() + return autorouter.groupMode === "sequential-trace" } } diff --git a/package.json b/package.json index ba8d73a7..48ce5cb5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@tscircuit/footprinter": "^0.0.97", "@tscircuit/infgrid-ijump-astar": "^0.0.33", "@tscircuit/math-utils": "^0.0.9", - "@tscircuit/props": "^0.0.142", + "@tscircuit/props": "^0.0.144", "@tscircuit/schematic-autolayout": "^0.0.6", "@tscircuit/soup-util": "^0.0.41", "circuit-json": "^0.0.136", diff --git a/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg index 18e3a18a..c7051fd3 100644 --- a/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg +++ b/tests/examples/__snapshots__/example19-subcircuit-overlap-traces-pcb.snap.svg @@ -10,4 +10,4 @@ .pcb-silkscreen-top { stroke: #f2eda1; } .pcb-silkscreen-bottom { stroke: #f2eda1; } .pcb-silkscreen-text { fill: #f2eda1; } - \ No newline at end of file + \ No newline at end of file diff --git a/tests/examples/example19-subcircuit-overlap-traces.test.tsx b/tests/examples/example19-subcircuit-overlap-traces.test.tsx index 3a11d15f..fb515763 100644 --- a/tests/examples/example19-subcircuit-overlap-traces.test.tsx +++ b/tests/examples/example19-subcircuit-overlap-traces.test.tsx @@ -83,7 +83,7 @@ test.skip("If the subcircuit is routing disabled, it should not have traces from `) }) -test("Autorouter should not create traces if the parent subcircuit has async autorouter enabled", async () => { +test("Autorouter should inherit if the parent subcircuit has async autorouter enabled", async () => { const { circuit } = getTestFixture() const { autoroutingServerUrl } = getTestAutoroutingServer() @@ -109,61 +109,44 @@ test("Autorouter should not create traces if the parent subcircuit has async aut expect(pcb_traces).toMatchInlineSnapshot(` [ { - "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", + "pcb_trace_id": "pcb_trace_0", "route": [ { "layer": "top", "route_type": "wire", - "width": 0.16, - "x": 1.5, + "width": 0.1, + "x": -2.5, "y": 0, }, { "layer": "top", "route_type": "wire", - "width": 0.16, - "x": 0.9483, + "width": 0.1, + "x": -2, "y": 0, }, - ], - "source_trace_id": "source_trace_0", - "trace_length": 0.5517, - "type": "pcb_trace", - }, - { - "pcb_trace_id": "pcb_trace_Net-(R1_source_component_0-Pad1)", - "route": [ { "layer": "top", "route_type": "wire", - "width": 0.16, - "x": 0.9483, - "y": 0, + "width": 0.1, + "x": -2, + "y": 1.3, }, { "layer": "top", "route_type": "wire", - "width": 0.16, - "x": 0.3966, - "y": -0.5517, - }, - { - "layer": "top", - "route_type": "wire", - "width": 0.16, - "x": -1.9483, - "y": -0.5517, + "width": 0.1, + "x": 1.5, + "y": 1.3, }, { "layer": "top", "route_type": "wire", - "width": 0.16, - "x": -2.5, + "width": 0.1, + "x": 1.5, "y": 0, }, ], - "source_trace_id": "source_trace_0", - "trace_length": 3.9053, "type": "pcb_trace", }, ] diff --git a/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg b/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg index 12831a8d..4c071f04 100644 --- a/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg +++ b/tests/subcircuits/__snapshots__/subcircuit3-dependent-autorouting-pcb.snap.svg @@ -10,4 +10,4 @@ .pcb-silkscreen-top { stroke: #f2eda1; } .pcb-silkscreen-bottom { stroke: #f2eda1; } .pcb-silkscreen-text { fill: #f2eda1; } - \ No newline at end of file + \ No newline at end of file diff --git a/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx b/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx index 590f2842..36d8bda0 100644 --- a/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx +++ b/tests/subcircuits/subcircuit3-dependent-autorouting.test.tsx @@ -33,7 +33,10 @@ test("subcircuit3-dependent-autorouting", async () => { /> - + { "effectName": "make-http-autorouting-request", "phase": "PcbTraceRender", }, - { - "componentDisplayName": "", - "effectName": "make-http-autorouting-request", - "phase": "PcbTraceRender", - }, ] `) diff --git a/tests/subcircuits/subcircuit4-nested-group-autorouter.test.tsx b/tests/subcircuits/subcircuit4-nested-group-autorouter.test.tsx new file mode 100644 index 00000000..272db4e4 --- /dev/null +++ b/tests/subcircuits/subcircuit4-nested-group-autorouter.test.tsx @@ -0,0 +1,59 @@ +import React from "react" +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" +import { getTestAutoroutingServer } from "tests/fixtures/get-test-autorouting-server" + +test("Nested group within a subcircuit triggers autorouter only once", async () => { + const { autoroutingServerUrl } = getTestAutoroutingServer() + + const cloudAutorouterConfig = { + serverUrl: autoroutingServerUrl, + serverMode: "solve-endpoint", + inputFormat: "simplified", + } as const + const { circuit } = getTestFixture() + + // Count the number of times the autorouter is triggered + let autorouterCallCount = 0 + circuit.on("asyncEffect:start", (event) => { + if (event.effectName === "make-http-autorouting-request") { + autorouterCallCount++ + } + }) + + // Add a board with autorouter configuration + circuit.add( + + + + + + + + + , + ) + + await circuit.renderUntilSettled() + + // Expect that the autorouter is called only once for the subcircuit, + // not once for the nested group + expect(autorouterCallCount).toBe(1) +}) From 2b6849e126dad689c9fbdc0341adc4f2a6455014 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 11 Feb 2025 06:42:01 +0000 Subject: [PATCH 33/33] v0.0.308 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 48ce5cb5..43ab01cf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tscircuit/core", "type": "module", - "version": "0.0.307", + "version": "0.0.308", "types": "dist/index.d.ts", "main": "dist/index.js", "module": "dist/index.js",