mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
📚 Add GitHub Copilot instructions (#8548)
This commit is contained in:
parent
adc3fa41e9
commit
05c71f7b75
42
.github/workflows/tests.yml
vendored
42
.github/workflows/tests.yml
vendored
@ -28,9 +28,47 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Check clojure code format
|
- name: Lint Common
|
||||||
|
working-directory: ./common
|
||||||
run: |
|
run: |
|
||||||
./scripts/lint
|
corepack enable;
|
||||||
|
corepack install;
|
||||||
|
pnpm install;
|
||||||
|
pnpm run lint:clj
|
||||||
|
|
||||||
|
- name: Lint Frontend
|
||||||
|
working-directory: ./frontend
|
||||||
|
run: |
|
||||||
|
corepack enable;
|
||||||
|
corepack install;
|
||||||
|
pnpm install;
|
||||||
|
pnpm run lint:clj
|
||||||
|
pnpm run lint:js
|
||||||
|
pnpm run lint:scss
|
||||||
|
|
||||||
|
- name: Lint Backend
|
||||||
|
working-directory: ./backend
|
||||||
|
run: |
|
||||||
|
corepack enable;
|
||||||
|
corepack install;
|
||||||
|
pnpm install;
|
||||||
|
pnpm run lint:clj
|
||||||
|
|
||||||
|
- name: Lint Exporter
|
||||||
|
working-directory: ./exporter
|
||||||
|
run: |
|
||||||
|
corepack enable;
|
||||||
|
corepack install;
|
||||||
|
pnpm install;
|
||||||
|
pnpm run lint:clj
|
||||||
|
|
||||||
|
- name: Lint Library
|
||||||
|
working-directory: ./library
|
||||||
|
run: |
|
||||||
|
corepack enable;
|
||||||
|
corepack install;
|
||||||
|
pnpm install;
|
||||||
|
pnpm run lint:clj
|
||||||
|
|
||||||
test-common:
|
test-common:
|
||||||
name: "Common Tests"
|
name: "Common Tests"
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -35,6 +35,7 @@
|
|||||||
/notes
|
/notes
|
||||||
/playground/
|
/playground/
|
||||||
/backend/*.md
|
/backend/*.md
|
||||||
|
!/backend/AGENTS.md
|
||||||
/backend/*.sql
|
/backend/*.sql
|
||||||
/backend/*.txt
|
/backend/*.txt
|
||||||
/backend/assets/
|
/backend/assets/
|
||||||
|
|||||||
265
AGENTS.md
Normal file
265
AGENTS.md
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# Penpot – Copilot Instructions
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
Penpot is a full-stack design tool composed of several distinct components:
|
||||||
|
|
||||||
|
| Component | Language | Role |
|
||||||
|
|-----------|----------|------|
|
||||||
|
| `frontend/` | ClojureScript + SCSS | Single-page React app (design editor) |
|
||||||
|
| `backend/` | Clojure (JVM) | HTTP/RPC server, PostgreSQL, Redis |
|
||||||
|
| `common/` | Cljc (shared Clojure/ClojureScript) | Data types, geometry, schemas, utilities |
|
||||||
|
| `exporter/` | ClojureScript (Node.js) | Headless Playwright-based export (SVG/PDF) |
|
||||||
|
| `render-wasm/` | Rust → WebAssembly | High-performance canvas renderer using Skia |
|
||||||
|
| `mcp/` | TypeScript | Model Context Protocol integration |
|
||||||
|
| `plugins/` | TypeScript | Plugin runtime and example plugins |
|
||||||
|
|
||||||
|
The monorepo is managed with `pnpm` workspaces. The `manage.sh`
|
||||||
|
orchestrates cross-component builds. `run-ci.sh` defines the CI
|
||||||
|
pipeline.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build, Test & Lint Commands
|
||||||
|
|
||||||
|
### Frontend (`cd frontend`)
|
||||||
|
|
||||||
|
Run `./scripts/setup` for setup all dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dev
|
||||||
|
pnpm run watch:app # Full dev build (WASM + CLJS + assets)
|
||||||
|
|
||||||
|
# Production Build
|
||||||
|
./scripts/build
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
pnpm run test # Build ClojureScript tests + run node target/tests/test.js
|
||||||
|
pnpm run watch:test # Watch + auto-rerun on change
|
||||||
|
pnpm run test:e2e # Playwright e2e tests
|
||||||
|
pnpm run test:e2e --grep "pattern" # Single e2e test by pattern
|
||||||
|
|
||||||
|
# Lint
|
||||||
|
pnpm run lint:js # format and linter check for JS
|
||||||
|
pnpm run lint:clj # format and linter check for CLJ
|
||||||
|
pnpm run lint:scss # prettier check for SCSS
|
||||||
|
|
||||||
|
# Code formatting
|
||||||
|
pnpm run fmt:clj # Format CLJ
|
||||||
|
pnpm run fmt:js # prettier for JS
|
||||||
|
pnpm run fmt:scss # prettier for SCSS
|
||||||
|
```
|
||||||
|
|
||||||
|
To run a focused ClojureScript unit test: edit
|
||||||
|
`test/frontend_tests/runner.cljs` to narrow the test suite, then `pnpm
|
||||||
|
run build:test && node target/tests/test.js`.
|
||||||
|
|
||||||
|
|
||||||
|
### Backend (`cd backend`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tests (Kaocha)
|
||||||
|
clojure -M:dev:test # Full suite
|
||||||
|
clojure -M:dev:test --focus backend-tests.my-ns-test # Single namespace
|
||||||
|
|
||||||
|
# Lint / Format
|
||||||
|
pnpm run lint:clj
|
||||||
|
pnpm run fmt:clj
|
||||||
|
```
|
||||||
|
|
||||||
|
Test config is in `backend/tests.edn`; test namespaces match `.*-test$` under `test/`.
|
||||||
|
|
||||||
|
|
||||||
|
### Common (`cd common`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm run test # Build + run node target/tests/test.js
|
||||||
|
pnpm run watch:test # Watch mode
|
||||||
|
pnpm run lint:clj
|
||||||
|
pnpm run fmt:clj
|
||||||
|
```
|
||||||
|
|
||||||
|
### Render-WASM (`cd render-wasm`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./test # Rust unit tests (cargo test)
|
||||||
|
./build # Compile to WASM (requires Emscripten)
|
||||||
|
cargo fmt --check
|
||||||
|
./lint --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
|
||||||
|
### Namespace Structure
|
||||||
|
|
||||||
|
**Backend:**
|
||||||
|
- `app.rpc.commands.*` – RPC command implementations (`auth`, `files`, `teams`, etc.)
|
||||||
|
- `app.http.*` – HTTP routes and middleware
|
||||||
|
- `app.db.*` – Database layer
|
||||||
|
- `app.tasks.*` – Background job tasks
|
||||||
|
- `app.main` – Integrant system setup and entrypoint
|
||||||
|
- `app.loggers` – Internal loggers (auditlog, mattermost, etc) (do not be confused with `app.common.loggin`)
|
||||||
|
|
||||||
|
**Frontend:**
|
||||||
|
- `app.main.ui.*` – React UI components (`workspace`, `dashboard`, `viewer`)
|
||||||
|
- `app.main.data.*` – Potok event handlers (state mutations + side effects)
|
||||||
|
- `app.main.refs` – Reactive subscriptions (okulary lenses)
|
||||||
|
- `app.main.store` – Potok event store
|
||||||
|
- `app.util.*` – Utilities (DOM, HTTP, i18n, keyboard shortcuts)
|
||||||
|
|
||||||
|
**Common:**
|
||||||
|
- `app.common.types.*` – Shared data types for shapes, files, pages
|
||||||
|
- `app.common.schema` – Malli validation schemas
|
||||||
|
- `app.common.geom.*` – Geometry utilities
|
||||||
|
- `app.common.data.macros` – Performance macros used everywhere
|
||||||
|
|
||||||
|
### Backend RPC Commands
|
||||||
|
|
||||||
|
All API calls go through a single RPC endpoint: `POST /api/rpc/command/<cmd-name>`.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(sv/defmethod ::my-command
|
||||||
|
{::rpc/auth true ;; requires auth
|
||||||
|
::doc/added "1.18"
|
||||||
|
::sm/params [:map ...] ;; malli input schema
|
||||||
|
::sm/result [:map ...]} ;; malli output schema
|
||||||
|
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id] :as params}]
|
||||||
|
;; return a plain map or throw
|
||||||
|
{:id (uuid/next)})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend State Management (Potok)
|
||||||
|
|
||||||
|
State is a single atom managed by a Potok store. Events implement protocols:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(defn my-event [data]
|
||||||
|
(ptk/reify ::my-event
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state] ;; synchronous state transition
|
||||||
|
(assoc state :key data))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream] ;; async: returns an observable
|
||||||
|
(->> (rp/cmd! :some-rpc-command params)
|
||||||
|
(rx/map success-event)
|
||||||
|
(rx/catch error-handler)))
|
||||||
|
|
||||||
|
ptk/EffectEvent
|
||||||
|
(effect [_ state _] ;; pure side effects (DOM, logging)
|
||||||
|
(.focus (dom/get-element "id")))))
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispatch with `(st/emit! (my-event data))`. Read state via reactive
|
||||||
|
refs: `(deref refs/selected-shapes)`. Prefer helpers from
|
||||||
|
`app.util.dom` instead of using direct dom calls, if no helper is
|
||||||
|
available, prefer adding a new helper for handling it and the use the
|
||||||
|
new helper.
|
||||||
|
|
||||||
|
|
||||||
|
### CSS Modules Pattern
|
||||||
|
|
||||||
|
Styles are co-located with components. Each `.cljs` file has a corresponding `.scss` file:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; In the component namespace:
|
||||||
|
(require '[app.main.style :as stl])
|
||||||
|
|
||||||
|
;; In the render function:
|
||||||
|
[:div {:class (stl/css :container :active)}]
|
||||||
|
|
||||||
|
;; Conditional:
|
||||||
|
[:div {:class (stl/css-case :some-class true :selected (= drawtool :rect))}]
|
||||||
|
|
||||||
|
;; When you need concat an existing class:
|
||||||
|
[:div {:class [existing-class (stl/css-case :some-class true :selected (= drawtool :rect))]}]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Macros (`app.common.data.macros`)
|
||||||
|
|
||||||
|
Always prefer these macros over their `clojure.core` equivalents — they compile to faster JavaScript:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(dm/select-keys m [:a :b]) ;; ~6x faster than core/select-keys
|
||||||
|
(dm/get-in obj [:a :b :c]) ;; faster than core/get-in
|
||||||
|
(dm/str "a" "b" "c") ;; string concatenation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shared Code (cljc)
|
||||||
|
|
||||||
|
Files in `common/src/app/common/` use reader conditionals to target both runtimes:
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
#?(:clj (import java.util.UUID)
|
||||||
|
:cljs (:require [cljs.core :as core]))
|
||||||
|
```
|
||||||
|
|
||||||
|
Both frontend and backend depend on `common` as a local library (`penpot/common {:local/root "../common"}`).
|
||||||
|
|
||||||
|
|
||||||
|
### Component Definition (Rumext / React)
|
||||||
|
|
||||||
|
The codebase has several kind of components, some of them use legacy
|
||||||
|
syntax. The current and the most recent syntax uses `*` suffix on the
|
||||||
|
name. This indicates to the `mf/defc` macro apply concrete rules on
|
||||||
|
how props should be treated.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(mf/defc my-component*
|
||||||
|
{::mf/wrap [mf/memo]} ;; React.memo
|
||||||
|
[{:keys [name on-click]}]
|
||||||
|
[:div {:class (stl/css :root)
|
||||||
|
:on-click on-click}
|
||||||
|
name])
|
||||||
|
```
|
||||||
|
|
||||||
|
Hooks: `(mf/use-state)`, `(mf/use-effect)`, `(mf/use-memo)` – analgous to react hooks.
|
||||||
|
|
||||||
|
|
||||||
|
The component usage should always follow the `[:> my-component*
|
||||||
|
props]`, where props should be a map literal or symbol pointing to
|
||||||
|
javascript props objects. The javascript props object can be created
|
||||||
|
manually `#js {:data-foo "bar"}` or using `mf/spread-object` helper
|
||||||
|
macro.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commit Guidelines
|
||||||
|
|
||||||
|
Format: `<emoji-code> <subject>`
|
||||||
|
|
||||||
|
```
|
||||||
|
:bug: Fix unexpected error on launching modal
|
||||||
|
|
||||||
|
Optional body explaining the why.
|
||||||
|
|
||||||
|
Signed-off-by: Fullname <email>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Subject rules:** imperative mood, capitalize first letter, no
|
||||||
|
trailing period, ≤ 80 characters. Add an entry to `CHANGES.md` if
|
||||||
|
applicable.
|
||||||
|
|
||||||
|
**Code patches must include a DCO sign-off** (`git commit -s`).
|
||||||
|
|
||||||
|
| Emoji | Emoji-Code | Use for |
|
||||||
|
|-------|------|---------|
|
||||||
|
| 🐛 | `:bug:` | Bug fix |
|
||||||
|
| ✨ | `:sparkles:` | Improvement |
|
||||||
|
| 🎉 | `:tada:` | New feature |
|
||||||
|
| ♻️ | `:recycle:` | Refactor |
|
||||||
|
| 💄 | `:lipstick:` | Cosmetic changes |
|
||||||
|
| 🚑 | `:ambulance:` | Critical bug fix |
|
||||||
|
| 📚 | `:books:` | Docs |
|
||||||
|
| 🚧 | `:construction:` | WIP |
|
||||||
|
| 💥 | `:boom:` | Breaking change |
|
||||||
|
| 🔧 | `:wrench:` | Config update |
|
||||||
|
| ⚡ | `:zap:` | Performance |
|
||||||
|
| 🐳 | `:whale:` | Docker |
|
||||||
|
| 📎 | `:paperclip:` | Other non-relevant changes |
|
||||||
|
| ⬆️ | `:arrow_up:` | Dependency upgrade |
|
||||||
|
| ⬇️ | `:arrow_down:` | Dependency downgrade |
|
||||||
|
| 🔥 | `:fire:` | Remove files or code |
|
||||||
|
| 🌐 | `:globe_with_meridians:` | Translations |
|
||||||
87
backend/AGENTS.md
Normal file
87
backend/AGENTS.md
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# backend – Agent Instructions
|
||||||
|
|
||||||
|
Clojure service running on the JVM. Uses Integrant for dependency injection, PostgreSQL for storage, and Redis for messaging/caching.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# REPL (primary dev workflow)
|
||||||
|
./scripts/repl # Start nREPL + load dev/user.clj utilities
|
||||||
|
|
||||||
|
# Tests (Kaocha)
|
||||||
|
clojure -M:dev:test # Full suite
|
||||||
|
clojure -M:dev:test --focus backend-tests.my-ns-test # Single namespace
|
||||||
|
|
||||||
|
# Lint / Format
|
||||||
|
pnpm run lint:clj
|
||||||
|
pnpm run fmt:clj
|
||||||
|
```
|
||||||
|
|
||||||
|
Test namespaces match `.*-test$` under `test/`. Config is in `tests.edn`.
|
||||||
|
|
||||||
|
## Integrant System
|
||||||
|
|
||||||
|
`src/app/main.clj` declares the system map. Each key is a component;
|
||||||
|
values are config maps with `::ig/ref` for dependencies. Components
|
||||||
|
implement `ig/init-key` / `ig/halt-key!`.
|
||||||
|
|
||||||
|
From the REPL (`dev/user.clj` is auto-loaded):
|
||||||
|
```clojure
|
||||||
|
(start!) ; boot the system
|
||||||
|
(stop!) ; halt the system
|
||||||
|
(restart!) ; stop + reload namespaces + start
|
||||||
|
```
|
||||||
|
|
||||||
|
## RPC Commands
|
||||||
|
|
||||||
|
All API calls: `POST /api/rpc/command/<cmd-name>`.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(sv/defmethod ::my-command
|
||||||
|
{::rpc/auth true ;; requires authentication (default)
|
||||||
|
::doc/added "1.18"
|
||||||
|
::sm/params [:map ...] ;; malli input schema
|
||||||
|
::sm/result [:map ...]} ;; malli output schema
|
||||||
|
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id] :as params}]
|
||||||
|
;; return a plain map; throw via ex/raise for errors
|
||||||
|
{:id (uuid/next)})
|
||||||
|
```
|
||||||
|
|
||||||
|
Add new commands in `src/app/rpc/commands/`.
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
`app.db` wraps next.jdbc. Queries use a SQL builder that auto-converts kebab-case ↔ snake_case.
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
;; Query helpers
|
||||||
|
(db/get pool :table {:id id}) ; fetch one row (throws if missing)
|
||||||
|
(db/get* pool :table {:id id}) ; fetch one row (returns nil)
|
||||||
|
(db/query pool :table {:team-id team-id}) ; fetch multiple rows
|
||||||
|
(db/insert! pool :table {:name "x" :team-id id}) ; insert
|
||||||
|
(db/update! pool :table {:name "y"} {:id id}) ; update
|
||||||
|
(db/delete! pool :table {:id id}) ; delete
|
||||||
|
;; Transactions
|
||||||
|
(db/tx-run cfg (fn [{:keys [::db/conn]}]
|
||||||
|
(db/insert! conn :table row)))
|
||||||
|
```
|
||||||
|
|
||||||
|
Almost all methods on `app.db` namespace accepts `pool`, `conn` or
|
||||||
|
`cfg` as params.
|
||||||
|
|
||||||
|
Migrations live in `src/app/migrations/` as numbered SQL files. They run automatically on startup.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(ex/raise :type :not-found
|
||||||
|
:code :object-not-found
|
||||||
|
:hint "File does not exist"
|
||||||
|
:context {:id file-id})
|
||||||
|
```
|
||||||
|
|
||||||
|
Common types: `:not-found`, `:validation`, `:authorization`, `:conflict`, `:internal`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
`src/app/config.clj` reads `PENPOT_*` environment variables, validated with Malli. Access anywhere via `(cf/get :smtp-host)`. Feature flags: `(cf/flags :enable-smtp)`.
|
||||||
@ -19,8 +19,7 @@
|
|||||||
"ws": "^8.17.0"
|
"ws": "^8.17.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
"lint:clj": "cljfmt check --parallel=false src/ test/ && clj-kondo --parallel --lint src/",
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
"fmt:clj": "cljfmt fix --parallel=true src/ test/"
|
||||||
"lint:clj": "clj-kondo --parallel --lint src/"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,8 @@
|
|||||||
"date-fns": "^4.1.0"
|
"date-fns": "^4.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
"lint:clj": "cljfmt check --parallel=false src/ test/ && clj-kondo --parallel=true --lint src/",
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||||
"lint:clj": "clj-kondo --parallel=true --lint src/",
|
|
||||||
"lint": "pnpm run lint:clj",
|
"lint": "pnpm run lint:clj",
|
||||||
"watch:test": "concurrently \"clojure -M:dev:shadow-cljs watch test\" \"nodemon -C -d 2 -w target/tests/ --exec 'node target/tests/test.js'\"",
|
"watch:test": "concurrently \"clojure -M:dev:shadow-cljs watch test\" \"nodemon -C -d 2 -w target/tests/ --exec 'node target/tests/test.js'\"",
|
||||||
"build:test": "clojure -M:dev:shadow-cljs compile test",
|
"build:test": "clojure -M:dev:shadow-cljs compile test",
|
||||||
|
|||||||
@ -34,8 +34,7 @@
|
|||||||
"watch": "pnpm run watch:app",
|
"watch": "pnpm run watch:app",
|
||||||
"build:app": "clojure -M:dev:shadow-cljs release main",
|
"build:app": "clojure -M:dev:shadow-cljs release main",
|
||||||
"build": "pnpm run clear:shadow-cache && pnpm run build:app",
|
"build": "pnpm run clear:shadow-cache && pnpm run build:app",
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/",
|
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/",
|
"fmt:clj": "cljfmt fix --parallel=true src/",
|
||||||
"lint:clj": "clj-kondo --parallel --lint src/"
|
"lint:clj": "cljfmt check --parallel src/ && clj-kondo --parallel --lint src/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,12 +24,11 @@
|
|||||||
"build:app:worker": "clojure -M:dev:shadow-cljs release worker",
|
"build:app:worker": "clojure -M:dev:shadow-cljs release worker",
|
||||||
"build:app": "pnpm run clear:shadow-cache && pnpm run build:app:main && pnpm run build:app:libs",
|
"build:app": "pnpm run clear:shadow-cache && pnpm run build:app:main && pnpm run build:app:libs",
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
"fmt:js": "prettier -c src/**/*.stories.jsx -c playwright/**/*.js -c scripts/**/*.js -c text-editor/**/*.js -w",
|
||||||
"fmt:js": "pnpx prettier -c src/**/*.stories.jsx -c playwright/**/*.js -c scripts/**/*.js -c text-editor/**/*.js -w",
|
"fmt:scss": "prettier -c resources/styles -c src/**/*.scss -w",
|
||||||
"fmt:js:check": "pnpx prettier -c src/**/*.stories.jsx -c playwright/**/*.js -c scripts/**/*.js text-editor/**/*.js",
|
"lint:clj": "cljfmt check --parallel=false src/ test/ && clj-kondo --parallel --lint src/",
|
||||||
"lint:clj": "clj-kondo --parallel --lint src/",
|
"lint:js": "prettier -c src/**/*.stories.jsx -c playwright/**/*.js -c scripts/**/*.js text-editor/**/*.js",
|
||||||
"lint:scss": "pnpx prettier -c resources/styles -c src/**/*.scss",
|
"lint:scss": "prettier -c resources/styles -c src/**/*.scss",
|
||||||
"lint:scss:fix": "pnpx prettier -c resources/styles -c src/**/*.scss -w",
|
|
||||||
"build:test": "clojure -M:dev:shadow-cljs compile test",
|
"build:test": "clojure -M:dev:shadow-cljs compile test",
|
||||||
"test": "pnpm run build:test && node target/tests/test.js",
|
"test": "pnpm run build:test && node target/tests/test.js",
|
||||||
"test:storybook": "vitest run --project=storybook",
|
"test:storybook": "vitest run --project=storybook",
|
||||||
|
|||||||
@ -5,14 +5,17 @@ import { readFile } from "node:fs/promises";
|
|||||||
* esbuild plugin to watch a directory recursively
|
* esbuild plugin to watch a directory recursively
|
||||||
*/
|
*/
|
||||||
const watchExtraDirPlugin = {
|
const watchExtraDirPlugin = {
|
||||||
name: 'watch-extra-dir',
|
name: "watch-extra-dir",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
build.onLoad({ filter: /target\/index.js/, namespace: 'file' }, async (args) => {
|
build.onLoad(
|
||||||
return {
|
{ filter: /target\/index.js/, namespace: "file" },
|
||||||
watchDirs: ["packages/ui/dist"],
|
async (args) => {
|
||||||
};
|
return {
|
||||||
});
|
watchDirs: ["packages/ui/dist"],
|
||||||
}
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const filter =
|
const filter =
|
||||||
|
|||||||
@ -27,8 +27,7 @@
|
|||||||
"build": "pnpm run clear:shadow-cache && clojure -M:dev:shadow-cljs release library",
|
"build": "pnpm run clear:shadow-cache && clojure -M:dev:shadow-cljs release library",
|
||||||
"build:bundle": "./scripts/build",
|
"build:bundle": "./scripts/build",
|
||||||
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
|
||||||
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
|
"lint:clj": "cljfmt check --parallel=false src/ test/ && clj-kondo --parallel --lint src/",
|
||||||
"lint:clj": "clj-kondo --parallel --lint src/",
|
|
||||||
"test": "node --test",
|
"test": "node --test",
|
||||||
"watch:test": "node --test --watch",
|
"watch:test": "node --test --watch",
|
||||||
"watch": "pnpm run clear:shadow-cache && clojure -M:dev:shadow-cljs watch library"
|
"watch": "pnpm run clear:shadow-cache && clojure -M:dev:shadow-cljs watch library"
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"fmt": "./scripts/fmt"
|
"fmt": "./scripts/fmt"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@github/copilot": "^1.0.2",
|
||||||
"@types/node": "^20.12.7",
|
"@types/node": "^20.12.7",
|
||||||
"esbuild": "^0.25.9"
|
"esbuild": "^0.25.9"
|
||||||
}
|
}
|
||||||
|
|||||||
370
pnpm-lock.yaml
generated
Normal file
370
pnpm-lock.yaml
generated
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
devDependencies:
|
||||||
|
'@github/copilot':
|
||||||
|
specifier: ^1.0.2
|
||||||
|
version: 1.0.2
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^20.12.7
|
||||||
|
version: 20.19.37
|
||||||
|
esbuild:
|
||||||
|
specifier: ^0.25.9
|
||||||
|
version: 0.25.12
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@github/copilot-darwin-arm64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-dYoeaTidsphRXyMjvAgpjEbBV41ipICnXURrLFEiATcjC4IY6x2BqPOocrExBYW/Tz2VZvDw51iIZaf6GXrTmw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot-darwin-x64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-8+Z9dYigEfXf0wHl9c2tgFn8Cr6v4RAY8xTgHMI9mZInjQyxVeBXCxbE2VgzUtDUD3a705Ka2d8ZOz05aYtGsg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot-linux-arm64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-ik0Y5aTXOFRPLFrNjZJdtfzkozYqYeJjVXGBAH3Pp1nFZRu/pxJnrnQ1HrqO/LEgQVbJzAjQmWEfMbXdQIxE4Q==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot-linux-x64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-mHSPZjH4nU9rwbfwLxYJ7CQ90jK/Qu1v2CmvBCUPfmuGdVwrpGPHB5FrB+f+b0NEXjmemDWstk2zG53F7ppHfw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot-win32-arm64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-tLW2CY/vg0fYLp8EuiFhWIHBVzbFCDDpohxT/F/XyMAdTVSZLnopCcxQHv2BOu0CVGrYjlf7YOIwPfAKYml1FA==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot-win32-x64@1.0.2':
|
||||||
|
resolution: {integrity: sha512-cFlc3xMkKKFRIYR00EEJ2XlYAemeh5EZHsGA8Ir2G0AH+DOevJbomdP1yyCC5gaK/7IyPkHX3sGie5sER2yPvQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@github/copilot@1.0.2':
|
||||||
|
resolution: {integrity: sha512-716SIZMYftldVcJay2uZOzsa9ROGGb2Mh2HnxbDxoisFsWNNgZlQXlV7A+PYoGsnAo2Zk/8e1i5SPTscGf2oww==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@types/node@20.19.37':
|
||||||
|
resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==}
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
undici-types@6.21.0:
|
||||||
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-darwin-arm64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-darwin-x64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-linux-arm64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-linux-x64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-win32-arm64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot-win32-x64@1.0.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@github/copilot@1.0.2':
|
||||||
|
optionalDependencies:
|
||||||
|
'@github/copilot-darwin-arm64': 1.0.2
|
||||||
|
'@github/copilot-darwin-x64': 1.0.2
|
||||||
|
'@github/copilot-linux-arm64': 1.0.2
|
||||||
|
'@github/copilot-linux-x64': 1.0.2
|
||||||
|
'@github/copilot-win32-arm64': 1.0.2
|
||||||
|
'@github/copilot-win32-x64': 1.0.2
|
||||||
|
|
||||||
|
'@types/node@20.19.37':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 6.21.0
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.25.12
|
||||||
|
'@esbuild/android-arm': 0.25.12
|
||||||
|
'@esbuild/android-arm64': 0.25.12
|
||||||
|
'@esbuild/android-x64': 0.25.12
|
||||||
|
'@esbuild/darwin-arm64': 0.25.12
|
||||||
|
'@esbuild/darwin-x64': 0.25.12
|
||||||
|
'@esbuild/freebsd-arm64': 0.25.12
|
||||||
|
'@esbuild/freebsd-x64': 0.25.12
|
||||||
|
'@esbuild/linux-arm': 0.25.12
|
||||||
|
'@esbuild/linux-arm64': 0.25.12
|
||||||
|
'@esbuild/linux-ia32': 0.25.12
|
||||||
|
'@esbuild/linux-loong64': 0.25.12
|
||||||
|
'@esbuild/linux-mips64el': 0.25.12
|
||||||
|
'@esbuild/linux-ppc64': 0.25.12
|
||||||
|
'@esbuild/linux-riscv64': 0.25.12
|
||||||
|
'@esbuild/linux-s390x': 0.25.12
|
||||||
|
'@esbuild/linux-x64': 0.25.12
|
||||||
|
'@esbuild/netbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/netbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/openbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openharmony-arm64': 0.25.12
|
||||||
|
'@esbuild/sunos-x64': 0.25.12
|
||||||
|
'@esbuild/win32-arm64': 0.25.12
|
||||||
|
'@esbuild/win32-ia32': 0.25.12
|
||||||
|
'@esbuild/win32-x64': 0.25.12
|
||||||
|
|
||||||
|
undici-types@6.21.0: {}
|
||||||
61
render-wasm/AGENTS.md
Normal file
61
render-wasm/AGENTS.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# render-wasm – Agent Instructions
|
||||||
|
|
||||||
|
This component compiles Rust to WebAssembly using Emscripten + Skia. It is consumed by the frontend as a canvas renderer.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build # Compile Rust → WASM (requires Emscripten environment)
|
||||||
|
./watch # Incremental rebuild on file change
|
||||||
|
./test # Run Rust unit tests (cargo test)
|
||||||
|
./lint # clippy -D warnings
|
||||||
|
cargo fmt --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Run a single test:
|
||||||
|
```bash
|
||||||
|
cargo test my_test_name # by test function name
|
||||||
|
cargo test shapes:: # by module prefix
|
||||||
|
```
|
||||||
|
|
||||||
|
Build output lands in `../frontend/resources/public/js/` (consumed directly by the frontend dev server).
|
||||||
|
|
||||||
|
## Build Environment
|
||||||
|
|
||||||
|
The `_build_env` script sets required env vars (Emscripten paths,
|
||||||
|
`EMCC_CFLAGS`). `./build` sources it automatically. The WASM heap is
|
||||||
|
configured to 256 MB initial with geometric growth.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**Global state** — a single `unsafe static mut State` accessed
|
||||||
|
exclusively through `with_state!` / `with_state_mut!` macros. Never
|
||||||
|
access it directly.
|
||||||
|
|
||||||
|
**Tile-based rendering** — only 512×512 tiles within the viewport
|
||||||
|
(plus a pre-render buffer) are drawn each frame. Tiles outside the
|
||||||
|
range are skipped.
|
||||||
|
|
||||||
|
**Two-phase updates** — shape data is written via exported setter
|
||||||
|
functions (called from ClojureScript), then a single `render_frame()`
|
||||||
|
triggers the actual Skia draw calls.
|
||||||
|
|
||||||
|
**Shape hierarchy** — shapes live in a flat pool indexed by UUID;
|
||||||
|
parent/child relationships are tracked separately.
|
||||||
|
|
||||||
|
## Key Source Modules
|
||||||
|
|
||||||
|
| Path | Role |
|
||||||
|
|------|------|
|
||||||
|
| `src/lib.rs` | WASM exports — all functions callable from JS |
|
||||||
|
| `src/state.rs` | Global `State` struct definition |
|
||||||
|
| `src/render/` | Tile rendering pipeline, Skia surface management |
|
||||||
|
| `src/shapes/` | Shape types and Skia draw logic per shape |
|
||||||
|
| `src/wasm/` | JS interop helpers (memory, string encoding) |
|
||||||
|
|
||||||
|
## Frontend Integration
|
||||||
|
|
||||||
|
The WASM module is loaded by `app.render-wasm.*` namespaces in the
|
||||||
|
frontend. ClojureScript calls exported Rust functions to push shape
|
||||||
|
data, then calls `render_frame`. Do not change export function
|
||||||
|
signatures without updating the ClojureScript bridge.
|
||||||
50
run-ci.sh
50
run-ci.sh
@ -1,50 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "################ test common ################"
|
|
||||||
pushd common
|
|
||||||
pnpm install
|
|
||||||
pnpm run fmt:clj:check
|
|
||||||
pnpm run lint:clj
|
|
||||||
clojure -M:dev:test
|
|
||||||
pnpm run test
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "################ test frontend ################"
|
|
||||||
pushd frontend
|
|
||||||
pnpm install
|
|
||||||
pnpm run fmt:clj:check
|
|
||||||
pnpm run fmt:js:check
|
|
||||||
pnpm run lint:scss
|
|
||||||
pnpm run lint:clj
|
|
||||||
pnpm run test
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "################ test integration ################"
|
|
||||||
pushd frontend
|
|
||||||
pnpm install
|
|
||||||
pnpm run test:e2e -x --workers=4
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "################ test backend ################"
|
|
||||||
pushd backend
|
|
||||||
pnpm install
|
|
||||||
pnpm run fmt:clj:check
|
|
||||||
pnpm run lint:clj
|
|
||||||
clojure -M:dev:test --reporter kaocha.report/documentation
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "################ test exporter ################"
|
|
||||||
pushd exporter
|
|
||||||
pnpm install
|
|
||||||
pnpm run fmt:clj:check
|
|
||||||
pnpm run lint:clj
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "################ test render-wasm ################"
|
|
||||||
pushd render-wasm
|
|
||||||
cargo fmt --check
|
|
||||||
./lint --debug
|
|
||||||
./test
|
|
||||||
popd
|
|
||||||
Loading…
x
Reference in New Issue
Block a user