# Spectral Codemods

When a Spectral release changes how you write custom connectors or code-native integrations, a **codemod** can make most of the change for you. `@prismatic-io/spectral-codemod` is a command-line tool that rewrites your project's source and package files in place, then reports what it couldn't migrate so you can finish by hand.

## Run a codemod[​](#run-a-codemod "Direct link to Run a codemod")

Run the latest codemods with `npx`; you don't need to add the package to your project. Name the codemod, pass the Spectral version you're upgrading to with `--target-spectral`, and give the path to your project:

Preview a codemod, then apply it

```bash
# Report the files that would change, without writing them
npx @prismatic-io/spectral-codemod@latest public-entry-points --target-spectral latest . --dry-run

# Apply the changes
npx @prismatic-io/spectral-codemod@latest public-entry-points --target-spectral latest .

```

A codemod can have more than one version as Spectral changes. The tool runs the latest version of that codemod at or below your target, so you don't need to know which Spectral release introduced it. A preview release, such as `10.36.0-preview.1`, counts as earlier than its release.

| Option                        | Description                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------------- |
| `--target-spectral <version>` | The Spectral version you're migrating to, such as `10.37.0` or `latest`. Required. |
| `--dry-run`                   | List the files that would change without writing them.                             |
| `--list`                      | Print the available codemods and what each one does.                               |
| `--help`                      | Print usage information.                                                           |

### Choose what to migrate[​](#choose-what-to-migrate "Direct link to Choose what to migrate")

The path argument defaults to the current directory, and it determines which files the codemod reads:

* **A directory with a `tsconfig.json`**: the files that `tsconfig.json` includes.
* **Any other directory**: every `.ts` and `.tsx` file beneath it, except in `node_modules` and `dist`.
* **A `tsconfig.json` file**: the files it includes.
* **A single source file**: that file, the files it imports, and the test files that import any of them.

If a project contains more than one code-native integration, pass the file that defines the integration you want to migrate.

### Review the result[​](#review-the-result "Direct link to Review the result")

Commit or stash your work before you run a codemod, so `git diff` shows exactly what it changed. After it runs, the codemod lists the files it changed:

```text
v10.36.0/integration-configuration: scanned 1 files, changed 1
  src/index.ts

```

It then prints a line beginning with `warning:` for each thing it left for you to handle, naming the file involved. Some codemods also leave `TODO` comments at the code that needs your attention. Run your type checker and tests before you publish the migrated project.

## Available codemods[​](#available-codemods "Direct link to Available codemods")

