Skip to main content

data-client-v0-18-migration

Migrate @data-client codebases to v0.18 delegate signatures. Drives the v0.18 codemod and then handles the cases it cannot — especially registering argsKey for schemas whose output depends on endpoint args. Use when upgrading to v0.18, seeing TS errors about unvisit/visit/args/delegate signatures, or adapting custom Schema implementations.

Datos de origen

Repositorio
reactive/data-client
Última actividad en el origen
19 de agosto de 2026 a las 17:11
Idioma detectado de SKILL.md
inglés
Estrellas
2037
Forks
99

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
data-client-v0.18-migration
description
Migrate @data-client codebases to v0.18 delegate signatures. Drives the v0.18 codemod and then handles the cases it cannot — especially registering argsKey for schemas whose output depends on endpoint args. Use when upgrading to v0.18, seeing TS errors about unvisit/visit/args/delegate signatures, or adapting custom Schema implementations.
# @data-client v0.18 Migration Applies to anyone implementing a custom [`Schema`](https://dataclient.io/rest/api/SchemaSimple) — `SchemaSimple`, `SchemaClass`, polymorphic wrappers, or types that subclass `EntityMixin` directly. Built-in schemas (`Entity`, `resource()`, `Collection`, `Union`, `Values`, `Array`, `Object`, `Query`, `Invalidate`, `Lazy`) are migrated by the library. ## What changed `Schema.denormalize` and `Schema.normalize` now take a single `delegate` instead of `(args, unvisit)` / `(args, visit, delegate)`: ```ts denormalize(input, delegate) { return delegate.unvisit(this.schema, input); } normalize(input, parent, key, delegate /*, parentEntity? */) { return delegate.visit(this.schema, input, parent, key); } ``` Critical semantic change: reading `delegate.args` does **not** contribute to cache invalidation. Schemas whose *output* varies with endpoint args must register that dependency through [`delegate.argsKey(fn)`](https://dataclient.io/rest/api/SchemaSimple). See [Step 2](#step-2-register-argskey-for-args-dependent-schemas-not-automatable) below. ## Step 1: run the codemod **Pre-check — skip the rest of this skill if it doesn't apply.** Most apps that only consume `@data-client` (use `Entity`, `resource()`, `Collection`, `Query`, etc.) need *zero* code changes for v0.18. Run the search below at your repo root — `rg` respects `.gitignore` so it won't dive into `node_modules`. If it returns nothing, you're done; bump the package versions and move on. ```bash # preferred (ripgrep) rg -n 'extends (Schema|SchemaSimple|SchemaClass|EntityMixin)\b|^\s*_?(de)?normalize\s*[(=:]|\bunvisit\b|\bvisit\(' . # fallback (POSIX grep) — adjust the path list to your source roots grep -rEn --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' \ 'extends (Schema|SchemaSimple|SchemaClass|EntityMixin)\b|^[[:space:]]*_?(de)?normalize[[:space:]]*[(=:]|\bunvisit\b|\bvisit\(' \ src app lib packages 2>/dev/null ``` The pre-check intentionally ignores `Entity` overrides of `pk`, `process`, and `merge` — those signatures didn't change in v0.18. Only the `denormalize` / `normalize` delegate signature did. Otherwise, commit first so you can diff, then run the codemod against your source roots — `src/` is the conventional location, but App Router (`app/`), Vue (`src/`), monorepo packages (`packages/`), and library (`lib/`) layouts all need the path adjusted: ```bash npx jscodeshift -t https://dataclient.io/codemods/v0.18.js --extensions=ts,tsx,js,jsx <source-root> ``` Do **not** point jscodeshift at the repo root — it doesn't respect `.gitignore` and will walk into `node_modules`. A clean run looks like `0 errors, N unmodified, 0 skipped` — that's expected, not a failure. The codemod rewrites parameter lists, body references (`unvisit(…)`, `visit(…)`, bare `args`), pass-through calls, TS method/property signatures, and adds `IDenormalizeDelegate` / `INormalizeDelegate` imports. After it runs, only the cases below need hand work. **Single-file components (Vue/Svelte/Astro/MDX):** the codemod uses jscodeshift's `tsx` parser, which can't parse SFCs — adding `.vue` (etc.) to `--extensions` produces parse errors, not transforms. If your schemas live inside SFC `<script>` blocks, either extract them to plain `.ts` first (preferred — schemas are usually shared across components anyway) or migrate those files by hand using the rewrite shape from [Step 3](#step-3-hand-migrate-cases-the-codemod-skips). ## Step 2: register `argsKey` for args-dependent schemas (not automatable) If your schema's *return value* depends on endpoint args, the codemod will rewrite `args` → `delegate.args`, but that read alone no longer participates in memoization. Register the dependency explicitly so the cache invalidates correctly. `argsKey(fn)` returns `fn(args)` and uses the function reference itself as the cache path key. **`fn` must be referentially stable** — bind it on the instance or at module scope. An inline arrow creates a new reference per call and misses the cache every time. ```ts class LensSchema { constructor({ lens }) { this.lensSelector = lens; } denormalize(input, delegate) { const lens = delegate.argsKey(this.lensSelector); return this.lookup(input, lens); } } ``` See [`Scalar`](https://dataclient.io/rest/api/Scalar) for a real-world example. ## Step 3: hand-migrate cases the codemod skips The codemod no-ops on these — find them and update by hand. The shape of the change is always the same: `(input, args, unvisit)` → `(input, delegate)` and `(input, parent, key, args, visit, delegate[, parentEntity])` → `(input, parent, key, delegate[, parentEntity])`, with `unvisit`/`visit` becoming `delegate.unvisit`/`delegate.visit` and bare `args` becoming `delegate.args`. - **Files with no `@data-client/*` import** — the codemod gates on this. Either add an import or migrate the file by hand. - **Class fields** — `denormalize = (input, args, unvisit) => { ... }`. Rewrite to a method (`denormalize(input, delegate) { ... }`) so future codemods catch it too. - **`const denormalize = function...`** / **`const normalize = function...`** — only `function` declarations and methods are matched. - **Computed or dynamic method keys** — `[name]: function(...)`, `obj.denormalize = function(...)`. Identifier and string-literal keys are matched; nothing else is. - **Interface methods named `_denormalize` / `_denormalizeNullable`** as `TSMethodSignature` — only the literal key `denormalize` is matched in that form. The same names *are* handled when written as `declare` fields or property signatures with a function type. Either rename to `denormalize` on the interface or edit the parameter list manually. - **Custom helper functions** that wrap `(args, unvisit)` and are passed around — update the helper signature and every caller. ## Step 4: verify 1. Run the type-checker. Residual errors about `unvisit`, `visit`, `args`, or delegate parameter counts point at code Step 3 missed. 2. Run your test suite. Cache-invalidation regressions usually surface as stale denormalized values when args change — that signals a missing `argsKey` from Step 2. 3. Grep for leftover patterns the codemod can't see: - `denormalize(` followed by three params, or `normalize(` with `args, visit, delegate` - bare `unvisit(` / `visit(` calls inside denormalize/normalize bodies - spread `...args` inside denormalize/normalize bodies ## Optional: Collection consolidation Unrelated to delegate signatures: v0.18 lets a single `Collection` carry both `argsKey` and `nestKey`, so the same instance can back a top-level endpoint schema and a nested entity field. See [Optional: consolidate Collection definitions](/blog/2026/05/01/v0.18-scalar-typed-downloads#collection-consolidation) in the v0.18 blog. ## Reference - New interfaces: [`IDenormalizeDelegate`](https://dataclient.io/rest/api/SchemaSimple), [`INormalizeDelegate`](https://dataclient.io/rest/api/SchemaSimple) - Built-in schema diffs: `packages/endpoint/src/schemas/{Array,Object,Values,Union,Query,Invalidate,Lazy,Collection}.ts` - Changesets: `.changeset/denormalize-delegate.md`, `.changeset/normalize-delegate.md` - Codemod source: [`website/static/codemods/v0.18.js`](https://github.com/reactive/data-client/blob/master/website/static/codemods/v0.18.js)
Ver en GitHub