@vzn/vx-migrate 0.0.611 → 0.0.612
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/turbo/turbo-map.ts +18 -5
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Rules:
|
|
|
55
55
|
- **Definition order**: root `pkg#name` if there is one, else root `name` (the first replaces the second whole, as Turbo looks it up), then each package config its own `turbo.json` extends (`"extends": ["//", "shared"]`, read by Turbo 2.11, refused by 2.5; nearest last, a parent missing or a cycle refused as Turbo refuses it) and its own, each winning field by field, except an overlay array holding `$TURBO_EXTENDS$` (Turbo 2.5+), which is the inherited list plus the overlay's other entries (`inputs: ["$TURBO_EXTENDS$", "config.json"]`).
|
|
56
56
|
- **The command is the script body** with its `pre<name>` / `post<name>` hooks folded in, in that order, through core's `foldScriptHooks`: each part in its own subshell, the chain stopping at the first that fails, forwarded `--` args reaching the body alone (npm and pnpm run them around `<name>` without being asked; novu's `prebuild` copies the CSS its `build` inlines), one process less per task than `pnpm run <name>` — except a body that calls yarn's `run` builtin (`run -T rollup -c`, `run clean && run build`; yarn ≥ 2 runs scripts in its own shell), which is `run: command not found` in sh: it runs as `yarn run <name>`, as Turbo and Nx run it, and yarn ≥ 2 runs no hooks, so none are folded there. A Yarn Plug'n'Play workspace (`.yarnrc.yml` with no `nodeLinker`, or `pnp`) has no `node_modules`: a dependency resolves only through `.pnp.cjs` and a bin only through yarn's shims, so there every script runs as `yarn run <name>`, and a `nodeLinker` change maps afresh. Same rules for `nx:run-script` below (strapi and novu, 2026-09-11).
|
|
57
57
|
- **Turbo 2.11's task `command`** (`futureFlags.experimentalTaskCommand`) wins over the script, as Turbo holds it: an argv is the command — each word quoted, run from the package dir, no `pre`/`post` hooks — and gives the package the task even with no script (turborepo's `@turbo/types#build`, `docs#schema`); `null` or `[]` is Turbo's no-op node, no task even where the script exists, its edges passed through; a per-toolchain map applies its `javascript` entry (or `typescript`, Turbo's alias), and without one the script runs. A shape Turbo would refuse keeps the script, with a todo.
|
|
58
|
-
- `dependsOn`: `^x` passes through when some package runs `x` or turbo.json defines it, and is dropped otherwise (core refuses a `^x` no project declares as a typo); `pkg#task` is kept only when `pkg` emits `task` (else a todo: edge dropped); a same-package task Turbo defines but the package has no script for is Turbo's no-op node, so its own edges pass through in its place (`test → codegen → ^build` with no `codegen` script is `test → ^build`); another package's `^x` or `pkg#x` reaches such a node through a group task when its edges name a task of its own package or another (with-tailwind's `ui` has no `build` script; its `build` builds `build:styles` and `build:components`, and `web#build` waits on them), and so does one whose `^` edge names another task (rallly's script-less `build` holds `^db:generate`), while one whose only edge is `^` to its own name needs none, since core's `^x` walks past a package without `x`; a no-op node nothing else reaches
|
|
58
|
+
- `dependsOn`: `^x` passes through when some package runs `x` or turbo.json defines it, and is dropped otherwise (core refuses a `^x` no project declares as a typo); `pkg#task` is kept only when `pkg` emits `task` (else a todo: edge dropped); a same-package task Turbo defines but the package has no script for is Turbo's no-op node, so its own edges pass through in its place (`test → codegen → ^build` with no `codegen` script is `test → ^build`); another package's `^x` or `pkg#x` reaches such a node through a group task when its edges name a task of its own package or another (with-tailwind's `ui` has no `build` script; its `build` builds `build:styles` and `build:components`, and `web#build` waits on them), and so does one whose `^` edge names another task (rallly's script-less `build` holds `^db:generate`), while one whose only edge is `^` to its own name needs none, since core's `^x` walks past a package without `x`; a no-op node nothing else reaches is a group too in a package nothing but the root depends on, since no dependant's `^` edge runs its edges there (vercel/ai's `turbo run type-check` builds each example through its script-less `type-check: [build]`, and kitchen-sink's `turbo run test` builds `@repo/ui` for `admin`, which has no `test` script); elsewhere it is none, its edges run by its dependants'; a name Turbo does not define has no edge; `$TURBO_ROOT$` deps are a todo. A task turbo.json defines and no package has a script for (documenso's `lint`, shadcn-ui's `check`) is a group task in each package that defines it, its edges kept (a `pkg#task` edge only in `pkg`), so `vx run lint` runs Turbo's no-op nodes and exits 0 as `turbo run lint` does. Root `//#task`s run in the workspace root, as under Turbo: `turbo()` names the root a project through core's `discover` stage when turbo.json declares one (no `vx.config` needed; a root no member glob lists), and `//#x` in `dependsOn` is an edge to it, named by the root `package.json` `name`; a root task's globs are the workspace's (`workspaceFiles`), since Turbo hashes a root task over the whole repo; with no root project (a root `package.json` with no `name`, or one a package holds) they are a note and such an edge a todo. Turbo runs no plain task in the root package of a monorepo, and neither does `turbo()`; in a single-package repo (no workspaces, Turbo's `non-monorepo` example) turbo.json's plain tasks run on the root package, as under Turbo.
|
|
59
59
|
- A transit node (Turbo's documented pattern, its with-vitest example: `transit: { dependsOn: ["^transit"] }` with no script anywhere, and `test: { dependsOn: ["transit"] }`) is a key-only task in each package that defines it: it runs `true`, cached and keyed on its inputs, with its `^transit` edge, so a dependant's `test` re-keys on its dependencies' sources as Turbo re-hashes it. A `^` task that some package has a script for, or that nothing depends on, is no transit node. A package without the script of a `^` task others run gets the same key-only task, as Turbo hashes a no-op node there: an edit to it re-keys its dependants. A `build` whose only edge is `^build` is not written: core gives every project with no `build` that node (solid's three script-less packages each got a `build` running `true`). A dependency without the script whose own edges lack `^x` gets it too, so a `^x` stops there as Turbo's does (opencode's `build: { dependsOn: [] }`: core walked past to the builds below, which Turbo's `^build` never reaches).
|
|
60
60
|
- `with` (tasks Turbo runs alongside, `web#dev` with `api#dev`): an edge to each sidecar that is persistent, so vx starts the task once the sidecar has spawned and runs the sidecar only when the task runs; a sidecar that ends would be waited for, so it is a todo instead, and a pair that names each other keeps one edge (two would be a cycle). A task with no script whose `with` names persistent sidecars (Turbo's with-tailwind example: `ui` has no `dev` script, its `dev` starts `dev:styles` and `dev:components`) is a group task that depends on them.
|
|
61
61
|
- `inputs`: a structured entry (Turbo 2.11) is its `globs`, plus `**/*` with `withDefaults`, for `startup` and `jit` alike; `dependencyOutputs` adds none where the producer is cached (vx folds each dependency's key); from a `cache: false` producer (vercel/vercel's `//#generate:cache-keys`, which records the host) the named files, or its outputs, are a `cache.inputs.workspaceRuntime` probe, and `cache.inputs.tasks` leaves the producer out, so core answers the probe after it ran. Then: absent or `[]` → `**/*` (Turbo's default); `$TURBO_DEFAULT$` → `**/*`; exclusions alone narrow `**/*`; `$TURBO_ROOT$/<path>` → `cache.inputs.workspaceFiles` (negation kept); any other `$TURBO_ROOT$` use is a todo. `globalDependencies` and Turbo 1's `globalDotEnv` land in `workspaceFiles` too, and a task's Turbo 1 `dotEnv` in its `files`. Turbo 1's `$NAME` entries, in `globalDependencies` or a task's `dependsOn`, are env vars: they join `cache.inputs.env` and `exec.env.passThrough`. A package nested in the task's package (cal.com's apps inside `@calcom/app-store`) is hashed by Turbo with its parent, and core's globs stop at a project: each glob that reaches one is also listed in `cache.inputs.workspaceFiles`. Turbo's glob grammar is translated as Nx's is (`*.[jt]s` is `*.{[jt],j,t}s`); an input with no safe form widens to `**/*` with a todo. A `.env`-shaped input (`.env*`, `.env.local`, a task's Turbo 1 `dotEnv`, create-turbo's `globalDependencies: ["**/.env.*local"]`) is gitignored as a rule, so it is keyed by a probe that hashes the `.env` files it can name (`cache.inputs.runtime`) or, for a root entry, the files its root-relative globs name, hidden ones too, as Turbo's `*` matches them (`workspaceRuntime`; `**/<name>` is a `find -name` that skips `node_modules`, and another `**` walks the workspace), rather than as a file glob git never reports. A package whose `.env` globs all sit at its root gets a one-shell probe of that directory; one below the root walks the package.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx-migrate",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.612",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Adopt @vzn/vx from Turborepo or Nx: run the repo unchanged, migrate it to vx.config.ts, and keep your Turbo or Nx remote cache",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@vzn/vx": "^0.0.
|
|
42
|
+
"@vzn/vx": "^0.0.612"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|
package/src/turbo/turbo-map.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { existsSync, readFileSync } from 'node:fs'
|
|
14
14
|
import path from 'node:path'
|
|
15
|
-
import { pruneOrphanPersistentNotes, type ProjectMeta, UserError } from '@vzn/vx'
|
|
15
|
+
import { buildPackageGraph, pruneOrphanPersistentNotes, type ProjectMeta, UserError } from '@vzn/vx'
|
|
16
16
|
import { literalGlob, minimatchToVx, withoutTakenBack } from '../glob-grammar.js'
|
|
17
17
|
import { shellQuote } from '../nx-command.js'
|
|
18
18
|
import { scriptCommand, yarnPnp } from '../script-command.js'
|
|
@@ -1075,9 +1075,20 @@ export async function mapTurboWorkspace(
|
|
|
1075
1075
|
// edge to a task of its own package or another (with-tailwind's
|
|
1076
1076
|
// `ui#build` → `build:styles`), is lost when
|
|
1077
1077
|
// another package reaches the node, and a persistent `with` sidecar
|
|
1078
|
-
// whenever the node is run: such a node is a group task (below).
|
|
1079
|
-
//
|
|
1080
|
-
//
|
|
1078
|
+
// whenever the node is run: such a node is a group task (below). So are
|
|
1079
|
+
// the edges of a package nothing depends on: no `^` reaches its `build`,
|
|
1080
|
+
// and `turbo run type-check` built ai's 16 examples through their
|
|
1081
|
+
// script-less `type-check: [build]` while vx built none. One no other
|
|
1082
|
+
// package reaches in a package something depends on stays none (a
|
|
1083
|
+
// `test: [build]` in a package with no tests adds nothing its
|
|
1084
|
+
// dependants' `^build` does not).
|
|
1085
|
+
let graph: ReturnType<typeof buildPackageGraph> | undefined
|
|
1086
|
+
// The root runs only its `//#` tasks, so its dependencies are no reach
|
|
1087
|
+
// (ai's root dev-depends on `konsistent-provider`).
|
|
1088
|
+
const depended = (pkg: string): boolean =>
|
|
1089
|
+
(graph ??= buildPackageGraph([...metas]))
|
|
1090
|
+
.transitiveDependents(pkg)
|
|
1091
|
+
.some((d) => d !== rootMeta?.name)
|
|
1081
1092
|
const sidecarGroups = new Set<string>()
|
|
1082
1093
|
for (const meta of metas) {
|
|
1083
1094
|
const scripts = packageScripts(meta)
|
|
@@ -1105,7 +1116,9 @@ export async function mapTurboWorkspace(
|
|
|
1105
1116
|
})
|
|
1106
1117
|
const reached = caretNames.has(name) || crossIds.has(`${meta.name}#${name}`)
|
|
1107
1118
|
if (sidecar) sidecarGroups.add(`${meta.name}#${name}`)
|
|
1108
|
-
|
|
1119
|
+
// A name no package has a script for is the entry rule's (below).
|
|
1120
|
+
const leaf = (): boolean => scripted.has(name) && !depended(meta.name)
|
|
1121
|
+
if (sidecar || (local && (reached || leaf()))) emitted.get(meta.name)!.add(name)
|
|
1109
1122
|
// A name no package has a script for is an entry point of its own:
|
|
1110
1123
|
// `turbo run ci` over `ci: { dependsOn: ["lint", "build"] }`, or
|
|
1111
1124
|
// cal.com's `deploy` → `@calcom/web#build`, runs its edges, and vx
|