From 9376cabca2a38816f262013864ce2d7e09c55c57 Mon Sep 17 00:00:00 2001 From: araharah-executor Date: Thu, 22 Oct 2026 23:24:41 +0800 Subject: [PATCH] feat(03-01): stand up web/ npm workspace with Wave-0 hand-rolled test runner (D-01, D-02, D-11, D-14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - web/ workspace: TS + Vite shell (maplibre-gl 6.15.0, vite 8.3.5, TS 5.9.3; no UI framework, no Telegram SDK script tag) - tsconfig mirrors bot/ strictness byte-for-byte except the three authorized keys (DOM lib, vite/client types, resolveJsonModule) - test/runner.mjs + harness.mjs copied verbatim from bot/test/ (body-identical past header) - root package.json: web workspace + web:* delegate scripts - web/src/main.ts entry module created (tsc include:['src'] needs ≥1 input; 03-02/03-03 mount here) --- package.json | 10 ++++++++-- web/index.html | 12 +++++++++++ web/package.json | 21 ++++++++++++++++++++ web/src/main.ts | 10 ++++++++++ web/test/harness.mjs | 10 ++++++++++ web/test/runner.mjs | 47 ++++++++++++++++++++++++++++++++++++++++++++ web/tsconfig.json | 18 +++++++++++++++++ web/vite.config.ts | 14 +++++++++++++ 8 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 web/index.html create mode 100644 web/package.json create mode 100644 web/src/main.ts create mode 100644 web/test/harness.mjs create mode 100644 web/test/runner.mjs create mode 100644 web/tsconfig.json create mode 100644 web/vite.config.ts diff --git a/package.json b/package.json index 2f33a1b..09b9243 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "type": "module", "workspaces": [ "theme", - "bot" + "bot", + "web" ], "scripts": { "build": "npm run build --workspace theme", @@ -16,6 +17,11 @@ "bot:typecheck": "npm run typecheck -w bot", "bot:dev": "npm run dev -w bot", "bot:deploy": "npm run deploy -w bot", - "bot:commands": "npm run commands -w bot" + "bot:commands": "npm run commands -w bot", + "web:test": "npm test -w web", + "web:typecheck": "npm run typecheck -w web", + "web:dev": "npm run dev -w web", + "web:build": "npm run build -w web", + "web:capture": "npm run capture -w web" } } diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..7336934 --- /dev/null +++ b/web/index.html @@ -0,0 +1,12 @@ + + + + + + araharah + + +
+ + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..5d8f052 --- /dev/null +++ b/web/package.json @@ -0,0 +1,21 @@ +{ + "name": "@araharah/web", + "private": true, + "type": "module", + "scripts": { + "test": "node test/runner.mjs", + "typecheck": "tsc --noEmit", + "dev": "vite", + "build": "vite build", + "capture": "node scripts/capture.mjs" + }, + "dependencies": { + "maplibre-gl": "^6.15.0", + "@araharah/theme": "*" + }, + "devDependencies": { + "vite": "^8.3.5", + "typescript": "^5.9.3", + "playwright": "^1.50.0" + } +} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..686efa1 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,10 @@ +/* + * main.ts — the Mini App entry module (D-01, D-02, D-11). + * -------------------------------------------------------- + * The one-and-only DOM entry: web/index.html loads it as `type="module"` + * into `
`. This plan (03-01) scaffolds the workspace; the + * Telegram WebApp binding behind the narrow TelegramWebAppLike interface + * and the map shell mount here in plans 03-02 and 03-03. Kept + * dependency-free until those plans introduce their modules. + */ +export {}; diff --git a/web/test/harness.mjs b/web/test/harness.mjs new file mode 100644 index 0000000..bebcfdc --- /dev/null +++ b/web/test/harness.mjs @@ -0,0 +1,10 @@ +/* + * harness.mjs — zero-dependency test registry (D-12). + * Suites import { test } and register async cases; runner.mjs drains the registry. + * Same hand-rolled shape as theme/scripts/audit.test.mjs (Phase 1 precedent). + */ +const tests = []; +export function test(name, fn) { + tests.push({ name, fn }); +} +export const registry = tests; diff --git a/web/test/runner.mjs b/web/test/runner.mjs new file mode 100644 index 0000000..333fe2f --- /dev/null +++ b/web/test/runner.mjs @@ -0,0 +1,47 @@ +#!/usr/bin/env node +/* + * runner.mjs — hand-rolled zero-dependency test runner (D-02, D-11). + * + * Auto-discovers *.test.mjs in this directory (sorted), dynamic-imports + * them, and drains the harness registry. A suite that fails to LOAD is + * recorded as one failing case — the run never crashes mid-way. + * Same hand-rolled shape as theme/scripts/audit.test.mjs (Phase 1) + * and bot/test/ (Phase 2) — copied verbatim, workspace-agnostic. + */ +import { readdirSync } from "node:fs"; +import { registry } from "./harness.mjs"; + +const dir = import.meta.dirname; +const suites = readdirSync(dir) + .filter((f) => f.endsWith(".test.mjs")) + .sort(); + +for (const file of suites) { + try { + await import(`./${file}`); + } catch (loadErr) { + registry.push({ + name: `suite load failed: ${file}`, + fn: () => { + throw loadErr; + }, + }); + } +} + +let passedCount = 0; +let failedCount = 0; +for (const { name, fn } of registry) { + try { + await fn(); + passedCount++; + console.log(`PASS ${name}`); + } catch (err) { + failedCount++; + console.log(`FAIL ${name}`); + console.error(` ${err && err.stack ? err.stack : String(err)}`); + } +} + +console.log(`[runner] ${passedCount} passed, ${failedCount} failed`); +process.exitCode = failedCount > 0 ? 1 : 0; diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..44e869e --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2023", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "types": ["vite/client"], + "strict": true, + "noUncheckedIndexedAccess": true, + "verbatimModuleSyntax": true, + "allowImportingTsExtensions": true, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "include": ["src"] +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 0000000..65f294e --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "vite"; + +export default defineConfig({ + base: "/", + build: { + outDir: "dist", + emptyOutDir: true, + target: "es2022", + }, + server: { + port: 5173, + strictPort: true, + }, +});