@waica/cli 0.3.0
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.
- package/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/cli.js +184 -0
- package/dist/editor/assets/abap-08VXUWAP.js +1 -0
- package/dist/editor/assets/apex-BWPQTe0t.js +1 -0
- package/dist/editor/assets/azcli-Bc_sGQ0U.js +1 -0
- package/dist/editor/assets/bat-i0X4ZdIN.js +1 -0
- package/dist/editor/assets/bicep-B5-_aFwp.js +2 -0
- package/dist/editor/assets/cameligo-DMUM7wLl.js +1 -0
- package/dist/editor/assets/clojure-Cm7r79vr.js +1 -0
- package/dist/editor/assets/codicon-DCmgc-ay.ttf +0 -0
- package/dist/editor/assets/coffee-Ba7i2nA0.js +1 -0
- package/dist/editor/assets/cpp-C7h46wYY.js +1 -0
- package/dist/editor/assets/csharp-BKxtCVv1.js +1 -0
- package/dist/editor/assets/csp-bTuwJoIa.js +1 -0
- package/dist/editor/assets/css-DIMkf-bt.js +3 -0
- package/dist/editor/assets/css.worker-Fwwr_HdT.js +88 -0
- package/dist/editor/assets/cssMode-CQE-WdwL.js +4 -0
- package/dist/editor/assets/cypher-CVaqCwHa.js +1 -0
- package/dist/editor/assets/dart-onAF5SnQ.js +1 -0
- package/dist/editor/assets/dockerfile-DZFCIeNp.js +1 -0
- package/dist/editor/assets/ecl-D05T4iGw.js +1 -0
- package/dist/editor/assets/editor.worker-DsBDrWS5.js +12 -0
- package/dist/editor/assets/elixir-6RTg0lbw.js +1 -0
- package/dist/editor/assets/flow9-C5_-GSwl.js +1 -0
- package/dist/editor/assets/freemarker2-CYgdVabn.js +3 -0
- package/dist/editor/assets/fsharp-C8Ef5oNN.js +1 -0
- package/dist/editor/assets/go-C-y9NEjX.js +1 -0
- package/dist/editor/assets/graphql-fmXr3nnJ.js +1 -0
- package/dist/editor/assets/handlebars-DdeORCJD.js +1 -0
- package/dist/editor/assets/hcl-CpzslTdj.js +1 -0
- package/dist/editor/assets/html-DTIAGV84.js +1 -0
- package/dist/editor/assets/html.worker-B3Ztmmz2.js +495 -0
- package/dist/editor/assets/htmlMode-CRV3iBih.js +4 -0
- package/dist/editor/assets/index-Btzc6zxr.css +1 -0
- package/dist/editor/assets/index-Dhkqk31v.js +11016 -0
- package/dist/editor/assets/ini-sBoK_t0W.js +1 -0
- package/dist/editor/assets/java-BEtHBSE6.js +1 -0
- package/dist/editor/assets/javascript-dxBW86cl.js +1 -0
- package/dist/editor/assets/json.worker-PWQxM7ZO.js +51 -0
- package/dist/editor/assets/jsonMode-DFA5-FFK.js +10 -0
- package/dist/editor/assets/julia-Bri6UV-V.js +1 -0
- package/dist/editor/assets/kotlin-B0qVs-E9.js +1 -0
- package/dist/editor/assets/less-B9JPFI3C.js +2 -0
- package/dist/editor/assets/lexon-CfSJPG6W.js +1 -0
- package/dist/editor/assets/liquid-CScWaXYV.js +1 -0
- package/dist/editor/assets/lua-CsQS60Ue.js +1 -0
- package/dist/editor/assets/m3-D-oSqn_W.js +1 -0
- package/dist/editor/assets/markdown-Cimd5fb3.js +1 -0
- package/dist/editor/assets/mdx-Bvp84SqA.js +1 -0
- package/dist/editor/assets/mips-CIPQ_RoX.js +1 -0
- package/dist/editor/assets/msdax-DauUninz.js +1 -0
- package/dist/editor/assets/mysql-SOo6toE5.js +1 -0
- package/dist/editor/assets/objective-c-FvmIjYaQ.js +1 -0
- package/dist/editor/assets/pascal-DrH0SRf2.js +1 -0
- package/dist/editor/assets/pascaligo-D-ptJ9y-.js +1 -0
- package/dist/editor/assets/perl-oz_6vUea.js +1 -0
- package/dist/editor/assets/pgsql-DTj74zXo.js +1 -0
- package/dist/editor/assets/php-nr791fC2.js +1 -0
- package/dist/editor/assets/pla-CopQ2nXW.js +1 -0
- package/dist/editor/assets/postiats-43DmfD33.js +1 -0
- package/dist/editor/assets/powerquery-D3hlyOfw.js +1 -0
- package/dist/editor/assets/powershell-DmHpPYUd.js +1 -0
- package/dist/editor/assets/protobuf-C531GsRP.js +2 -0
- package/dist/editor/assets/pug-Z5eAx3Zn.js +1 -0
- package/dist/editor/assets/python-CG-OtvFa.js +1 -0
- package/dist/editor/assets/qsharp-DkqhCAOL.js +1 -0
- package/dist/editor/assets/r-BwWrilGY.js +1 -0
- package/dist/editor/assets/razor-r-iUEZPj.js +1 -0
- package/dist/editor/assets/redis-ClamHrr6.js +1 -0
- package/dist/editor/assets/redshift-DT7zqm-g.js +1 -0
- package/dist/editor/assets/restructuredtext-BYgofb2h.js +1 -0
- package/dist/editor/assets/ruby-DezsRK8O.js +1 -0
- package/dist/editor/assets/rust-DdL9SqIa.js +1 -0
- package/dist/editor/assets/sb-CcwsVR0C.js +1 -0
- package/dist/editor/assets/scala-DHpiXF5c.js +1 -0
- package/dist/editor/assets/scheme-BeGwcela.js +1 -0
- package/dist/editor/assets/scss-gp-XZpBa.js +3 -0
- package/dist/editor/assets/shell-CC2rA5mh.js +1 -0
- package/dist/editor/assets/solidity-BEEn4gHE.js +1 -0
- package/dist/editor/assets/sophia-CRfGWb83.js +1 -0
- package/dist/editor/assets/sparql-D_Lu-MrJ.js +1 -0
- package/dist/editor/assets/sql-NEE52Syq.js +1 -0
- package/dist/editor/assets/st-DbInun42.js +1 -0
- package/dist/editor/assets/swift-Bxkupp3x.js +1 -0
- package/dist/editor/assets/systemverilog-Bz4Y3fRF.js +1 -0
- package/dist/editor/assets/tcl-DISqw1ZD.js +1 -0
- package/dist/editor/assets/ts.worker-0mEyHVru.js +51339 -0
- package/dist/editor/assets/tsMode-Bth1rJwM.js +11 -0
- package/dist/editor/assets/twig-De2hgUGE.js +1 -0
- package/dist/editor/assets/typescript-tNRuHsoe.js +1 -0
- package/dist/editor/assets/typespec-B8J7ngcE.js +1 -0
- package/dist/editor/assets/vb-DV3o63ZY.js +1 -0
- package/dist/editor/assets/wgsl-DpFanUEy.js +298 -0
- package/dist/editor/assets/xml-BCx9e6CK.js +1 -0
- package/dist/editor/assets/yaml-Bb-peGP_.js +1 -0
- package/dist/editor/index.html +14 -0
- package/dist/mcp/archetypes.js +103 -0
- package/dist/mcp/cli.js +6 -0
- package/dist/mcp/create-project.js +151 -0
- package/dist/mcp/introspection.js +201 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-coin.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-dog.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/assets/waica-slime.png +0 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.d.ts +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/art.js +13 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.d.ts +3 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/bundle.js +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.d.ts +5 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/controls.js +12 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.d.ts +38 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/index.js +34 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.d.ts +15 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/manifest.js +26 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.d.ts +7 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/prefabs.js +97 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.d.ts +5 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry-data.js +45 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.d.ts +6 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/registry.js +15 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.d.ts +40 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/scene-default.js +93 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.d.ts +10 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/dist/ui.js +24 -0
- package/dist/mcp/node_modules/@waica/archetype-platformer/package.json +30 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.d.ts +59 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/chaser.js +127 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.d.ts +25 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/collectible.js +27 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.d.ts +29 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/hazard.js +42 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/index.d.ts +9 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/index.js +9 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.d.ts +16 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/lifetime.js +19 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/npc.d.ts +4 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/npc.js +14 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.d.ts +43 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.js +68 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.d.ts +124 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/platformer-motor.js +146 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.d.ts +3 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-identity.js +5 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.d.ts +18 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/player-states.js +95 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.d.ts +23 -0
- package/dist/mcp/node_modules/@waica/behaviors/dist/respawnable.js +27 -0
- package/dist/mcp/node_modules/@waica/behaviors/package.json +24 -0
- package/dist/mcp/node_modules/@waica/engine/dist/aabb.d.ts +2 -0
- package/dist/mcp/node_modules/@waica/engine/dist/aabb.js +4 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.d.ts +20 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/clip-player.js +24 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.d.ts +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/contract.js +23 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.d.ts +65 -0
- package/dist/mcp/node_modules/@waica/engine/dist/animation/sheet.js +44 -0
- package/dist/mcp/node_modules/@waica/engine/dist/archetype.d.ts +37 -0
- package/dist/mcp/node_modules/@waica/engine/dist/archetype.js +1 -0
- package/dist/mcp/node_modules/@waica/engine/dist/camera.d.ts +71 -0
- package/dist/mcp/node_modules/@waica/engine/dist/camera.js +59 -0
- package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.d.ts +26 -0
- package/dist/mcp/node_modules/@waica/engine/dist/collision-shape.js +136 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component-registry.d.ts +16 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component-registry.js +44 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component.d.ts +58 -0
- package/dist/mcp/node_modules/@waica/engine/dist/component.js +11 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.d.ts +80 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.js +210 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.d.ts +68 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.js +189 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.d.ts +25 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/hitbox.js +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/solid.d.ts +32 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/solid.js +45 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.d.ts +51 -0
- package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.js +112 -0
- package/dist/mcp/node_modules/@waica/engine/dist/entity.d.ts +22 -0
- package/dist/mcp/node_modules/@waica/engine/dist/entity.js +52 -0
- package/dist/mcp/node_modules/@waica/engine/dist/events.d.ts +8 -0
- package/dist/mcp/node_modules/@waica/engine/dist/events.js +20 -0
- package/dist/mcp/node_modules/@waica/engine/dist/game.d.ts +95 -0
- package/dist/mcp/node_modules/@waica/engine/dist/game.js +263 -0
- package/dist/mcp/node_modules/@waica/engine/dist/index.d.ts +39 -0
- package/dist/mcp/node_modules/@waica/engine/dist/index.js +26 -0
- package/dist/mcp/node_modules/@waica/engine/dist/input.d.ts +40 -0
- package/dist/mcp/node_modules/@waica/engine/dist/input.js +84 -0
- package/dist/mcp/node_modules/@waica/engine/dist/scene.d.ts +80 -0
- package/dist/mcp/node_modules/@waica/engine/dist/scene.js +93 -0
- package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.d.ts +21 -0
- package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.js +77 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.d.ts +90 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/hooks.js +81 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.d.ts +83 -0
- package/dist/mcp/node_modules/@waica/engine/dist/state/state-machine.js +173 -0
- package/dist/mcp/node_modules/@waica/engine/dist/stats.d.ts +27 -0
- package/dist/mcp/node_modules/@waica/engine/dist/stats.js +54 -0
- package/dist/mcp/node_modules/@waica/engine/dist/ui.d.ts +47 -0
- package/dist/mcp/node_modules/@waica/engine/dist/ui.js +175 -0
- package/dist/mcp/node_modules/@waica/engine/package.json +25 -0
- package/dist/mcp/package-resolver.js +240 -0
- package/dist/mcp/project-path.js +86 -0
- package/dist/mcp/scaffolds.js +153 -0
- package/dist/mcp/server.js +217 -0
- package/dist/mcp/stdio.js +13 -0
- package/dist/mcp/template/README.md +22 -0
- package/dist/mcp/template/_gitignore +5 -0
- package/dist/mcp/template/index.html +25 -0
- package/dist/mcp/template/package.json.tpl +20 -0
- package/dist/mcp/template/public/waica.params.json +1 -0
- package/dist/mcp/template/src/art/waica-coin.png +0 -0
- package/dist/mcp/template/src/art/waica-dog.png +0 -0
- package/dist/mcp/template/src/art/waica-slime.png +0 -0
- package/dist/mcp/template/src/characters/player.character.json +133 -0
- package/dist/mcp/template/src/characters/slime.character.json +61 -0
- package/dist/mcp/template/src/controls.json +8 -0
- package/dist/mcp/template/src/game.json +10 -0
- package/dist/mcp/template/src/main.ts +105 -0
- package/dist/mcp/template/src/objects/coin.object.json +41 -0
- package/dist/mcp/template/src/scenes/main.scene.json +217 -0
- package/dist/mcp/template/src/stats.json +7 -0
- package/dist/mcp/template/src/tiles/block.tile.json +21 -0
- package/dist/mcp/template/src/tiles/decor.tile.json +14 -0
- package/dist/mcp/template/src/tiles/platform.tile.json +21 -0
- package/dist/mcp/template/src/ui/coin-counter.html +12 -0
- package/dist/mcp/template/tsconfig.json +15 -0
- package/dist/mcp/template/vite.config.ts +3 -0
- package/dist/mcp/validation.js +323 -0
- package/dist/mcp/workspace-loader.js +14 -0
- package/dist/mcp/workspace-runtime.js +109 -0
- package/dist/server.js +210 -0
- package/package.json +38 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"waicaPrefab": 1,
|
|
3
|
+
"type": "tile",
|
|
4
|
+
"components": [
|
|
5
|
+
{
|
|
6
|
+
"type": "Sprite",
|
|
7
|
+
"props": {
|
|
8
|
+
"width": 2,
|
|
9
|
+
"height": 2,
|
|
10
|
+
"color": 2508371
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "Solid",
|
|
15
|
+
"props": {
|
|
16
|
+
"width": 2,
|
|
17
|
+
"height": 2
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"waicaPrefab": 1,
|
|
3
|
+
"type": "tile",
|
|
4
|
+
"components": [
|
|
5
|
+
{
|
|
6
|
+
"type": "Sprite",
|
|
7
|
+
"props": {
|
|
8
|
+
"width": 3,
|
|
9
|
+
"height": 0.5,
|
|
10
|
+
"color": 2792847
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "Solid",
|
|
15
|
+
"props": {
|
|
16
|
+
"width": 3,
|
|
17
|
+
"height": 0.5
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"verbatimModuleSyntax": true,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"types": ["vite/client"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { discoverArchetypes, pickArchetype } from './archetypes.js';
|
|
4
|
+
import { PackageResolver, mixedSourceWarnings, provenanceRows, } from './package-resolver.js';
|
|
5
|
+
import { directFiles, requireWaicaProject } from './project-path.js';
|
|
6
|
+
function add(context, severity, code, message, file, ref) {
|
|
7
|
+
context.findings.push({ severity, code, message, file, ...(ref ? { ref } : {}) });
|
|
8
|
+
}
|
|
9
|
+
async function parseJson(projectPath, relative, findings) {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(await readFile(path.join(projectPath, relative), 'utf8'));
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error.code === 'ENOENT')
|
|
15
|
+
return undefined;
|
|
16
|
+
add({ findings }, 'error', 'unparseable-json', `Cannot parse JSON: ${error.message}`, relative);
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function projectComponentCandidates(projectPath) {
|
|
21
|
+
const names = new Set();
|
|
22
|
+
for (const directory of ['components', 'roles', 'states']) {
|
|
23
|
+
for (const file of await directFiles(path.join(projectPath, 'src', directory), '.ts')) {
|
|
24
|
+
const source = await readFile(path.join(projectPath, 'src', directory, file), 'utf8');
|
|
25
|
+
for (const match of source.matchAll(/\bcomponentName\s*=\s*['"]([^'"]+)['"]/g)) {
|
|
26
|
+
const name = match[1];
|
|
27
|
+
if (name)
|
|
28
|
+
names.add(name);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return names;
|
|
33
|
+
}
|
|
34
|
+
function checkComponent(component, file, ref, context) {
|
|
35
|
+
if (context.knownComponents.has(component.type))
|
|
36
|
+
return;
|
|
37
|
+
if (context.projectComponents.has(component.type)) {
|
|
38
|
+
add(context, 'info', 'unknown-component', `Component "${component.type}" is project-owned, not validated.`, file, ref);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
add(context, 'error', 'unknown-component', `Unknown component "${component.type}".`, file, ref);
|
|
42
|
+
}
|
|
43
|
+
function componentList(value) {
|
|
44
|
+
if (!Array.isArray(value))
|
|
45
|
+
return [];
|
|
46
|
+
return value.filter((entry) => !!entry && typeof entry === 'object' && typeof entry.type === 'string');
|
|
47
|
+
}
|
|
48
|
+
function objectRecord(value) {
|
|
49
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
50
|
+
? value
|
|
51
|
+
: {};
|
|
52
|
+
}
|
|
53
|
+
function machineStates(component) {
|
|
54
|
+
return objectRecord(component.props?.states);
|
|
55
|
+
}
|
|
56
|
+
function escapedRegex(value) {
|
|
57
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
58
|
+
}
|
|
59
|
+
async function projectRoleStateSources(projectPath) {
|
|
60
|
+
const sources = new Map();
|
|
61
|
+
for (const file of await directFiles(path.join(projectPath, 'src/roles'), '.ts')) {
|
|
62
|
+
const source = await readFile(path.join(projectPath, 'src/roles', file), 'utf8');
|
|
63
|
+
for (const match of source.matchAll(/\bdefine(?:Role|States)\s*\(\s*(['"])([^'"]+)\1/g)) {
|
|
64
|
+
const role = match[2];
|
|
65
|
+
if (!role)
|
|
66
|
+
continue;
|
|
67
|
+
sources.set(role, [...(sources.get(role) ?? []), source.slice(match.index)]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return sources;
|
|
71
|
+
}
|
|
72
|
+
function roleSourceHasState(source, state) {
|
|
73
|
+
const statesMarkers = [...source.matchAll(/\bstates\s*:/g)];
|
|
74
|
+
const candidate = statesMarkers.at(-1);
|
|
75
|
+
const registration = candidate ? source.slice(candidate.index) : source;
|
|
76
|
+
return new RegExp(`\\b${escapedRegex(state)}\\s*:`).test(registration);
|
|
77
|
+
}
|
|
78
|
+
/** Mirrors flat state files and textually recognizes project role registrations. */
|
|
79
|
+
function stateCodeExists(role, state, context) {
|
|
80
|
+
const roleStates = context.manifest.bundle.roles[role]?.states;
|
|
81
|
+
const logicStates = context.manifest.bundle.logicSets?.[role];
|
|
82
|
+
return ((!!roleStates && Object.hasOwn(roleStates, state)) ||
|
|
83
|
+
(!!logicStates && Object.hasOwn(logicStates, state)) ||
|
|
84
|
+
context.stateFiles.has(state) ||
|
|
85
|
+
(context.roleStateSources.get(role) ?? []).some((source) => roleSourceHasState(source, state)));
|
|
86
|
+
}
|
|
87
|
+
function validateStateMachines(components, file, ref, context) {
|
|
88
|
+
const animated = components.find((component) => component.type === 'AnimatedSprite');
|
|
89
|
+
const clips = animated
|
|
90
|
+
? new Set(Object.keys(objectRecord(animated.props?.clips)))
|
|
91
|
+
: undefined;
|
|
92
|
+
for (const machine of components.filter((component) => component.type === 'StateMachine')) {
|
|
93
|
+
const states = machineStates(machine);
|
|
94
|
+
const realNames = Object.keys(states).filter((name) => name !== '*');
|
|
95
|
+
const role = typeof machine.props?.role === 'string' ? machine.props.role : '';
|
|
96
|
+
const initial = typeof machine.props?.initial === 'string' && machine.props.initial
|
|
97
|
+
? machine.props.initial
|
|
98
|
+
: (realNames[0] ?? '');
|
|
99
|
+
for (const name of realNames) {
|
|
100
|
+
const definition = objectRecord(states[name]);
|
|
101
|
+
const clip = typeof definition.clip === 'string' ? definition.clip : name;
|
|
102
|
+
if (clips && !clips.has(clip)) {
|
|
103
|
+
add(context, 'warning', 'missing-clip', `State "${name}" uses missing animation clip "${clip}".`, file, ref ?? name);
|
|
104
|
+
}
|
|
105
|
+
const transitions = Array.isArray(definition.transitions) ? definition.transitions : [];
|
|
106
|
+
for (const transition of transitions) {
|
|
107
|
+
if (!transition || typeof transition !== 'object')
|
|
108
|
+
continue;
|
|
109
|
+
const to = transition.to;
|
|
110
|
+
const on = transition.on;
|
|
111
|
+
if (typeof to === 'string' && to !== '*' && !Object.hasOwn(states, to)) {
|
|
112
|
+
add(context, 'warning', 'dangling-transition-target', `State "${name}" transitions to missing state "${to}".`, file, ref ?? name);
|
|
113
|
+
}
|
|
114
|
+
if (typeof on === 'string' && on.startsWith('input:')) {
|
|
115
|
+
const action = on.slice('input:'.length);
|
|
116
|
+
if (!context.bindings[action]?.length) {
|
|
117
|
+
add(context, 'warning', 'input-action-unbound', `Input action "${action}" has no bindings.`, file, action);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (name !== initial) {
|
|
122
|
+
const reachable = Object.values(states).some((candidate) => (Array.isArray(candidate?.transitions) ? candidate.transitions : []).some((transition) => transition?.to === name));
|
|
123
|
+
if (!reachable) {
|
|
124
|
+
add(context, 'warning', 'unreachable-state', `Nothing transitions to state "${name}" and it is not initial.`, file, ref ?? name);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!stateCodeExists(role, name, context)) {
|
|
128
|
+
add(context, 'info', 'no-state-code', `State "${name}" has no built-in code, project role registration or src/states/${name}.ts.`, file, ref ?? name);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function resolvedEntityComponents(entity, prefab) {
|
|
134
|
+
const overrides = objectRecord(entity.overrides);
|
|
135
|
+
const inherited = componentList(prefab?.components).map((component) => ({
|
|
136
|
+
type: component.type,
|
|
137
|
+
props: {
|
|
138
|
+
...objectRecord(component.props),
|
|
139
|
+
...objectRecord(overrides[component.type]),
|
|
140
|
+
},
|
|
141
|
+
}));
|
|
142
|
+
return [...inherited, ...componentList(entity.components)];
|
|
143
|
+
}
|
|
144
|
+
function validatePrefab(prefab, file, ref, context) {
|
|
145
|
+
const components = componentList(prefab.components);
|
|
146
|
+
for (const component of components)
|
|
147
|
+
checkComponent(component, file, ref, context);
|
|
148
|
+
validateStateMachines(components, file, ref, context);
|
|
149
|
+
}
|
|
150
|
+
function validateScene(scene, file, prefabs, uiNames, context) {
|
|
151
|
+
const rawEntities = Array.isArray(scene.entities) ? scene.entities : [];
|
|
152
|
+
const entities = rawEntities
|
|
153
|
+
.map((entity, index) => ({ entity, index }))
|
|
154
|
+
.filter((entry) => !!entry.entity && typeof entry.entity === 'object' && !Array.isArray(entry.entity));
|
|
155
|
+
const entityNames = new Set(entities
|
|
156
|
+
.map(({ entity }) => (typeof entity.name === 'string' ? entity.name : ''))
|
|
157
|
+
.filter(Boolean));
|
|
158
|
+
const follow = scene.camera?.follow;
|
|
159
|
+
if (typeof follow === 'string' && follow && !entityNames.has(follow)) {
|
|
160
|
+
add(context, 'warning', 'camera-follow-unknown-entity', `Camera follows unknown entity "${follow}".`, file, follow);
|
|
161
|
+
}
|
|
162
|
+
for (const ui of Array.isArray(scene.ui) ? scene.ui : []) {
|
|
163
|
+
if (typeof ui === 'string' && !uiNames.has(ui)) {
|
|
164
|
+
add(context, 'warning', 'unknown-ui-piece', `Unknown UI piece "${ui}".`, file, ui);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
for (const { entity, index } of entities) {
|
|
168
|
+
const entityRef = typeof entity.name === 'string' && entity.name ? entity.name : `entity[${index}]`;
|
|
169
|
+
const inline = componentList(entity.components);
|
|
170
|
+
for (const component of inline)
|
|
171
|
+
checkComponent(component, file, entityRef, context);
|
|
172
|
+
const prefabRef = typeof entity.prefab === 'string' ? entity.prefab : undefined;
|
|
173
|
+
const overrides = objectRecord(entity.overrides);
|
|
174
|
+
let prefab;
|
|
175
|
+
if (prefabRef) {
|
|
176
|
+
prefab = prefabs.get(prefabRef);
|
|
177
|
+
if (!prefab) {
|
|
178
|
+
add(context, 'error', 'broken-prefab-ref', `Entity "${entityRef}" references missing prefab "${prefabRef}".`, file, prefabRef);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const componentTypes = new Set(componentList(prefab.components).map((component) => component.type));
|
|
182
|
+
for (const override of Object.keys(overrides)) {
|
|
183
|
+
if (!componentTypes.has(override)) {
|
|
184
|
+
add(context, 'warning', 'override-key-not-in-prefab', `Override "${override}" is not a component in prefab "${prefabRef}".`, file, prefabRef);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Re-evaluate inherited state behavior only when this entity actually
|
|
190
|
+
// changes a StateMachine or AnimatedSprite. Unrelated overrides keep the
|
|
191
|
+
// prefab-level finding as the single source of truth.
|
|
192
|
+
const stateTypes = new Set(['StateMachine', 'AnimatedSprite']);
|
|
193
|
+
const changesStateBehavior = inline.some((component) => stateTypes.has(component.type)) ||
|
|
194
|
+
Object.keys(overrides).some((type) => stateTypes.has(type));
|
|
195
|
+
if (changesStateBehavior) {
|
|
196
|
+
validateStateMachines(resolvedEntityComponents(entity, prefab), file, entityRef, context);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function statBindings(html) {
|
|
201
|
+
// GameUi binds text nodes only: attributes, comments, style and script
|
|
202
|
+
// contents are not runtime bindings and must not create validator findings.
|
|
203
|
+
const textOnly = html
|
|
204
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
205
|
+
.replace(/<(style|script)\b[^>]*>[\s\S]*?<\/\1>/gi, '')
|
|
206
|
+
.replace(/<[^>]*>/g, ' ');
|
|
207
|
+
const names = new Set();
|
|
208
|
+
for (const match of textOnly.matchAll(/\{\{\s*([\w-]+)\s*\}\}/g)) {
|
|
209
|
+
if (match[1])
|
|
210
|
+
names.add(match[1]);
|
|
211
|
+
}
|
|
212
|
+
return names;
|
|
213
|
+
}
|
|
214
|
+
export async function validateProject(projectPath) {
|
|
215
|
+
const check = await requireWaicaProject(projectPath);
|
|
216
|
+
const findings = [];
|
|
217
|
+
const fixedPaths = [
|
|
218
|
+
'package.json',
|
|
219
|
+
'src/game.json',
|
|
220
|
+
'src/controls.json',
|
|
221
|
+
'src/stats.json',
|
|
222
|
+
'public/waica.params.json',
|
|
223
|
+
];
|
|
224
|
+
const fixed = new Map();
|
|
225
|
+
for (const relative of fixedPaths) {
|
|
226
|
+
fixed.set(relative, await parseJson(projectPath, relative, findings));
|
|
227
|
+
}
|
|
228
|
+
const game = objectRecord(fixed.get('src/game.json'));
|
|
229
|
+
const gameWasUnparseable = findings.some((finding) => finding.code === 'unparseable-json' && finding.file === 'src/game.json');
|
|
230
|
+
const activeId = typeof game.archetype === 'string' && game.archetype
|
|
231
|
+
? game.archetype
|
|
232
|
+
: gameWasUnparseable
|
|
233
|
+
? 'platformer'
|
|
234
|
+
: null;
|
|
235
|
+
const resolver = new PackageResolver(projectPath);
|
|
236
|
+
const discoveryWarnings = [];
|
|
237
|
+
const [engine, behaviors, archetypes, projectComponents, roleStateSources] = await Promise.all([
|
|
238
|
+
resolver.load('@waica/engine'),
|
|
239
|
+
resolver.load('@waica/behaviors'),
|
|
240
|
+
discoverArchetypes(projectPath, resolver, discoveryWarnings, activeId ? [activeId] : []),
|
|
241
|
+
projectComponentCandidates(projectPath),
|
|
242
|
+
projectRoleStateSources(projectPath),
|
|
243
|
+
]);
|
|
244
|
+
const manifest = pickArchetype(archetypes, activeId, projectPath).manifest;
|
|
245
|
+
const controls = objectRecord(objectRecord(fixed.get('src/controls.json')).bindings);
|
|
246
|
+
const bindings = {};
|
|
247
|
+
for (const [name, value] of Object.entries(controls)) {
|
|
248
|
+
if (Array.isArray(value) && value.every((entry) => typeof entry === 'string')) {
|
|
249
|
+
bindings[name] = value;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const stateFiles = new Set((await directFiles(path.join(projectPath, 'src/states'), '.ts')).map((file) => file.slice(0, -'.ts'.length)));
|
|
253
|
+
const context = {
|
|
254
|
+
findings,
|
|
255
|
+
manifest,
|
|
256
|
+
knownComponents: new Set(Object.keys(manifest.registry.components)),
|
|
257
|
+
projectComponents,
|
|
258
|
+
stateFiles,
|
|
259
|
+
roleStateSources,
|
|
260
|
+
bindings,
|
|
261
|
+
};
|
|
262
|
+
const prefabs = new Map();
|
|
263
|
+
for (const [directory, type] of [
|
|
264
|
+
['characters', 'character'],
|
|
265
|
+
['objects', 'object'],
|
|
266
|
+
['tiles', 'tile'],
|
|
267
|
+
]) {
|
|
268
|
+
const suffix = `.${type}.json`;
|
|
269
|
+
for (const file of await directFiles(path.join(projectPath, 'src', directory), suffix)) {
|
|
270
|
+
const relative = `src/${directory}/${file}`;
|
|
271
|
+
const parsed = await parseJson(projectPath, relative, findings);
|
|
272
|
+
if (!parsed || typeof parsed !== 'object')
|
|
273
|
+
continue;
|
|
274
|
+
const ref = `${directory}/${file.slice(0, -suffix.length)}`;
|
|
275
|
+
const prefab = parsed;
|
|
276
|
+
prefabs.set(ref, prefab);
|
|
277
|
+
validatePrefab(prefab, relative, ref, context);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const uiFiles = await directFiles(path.join(projectPath, 'src/ui'), '.html');
|
|
281
|
+
const uiNames = new Set(uiFiles.map((file) => file.slice(0, -'.html'.length)));
|
|
282
|
+
const declaredStats = new Set(Object.keys(objectRecord(objectRecord(fixed.get('src/stats.json')).stats)));
|
|
283
|
+
for (const file of uiFiles) {
|
|
284
|
+
const relative = `src/ui/${file}`;
|
|
285
|
+
const html = await readFile(path.join(projectPath, relative), 'utf8');
|
|
286
|
+
for (const stat of statBindings(html)) {
|
|
287
|
+
if (!declaredStats.has(stat)) {
|
|
288
|
+
add(context, 'warning', 'undeclared-stat', `UI references undeclared stat "${stat}"; runtime writes may still create it.`, relative, stat);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const sceneFiles = await directFiles(path.join(projectPath, 'src/scenes'), '.scene.json');
|
|
293
|
+
for (const file of sceneFiles) {
|
|
294
|
+
const relative = `src/scenes/${file}`;
|
|
295
|
+
const parsed = await parseJson(projectPath, relative, findings);
|
|
296
|
+
if (!parsed || typeof parsed !== 'object')
|
|
297
|
+
continue;
|
|
298
|
+
validateScene(parsed, relative, prefabs, uiNames, context);
|
|
299
|
+
}
|
|
300
|
+
const params = objectRecord(fixed.get('public/waica.params.json'));
|
|
301
|
+
for (const [entity, rawComponents] of Object.entries(params)) {
|
|
302
|
+
for (const component of Object.keys(objectRecord(rawComponents))) {
|
|
303
|
+
checkComponent({ type: component }, 'public/waica.params.json', entity, context);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const summary = {
|
|
307
|
+
errors: findings.filter((finding) => finding.severity === 'error').length,
|
|
308
|
+
warnings: findings.filter((finding) => finding.severity === 'warning').length,
|
|
309
|
+
infos: findings.filter((finding) => finding.severity === 'info').length,
|
|
310
|
+
};
|
|
311
|
+
const provenance = provenanceRows([engine, behaviors, ...archetypes.map((entry) => entry.loaded)]);
|
|
312
|
+
return {
|
|
313
|
+
findings,
|
|
314
|
+
summary,
|
|
315
|
+
ok: summary.errors === 0,
|
|
316
|
+
notes: [
|
|
317
|
+
...check.notes,
|
|
318
|
+
'The shipped runtime loads src/scenes/main.scene.json; other scenes are validated but are not loaded automatically.',
|
|
319
|
+
],
|
|
320
|
+
provenance,
|
|
321
|
+
warnings: [...discoveryWarnings, ...mixedSourceWarnings(provenance)],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
let mappings = {};
|
|
2
|
+
let parentPrefixes = [];
|
|
3
|
+
export function initialize(data) {
|
|
4
|
+
mappings = data.mappings;
|
|
5
|
+
parentPrefixes = data.parentPrefixes;
|
|
6
|
+
}
|
|
7
|
+
export function resolve(specifier, context, nextResolve) {
|
|
8
|
+
const mapped = mappings[specifier];
|
|
9
|
+
const parentURL = context.parentURL;
|
|
10
|
+
const bundledParent = parentURL !== undefined && parentPrefixes.some((prefix) => parentURL.startsWith(prefix));
|
|
11
|
+
return mapped && bundledParent
|
|
12
|
+
? Promise.resolve({ url: mapped, shortCircuit: true })
|
|
13
|
+
: nextResolve(specifier, context);
|
|
14
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { access, readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const WORKSPACE_DIRECTORIES = {
|
|
6
|
+
'@waica/engine': 'engine',
|
|
7
|
+
'@waica/behaviors': 'behaviors',
|
|
8
|
+
'@waica/archetype-platformer': 'archetype-platformer',
|
|
9
|
+
};
|
|
10
|
+
let workspaceHooks;
|
|
11
|
+
let workspacePackages;
|
|
12
|
+
async function exists(target) {
|
|
13
|
+
try {
|
|
14
|
+
await access(target);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === 'ENOENT')
|
|
19
|
+
return false;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The server runs both from `packages/mcp/dist` and from the copy the waica CLI
|
|
25
|
+
* bundles under its own `dist`, so the checkout root is searched for rather than
|
|
26
|
+
* assumed at a fixed depth. An unrelated pnpm workspace is harmless: the built
|
|
27
|
+
* engine files below are what actually gate the hook.
|
|
28
|
+
*/
|
|
29
|
+
async function findWorkspaceRoot() {
|
|
30
|
+
for (let current = here;; current = path.dirname(current)) {
|
|
31
|
+
if (await exists(path.join(current, 'pnpm-workspace.yaml')))
|
|
32
|
+
return current;
|
|
33
|
+
const parent = path.dirname(current);
|
|
34
|
+
if (parent === current)
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function isPackageNamed(packageRoot, packageName) {
|
|
39
|
+
try {
|
|
40
|
+
const manifest = JSON.parse(await readFile(path.join(packageRoot, 'package.json'), 'utf8'));
|
|
41
|
+
return manifest.name === packageName;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function loadWorkspacePackages() {
|
|
48
|
+
const found = new Map();
|
|
49
|
+
const repositoryRoot = await findWorkspaceRoot();
|
|
50
|
+
if (repositoryRoot === undefined)
|
|
51
|
+
return found;
|
|
52
|
+
for (const [packageName, directory] of Object.entries(WORKSPACE_DIRECTORIES)) {
|
|
53
|
+
const packageRoot = path.join(repositoryRoot, 'packages', directory);
|
|
54
|
+
if ((await exists(path.join(packageRoot, 'dist/index.js'))) &&
|
|
55
|
+
(await isPackageNamed(packageRoot, packageName))) {
|
|
56
|
+
found.set(packageName, packageRoot);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The built checkout copy of a bundled package, when the server runs from this
|
|
63
|
+
* repository. The waica CLI vendors its own copies under `dist`, so without
|
|
64
|
+
* this a workspace-linked project would look like a mismatch against them
|
|
65
|
+
* instead of like the very same package.
|
|
66
|
+
*/
|
|
67
|
+
export async function workspacePackageRoot(packageName) {
|
|
68
|
+
workspacePackages ??= loadWorkspacePackages();
|
|
69
|
+
return (await workspacePackages).get(packageName);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Built workspace packages still import one another by bare package name while
|
|
73
|
+
* checkout exports point at source TypeScript. Map only imports whose parent is
|
|
74
|
+
* already inside one of those built dist trees. Project-anchored resolution is
|
|
75
|
+
* deliberately outside this scope and therefore remains authoritative.
|
|
76
|
+
*/
|
|
77
|
+
export async function prepareWorkspaceRuntime() {
|
|
78
|
+
const repositoryRoot = await findWorkspaceRoot();
|
|
79
|
+
if (repositoryRoot === undefined)
|
|
80
|
+
return;
|
|
81
|
+
const files = {
|
|
82
|
+
'@waica/engine': path.join(repositoryRoot, 'packages/engine/dist/index.js'),
|
|
83
|
+
'@waica/behaviors': path.join(repositoryRoot, 'packages/behaviors/dist/index.js'),
|
|
84
|
+
'@waica/archetype-platformer': path.join(repositoryRoot, 'packages/archetype-platformer/dist/index.js'),
|
|
85
|
+
'@waica/archetype-platformer/manifest': path.join(repositoryRoot, 'packages/archetype-platformer/dist/manifest.js'),
|
|
86
|
+
};
|
|
87
|
+
if (!(await Promise.all(Object.values(files).map(exists))).every(Boolean))
|
|
88
|
+
return;
|
|
89
|
+
const mappings = Object.fromEntries(Object.entries(files).map(([specifier, file]) => [specifier, pathToFileURL(file).href]));
|
|
90
|
+
const parentPrefixes = ['engine', 'behaviors', 'archetype-platformer'].map((directory) => `${pathToFileURL(path.join(repositoryRoot, 'packages', directory, 'dist')).href}/`);
|
|
91
|
+
const moduleApi = await import('node:module');
|
|
92
|
+
if (typeof moduleApi.registerHooks === 'function') {
|
|
93
|
+
workspaceHooks = moduleApi.registerHooks({
|
|
94
|
+
resolve(specifier, context, nextResolve) {
|
|
95
|
+
const mapped = mappings[specifier];
|
|
96
|
+
const parentURL = context.parentURL;
|
|
97
|
+
const bundledParent = parentURL !== undefined && parentPrefixes.some((prefix) => parentURL.startsWith(prefix));
|
|
98
|
+
return mapped && bundledParent
|
|
99
|
+
? { url: mapped, shortCircuit: true }
|
|
100
|
+
: nextResolve(specifier, context);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
moduleApi.register(new URL('./workspace-loader.js', import.meta.url), {
|
|
106
|
+
parentURL: import.meta.url,
|
|
107
|
+
data: { mappings, parentPrefixes },
|
|
108
|
+
});
|
|
109
|
+
}
|