| Codemod                                                                                                                | Minimum `--target-spectral` | Use it when                                                                          |
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------ |
| [`public-entry-points`](https://prismatic.io/docs/spectral/spectral-codemods.md#public-entry-points)                   | `10.35.1`                   | Your code imports from `@prismatic-io/spectral/dist/...` paths.                      |
| [`integration-configuration`](https://prismatic.io/docs/spectral/spectral-codemods.md#integration-configuration)       | `10.36.0`                   | You're moving a code-native integration from config pages to headless configuration. |
| [`callable-component-packaging`](https://prismatic.io/docs/spectral/spectral-codemods.md#callable-component-packaging) | `10.36.0`                   | You want to publish a custom connector as an npm package as well as to Prismatic.    |

Run `npx @prismatic-io/spectral-codemod@latest --list` for the current list. The list names each codemod version with its Spectral version, such as `v10.35.1/public-entry-points`; you can pass that name in place of the codemod name and `--target-spectral`.

### Public entry points[​](#public-entry-points "Direct link to Public entry points")

`public-entry-points` moves imports of Spectral's `dist/` paths to the public entry points that load the same modules. It works on both custom connectors and code-native integrations.

| From                                                                                         | To                               |
| -------------------------------------------------------------------------------------------- | -------------------------------- |
| `@prismatic-io/spectral/dist`, `@prismatic-io/spectral/dist/index`                           | `@prismatic-io/spectral`         |
| `@prismatic-io/spectral/dist/clients/http`, `@prismatic-io/spectral/dist/clients/http/index` | `@prismatic-io/spectral/http`    |
| `@prismatic-io/spectral/dist/testing`                                                        | `@prismatic-io/spectral/testing` |

The codemod also rewrites these paths with a `.js` extension or trailing slash, and in `export ... from`, `import()` types, `require()`, dynamic `import()`, and mocks such as `vi.mock()`. Other `dist/` paths, such as `@prismatic-io/spectral/dist/conditionalLogic`, have no public entry point and stay as they are; the codemod prints a warning naming each file that imports one. See the [Spectral 10.35 upgrade guide](https://prismatic.io/docs/spectral/spectral-10-35-upgrade-guide.md) for how to update those imports.

### Integration configuration[​](#integration-configuration "Direct link to Integration configuration")

`integration-configuration` converts a code-native integration that uses [config pages](https://prismatic.io/docs/integrations/code-native/config-wizard.md) to [headless configuration](https://prismatic.io/docs/integrations/headless-configuration.md). It performs the code changes described in [Migrating from config pages](https://prismatic.io/docs/integrations/headless-configuration/migrating-from-config-pages.md), starting from the config pages you already have:

* **Configuration**: Replaces `configPages`, `userLevelConfigPages`, and `scopedConfigVars` with a `configuration()`. Config pages become the `instance` scope, and user-level config pages become the `userLevel` scope.
* **Schema**: Writes a zod `configPagesSchema` for each scope, with a required field for each config variable, keyed by config variable name. The scope's `schema` starts as the same shape, and its `version` is `"INITIAL"`.
* **Connections**: Moves each connection into the `connections` of its scope.
* **Init**: Adds an `init` function that proposes each instance's saved config page values unchanged.
* **Data sources**: Converts each data source with an inline `perform` to a [server function](https://prismatic.io/docs/integrations/headless-configuration/server-functions.md) declared beside it.
* **Flows**: Rewrites `context.configVars` reads to `context.configuration`, `context.userConfiguration`, or `context.connections`, and rewrites `invokeFlow` calls in flow tests to pass the configuration instead of `configVars`.
* **Schedules**: Changes each flow schedule that reads a config variable to `{ fromDeployer: true }`, so the deploying user supplies the schedule.

The codemod adds an import from `zod`; install it if your project doesn't already depend on it.

After the codemod runs, finish the migration yourself:

1. **Convert the config page values in `init`.** The generated `init` passes the old values through with a type cast that isn't checked at runtime. Config pages stored values such as numbers and booleans as strings, so parse them as shown in [Migrating from config pages](https://prismatic.io/docs/integrations/headless-configuration/migrating-from-config-pages.md#migrate-the-integration).
2. **Resolve each warning, `TODO`, and type error.** The codemod leaves a `TODO` where it can't follow a `configVars` read, such as a computed key or `configVars` passed whole to a helper. It also leaves component data source references, and data sources whose `perform` is declared elsewhere, for you to convert.
3. **Handle missing values in flows.** The rewritten reads are optional, such as `context.configuration?.["Batch Size"]`, because an instance's configuration can be absent. Code that assumed a config variable always had a value needs to handle `undefined`.
4. **Review the schema.** The generated schema doesn't carry over default values, visibility settings, or permissions, and it describes `jsonForm` values as `z.unknown()`. To change the schema later, give the scope a new `version` as described in [Configuration versions](https://prismatic.io/docs/integrations/headless-configuration/configuration-versions.md).
5. **Delete the config page declarations** once you've reviewed the result. The generated configuration references connections where they're declared, such as `configPages.Connections.elements["Acme Connection"]`, so move those definitions before you delete the pages.

When the codemod can't resolve a page, element, or spread to an object literal, it stops and reports the location rather than drop what it holds. The migrated flow tests require a Spectral release whose `invokeFlow` accepts `configuration`, `userConfiguration`, and `connections`.

### Callable component packaging[​](#callable-component-packaging "Direct link to Callable component packaging")

`callable-component-packaging` configures a custom connector to build a CommonJS npm package alongside its Prismatic build. Pass the connector's project directory as the path; this codemod doesn't accept a single file.

Before it writes anything, the codemod checks that the project meets these requirements, and stops if it doesn't:

* Dependencies on tsdown `>=0.22.3` and Spectral `>=10.36.0` whose declared ranges exclude older releases, plus TypeScript and a `tsconfig.json`. The codemod doesn't upgrade dependencies for you.
* `src/index.ts` default-exports Spectral's `component()`.
* A single static tsdown `defineConfig` that builds `src/index.ts` to a self-contained CommonJS `dist/index.js`. The config may load Markdown files as text and copy `assets/**/*`, or the flattened `assets/*` that Prism scaffolded before October 2026; other loaders, copy rules, or additional builds require manual changes.
* A CommonJS package whose `build` script ends with `tsdown`, such as `npm run lint && tsdown`.

The codemod adds an `npm-dist/index.cjs` entry point and its type declarations, configures the package's exports and the files it publishes, and sets `prismatic.component` to `./dist/index.js`. It moves Spectral to `peerDependencies` and `devDependencies`, appends `npm run build` to the `prepare` script, and excludes `npm-dist` wherever `.gitignore` or a Biome config excludes `dist`. Running it again makes no further changes.

The codemod warns about dependencies declared with `file:`, `link:`, or `portal:`, because npm can't install them from the published package. Bundle those dependencies into the npm build with `deps.alwaysBundle` in your tsdown config.

After applying the codemod, reinstall dependencies to update your lockfile, run your tests, and run `npm pack` to check the package contents. Projects that install the package need Spectral installed, and access the callable component through the package's default export.
