Skip to content

Commit 619565d

Browse files
hyperpolymathclaude
andcommitted
docs(migrations): canonical npm→Deno template + 2026-05-30 re-inventory (closes #262)
STEP 2 of campaign #253. Adds: - docs/migrations/npm-to-deno-template/deno.json — canonical shape derived from echidna + svalinn + oikos Phase 5 follow-ups. Class A (pure-Deno port) defaults to nodeModulesDir: "none"; Class B (npm wrapper via Deno) sets "auto" per task. - docs/migrations/npm-to-deno-template/MIGRATION.md — per-repo recipe: class triage, scaffolding deletion, CI workflow swaps, commit pattern, PR + auto-merge convention. - docs/migrations/npm-to-deno-template/INVENTORY-2026-05-30.md — re-run with documented excludes returns 162 manifests across 63 repos. Drift from umbrella baseline (172) is -5.8%, within tolerance. No STEP re-ordering required. Source TSV at ~/Documents/npm-to-deno-inventory-2026-05-30.tsv. Closes #262. STEPs 3-7 unblocked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5f83ea9 commit 619565d

3 files changed

Lines changed: 277 additions & 0 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# npm → Deno estate inventory — 2026-05-30 re-run
2+
3+
Re-inventory per `hyperpolymath/standards#262` acceptance criterion. The
4+
umbrella body (`#253`) cited **172** `package.json` manifests as of
5+
2026-05-28; a looser `find` on 2026-05-30 returned **437** before excludes.
6+
7+
Re-running with the umbrella's documented exclude set produces **162**
8+
manifests across **63** repositories — within 6 % of the planning baseline,
9+
no STEP re-sizing required.
10+
11+
## Exclude set applied
12+
13+
Parallel to `hypatia/lib/rules/cicd_rules.ex :nodejs_detected
14+
path_allow_prefixes`:
15+
16+
- `**/node_modules/**`, `**/deps/**` (vendored)
17+
- `rescript/`, `servers/`, `repos-monorepo/`, `linguist/` (upstream forks)
18+
- `hyperpolymath-archive/**` (archived)
19+
- `**/vscode/**` (VSCode extension host-required)
20+
- `affinescript-deno-test/`, `affinescript-cli/` (bootstrap shims)
21+
- `**/example/**`, `**/examples/**`, `**/test-fixtures/**`, `**/fixtures/**` (fixtures)
22+
- `**/.git/**`
23+
24+
## Per-repo manifest count (top 25)
25+
26+
| Manifests | Repo |
27+
|---|---|
28+
| 28 | developer-ecosystem |
29+
| 14 | ssg-collection |
30+
| 10 | affinescript |
31+
| 9 | accessibility-everywhere |
32+
| 7 | burble |
33+
| 7 | affinescript-stdlib-pr |
34+
| 5 | stapeln |
35+
| 5 | boj-server |
36+
| 4 | standards |
37+
| 4 | reposystem |
38+
| 4 | flat-mate |
39+
| 3 | wordpress-tools |
40+
| 3 | julia-the-viper |
41+
| 3 | idaptik |
42+
| 2 | zotero-tools, typed-wasm, proven, patallm-gallery, my-lang, kaldor-iiot, claude-integrations |
43+
44+
## STEP sizing (refreshed)
45+
46+
| STEP | Tier | Repos | Manifests |
47+
|---|---|---|---|
48+
| 3 | ≤2 manifest, smallest-first | ~45 | ~50 |
49+
| 4 | 3-7 manifest, mid | ~13 | ~57 |
50+
| 5 | 8+ manifest, larger | 3 | 27 |
51+
| 6 | developer-ecosystem only | 1 | 28 |
52+
| 7 | workspace finalisation | multi-repo wrap-up ||
53+
54+
162 = 50 + 57 + 27 + 28. STEP-7 wrap-up captures any post-batch hygiene.
55+
56+
## Drift from umbrella
57+
58+
| Source | Count | Note |
59+
|---|---|---|
60+
| Umbrella `#253` (2026-05-28) | 172 | Planning baseline |
61+
| Loose `find` (2026-05-30) | 437 | Without excludes |
62+
| **This re-run (2026-05-30)** | **162** | Documented excludes; canonical |
63+
64+
Drift -10 (-5.8 %) vs umbrella. Within tolerance; no STEP re-ordering.
65+
66+
Source TSV: `~/Documents/npm-to-deno-inventory-2026-05-30.tsv`
67+
(`<repo>\t<manifest-path>` per row, 162 rows).
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# npm → Deno per-repo migration recipe
2+
3+
Canonical procedure for migrating a hyperpolymath estate repository from
4+
`package.json` + npm/Node to `deno.json` + Deno.
5+
6+
Policy: `docs/JS-RUNTIME-POLICY.adoc` (Deno > Bun > pnpm > npm).
7+
Campaign tracker: hyperpolymath/standards#253.
8+
Rule enforcement: hypatia `cicd_rules/nodejs_detected` + `npx_or_npm_run_in_ci`.
9+
10+
## 0. Decide which class the repo is in
11+
12+
Before touching anything, decide which of the migration classes applies.
13+
Each class has a different end-state.
14+
15+
| Class | Signal | End-state |
16+
|---|---|---|
17+
| **A. Pure-Deno port** | Repo's `package.json` only lists dev-only Node-compatible tools (`typescript`, `vitest`, build helpers). No host contract requires Node. | Delete `package.json` + `package-lock.json`. Author `deno.json`. CI workflows swap to `deno test`/`deno task`. |
18+
| **B. npm wrapper via Deno** | Repo wraps an npm-published tool that does not yet have a Deno-native fork (e.g., `rescript`, `vite`, `tailwindcss`). | Keep dependency expressed as `npm:pkg@semver` inside `deno.json`'s `imports`. Tasks call `deno run -A --node-modules-dir=auto npm:pkg`. No `package.json`. |
19+
| **C. Carve-out** | One of the six classes in `cicd_rules/nodejs_detected` `path_allow_prefixes` (VSCode extension, bootstrap shim, upstream fork, archived, vendored, example/fixture). | **Skip migration.** File stays on npm; no PR. |
20+
21+
A given repo with multiple `package.json` files can split across classes — handle each manifest on its own merit.
22+
23+
## 1. Inventory the current `package.json`
24+
25+
```bash
26+
# Capture starting point.
27+
cat package.json
28+
ls -la package-lock.json bun.lockb yarn.lock pnpm-lock.yaml 2>/dev/null
29+
```
30+
31+
Record:
32+
33+
- Direct deps (`dependencies` + `devDependencies`).
34+
- Scripts (`scripts.*`).
35+
- `engines.node`, `engines.npm` — note for replacement by `engines.deno`.
36+
- `private`, `type`, `exports` — preserved as needed.
37+
38+
## 2. Author `deno.json` from the canonical template
39+
40+
Copy `deno.json` from this directory. Adjust:
41+
42+
- `name``@hyperpolymath/<repo-name>`.
43+
- `version` — preserve from `package.json`.
44+
- `license``MPL-2.0-or-later` (estate default) unless repo policy differs.
45+
- `compilerOptions` — preserve `strict` and friends from `tsconfig.json` if present.
46+
- `imports` — populate from `dependencies`:
47+
- Deno-native: `"@std/": "https://deno.land/std@0.224.0/"` (and similar).
48+
- JSR: `"@scope/pkg": "jsr:@scope/pkg@^1.2.3"`.
49+
- npm fallback: `"pkg": "npm:pkg@^1.2.3"` (Class B only).
50+
- `tasks` — port from `scripts`:
51+
- `"build": "rescript"``"build": "deno run -A --node-modules-dir=auto npm:rescript"`.
52+
- `"test": "vitest"``"test": "deno test -A src/"` (port tests to Deno test API where reachable; if not yet portable, `"test": "deno run -A --node-modules-dir=auto npm:vitest"`).
53+
- `nodeModulesDir`:
54+
- Default `"none"` (Class A — pure Deno).
55+
- Set to `"auto"` only when an npm package's lifecycle requires it (Class B; rescript and most ESM-shipped npm packages are fine without it).
56+
57+
## 3. Delete the npm scaffolding
58+
59+
```bash
60+
git rm package.json package-lock.json
61+
# Also remove bun.lockb / yarn.lock / pnpm-lock.yaml / .npmrc if present.
62+
git rm -f bun.lockb yarn.lock pnpm-lock.yaml .npmrc 2>/dev/null || true
63+
64+
# node_modules/ should already be in .gitignore.
65+
rm -rf node_modules
66+
```
67+
68+
## 4. Update `.gitignore`
69+
70+
Confirm these entries are present (RSR canonical template propagates them — see `docs/JS-RUNTIME-POLICY.adoc §Canonical .gitignore Entries`):
71+
72+
```
73+
# npm-avoidant (standards#67): estate JS-runtime policy is Deno>Bun>pnpm>npm.
74+
package-lock.json
75+
**/package-lock.json
76+
node_modules/
77+
**/node_modules/
78+
bun.lockb
79+
yarn.lock
80+
pnpm-lock.yaml
81+
```
82+
83+
## 5. Migrate CI workflows
84+
85+
Search for any of these and replace:
86+
87+
| Before | After |
88+
|---|---|
89+
| `actions/setup-node@<sha>` | `denoland/setup-deno@<sha>` (or remove if no JS step remains) |
90+
| `npm ci` / `npm install` | `deno cache <entrypoint>` (often unnecessary — Deno caches at first run) |
91+
| `npm test` / `npm run test` | `deno task test` (or `deno test -A src/`) |
92+
| `npx <tool>` | `deno run -A --node-modules-dir=auto npm:<tool>` (Class B) or Deno-native equivalent (Class A) |
93+
94+
Note: hypatia `cicd_rules/npx_or_npm_run_in_ci` blocks `npx` and `npm run` in CI run-blocks (added 2026-05-28). Don't leave any.
95+
96+
## 6. Verify locally
97+
98+
```bash
99+
deno check src/
100+
deno lint src/
101+
deno fmt --check src/
102+
deno test -A src/
103+
```
104+
105+
Class B (npm wrapper) — exercise the wrapped tool end-to-end:
106+
107+
```bash
108+
deno task build
109+
deno task test
110+
```
111+
112+
## 7. Commit pattern
113+
114+
```bash
115+
git add deno.json .gitignore .github/workflows/
116+
git rm package.json package-lock.json
117+
git commit -m "feat(deno): migrate <repo> npm → Deno (standards#253)
118+
119+
<class-specific summary: deleted N npm manifests, added deno.json with
120+
M imports, ported K tasks, CI now runs on deno test>
121+
122+
Class: A | B (per docs/migrations/npm-to-deno-template/MIGRATION.md)
123+
Carry-forward: <any blocked Deno-native equivalent, e.g. \"vitest not
124+
portable until deno-test gets <feature>\">"
125+
```
126+
127+
## 8. PR + auto-merge
128+
129+
Per estate convention: auto-merge with squash.
130+
131+
```bash
132+
gh pr create --title "feat(deno): <repo> npm → Deno (standards#253)" \
133+
--body "<paste commit body + cross-ref campaign>"
134+
gh pr merge --auto --squash --delete-branch
135+
```
136+
137+
## Carry-forward patterns observed in oikos Phase 5 + 5 follow-ups (memory)
138+
139+
- **ReScript wrapping** (canonical Class B): `deno run -A --node-modules-dir=auto npm:rescript@^12.0.0`. `--allow-scripts=npm:rescript` when the install lifecycle requires it.
140+
- **Tailwind / vite / esbuild** — same pattern as rescript: `npm:<tool>@<semver>`, `--node-modules-dir=auto`.
141+
- **`type: "module"` repos** — Deno is ESM-native, no extra step.
142+
- **`exports` field** — preserve in `deno.json` if the package is published; otherwise drop.
143+
144+
## Anti-patterns
145+
146+
- ❌ Don't keep `package.json` "for tooling only" — `deno.json` covers fmt/lint/test/tasks.
147+
- ❌ Don't fall back to `npm:` specifiers when a JSR or Deno-native equivalent exists (use `deno info <pkg>` to check).
148+
- ❌ Don't commit `node_modules/` even on Class B — `--node-modules-dir=auto` regenerates at run-time.
149+
- ❌ Don't add `"engines": {"node": "..."}` to `deno.json` — Deno doesn't honour it and it signals the repo isn't fully migrated.
150+
151+
## When migration is blocked
152+
153+
If a `package.json` cannot be removed (host-required, Node-only library, npm publish target), the path goes in the hypatia rule's `path_allow_prefixes` instead. See `standards/.claude/CLAUDE.md §npm Exemptions (Approved)` for the canonical exemption table.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
3+
"name": "@hyperpolymath/REPO-NAME",
4+
"version": "0.1.0",
5+
"license": "MPL-2.0-or-later",
6+
7+
"compilerOptions": {
8+
"strict": true,
9+
"noImplicitAny": true,
10+
"noUnusedLocals": true,
11+
"noUnusedParameters": true
12+
},
13+
14+
"imports": {
15+
"@std/": "https://deno.land/std@0.224.0/"
16+
},
17+
18+
"tasks": {
19+
"check": "deno check src/",
20+
"lint": "deno lint src/",
21+
"fmt": "deno fmt src/",
22+
"test": "deno test -A src/",
23+
24+
"ban-npm": "echo '❌ npm is BANNED estate-wide (standards#253). Use deno task / deno run.' && exit 1"
25+
},
26+
27+
"fmt": {
28+
"include": ["src/"],
29+
"exclude": [],
30+
"options": {
31+
"useTabs": false,
32+
"lineWidth": 100,
33+
"indentWidth": 2,
34+
"singleQuote": false,
35+
"proseWrap": "preserve"
36+
}
37+
},
38+
39+
"lint": {
40+
"include": ["src/"],
41+
"exclude": [],
42+
"rules": {
43+
"tags": ["recommended"],
44+
"include": [
45+
"ban-untagged-todo",
46+
"no-sync-fn-in-async-fn",
47+
"single-var-declarator"
48+
]
49+
}
50+
},
51+
52+
"test": {
53+
"include": ["src/**/*_test.ts", "src/**/*.test.ts"]
54+
},
55+
56+
"nodeModulesDir": "none"
57+
}

0 commit comments

Comments
 (0)