Skip to main content

Migrating existing JS

Nudo does not require annotations up front. The migration path is code-first: keep the implementation, generate reviewable contracts, tighten by hand, then lock CI.

existing JS  →  --draft  →  human review  →  *.nudo.js  →  check / doctor / IDE

0. Prerequisites​

pnpm add -D @nudojs/cli @nudojs/lsp   # or npx @nudojs/cli
# optional project config in package.json
{
"nudo": {
"analysis": {
"mode": "exports",
"diagnostics": "default",
"evalMissingSlot": "off"
},
"interface": { "autoBind": true }
}
}

See Coexistence with TypeScript if the repo already has tsc.

1. Inventory​

nudo interface src/

Prints every top-level export with its tier:

TierMeaningMigration action
handwrittenAlready contracted (sidecar / @nudo:refine)Leave; enforce with check
generatedCall-site domains frozen into @generatedRefresh with --emit when usage changes
implicitInference only — displayDraft candidates

2. Draft contracts from code​

nudo interface --draft src/lib.js
nudo interface --draft --write src/lib.js --fn greet --fn double
# or IDE: CodeLens ⚡ draft interface / VS Code “Nudo: Draft Interface”

Evidence in the draft module (never invents check obligations):

EvidenceSourceUse
callsite / directiveObserved argumentsBest starting point
bodyFields the implementation readsSuggestions only — fill types by hand
symbolicgeneralize return shapeReturn slot when no cases
omitted slotsNo evidenceTODO comments

Output lands in src/lib.nudo.draft.js — not ambient-loaded. Copy reviewed lines into src/lib.nudo.js.

Worked sample: docs/examples/interface-draft/.

Runnable demo (temp dir: inventory → draft → accept → check):

pnpm run migrate-demo
# from the nudo monorepo — scripts/migrate-demo.sh

3. Review checklist​

For each draft export:

  1. Params — are call-site shapes too narrow for future callers? Widen (number() vs lit(21)).
  2. Body-read fields — promote shape({ name }) only if every caller must provide them (that is a real obligation).
  3. Returns — match the contract you want enforced, not every historical result.
  4. Handwritten clash — if *.nudo.js already binds the name, keep handwritten (draft never overwrites).

Example accept:

// src/lib.nudo.js
import { fn, number, shape, string } from "@nudojs/core";

export const double = fn({ x: number() }, number());
export const greet = fn({ user: shape({ name: string() }) }, string());

4. Gate with check​

nudo check src/
nudo check src/lib.js --json # CI
  • Violations on handwritten contracts fail the build.
  • generated segments report drift as warnings (facts + refresh), not as new obligations.
  • implicit display never invents errors by itself.

Optional evaluation hints (default off):

{ "nudo": { "analysis": { "evalMissingSlot": "warning" } } }

Surfaces nudo:missing-slot when evaluation hits a closed object shape without a field — a hint to tighten drafts, not an automatic contract.

5. Freeze call-site domains (optional)​

nudo interface --emit src/lib.js --fn double --callsites test/
nudo interface --emit src/lib.js --dry-run --exit-on-diff # CI drift gate

--emit writes @generated segments from observed arguments. Use it for usage sites you trust; keep handwritten contracts for API surface you want enforced.

6. IDE / agents​

SurfaceEntry
Hover tier● interface / handwritten|generated|implicit
CodeLenspersist / update / draft
VS CodeOutput channel commands
Agentnudo.interface, nudo.interface.draft, nudo.check
CLInudo interface, --draft, --emit, nudo check, nudo doctor

7. Ongoing health​

nudo doctor src/                    # uncovered fns, drift, analysis errors
nudo infer src/lib.js --callsites test/ --emit-cases=update

Pin package versions per Versioning & Releases (0.x minors may break; 1.x core/service/cli follow SemVer).

What not to do​

  • Do not expect body if (p.foo) reads to become check obligations (C0 model).
  • Do not commit *.nudo.draft.js as if it were a live contract — copy into *.nudo.js first.
  • Do not treat generated snapshots as the full API you intend to enforce — promote to handwritten when it matters.

See also​