From 0e93b6898218a620ec49c76f7240fcf08f2d0056 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 8 Jul 2026 20:37:59 +0200 Subject: [PATCH] EANCH-WP-0001 T02: bootstrap standalone TS package + test harness Add package.json (name evidence-anchor, exports . and ./pdf, scripts test/typecheck/lint), tsconfig.json (mirrors engine, DOM+jsx), vitest.config.ts (happy-dom + react plugin), eslint.config.js (confines viewer libs to src/pdf/), .nvmrc, and placeholder src entrypoints. Depends on @citation-evidence/engine via sibling-checkout link only; no citation-evidence internals. Co-Authored-By: Claude Opus 4.8 --- .claude/ralph-loop.local.md | 2 +- .nvmrc | 1 + eslint.config.js | 49 +++++++++++++++ package.json | 59 +++++++++++++++++++ src/index.ts | 10 ++++ src/pdf/index.ts | 6 ++ tsconfig.json | 26 ++++++++ vitest.config.ts | 17 ++++++ workplans/EANCH-WP-0001-intent-placeholder.md | 2 +- 9 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 .nvmrc create mode 100644 eslint.config.js create mode 100644 package.json create mode 100644 src/index.ts create mode 100644 src/pdf/index.ts create mode 100644 tsconfig.json create mode 100644 vitest.config.ts diff --git a/.claude/ralph-loop.local.md b/.claude/ralph-loop.local.md index a336f9d..9d10a6d 100644 --- a/.claude/ralph-loop.local.md +++ b/.claude/ralph-loop.local.md @@ -1,6 +1,6 @@ --- active: true -iteration: 1 +iteration: 2 session_id: b236681f-560d-497b-aa7d-07eab42bba2b max_iterations: 12 completion_promise: "HEUREKA" diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..d5a1596 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20.10.0 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..48b7eae --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,49 @@ +// ESLint flat config — keeps viewer-library imports behind the PDF adapter +// boundary and the selector/resolution core pure. + +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; +import importPlugin from "eslint-plugin-import"; +import globals from "globals"; + +const VIEWER_LIBS = ["pdfjs-dist", "react", "react-dom", "react-pdf-highlighter-plus"]; + +export default tseslint.config( + { + ignores: ["dist/", "node_modules/", "coverage/", "**/*.d.ts"], + }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ["src/**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2022, + sourceType: "module", + globals: { ...globals.node, ...globals.browser }, + }, + plugins: { + import: importPlugin, + }, + settings: { + "import/resolver": { + typescript: { project: "./tsconfig.json" }, + }, + }, + }, + { + // The pure core (selectors, resolution, highlight helpers) must not pull in + // any concrete viewer library — those live only under src/pdf/. + files: ["src/selectors/**/*.ts", "src/highlight/**/*.ts", "src/types.ts"], + rules: { + "no-restricted-imports": [ + "error", + { + paths: VIEWER_LIBS.map((name) => ({ + name, + message: "Viewer libraries are confined to src/pdf/ (adapter boundary).", + })), + }, + ], + }, + }, +); diff --git a/package.json b/package.json new file mode 100644 index 0000000..293f3fe --- /dev/null +++ b/package.json @@ -0,0 +1,59 @@ +{ + "name": "evidence-anchor", + "version": "0.1.0", + "private": true, + "description": "Selector creation, resolution, re-anchoring, and highlight/scroll contracts for the citation-evidence ecosystem.", + "license": "Apache-2.0", + "type": "module", + "packageManager": "pnpm@9.15.0", + "engines": { + "node": ">=20.10.0" + }, + "files": [ + "src", + "README.md", + "SCOPE.md", + "INTENT.md", + "LICENSE" + ], + "exports": { + ".": "./src/index.ts", + "./pdf": "./src/pdf/index.ts" + }, + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "lint": "eslint .", + "typecheck": "tsc -b --noEmit" + }, + "dependencies": { + "@citation-evidence/engine": "link:../citation-engine" + }, + "peerDependencies": { + "pdfjs-dist": "^4.4.168", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-pdf-highlighter-plus": "^1.1.4" + }, + "devDependencies": { + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/node": "^20.14.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^9.7.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.30.0", + "globals": "^15.9.0", + "happy-dom": "^20.9.0", + "pdfjs-dist": "^4.4.168", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-pdf-highlighter-plus": "^1.1.4", + "typescript": "^5.5.4", + "typescript-eslint": "^8.0.0", + "vitest": "^2.0.5" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f986c68 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,10 @@ +// Public entrypoint for `evidence-anchor`. +// +// The stable surface consumers depend on is re-exported from here: +// - selector creation/resolution: ./selectors (T03) +// - adapter-side types + contract: ./types (T03) +// - the concrete PDF adapter: ./pdf (T04, also exposed at `evidence-anchor/pdf`) +// +// Populated during the extraction tasks; kept as an explicit placeholder so the +// package resolves and typechecks before the code lands. +export {}; diff --git a/src/pdf/index.ts b/src/pdf/index.ts new file mode 100644 index 0000000..c413a8d --- /dev/null +++ b/src/pdf/index.ts @@ -0,0 +1,6 @@ +// Subpath entrypoint `evidence-anchor/pdf` — the concrete PDF viewer adapter and +// its helpers. Keeping the adapter behind a subpath lets pure consumers use the +// selector/resolution core without pulling PDF.js or React into their bundle. +// +// Populated in T04 (PDF adapter extraction); explicit placeholder for now. +export {}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bee5967 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "noImplicitOverride": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noEmit": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "verbatimModuleSyntax": true, + "baseUrl": "." + }, + "include": ["src", "vitest.config.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..c1a3a88 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vitest/config"; +import react from "@vitejs/plugin-react"; + +// Pure selector/resolution tests are node-safe; the scroll/highlight and PDF +// adapter tests touch the DOM, so the default environment is happy-dom. The +// react plugin lets the PDF adapter (.tsx) compile under test. +// +// The one shared-type dependency, `@citation-evidence/engine`, resolves through +// its package `exports` map (`./shared`) via the sibling-checkout link — no +// local alias needed. Nothing here imports `citation-evidence` internals. +export default defineConfig({ + plugins: [react()], + test: { + environment: "happy-dom", + globals: false, + }, +}); diff --git a/workplans/EANCH-WP-0001-intent-placeholder.md b/workplans/EANCH-WP-0001-intent-placeholder.md index 3edbcf6..9f7b6dd 100644 --- a/workplans/EANCH-WP-0001-intent-placeholder.md +++ b/workplans/EANCH-WP-0001-intent-placeholder.md @@ -144,7 +144,7 @@ here and what must stay elsewhere. ```task id: EANCH-WP-0001-T02 -status: todo +status: done priority: high depends_on: [T01] state_hub_task_id: "59c07bc6-7a80-4f58-b1cf-ee2f0c26e8ed"