From 0528e234f977d23e9b9ca9f29242f873dd2e5fff Mon Sep 17 00:00:00 2001 From: Severin Ibarluzea Date: Sat, 4 May 2024 10:21:25 -0700 Subject: [PATCH] Edit PCB Layout in Preview Window (#44) * prepare for pcb dragging, api endpoint setup to submit, dragging installed * manual edit reading/editing basic version * wip * add pcb_placement derivation and editing * edit existing placements * initial implementation working --- bun.lockb | Bin 212385 -> 215624 bytes .../routes/api/dev_package_examples/get.ts | 4 + .../routes/api/dev_package_examples/list.ts | 1 + .../routes/api/dev_package_examples/update.ts | 18 +- dev-server-api/src/db/create-schema.ts | 3 + dev-server-api/src/db/get-db.ts | 2 + dev-server-frontend/bun.lockb | Bin 216464 -> 215597 bytes dev-server-frontend/package-lock.json | 327 +++++++++++++++--- dev-server-frontend/package.json | 6 +- .../src/ExampleContentView.tsx | 38 +- .../derive-selector-from-pcb-component-id.ts | 23 ++ lib/cmd-fns/dev/index.ts | 5 +- lib/cmd-fns/dev/start-edit-event-watcher.ts | 219 ++++++++++++ .../dev/start-export-request-watcher.ts | 8 +- lib/cmd-fns/init/index.ts | 39 ++- package-lock.json | 172 +++++++-- package.json | 12 +- .../example-project/examples/basic-bug.tsx | 34 +- .../assets/example-project/package-lock.json | 105 +++++- tests/assets/example-project/package.json | 4 +- .../assets/example-project/src/MyCircuit.tsx | 10 +- .../example-project/src/manual-edits.ts | 28 ++ 22 files changed, 917 insertions(+), 141 deletions(-) create mode 100644 lib/cmd-fns/dev/derive-selector-from-pcb-component-id.ts create mode 100644 lib/cmd-fns/dev/start-edit-event-watcher.ts create mode 100644 tests/assets/example-project/src/manual-edits.ts diff --git a/bun.lockb b/bun.lockb index c7ace95f4d46b11ad532e8fca87bedd90cc671b1..be76f10b26c1f7e0ec8e676be7332912f925d0bb 100755 GIT binary patch delta 35979 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.as("is_loading"), ]) .execute() diff --git a/dev-server-api/routes/api/dev_package_examples/update.ts b/dev-server-api/routes/api/dev_package_examples/update.ts index 515b3fb9..ee433ab5 100644 --- a/dev-server-api/routes/api/dev_package_examples/update.ts +++ b/dev-server-api/routes/api/dev_package_examples/update.ts @@ -7,6 +7,7 @@ export default withEdgeSpec({ jsonBody: z.object({ dev_package_example_id: z.coerce.number(), tscircuit_soup: z.any().optional(), + completed_edit_events: z.array(z.any()).optional(), error: z.string().nullable().optional().default(null), }), jsonResponse: z.object({ @@ -23,10 +24,23 @@ export default withEdgeSpec({ dev_package_example: await ctx.db .updateTable("dev_package_example") .set({ - tscircuit_soup: req.jsonBody.tscircuit_soup, - error: req.jsonBody.error, last_updated_at: new Date().toISOString(), }) + .$if(req.jsonBody.tscircuit_soup !== undefined, (q) => + q + .set("tscircuit_soup", req.jsonBody.tscircuit_soup) + .set("error", null) + .set("soup_last_updated_at", new Date().toISOString()) + ) + .$if(req.jsonBody.error !== undefined, (q) => + q.set("error", req.jsonBody.error) + ) + .$if(req.jsonBody.completed_edit_events !== undefined, (q) => + q.set( + "completed_edit_events", + JSON.stringify(req.jsonBody.completed_edit_events) + ) + ) .returningAll() .where("dev_package_example_id", "=", req.jsonBody.dev_package_example_id) .executeTakeFirstOrThrow(), diff --git a/dev-server-api/src/db/create-schema.ts b/dev-server-api/src/db/create-schema.ts index 61bb1dd0..e32a2162 100644 --- a/dev-server-api/src/db/create-schema.ts +++ b/dev-server-api/src/db/create-schema.ts @@ -1,6 +1,7 @@ import type { DbClient } from "./get-db" export const createSchema = async (db: DbClient) => { + console.log("Creating schema...") await db.schema .createTable("dev_package_example") .addColumn("dev_package_example_id", "integer", (col) => @@ -9,8 +10,10 @@ export const createSchema = async (db: DbClient) => { .addColumn("file_path", "text", (col) => col.unique()) .addColumn("export_name", "text") .addColumn("tscircuit_soup", "json") + .addColumn("completed_edit_events", "json") .addColumn("error", "text") .addColumn("is_loading", "boolean", (cb) => cb.defaultTo(0).notNull()) + .addColumn("soup_last_updated_at", "text") .addColumn("last_updated_at", "text") .execute() diff --git a/dev-server-api/src/db/get-db.ts b/dev-server-api/src/db/get-db.ts index 1eb1ae4f..33f36b6e 100644 --- a/dev-server-api/src/db/get-db.ts +++ b/dev-server-api/src/db/get-db.ts @@ -6,11 +6,13 @@ import * as Path from "path" export interface DevPackageExample { dev_package_example_id: Generated tscircuit_soup: any + completed_edit_events: any file_path: string export_name: string error: string | null is_loading: 1 | 0 last_updated_at: string + soup_last_updated_at: string } export interface ExportRequest { diff --git a/dev-server-frontend/bun.lockb b/dev-server-frontend/bun.lockb index d1da78859d5e01b104a755829959aa4c46361c36..f1af2cd8c5de15b34a9cdb034ea2578bc7646d1a 100755 GIT binary patch delta 21253 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.8.0" @@ -147,7 +141,6 @@ }, "node_modules/@babel/code-frame/node_modules/chalk/node_modules/supports-color": { "version": "5.5.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -158,7 +151,6 @@ }, "node_modules/@babel/code-frame/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -292,7 +284,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.15", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.15" @@ -351,7 +342,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.23.4", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -359,7 +349,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -388,7 +377,6 @@ }, "node_modules/@babel/highlight": { "version": "7.23.4", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -401,7 +389,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -414,7 +401,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles": { "version": "3.2.1", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -425,7 +411,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert": { "version": "1.9.3", - "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -433,12 +418,10 @@ }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules/color-name": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -446,7 +429,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color": { "version": "5.5.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -457,7 +439,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -555,7 +536,6 @@ }, "node_modules/@babel/types": { "version": "7.24.0", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -566,6 +546,95 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/css": { + "version": "11.11.2", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.11.2.tgz", + "integrity": "sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew==", + "dependencies": { + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@esbuild/linux-x64": { "version": "0.19.12", "cpu": [ @@ -1831,16 +1900,20 @@ } }, "node_modules/@tscircuit/builder": { - "version": "1.5.53", - "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.53.tgz", - "integrity": "sha512-DJWEJAacSN+5p4Sc1RSbYAUEMqbKarS8HusrLpyDHnP+K3NzDG4/kxMGrD9rzTZSq2hfed97Zne/BZlVqfigVQ==", + "version": "1.5.85", + "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.85.tgz", + "integrity": "sha512-QKLkkVGLCuhmN5YgWnpETRGyn3POp+92Eam3CDo0b4qrCYheV7DQoJ87HG4iAPr4WBvUy7NxtAPTeZRVOtccdA==", "dependencies": { "@lume/kiwi": "^0.1.0", "@tscircuit/footprints": "^0.0.14", + "@tscircuit/layout": "^0.0.7", "@tscircuit/routing": "^1.3.1", - "@tscircuit/sparkfun-packages": "^1.2.0", + "@tscircuit/schematic-autolayout": "^0.0.5", + "@tscircuit/sparkfun-packages": "^1.2.1", "convert-units": "^2.3.4", "fast-json-stable-stringify": "^2.1.0", + "format-si-prefix": "^0.3.2", + "papaparse": "^5.4.1", "rectilinear-router": "^1.0.1", "svg-path-bounds": "^1.0.2", "transformation-matrix": "^2.12.0" @@ -1857,6 +1930,18 @@ "typescript": "^5.0.0" } }, + "node_modules/@tscircuit/layout": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@tscircuit/layout/-/layout-0.0.7.tgz", + "integrity": "sha512-Jdd6j0+p4yK8zAqFX7dgmb5PT8A9KJduDBhEgAm+OgwDrw3Mp0hQ80pbR2Mvm02UF2Gu9H7TWpMytACCoNqPdA==", + "dependencies": { + "transformation-matrix": "^2.16.1" + }, + "peerDependencies": { + "@tscircuit/builder": "*", + "zod": "*" + } + }, "node_modules/@tscircuit/mm": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@tscircuit/mm/-/mm-0.0.4.tgz", @@ -1869,12 +1954,15 @@ } }, "node_modules/@tscircuit/pcb-viewer": { - "version": "1.2.24", - "resolved": "https://registry.npmjs.org/@tscircuit/pcb-viewer/-/pcb-viewer-1.2.24.tgz", - "integrity": "sha512-T1ohSL9vVI2nPxeXiYnSDJHMVV55Zspa9MqcLCfb4MDFhm8kf/Ba/kMSkmvwkzv8jLFJkdS+HkEcEu9yfncl2Q==", - "dependencies": { - "react-supergrid": "^1.0.7", - "transformation-matrix": "^2.13.0" + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@tscircuit/pcb-viewer/-/pcb-viewer-1.3.6.tgz", + "integrity": "sha512-57emRZm9jK6MlZ4+EUtdgTqtnl7zYPjczzSRlfWL3srzcKGLTSQxvrvF7b/g9kVpmQKmkaDkp7sZ5G4lm/yywQ==", + "dependencies": { + "@emotion/css": "^11.11.2", + "color": "^4.2.3", + "react-supergrid": "^1.0.10", + "transformation-matrix": "^2.13.0", + "zustand": "^4.5.2" }, "peerDependencies": { "@tscircuit/builder": "*", @@ -1882,6 +1970,18 @@ "react": "*" } }, + "node_modules/@tscircuit/pcb-viewer/node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/@tscircuit/react-fiber": { "version": "1.0.6", "license": "MIT", @@ -1904,13 +2004,25 @@ "react-error-boundary": "^4.0.11" } }, + "node_modules/@tscircuit/schematic-autolayout": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@tscircuit/schematic-autolayout/-/schematic-autolayout-0.0.5.tgz", + "integrity": "sha512-I4CtLQfqTPTxDSumnquaJtkJkc16VjLC4bwU3jQdBXwwh9ODzBf88clUznUtDDzwV+BPM5P0W0VCfFhvPL3/Cw==", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-supergrid": "^1.0.10", + "transformation-matrix": "^2.16.1", + "use-mouse-matrix-transform": "^1.1.12" + } + }, "node_modules/@tscircuit/schematic-viewer": { - "version": "1.1.22", - "resolved": "https://registry.npmjs.org/@tscircuit/schematic-viewer/-/schematic-viewer-1.1.22.tgz", - "integrity": "sha512-aU2CGv9fGnjiMsP0Cg2LAC2nzmXTSfWqu5TEl3MNj5sPbPLpft0kBT4hdKfyrwxPCoL5p0GJnlPesW9byjSySA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@tscircuit/schematic-viewer/-/schematic-viewer-1.2.3.tgz", + "integrity": "sha512-fkG+tmSkIrfmk8vHZrWWy4XcIVb86On8Cu4hKXbGbAlAZrt7YxrvqkUPXE0p3jErzEsIbWpm8d8QbyD+vwbr7Q==", "dependencies": { "react-error-boundary": "^4.0.4", - "react-supergrid": "^1.0.8", + "react-supergrid": "^1.0.10", "use-mouse-matrix-transform": "^1.1.12" }, "peerDependencies": { @@ -1921,17 +2033,17 @@ } }, "node_modules/@tscircuit/sparkfun-packages": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.0.tgz", - "integrity": "sha512-m+jCOaSBpwRzUN5trc9z5f8yh2zzLITANgNhuNQOtxNZRIrv98iYfL3dSSmf73xknh0Nz68EephNvKVZmproCQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.1.tgz", + "integrity": "sha512-2HzmmHydo5vgoKmNBAHd6RD93LaIMXRSt6t//1zx19/ZwrOA43qVOvb7cCTA82GHib1bSxoL7bqgii9sYudCHw==", "dependencies": { "change-case": "^5.4.3" } }, "node_modules/@tscircuit/table-viewer": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@tscircuit/table-viewer/-/table-viewer-0.0.7.tgz", - "integrity": "sha512-DhQetibJG5nOwmrA+gFHdNJPZvjPtM7wV8nB++oxkYsfHLhYblMUrUo2dlSvFoCVJLaOdUgIF7sPxNXqs+PG6Q==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@tscircuit/table-viewer/-/table-viewer-0.0.8.tgz", + "integrity": "sha512-55PRjpIvIN6wGnGi2tbAsyiUHEUPWOQcV/YDDxMApIPHEBxQngNgjIuzA5DiPq5rjX9xSrikt3mfOK78qQMJbA==", "dependencies": { "react-json-tree": "^0.18.0" }, @@ -1996,6 +2108,11 @@ "version": "4.17.0", "license": "MIT" }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, "node_modules/@types/prop-types": { "version": "15.7.11", "license": "MIT" @@ -2402,6 +2519,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "license": "MIT" @@ -2489,7 +2620,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2689,6 +2819,29 @@ "lodash.keys": "2.3.x" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "license": "MIT", @@ -2794,6 +2947,19 @@ "version": "9.2.2", "license": "MIT" }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/esbuild": { "version": "0.19.12", "dev": true, @@ -2841,7 +3007,6 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3069,6 +3234,11 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "dev": true, @@ -3146,6 +3316,14 @@ "node": ">= 6" } }, + "node_modules/format-si-prefix": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/format-si-prefix/-/format-si-prefix-0.3.2.tgz", + "integrity": "sha512-gtCZh4RpmlmEZtyzyvs+FXXWOmdfpQQ0M7mjc81zpAYm5QpsoUDPKhAK+Lj7fJCtZSJpE5xbpCYgspCBxahObQ==", + "dependencies": { + "parseunit": "^0" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "dev": true, @@ -3319,7 +3497,6 @@ }, "node_modules/import-fresh": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -3495,6 +3672,11 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -3937,9 +4119,13 @@ "version": "2.1.0", "license": "(MIT AND Zlib)" }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -3948,10 +4134,32 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-svg-path": { "version": "0.1.2", "license": "MIT" }, + "node_modules/parseunit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/parseunit/-/parseunit-0.3.1.tgz", + "integrity": "sha512-kKtTgCJDsktOHsnvRR/B5DhWi3a/RZ5M9XjVQZGbOatcam+/tk4sMOCQ1WM9Rswfr78zWGBgHNbWTyJvfR0ejg==" + }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -4001,7 +4209,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4411,8 +4618,9 @@ } }, "node_modules/react-supergrid": { - "version": "1.0.8", - "license": "ISC", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/react-supergrid/-/react-supergrid-1.0.10.tgz", + "integrity": "sha512-dJd9wkH6BJkdfkv62EcRAIBn59e2wj58bJFVXiW/ZHQzxz20qIql63fTU2qFMOujXnBIDaMG0uTod67/mjEGeA==", "peerDependencies": { "react": "*", "react-dom": "*", @@ -4469,7 +4677,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -4643,6 +4850,14 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "license": "BSD-3-Clause", @@ -4710,6 +4925,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "license": "MIT", @@ -4842,7 +5062,6 @@ }, "node_modules/to-fast-properties": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" diff --git a/dev-server-frontend/package.json b/dev-server-frontend/package.json index e027e6f4..01af260a 100644 --- a/dev-server-frontend/package.json +++ b/dev-server-frontend/package.json @@ -30,9 +30,9 @@ "@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", - "@tscircuit/builder": "^1.5.66", - "@tscircuit/pcb-viewer": "^1.3.4", - "@tscircuit/schematic-viewer": "^1.1.22", + "@tscircuit/builder": "^1.5.85", + "@tscircuit/pcb-viewer": "^1.3.7", + "@tscircuit/schematic-viewer": "^1.2.3", "@tscircuit/table-viewer": "0.0.8", "axios": "^1.6.7", "class-variance-authority": "^0.7.0", diff --git a/dev-server-frontend/src/ExampleContentView.tsx b/dev-server-frontend/src/ExampleContentView.tsx index b44f4efb..629c5976 100644 --- a/dev-server-frontend/src/ExampleContentView.tsx +++ b/dev-server-frontend/src/ExampleContentView.tsx @@ -7,6 +7,8 @@ import { cn } from "./lib/utils" import { ErrorBoundary } from "react-error-boundary" import { SoupTableViewer } from "@tscircuit/table-viewer" import "react-data-grid/lib/styles.css" +import { useRef, useState } from "react" +import type { EditEvent } from "@tscircuit/pcb-viewer" export const ExampleContentView = () => { const devExamplePackageId = useGlobalStore( @@ -34,10 +36,13 @@ export const ExampleContentView = () => { } ) + const sentEditEvents = useRef>({}) + const notFound = (error as any)?.response?.status === 404 const viewMode = useGlobalStore((s) => s.view_mode) const splitMode = useGlobalStore((s) => s.split_mode) + const [editEvents, setEditEvents] = useState([]) const editorHeight = window.innerHeight - 52 const halfHeight = Math.floor(editorHeight / 2) @@ -47,7 +52,7 @@ export const ExampleContentView = () => { return (
{ {pkg && (viewMode === "schematic" || viewMode === "split") && ( Failed to render Schematic
}> { {pkg && (viewMode === "pcb" || viewMode === "split") && ( Failed to render PCB}> { + // Look for any edit events that have not been sent to the server + // and send them, then mark them as sent + let hasUnsentEditEvents = false + for (const editEvent of changedEditEvents) { + if ( + !editEvent.in_progress && + !sentEditEvents.current[editEvent.edit_event_id] + ) { + hasUnsentEditEvents = true + sentEditEvents.current[editEvent.edit_event_id] = true + } + } + if (hasUnsentEditEvents) { + axios.post(`/api/dev_package_examples/update`, { + dev_package_example_id: devExamplePackageId, + completed_edit_events: changedEditEvents.filter( + (ee) => ee.in_progress === false + ), + }) + } + setEditEvents(changedEditEvents) + }} soup={pkg.tscircuit_soup} /> @@ -79,7 +109,7 @@ export const ExampleContentView = () => { {pkg && viewMode === "soup" && ( Failed to render Soup}> { + const source_component = su(soup).source_component.getUsing({ + pcb_component_id, + }) + if (!source_component) { + throw new Error( + `Could not find source component for pcb_component_id="${pcb_component_id}"` + ) + } + + // TODO travel up the tree to make the selector more specific + + return `.${source_component.name}` +} diff --git a/lib/cmd-fns/dev/index.ts b/lib/cmd-fns/dev/index.ts index 471bcc8e..0420d9c3 100644 --- a/lib/cmd-fns/dev/index.ts +++ b/lib/cmd-fns/dev/index.ts @@ -14,6 +14,7 @@ import { checkIfInitialized } from "./check-if-initialized" import { initCmd } from "../init" import { startExportRequestWatcher } from "./start-export-request-watcher" import $ from "dax-sh" +import { startEditEventWatcher } from "./start-edit-event-watcher" export const devCmd = async (ctx: AppContext, args: any) => { const params = z @@ -75,9 +76,10 @@ export const devCmd = async (ctx: AppContext, args: any) => { console.log(`Loading examples...`) await uploadExamplesFromDirectory({ devServerAxios, cwd }, ctx) - // Start watcher + // Start watchers const fs_watcher = await startFsWatcher({ cwd, devServerAxios }, ctx) const er_watcher = await startExportRequestWatcher({ devServerAxios }, ctx) + const ee_watcher = await startEditEventWatcher({ devServerAxios }, ctx) while (true) { const { action } = await prompts({ @@ -108,6 +110,7 @@ export const devCmd = async (ctx: AppContext, args: any) => { if (server.close) server.close() fs_watcher.stop() er_watcher.stop() + ee_watcher.stop() break } } diff --git a/lib/cmd-fns/dev/start-edit-event-watcher.ts b/lib/cmd-fns/dev/start-edit-event-watcher.ts new file mode 100644 index 00000000..28a43b5d --- /dev/null +++ b/lib/cmd-fns/dev/start-edit-event-watcher.ts @@ -0,0 +1,219 @@ +import { DevPackageExample } from "@server/db/get-db" +import { AxiosInstance } from "axios" +import kleur from "kleur" +import { AppContext } from "lib/util/app-context" +import fg from "fast-glob" +import fs from "fs" +import { Project, ts } from "ts-morph" +import * as Path from "path" +import { ManualPcbPosition } from "@tscircuit/builder" +import { deriveSelectorFromPcbComponentId } from "./derive-selector-from-pcb-component-id" + +// TODO import from builder when builder exports it +type EditEvent = { + edit_event_id: string + pcb_edit_event_type: "edit_component_location" + pcb_component_id: string + original_center: { x: number; y: number } + new_center: { x: number; y: number } +} + +export const startEditEventWatcher = async ( + { + devServerAxios, + }: { + devServerAxios: AxiosInstance + }, + ctx: AppContext +) => { + let running = true + + ;(async () => { + let last_edit_event_update_time: Record = {} + + while (running) { + try { + const dev_package_examples: DevPackageExample[] = await devServerAxios + .post("/api/dev_package_examples/list", {}) + .then((r) => r.data.dev_package_examples) + + for (const dev_package_example of dev_package_examples) { + const dev_package_example_id: number = + dev_package_example.dev_package_example_id as any + + const last_recorded_update_time = + last_edit_event_update_time[dev_package_example_id] + + // TODO use last_edit_event_updated_at + if ( + last_recorded_update_time !== dev_package_example.last_updated_at + ) { + console.log( + kleur.gray( + `Edit event detected for dev_package_example ${dev_package_example.dev_package_example_id}` + ) + ) + console.log( + kleur.gray(` file_path: ${dev_package_example.file_path}`) + ) + + last_edit_event_update_time[dev_package_example_id] = + dev_package_example.last_updated_at // TODO last_edit_event_updated_at + + console.log(kleur.gray(` getting new edit events...`)) + + const dev_package_example_full = await devServerAxios + .post("/api/dev_package_examples/get", { + dev_package_example_id, + }) + .then((r) => r.data.dev_package_example) + + // 1. Find the *.manual-edits.ts, if there are multiple error + const manual_edit_files = fg.sync( + ["**/*.manual-edits.ts", "**/manual-edits.ts"], + { + cwd: ctx.cwd, + } + ) + + if (manual_edit_files.length === 0) { + console.log( + kleur.red( + `No manual edit files found in "${ctx.cwd}", please create a file "manual-edits.ts" or "*.manual-edits.ts" to persist manual edits` + ) + ) + continue + } + + if (manual_edit_files.length > 1) { + console.log( + kleur.red( + `Multiple manual edit files found, tsci currently doesn't know how to handle this, you should go upvote an issue` + ) + ) + continue + } + + const manual_edit_file = manual_edit_files[0] + const manual_edit_file_content = fs.readFileSync( + Path.join(ctx.cwd, manual_edit_file), + "utf-8" + ) + + console.log( + kleur.gray(` found manual edit file: ${manual_edit_file}`) + ) + + // 2. Convert the edit events into ManualPcbPosition[] and append, + // removing any old placements/positions for the same selector. + // We can completely rewrite the file here for now (we'll need + // to preserve comments etc. later) + + const edit_events: EditEvent[] = + dev_package_example_full.completed_edit_events ?? [] + + if (edit_events.length === 0) continue + + const project = new Project() + + const ts_manual_edits_file = project.createSourceFile( + "manual-edits.ts", + manual_edit_file_content + ) + + // Access the default export declaration + const default_export_dec = ts_manual_edits_file + .getDefaultExportSymbol()! + .getDeclarations()[0] + + // Get the object literal expression from the export default statement + const object_literal = + default_export_dec.getFirstChildByKindOrThrow( + ts.SyntaxKind.ObjectLiteralExpression + ) + + // Get the `pcb_placements` property + const pcb_placements_ts = + object_literal.getPropertyOrThrow("pcb_placements") + + let pcb_placements: (ManualPcbPosition & { + _edit_event_id?: string + })[] + try { + pcb_placements = JSON.parse( + pcb_placements_ts.getText().replace(/pcb_placements:\s/, "") + ) + } catch (e: any) { + console.log( + kleur.red( + `Error parsing pcb_placements from manual edits file: ${pcb_placements_ts.getText()} ${e.toString()}` + ) + ) + continue + } + + const handled_edit_events = new Set( + pcb_placements + .map((p) => (p as any)._edit_event_id) + .filter(Boolean) + ) + + // Add PCB placements from edit events + for (const edit_event of edit_events) { + if (handled_edit_events.has(edit_event.edit_event_id)) continue + + // TODO Figure out a good selector for this pcb_component + const selector = deriveSelectorFromPcbComponentId({ + soup: dev_package_example_full.tscircuit_soup, + pcb_component_id: edit_event.pcb_component_id, + }) + + const existing_placement_for_selector = pcb_placements.find( + (pp) => pp.selector === selector + ) + + if (!existing_placement_for_selector) { + console.log( + kleur.gray( + ` adding PCB placement from edit event for "${selector}"` + ) + ) + + pcb_placements.push({ + _edit_event_id: edit_event.edit_event_id, + selector, + center: edit_event.new_center, + relative_to: "group_center", + }) + } else { + existing_placement_for_selector.center = edit_event.new_center + } + + // Edit the pcb placements object + pcb_placements_ts.replaceWithText( + `pcb_placements: ${JSON.stringify(pcb_placements, null, " ")}` + ) + + // Save the file + + fs.writeFileSync( + Path.join(ctx.cwd, manual_edit_file), + ts_manual_edits_file.getFullText() + ) + } + } + } + } catch (err: any) { + console.log(kleur.red(`Error in edit event watcher: ${err.toString()}`)) + } + + await new Promise((resolve) => setTimeout(resolve, 100)) + } + })() + + return { + stop: () => { + running = false + }, + } +} diff --git a/lib/cmd-fns/dev/start-export-request-watcher.ts b/lib/cmd-fns/dev/start-export-request-watcher.ts index b39f869d..e53754c6 100644 --- a/lib/cmd-fns/dev/start-export-request-watcher.ts +++ b/lib/cmd-fns/dev/start-export-request-watcher.ts @@ -15,7 +15,13 @@ export const startExportRequestWatcher = async ( ;(async () => { while (running) { - await fulfillExportRequests({ dev_server_axios: devServerAxios }, ctx) + try { + await fulfillExportRequests({ dev_server_axios: devServerAxios }, ctx) + } catch (err: any) { + console.log( + kleur.red(`Error in export request watcher: ${err.toString()}`) + ) + } await new Promise((resolve) => setTimeout(resolve, 100)) } })() diff --git a/lib/cmd-fns/init/index.ts b/lib/cmd-fns/init/index.ts index dbe91e99..0ba6e408 100644 --- a/lib/cmd-fns/init/index.ts +++ b/lib/cmd-fns/init/index.ts @@ -111,15 +111,44 @@ export const initCmd = async (ctx: AppContext, args: any) => { mkdirSync("examples", { recursive: true }) mkdirSync("lib", { recursive: true }) + writeFileSync( + Path.join("lib", "MyCircuit.manual-edits.ts"), + ` +/** + * DO NOT EDIT THIS FILE DIRECTLY! + * + * This file is automatically edited when running \`tsci dev\` and dragging things + * around. \`tsci dev\` searches for a file named "*.manual-edits.ts" and edits + * it when you e.g. move a footprint. If there are multiple files, it'll try + * to pick one based on context or ask. + * + * If you're not running \`tsci dev\`, you can safely edit this file. + */ +export default { + // Generated when this file is created, this unique identifier is used to help + // determine which file to edit when there are many *.manual-edits.ts files + manual_edit_id: "abcdef", + + // Manual pcb placements, added when you drag a footprint + pcb_placements: [], +} +`.trim() + ) + writeFileSync( Path.join("lib", "MyCircuit.tsx"), ` + import { layout } from "tscircuit" + import manual_edits from "./MyCircuit.manual-edits" + export const MyCircuit = () => ( - + + + ) `.trim() ) diff --git a/package-lock.json b/package-lock.json index d9311db3..e7b9ea07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "@tscircuit/cli", - "version": "0.0.74", + "version": "0.0.83", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tscircuit/cli", - "version": "0.0.74", + "version": "0.0.83", "license": "ISC", "dependencies": { "@edge-runtime/primitives": "^4.1.0", "@hono/node-server": "^1.8.2", - "@tscircuit/builder": "1.5.69", - "@tscircuit/react-fiber": "^1.0.35", + "@tscircuit/builder": "^1.5.85", + "@tscircuit/react-fiber": "^1.0.39", + "@tscircuit/soup-util": "^0.0.1", "archiver": "^7.0.1", "axios": "^1.6.7", "better-sqlite3": "^9.4.3", @@ -25,6 +26,7 @@ "delay": "^6.0.0", "edgespec": "^0.0.69", "esbuild": "^0.20.2", + "fast-glob": "^3.3.2", "glob": "^10.3.10", "hono": "^4.1.0", "ignore": "^5.3.1", @@ -39,6 +41,7 @@ "prompts": "^2.4.2", "react": "^18.2.0", "semver": "^7.6.0", + "ts-morph": "^22.0.0", "tsup": "^8.0.2", "zod": "latest" }, @@ -889,9 +892,9 @@ } }, "node_modules/@ts-morph/common": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", - "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.23.0.tgz", + "integrity": "sha512-m7Lllj9n/S6sOkCkRftpM7L24uvmfXQFedlW/4hENcuJH1HHm9u5EgxZb9uVjQSCGrbBWBkOGgcTxNg36r6ywA==", "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.3", @@ -914,14 +917,16 @@ } }, "node_modules/@tscircuit/builder": { - "version": "1.5.69", - "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.69.tgz", - "integrity": "sha512-T4XTkzNlL9TPE8LVhwmR0TZzAmQMylX3VpNGf9nhri8HjCtbdQi3eIVR7qRrNngwtxFH/APXd01DUgqIo6xQjQ==", + "version": "1.5.85", + "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.85.tgz", + "integrity": "sha512-QKLkkVGLCuhmN5YgWnpETRGyn3POp+92Eam3CDo0b4qrCYheV7DQoJ87HG4iAPr4WBvUy7NxtAPTeZRVOtccdA==", "dependencies": { "@lume/kiwi": "^0.1.0", "@tscircuit/footprints": "^0.0.14", + "@tscircuit/layout": "^0.0.7", "@tscircuit/routing": "^1.3.1", - "@tscircuit/sparkfun-packages": "^1.2.0", + "@tscircuit/schematic-autolayout": "^0.0.5", + "@tscircuit/sparkfun-packages": "^1.2.1", "convert-units": "^2.3.4", "fast-json-stable-stringify": "^2.1.0", "format-si-prefix": "^0.3.2", @@ -942,6 +947,18 @@ "typescript": "^5.0.0" } }, + "node_modules/@tscircuit/layout": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@tscircuit/layout/-/layout-0.0.7.tgz", + "integrity": "sha512-Jdd6j0+p4yK8zAqFX7dgmb5PT8A9KJduDBhEgAm+OgwDrw3Mp0hQ80pbR2Mvm02UF2Gu9H7TWpMytACCoNqPdA==", + "dependencies": { + "transformation-matrix": "^2.16.1" + }, + "peerDependencies": { + "@tscircuit/builder": "*", + "zod": "*" + } + }, "node_modules/@tscircuit/mm": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@tscircuit/mm/-/mm-0.0.4.tgz", @@ -954,9 +971,9 @@ } }, "node_modules/@tscircuit/react-fiber": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/@tscircuit/react-fiber/-/react-fiber-1.0.35.tgz", - "integrity": "sha512-VGtzN70TvOX7qwajJ2/hYlGcA3bdlulVZndF4APf1+tMVS+MMATKH6luN8ym/97Qh8a0KWBgpGBVEnXYBv0prA==", + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@tscircuit/react-fiber/-/react-fiber-1.0.39.tgz", + "integrity": "sha512-xdEghvKDm9xr5j+zvEH8VVLj6haYCsQ5V8vNOyuXLoc63o7B/Maibsp5Yf6DdoC+SsxYYdZIt8cc0lAj7REfFg==", "dependencies": { "react-reconciler": "^0.29.0" }, @@ -974,10 +991,31 @@ "react-error-boundary": "^4.0.11" } }, + "node_modules/@tscircuit/schematic-autolayout": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@tscircuit/schematic-autolayout/-/schematic-autolayout-0.0.5.tgz", + "integrity": "sha512-I4CtLQfqTPTxDSumnquaJtkJkc16VjLC4bwU3jQdBXwwh9ODzBf88clUznUtDDzwV+BPM5P0W0VCfFhvPL3/Cw==", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-supergrid": "^1.0.10", + "transformation-matrix": "^2.16.1", + "use-mouse-matrix-transform": "^1.1.12" + } + }, + "node_modules/@tscircuit/soup-util": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@tscircuit/soup-util/-/soup-util-0.0.1.tgz", + "integrity": "sha512-hNJayJ/Z+Clms1uAv8j6TCkK2aVNrm/C0PnAUcbSMY3gZfA+os7ovTxS/hCJfC22K4wHoBwsbZ+mE8R3KxaFfQ==", + "peerDependencies": { + "@tscircuit/builder": "*", + "zod": "*" + } + }, "node_modules/@tscircuit/sparkfun-packages": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.0.tgz", - "integrity": "sha512-m+jCOaSBpwRzUN5trc9z5f8yh2zzLITANgNhuNQOtxNZRIrv98iYfL3dSSmf73xknh0Nz68EephNvKVZmproCQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.1.tgz", + "integrity": "sha512-2HzmmHydo5vgoKmNBAHd6RD93LaIMXRSt6t//1zx19/ZwrOA43qVOvb7cCTA82GHib1bSxoL7bqgii9sYudCHw==", "dependencies": { "change-case": "^5.4.3" } @@ -2028,9 +2066,9 @@ } }, "node_modules/code-block-writer": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", - "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==" + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.1.tgz", + "integrity": "sha512-c5or4P6erEA69TxaxTNcHUNcIn+oyxSRTOWV+pSYF+z4epXqNvwvJ70XPGjPNgue83oAFAPBRQYwpAJ/Hpe/Sg==" }, "node_modules/code-excerpt": { "version": "4.0.0", @@ -3069,6 +3107,22 @@ "node": ">=12" } }, + "node_modules/edgespec/node_modules/@ts-morph/common": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", + "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", + "dependencies": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.3", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/edgespec/node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==" + }, "node_modules/edgespec/node_modules/esbuild": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", @@ -3106,6 +3160,29 @@ "@esbuild/win32-x64": "0.19.12" } }, + "node_modules/edgespec/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/edgespec/node_modules/ts-morph": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", + "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", + "dependencies": { + "@ts-morph/common": "~0.22.0", + "code-block-writer": "^12.0.0" + } + }, "node_modules/emittery": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.0.2.tgz", @@ -5130,9 +5207,9 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -5140,6 +5217,18 @@ "node": ">=0.10.0" } }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/react-error-boundary": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", @@ -5166,6 +5255,16 @@ "react": "^18.2.0" } }, + "node_modules/react-supergrid": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/react-supergrid/-/react-supergrid-1.0.10.tgz", + "integrity": "sha512-dJd9wkH6BJkdfkv62EcRAIBn59e2wj58bJFVXiW/ZHQzxz20qIql63fTU2qFMOujXnBIDaMG0uTod67/mjEGeA==", + "peerDependencies": { + "react": "*", + "react-dom": "*", + "transformation-matrix": "*" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -5456,9 +5555,9 @@ ] }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -6087,12 +6186,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/ts-morph": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", - "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-22.0.0.tgz", + "integrity": "sha512-M9MqFGZREyeb5fTl6gNHKZLqBQA0TjA1lea+CR48R8EBTDuWrNqW6ccC5QvjNR4s6wDumD3LTCjOFSp9iwlzaw==", "dependencies": { - "@ts-morph/common": "~0.22.0", - "code-block-writer": "^12.0.0" + "@ts-morph/common": "~0.23.0", + "code-block-writer": "^13.0.1" } }, "node_modules/tslib": { @@ -7048,6 +7147,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/use-mouse-matrix-transform": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/use-mouse-matrix-transform/-/use-mouse-matrix-transform-1.1.13.tgz", + "integrity": "sha512-NsP0j0Ifv9TywhqrNGfIhjpGzuyEzPK553ahn+LBVvZHZ6Gv+2T3tn41pJV6Syos1W7crWKolbP+XLfqa5BpCQ==", + "dependencies": { + "transformation-matrix": "^2.14.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index b38971bf..b52c1c3e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "bootstrap": "bun i && cd dev-server-api && bun i && cd ../dev-server-frontend && bun i", "bootstrap:ci": "bun i --frozen-lockfile && cd dev-server-api && bun i --frozen-lockfile && cd ../dev-server-frontend && bun i --frozen-lockfile", "start": "bun cli.ts", - "start:dev-server:dev": "TSCI_DEV_SERVER_DB=$(pwd)/.tscircuit/dev-server.sqlite concurrently 'cd dev-server-api && bun start' 'cd dev-server-frontend && bun start'", + "dev": "TSCI_DEV_SERVER_DB=$(pwd)/.tscircuit/dev-server.sqlite concurrently 'cd dev-server-api && bun run build && bun start' 'cd dev-server-frontend && bun start' 'bun run dev-with-test-project'", + "clear": "rm -rf .tscircuit", "start:dev-server": "bun build:dev-server && bun cli.ts dev -y --cwd ./tests/assets/example-project", "build:dev-server": "cd dev-server-api && bun run build && cd ../dev-server-frontend && bun run build", "build:dev-server:api": "cd dev-server-api && bun run build", @@ -17,7 +18,7 @@ "build": "bun build:dev-server && npm run build:cli", "dev-with-test-project": "bun cli.ts dev --cwd ./tests/assets/example-project", "test:init": "bun cli.ts init --dir ./tmp/test --name test", - "update-deps": "bun add @tscircuit/builder@latest @tscircuit/react-fiber@latest && cd dev-server-frontend && bun run update-deps" + "update-deps": "npm add @tscircuit/builder@latest @tscircuit/react-fiber@latest && cd dev-server-frontend && npm run update-deps && cd ../tests/assets/example-project && npm add @tscircuit/builder@latest @tscircuit/react-fiber@latest" }, "bin": { "tscircuit": "./dist/cli.js", @@ -35,8 +36,9 @@ "dependencies": { "@edge-runtime/primitives": "^4.1.0", "@hono/node-server": "^1.8.2", - "@tscircuit/builder": "1.5.72", - "@tscircuit/react-fiber": "^1.0.35", + "@tscircuit/builder": "^1.5.85", + "@tscircuit/react-fiber": "^1.0.39", + "@tscircuit/soup-util": "^0.0.1", "archiver": "^7.0.1", "axios": "^1.6.7", "better-sqlite3": "^9.4.3", @@ -49,6 +51,7 @@ "delay": "^6.0.0", "edgespec": "^0.0.69", "esbuild": "^0.20.2", + "fast-glob": "^3.3.2", "glob": "^10.3.10", "hono": "^4.1.0", "ignore": "^5.3.1", @@ -63,6 +66,7 @@ "prompts": "^2.4.2", "react": "^18.2.0", "semver": "^7.6.0", + "ts-morph": "^22.0.0", "tsup": "^8.0.2", "zod": "latest" }, diff --git a/tests/assets/example-project/examples/basic-bug.tsx b/tests/assets/example-project/examples/basic-bug.tsx index 4c1bdce4..64afd280 100644 --- a/tests/assets/example-project/examples/basic-bug.tsx +++ b/tests/assets/example-project/examples/basic-bug.tsx @@ -1,16 +1,22 @@ +import { layout } from "@tscircuit/layout" +import manual_edits from "../src/manual-edits" + export const BasicBug = () => ( - + + + ) diff --git a/tests/assets/example-project/package-lock.json b/tests/assets/example-project/package-lock.json index 20a09970..2175f21e 100644 --- a/tests/assets/example-project/package-lock.json +++ b/tests/assets/example-project/package-lock.json @@ -8,8 +8,8 @@ "name": "example-project", "version": "1.2.26", "dependencies": { - "@tscircuit/builder": "^1.5.61", - "@tscircuit/react-fiber": "^1.0.34" + "@tscircuit/builder": "^1.5.85", + "@tscircuit/react-fiber": "^1.0.39" } }, "node_modules/@babel/runtime": { @@ -29,14 +29,16 @@ "integrity": "sha512-iB+oaYyaVK1hQ0cODubnoSDg4gGYL9cp/4ad7G1b9Z0/IqehPztp5qE3KP2mV9Ns0UYmzwvtkEhTCmKUuhorbg==" }, "node_modules/@tscircuit/builder": { - "version": "1.5.61", - "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.61.tgz", - "integrity": "sha512-pkaIte2C6Kksp3B79eQIG5f0/9KO2x0fdkHe/a0757lMYVUbcSvqjanL7RmJJ983C2wnEMo2au5ycgXvZseMUQ==", + "version": "1.5.85", + "resolved": "https://registry.npmjs.org/@tscircuit/builder/-/builder-1.5.85.tgz", + "integrity": "sha512-QKLkkVGLCuhmN5YgWnpETRGyn3POp+92Eam3CDo0b4qrCYheV7DQoJ87HG4iAPr4WBvUy7NxtAPTeZRVOtccdA==", "dependencies": { "@lume/kiwi": "^0.1.0", "@tscircuit/footprints": "^0.0.14", + "@tscircuit/layout": "^0.0.7", "@tscircuit/routing": "^1.3.1", - "@tscircuit/sparkfun-packages": "^1.2.0", + "@tscircuit/schematic-autolayout": "^0.0.5", + "@tscircuit/sparkfun-packages": "^1.2.1", "convert-units": "^2.3.4", "fast-json-stable-stringify": "^2.1.0", "format-si-prefix": "^0.3.2", @@ -57,6 +59,18 @@ "typescript": "^5.0.0" } }, + "node_modules/@tscircuit/layout": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@tscircuit/layout/-/layout-0.0.7.tgz", + "integrity": "sha512-Jdd6j0+p4yK8zAqFX7dgmb5PT8A9KJduDBhEgAm+OgwDrw3Mp0hQ80pbR2Mvm02UF2Gu9H7TWpMytACCoNqPdA==", + "dependencies": { + "transformation-matrix": "^2.16.1" + }, + "peerDependencies": { + "@tscircuit/builder": "*", + "zod": "*" + } + }, "node_modules/@tscircuit/mm": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@tscircuit/mm/-/mm-0.0.4.tgz", @@ -69,9 +83,9 @@ } }, "node_modules/@tscircuit/react-fiber": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/@tscircuit/react-fiber/-/react-fiber-1.0.34.tgz", - "integrity": "sha512-kI5oOe/dbJGbeWlInx239hXNWPIRMRTgD8pO9IXvAvZ4YOldR6CJanx9DuT5vgTcZTjoswaXJzRJZZB1Ib2jmw==", + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@tscircuit/react-fiber/-/react-fiber-1.0.39.tgz", + "integrity": "sha512-xdEghvKDm9xr5j+zvEH8VVLj6haYCsQ5V8vNOyuXLoc63o7B/Maibsp5Yf6DdoC+SsxYYdZIt8cc0lAj7REfFg==", "dependencies": { "react-reconciler": "^0.29.0" }, @@ -89,10 +103,22 @@ "react-error-boundary": "^4.0.11" } }, + "node_modules/@tscircuit/schematic-autolayout": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@tscircuit/schematic-autolayout/-/schematic-autolayout-0.0.5.tgz", + "integrity": "sha512-I4CtLQfqTPTxDSumnquaJtkJkc16VjLC4bwU3jQdBXwwh9ODzBf88clUznUtDDzwV+BPM5P0W0VCfFhvPL3/Cw==", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-supergrid": "^1.0.10", + "transformation-matrix": "^2.16.1", + "use-mouse-matrix-transform": "^1.1.12" + } + }, "node_modules/@tscircuit/sparkfun-packages": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.0.tgz", - "integrity": "sha512-m+jCOaSBpwRzUN5trc9z5f8yh2zzLITANgNhuNQOtxNZRIrv98iYfL3dSSmf73xknh0Nz68EephNvKVZmproCQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tscircuit/sparkfun-packages/-/sparkfun-packages-1.2.1.tgz", + "integrity": "sha512-2HzmmHydo5vgoKmNBAHd6RD93LaIMXRSt6t//1zx19/ZwrOA43qVOvb7cCTA82GHib1bSxoL7bqgii9sYudCHw==", "dependencies": { "change-case": "^5.4.3" } @@ -359,10 +385,9 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "peer": true, + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -370,6 +395,18 @@ "node": ">=0.10.0" } }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/react-error-boundary": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", @@ -396,6 +433,16 @@ "react": "^18.2.0" } }, + "node_modules/react-supergrid": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/react-supergrid/-/react-supergrid-1.0.10.tgz", + "integrity": "sha512-dJd9wkH6BJkdfkv62EcRAIBn59e2wj58bJFVXiW/ZHQzxz20qIql63fTU2qFMOujXnBIDaMG0uTod67/mjEGeA==", + "peerDependencies": { + "react": "*", + "react-dom": "*", + "transformation-matrix": "*" + } + }, "node_modules/rectilinear-router": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/rectilinear-router/-/rectilinear-router-1.0.1.tgz", @@ -419,9 +466,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -462,6 +509,26 @@ "engines": { "node": ">=14.17" } + }, + "node_modules/use-mouse-matrix-transform": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/use-mouse-matrix-transform/-/use-mouse-matrix-transform-1.1.13.tgz", + "integrity": "sha512-NsP0j0Ifv9TywhqrNGfIhjpGzuyEzPK553ahn+LBVvZHZ6Gv+2T3tn41pJV6Syos1W7crWKolbP+XLfqa5BpCQ==", + "dependencies": { + "transformation-matrix": "^2.14.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/zod": { + "version": "3.23.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.6.tgz", + "integrity": "sha512-RTHJlZhsRbuA8Hmp/iNL7jnfc4nZishjsanDAfEY1QpDQZCahUp3xDzl+zfweE9BklxMUcgBgS1b7Lvie/ZVwA==", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/tests/assets/example-project/package.json b/tests/assets/example-project/package.json index 43342b1f..761811f0 100644 --- a/tests/assets/example-project/package.json +++ b/tests/assets/example-project/package.json @@ -4,7 +4,7 @@ "type": "module", "main": "dist/index.js", "dependencies": { - "@tscircuit/builder": "^1.5.61", - "@tscircuit/react-fiber": "^1.0.34" + "@tscircuit/builder": "^1.5.85", + "@tscircuit/react-fiber": "^1.0.39" } } diff --git a/tests/assets/example-project/src/MyCircuit.tsx b/tests/assets/example-project/src/MyCircuit.tsx index 088144a9..03359134 100644 --- a/tests/assets/example-project/src/MyCircuit.tsx +++ b/tests/assets/example-project/src/MyCircuit.tsx @@ -1,7 +1,15 @@ import "@tscircuit/react-fiber" +import { layout } from "@tscircuit/layout" +import manual_edits from "./manual-edits" export const MyCircuit = () => ( - +