@mertdogar/phaser-procedural-walls 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Wallcraft Prototype</title>
7
- <script type="module" crossorigin src="/assets/index-DvPiYA-G.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-BIMJ5usj.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-BVmRKDUb.css">
9
9
  </head>
10
10
  <body>
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { WallMapPlugin } from "./WallMapPlugin";
2
2
  export { WallMap } from "./WallMap";
3
+ export { WallEditor } from "./WallEditor";
4
+ export type { WallEditorCallbacks, WallEditorOptions, WallEditorState, WallEditorTool } from "./WallEditor";
3
5
  export { resolveWalls } from "./geometry";
4
6
  export type * from "./types";
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- var g = Object.defineProperty;
2
- var x = (n, t, i) => t in n ? g(n, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : n[t] = i;
3
- var a = (n, t, i) => x(n, typeof t != "symbol" ? t + "" : t, i);
4
- import b from "phaser";
5
- import { resolveWalls as p } from "./geometry.js";
6
- class R {
1
+ var m = Object.defineProperty;
2
+ var S = (f, t, i) => t in f ? m(f, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : f[t] = i;
3
+ var a = (f, t, i) => S(f, typeof t != "symbol" ? t + "" : t, i);
4
+ import h from "phaser";
5
+ import { resolveWalls as g } from "./geometry.js";
6
+ class D {
7
7
  constructor(t, i) {
8
8
  a(this, "scene");
9
9
  a(this, "containers", []);
@@ -26,47 +26,276 @@ class R {
26
26
  this.containers = [], (t = this.bodies) == null || t.destroy(!0), this.bodies = null;
27
27
  }
28
28
  build() {
29
- const { presets: t, walls: i, collide: s } = this.config, o = p(i, t);
30
- s && (this.bodies = this.scene.physics.add.staticGroup());
31
- for (const l of o)
32
- this.containers.push(this.drawWall(l, t[l.spec.preset])), this.bodies && this.addBody(l);
29
+ const { presets: t, walls: i, collide: e } = this.config, n = g(i, t);
30
+ e && (this.bodies = this.scene.physics.add.staticGroup());
31
+ for (const s of n)
32
+ this.containers.push(this.drawWall(s, t[s.spec.preset])), this.bodies && this.addBody(s);
33
33
  }
34
34
  drawWall(t, i) {
35
- const { body: s, lip: o, bodyPieces: l, lipPieces: r, windows: f, sills: w } = t, c = this.scene.add.container(0, 0), h = this.scene.add.graphics(), d = this.scene.add.graphics(), y = i.edgeWidth ?? 2;
36
- for (const e of l) this.fillRect(c, h, e, i.fill, i.texture);
37
- for (const e of r) this.fillRect(c, h, e, i.lipFill ?? i.fill, i.lipTexture);
38
- const u = i.windowFill ?? 4030344;
39
- for (const e of f)
40
- h.fillStyle(u, i.windowAlpha ?? 0.5), h.fillRect(e.x, e.y, e.w, e.h);
41
- c.add(h);
42
- for (const e of w) this.fillRect(c, d, e, i.fill, i.texture);
43
- for (const e of w) d.lineStyle(1, i.edge).lineBetween(e.x, e.y, e.x + e.w, e.y);
35
+ const { body: e, lip: n, bodyPieces: s, lipPieces: l, windows: c, sills: r } = t, d = this.scene.add.container(0, 0), u = this.scene.add.graphics(), w = this.scene.add.graphics(), x = i.edgeWidth ?? 2;
36
+ for (const o of s) this.fillRect(d, u, o, i.fill, i.texture);
37
+ for (const o of l) this.fillRect(d, u, o, i.lipFill ?? i.fill, i.lipTexture);
38
+ const y = i.windowFill ?? 4030344;
39
+ for (const o of c)
40
+ u.fillStyle(y, i.windowAlpha ?? 0.5), u.fillRect(o.x, o.y, o.w, o.h);
41
+ d.add(u);
42
+ for (const o of r) this.fillRect(d, w, o, i.fill, i.texture);
43
+ for (const o of r) w.lineStyle(1, i.edge).lineBetween(o.x, o.y, o.x + o.w, o.y);
44
44
  if (i.windowFrame !== void 0)
45
- for (const e of f) d.lineStyle(1, i.windowFrame).strokeRect(e.x, e.y, e.w, e.h);
46
- return d.lineStyle(y, i.edge), d.strokeRect(s.x, s.y, s.w, s.h), o && d.lineStyle(y, i.edge).strokeRect(o.x, o.y, o.w, o.h), c.add(d), c.setDepth(t.depth), c;
45
+ for (const o of c) w.lineStyle(1, i.windowFrame).strokeRect(o.x, o.y, o.w, o.h);
46
+ return w.lineStyle(x, i.edge), w.strokeRect(e.x, e.y, e.w, e.h), n && w.lineStyle(x, i.edge).strokeRect(n.x, n.y, n.w, n.h), d.add(w), d.setDepth(t.depth), d;
47
47
  }
48
- fillRect(t, i, s, o, l) {
49
- if (!l) {
50
- i.fillStyle(o).fillRect(s.x, s.y, s.w, s.h);
48
+ fillRect(t, i, e, n, s) {
49
+ if (!s) {
50
+ i.fillStyle(n).fillRect(e.x, e.y, e.w, e.h);
51
51
  return;
52
52
  }
53
- const r = this.scene.add.tileSprite(s.x + s.w / 2, s.y + s.h / 2, s.w, s.h, l);
54
- r.setTilePosition(s.x, s.y), t.add(r);
53
+ const l = this.scene.add.tileSprite(e.x + e.w / 2, e.y + e.h / 2, e.w, e.h, s);
54
+ l.setTilePosition(e.x, e.y), t.add(l);
55
55
  }
56
56
  addBody(t) {
57
- const { collider: i } = t, s = this.scene.add.zone(i.x + i.w / 2, i.y + i.h / 2, i.w, i.h);
58
- this.scene.physics.add.existing(s, !0), this.bodies.add(s);
57
+ const { collider: i } = t, e = this.scene.add.zone(i.x + i.w / 2, i.y + i.h / 2, i.w, i.h);
58
+ this.scene.physics.add.existing(e, !0), this.bodies.add(e);
59
59
  }
60
60
  }
61
- class P extends b.Plugins.ScenePlugin {
62
- constructor(t, i, s) {
63
- super(t, i, s), typeof t.add.wallMap != "function" && i.registerGameObject("wallMap", function(o) {
64
- return new R(this.scene, o);
61
+ class M extends h.Plugins.ScenePlugin {
62
+ constructor(t, i, e) {
63
+ super(t, i, e), typeof t.add.wallMap != "function" && i.registerGameObject("wallMap", function(n) {
64
+ return new D(this.scene, n);
65
65
  });
66
66
  }
67
67
  }
68
+ class P {
69
+ constructor(t, i) {
70
+ a(this, "configData");
71
+ a(this, "selectedIndex");
72
+ a(this, "tool");
73
+ a(this, "enabled");
74
+ a(this, "camera");
75
+ a(this, "gridSize");
76
+ a(this, "overlay");
77
+ a(this, "callbacks");
78
+ a(this, "newWall");
79
+ a(this, "drawStart", null);
80
+ a(this, "pointerPosition", null);
81
+ a(this, "anchorDrag", null);
82
+ a(this, "windowDrag", null);
83
+ a(this, "wallDrag", null);
84
+ a(this, "wallPreview", null);
85
+ var e;
86
+ if (this.scene = t, this.gridSize = i.gridSize ?? 32, !Number.isFinite(this.gridSize) || this.gridSize <= 0) throw new Error("gridSize must be positive and finite");
87
+ this.camera = i.camera ?? t.cameras.main, this.configData = i.config, this.selectedIndex = i.selectedIndex, this.tool = i.tool, this.enabled = i.enabled ?? !0, this.callbacks = i, this.newWall = { ...i.newWall, thickness: ((e = i.newWall) == null ? void 0 : e.thickness) ?? 16 }, this.overlay = t.add.graphics().setDepth(i.overlayDepth ?? 1e4), t.input.on("pointerdown", this.handlePointerDown, this), t.input.on("pointermove", this.handlePointerMove, this), t.input.on("pointerup", this.handlePointerUp, this), t.input.on("pointerupoutside", this.handlePointerUp, this), t.events.once("shutdown", this.destroy, this), this.refresh();
88
+ }
89
+ setState(t) {
90
+ (t.config !== this.configData || t.selectedIndex !== this.selectedIndex || t.tool !== this.tool || (t.enabled ?? !0) !== this.enabled) && this.cancel(), this.configData = t.config, this.selectedIndex = t.selectedIndex, this.tool = t.tool, this.enabled = t.enabled ?? !0, this.refresh();
91
+ }
92
+ setNewWall(t) {
93
+ this.newWall = { ...t, thickness: t.thickness ?? 16 };
94
+ }
95
+ get dragging() {
96
+ return !!(this.drawStart || this.anchorDrag || this.windowDrag || this.wallDrag);
97
+ }
98
+ cancel() {
99
+ var t;
100
+ this.drawStart = null, this.pointerPosition = null, this.anchorDrag = null, this.windowDrag = null, this.wallDrag = null, (t = this.wallPreview) == null || t.destroy(), this.wallPreview = null, this.scene.input.setDefaultCursor("default"), this.refresh();
101
+ }
102
+ destroy() {
103
+ this.cancel(), this.scene.input.off("pointerdown", this.handlePointerDown, this), this.scene.input.off("pointermove", this.handlePointerMove, this), this.scene.input.off("pointerup", this.handlePointerUp, this), this.scene.input.off("pointerupoutside", this.handlePointerUp, this), this.scene.events.off("shutdown", this.destroy, this), this.scene.input.setDefaultCursor("default"), this.overlay.destroy();
104
+ }
105
+ handlePointerDown(t) {
106
+ if (!this.enabled || !t.leftButtonDown()) return;
107
+ t.updateWorldPoint(this.camera);
108
+ const i = this.snapPoint(t.worldX, t.worldY);
109
+ if (this.tool === "select") {
110
+ const e = this.findAnchor(t.worldX, t.worldY);
111
+ if (e && this.selectedIndex !== null) {
112
+ this.anchorDrag = {
113
+ index: this.selectedIndex,
114
+ endpoint: e,
115
+ wall: { ...this.configData.walls[this.selectedIndex] }
116
+ }, this.scene.input.setDefaultCursor("grabbing");
117
+ return;
118
+ }
119
+ const n = this.findWindow(t.worldX, t.worldY);
120
+ if (n !== null && this.selectedIndex !== null) {
121
+ this.windowDrag = {
122
+ index: this.selectedIndex,
123
+ windowIndex: n,
124
+ wall: { ...this.configData.walls[this.selectedIndex] }
125
+ }, this.scene.input.setDefaultCursor("grabbing");
126
+ return;
127
+ }
128
+ if (this.selectedIndex !== null && this.onSelectedLine(t.worldX, t.worldY)) {
129
+ const s = this.configData.walls[this.selectedIndex];
130
+ this.wallDrag = { index: this.selectedIndex, wall: s, start: new h.Math.Vector2(t.worldX, t.worldY), preview: s }, this.scene.input.setDefaultCursor("grabbing");
131
+ return;
132
+ }
133
+ this.callbacks.onSelectWall(this.findWall(t.worldX, t.worldY));
134
+ return;
135
+ }
136
+ this.drawStart = i, this.pointerPosition = i.clone(), this.refresh();
137
+ }
138
+ handlePointerMove(t) {
139
+ if (this.enabled) {
140
+ if (t.updateWorldPoint(this.camera), this.wallDrag && t.isDown) {
141
+ const i = this.wallDrag;
142
+ i.preview = this.moveWall(i, t.worldX, t.worldY), this.wallPreview ?? (this.wallPreview = new D(this.scene, { presets: this.configData.presets, walls: [i.wall] }));
143
+ for (const e of this.wallPreview.containers)
144
+ e.setPosition(i.preview.x1 - i.wall.x1, i.preview.y1 - i.wall.y1).setAlpha(0.65).setDepth(this.overlay.depth - 1);
145
+ this.refresh();
146
+ return;
147
+ }
148
+ if (this.windowDrag && t.isDown) {
149
+ this.windowDrag.wall = this.moveWindow(
150
+ this.windowDrag.wall,
151
+ this.windowDrag.windowIndex,
152
+ t.worldX,
153
+ t.worldY
154
+ ), this.refresh();
155
+ return;
156
+ }
157
+ if (this.anchorDrag && t.isDown) {
158
+ this.anchorDrag.wall = this.moveEndpoint(
159
+ this.anchorDrag.wall,
160
+ this.anchorDrag.endpoint,
161
+ this.snapPoint(t.worldX, t.worldY)
162
+ ), this.refresh();
163
+ return;
164
+ }
165
+ if (this.tool === "select" && !t.isDown)
166
+ if (this.findWindow(t.worldX, t.worldY) !== null && this.selectedIndex !== null) {
167
+ const e = this.configData.walls[this.selectedIndex];
168
+ this.scene.input.setDefaultCursor(e.y1 === e.y2 ? "ew-resize" : "ns-resize");
169
+ } else
170
+ this.scene.input.setDefaultCursor(this.findAnchor(t.worldX, t.worldY) || this.onSelectedLine(t.worldX, t.worldY) ? "grab" : "default");
171
+ !this.drawStart || !t.isDown || (this.pointerPosition = this.axisLock(this.drawStart, this.snapPoint(t.worldX, t.worldY)), this.refresh());
172
+ }
173
+ }
174
+ handlePointerUp(t) {
175
+ if (!this.enabled) return;
176
+ if (t.updateWorldPoint(this.camera), this.wallDrag) {
177
+ const n = this.wallDrag, s = this.moveWall(n, t.worldX, t.worldY);
178
+ this.cancel(), (s.x1 !== n.wall.x1 || s.y1 !== n.wall.y1) && this.callbacks.onUpdateWall(n.index, { x1: s.x1, y1: s.y1, x2: s.x2, y2: s.y2 });
179
+ return;
180
+ }
181
+ if (this.windowDrag) {
182
+ const n = this.windowDrag, s = this.moveWindow(n.wall, n.windowIndex, t.worldX, t.worldY);
183
+ this.windowDrag = null, this.scene.input.setDefaultCursor("default"), this.callbacks.onUpdateWall(n.index, { windows: s.windows }), this.refresh();
184
+ return;
185
+ }
186
+ if (this.anchorDrag) {
187
+ const n = this.anchorDrag, s = this.moveEndpoint(
188
+ n.wall,
189
+ n.endpoint,
190
+ this.snapPoint(t.worldX, t.worldY)
191
+ );
192
+ this.anchorDrag = null, this.scene.input.setDefaultCursor("default"), h.Math.Distance.Between(s.x1, s.y1, s.x2, s.y2) >= this.gridSize && this.callbacks.onUpdateWall(n.index, {
193
+ x1: s.x1,
194
+ y1: s.y1,
195
+ x2: s.x2,
196
+ y2: s.y2
197
+ }), this.refresh();
198
+ return;
199
+ }
200
+ if (!this.drawStart) return;
201
+ const i = this.axisLock(this.drawStart, this.snapPoint(t.worldX, t.worldY)), e = this.drawStart;
202
+ if (this.drawStart = null, this.pointerPosition = null, h.Math.Distance.Between(e.x, e.y, i.x, i.y) >= this.gridSize) {
203
+ const n = this.newWall.preset ?? (Object.hasOwn(this.configData.presets, "interior") ? "interior" : Object.keys(this.configData.presets)[0]);
204
+ if (!n || !Object.hasOwn(this.configData.presets, n)) throw new Error("Choose an existing wall preset before drawing");
205
+ this.callbacks.onAddWall({
206
+ x1: e.x,
207
+ y1: e.y,
208
+ x2: i.x,
209
+ y2: i.y,
210
+ ...this.newWall,
211
+ preset: n
212
+ });
213
+ }
214
+ this.refresh();
215
+ }
216
+ refresh() {
217
+ var i, e, n, s;
218
+ if (!this.overlay || (this.overlay.clear(), !this.enabled)) return;
219
+ const t = ((i = this.wallDrag) == null ? void 0 : i.preview) ?? ((e = this.windowDrag) == null ? void 0 : e.wall) ?? ((n = this.anchorDrag) == null ? void 0 : n.wall) ?? (this.selectedIndex === null ? null : this.configData.walls[this.selectedIndex]);
220
+ if (t) {
221
+ const l = 8 / this.camera.zoom;
222
+ this.overlay.lineStyle(4, 2980428, 1).lineBetween(t.x1, t.y1, t.x2, t.y2), this.overlay.fillStyle(16777215, 1).fillCircle(t.x1, t.y1, l).fillCircle(t.x2, t.y2, l), this.overlay.lineStyle(3 / this.camera.zoom, 2980428, 1).strokeCircle(t.x1, t.y1, l).strokeCircle(t.x2, t.y2, l);
223
+ for (const [c, r] of this.getWindowRects(t).entries()) {
224
+ const d = ((s = this.windowDrag) == null ? void 0 : s.windowIndex) === c;
225
+ this.overlay.fillStyle(d ? 2980428 : 16777215, d ? 0.35 : 0.75).fillRect(r.x, r.y, r.w, r.h), this.overlay.lineStyle(3, 2980428, 1).strokeRect(r.x, r.y, r.w, r.h);
226
+ }
227
+ }
228
+ this.drawStart && this.pointerPosition && (this.overlay.lineStyle(4, 14916150, 0.95).lineBetween(
229
+ this.drawStart.x,
230
+ this.drawStart.y,
231
+ this.pointerPosition.x,
232
+ this.pointerPosition.y
233
+ ), this.overlay.fillStyle(14916150).fillCircle(this.drawStart.x, this.drawStart.y, 5));
234
+ }
235
+ findWall(t, i) {
236
+ let e = null;
237
+ for (const [n, s] of this.configData.walls.entries()) {
238
+ const l = s.x1 === s.x2 ? Math.hypot(t - s.x1, i - h.Math.Clamp(i, Math.min(s.y1, s.y2), Math.max(s.y1, s.y2))) : Math.hypot(t - h.Math.Clamp(t, Math.min(s.x1, s.x2), Math.max(s.x1, s.x2)), i - s.y1);
239
+ l <= s.thickness / 2 + 10 / this.camera.zoom && (!e || l < e.distance) && (e = { index: n, distance: l });
240
+ }
241
+ return (e == null ? void 0 : e.index) ?? null;
242
+ }
243
+ onSelectedLine(t, i) {
244
+ const e = this.selectedIndex === null ? void 0 : this.configData.walls[this.selectedIndex];
245
+ if (!e) return !1;
246
+ const n = e.y1 === e.y2, s = n ? t : i, l = n ? e.x1 : e.y1, c = n ? e.x2 : e.y2;
247
+ return s >= Math.min(l, c) && s <= Math.max(l, c) && Math.abs(n ? i - e.y1 : t - e.x1) <= 6 / this.camera.zoom;
248
+ }
249
+ moveWall(t, i, e) {
250
+ const n = Math.round((i - t.start.x) / this.gridSize) * this.gridSize, s = Math.round((e - t.start.y) / this.gridSize) * this.gridSize, l = t.wall;
251
+ return { ...l, x1: l.x1 + n, y1: l.y1 + s, x2: l.x2 + n, y2: l.y2 + s };
252
+ }
253
+ findAnchor(t, i) {
254
+ if (this.selectedIndex === null) return null;
255
+ const e = this.configData.walls[this.selectedIndex];
256
+ if (!e) return null;
257
+ const n = h.Math.Distance.Between(t, i, e.x1, e.y1), s = h.Math.Distance.Between(t, i, e.x2, e.y2);
258
+ return Math.min(n, s) > 16 / this.camera.zoom ? null : n <= s ? "start" : "end";
259
+ }
260
+ findWindow(t, i) {
261
+ if (this.selectedIndex === null) return null;
262
+ const e = this.configData.walls[this.selectedIndex];
263
+ if (!e) return null;
264
+ const n = 10 / this.camera.zoom, s = this.getWindowRects(e).findIndex((l) => t >= l.x - n && t <= l.x + l.w + n && i >= l.y - n && i <= l.y + l.h + n);
265
+ return s === -1 ? null : s;
266
+ }
267
+ getWindowRects(t) {
268
+ var i;
269
+ return ((i = g([t], this.configData.presets)[0]) == null ? void 0 : i.windows) ?? [];
270
+ }
271
+ moveWindow(t, i, e, n) {
272
+ var y;
273
+ const s = ((y = t.windows) == null ? void 0 : y.map((o) => ({ ...o }))) ?? [], l = s[i];
274
+ if (!l) return t;
275
+ const c = t.y1 === t.y2, r = c ? Math.sign(t.x2 - t.x1) || 1 : Math.sign(t.y2 - t.y1) || 1, d = c ? (e - t.x1) * r : (n - t.y1) * r, u = Math.abs(t.x2 - t.x1) + Math.abs(t.y2 - t.y1), w = Math.max(0, u - l.width), x = h.Math.Clamp(
276
+ Math.round((d - l.width / 2) / this.gridSize) * this.gridSize,
277
+ 0,
278
+ w
279
+ );
280
+ return s[i] = { ...l, offset: x }, { ...t, windows: s };
281
+ }
282
+ moveEndpoint(t, i, e) {
283
+ const n = i === "start" ? new h.Math.Vector2(t.x2, t.y2) : new h.Math.Vector2(t.x1, t.y1), s = this.axisLock(n, e);
284
+ return i === "start" ? { ...t, x1: s.x, y1: s.y } : { ...t, x2: s.x, y2: s.y };
285
+ }
286
+ snapPoint(t, i) {
287
+ return new h.Math.Vector2(
288
+ Math.round(t / this.gridSize) * this.gridSize,
289
+ Math.round(i / this.gridSize) * this.gridSize
290
+ );
291
+ }
292
+ axisLock(t, i) {
293
+ return Math.abs(i.x - t.x) >= Math.abs(i.y - t.y) ? new h.Math.Vector2(i.x, t.y) : new h.Math.Vector2(t.x, i.y);
294
+ }
295
+ }
68
296
  export {
69
- R as WallMap,
70
- P as WallMapPlugin,
71
- p as resolveWalls
297
+ P as WallEditor,
298
+ D as WallMap,
299
+ M as WallMapPlugin,
300
+ g as resolveWalls
72
301
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mertdogar/phaser-procedural-walls",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Phaser 4 scene plugin that renders procedural top-down walls with faces, see-through windows, depth sorting and Arcade colliders from wall centerline data.",
5
5
  "keywords": [
6
6
  "phaser",
@@ -53,16 +53,6 @@
53
53
  "publishConfig": {
54
54
  "access": "public"
55
55
  },
56
- "scripts": {
57
- "dev": "vite",
58
- "build": "vite build && tsc -p tsconfig.lib.json && vite build --mode editor",
59
- "editor": "node bin/cli.mjs editor",
60
- "test:cli": "node --test tests/cli.test.mjs",
61
- "test": "vitest run",
62
- "typecheck": "tsc --noEmit",
63
- "lint": "oxlint src demo tests bin",
64
- "prepublishOnly": "pnpm typecheck && pnpm lint && pnpm test && pnpm build && pnpm test:cli"
65
- },
66
56
  "peerDependencies": {
67
57
  "phaser": "^4.0.0"
68
58
  },
@@ -88,5 +78,14 @@
88
78
  "react-dom": "^19.3.0",
89
79
  "react-resizable-panels": "^4.12.4",
90
80
  "tailwind-merge": "^3.7.0"
81
+ },
82
+ "scripts": {
83
+ "dev": "vite",
84
+ "build": "vite build && tsc -p tsconfig.lib.json && vite build --mode editor",
85
+ "editor": "node bin/cli.mjs editor",
86
+ "test:cli": "node --test tests/cli.test.mjs",
87
+ "test": "vitest run",
88
+ "typecheck": "tsc --noEmit",
89
+ "lint": "oxlint src demo tests bin"
91
90
  }
92
- }
91
+ }