@tailor-platform/sdk-codemod 0.4.0 → 0.4.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @tailor-platform/sdk-codemod
2
2
 
3
+ ## 0.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1934](https://github.com/tailor-platform/sdk/pull/1934) [`2a3ec7b`](https://github.com/tailor-platform/sdk/commit/2a3ec7b108275410bf5b35d23784b07aa147c5ea) Thanks [@toiroakr](https://github.com/toiroakr)! - Drop the `chalk` dependency in favor of Node's built-in styling, and decide color support per output stream. Diagnostics on stderr now keep their colors when you redirect stdout (`tailor executor list > out.txt`), and stop writing escape codes into the file when you redirect stderr (`tailor deploy 2> log.txt`). `NO_COLOR`, `FORCE_COLOR` and non-TTY detection keep working as before.
8
+
9
+ `@tailor-platform/sdk-codemod`, `@tailor-platform/sdk-plugin-seed` and `@tailor-platform/sdk-plugin-tailordb-erd` now declare the Node and Bun versions they need (`node >=22.15.0`, `bun >=1.2.0`), matching `@tailor-platform/sdk`. Installing them on an older runtime reports the mismatch instead of failing once the CLI runs.
10
+
11
+ - [#2008](https://github.com/tailor-platform/sdk/pull/2008) [`f2135ab`](https://github.com/tailor-platform/sdk/commit/f2135ab6dd3d130d88803b9829a26024de930ed3) Thanks [@toiroakr](https://github.com/toiroakr)! - Consistently call a TailorDB schema definition a "table" instead of a "type" across the docs, matching the `db.type()` → `db.table()` rename. Also fix three leftover `db.type(...)` code samples in `docs/services/tailordb.md` that should have read `db.table(...)`.
12
+
13
+ Update the `v2/idp-publish-events-rename` codemod registry description to say "tables" instead of "types", matching the same wording fix.
14
+
15
+ ## 0.4.1
16
+
17
+ ### Patch Changes
18
+
19
+ - [#1957](https://github.com/tailor-platform/sdk/pull/1957) [`a465547`](https://github.com/tailor-platform/sdk/commit/a465547df712ca8c607c1e42cf12c15fe3e830d1) Thanks [@toiroakr](https://github.com/toiroakr)! - Invoke the CLI as `npx @tailor-platform/sdk <command>` wherever an invocation is written for you. `npx` resolves a command it cannot find locally as a package name, so `npx tailor` fell through to an unrelated `tailor` package on npm whenever the SDK was not installed in the project — including in CI, where npm installs without prompting. Omitting the version specifier keeps using the project's installed SDK when there is one.
20
+
21
+ - Setup examples in the README, the quickstart, and the scaffolded project READMEs now use the package-runner form. Bun examples use `bun tailor <command>`, which resolves the local binary without fetching from the registry.
22
+ - Workflows generated by `tailor setup` use `npx @tailor-platform/sdk` for npm projects and `bun run tailor` for Bun projects. `tailor setup check` reports the template as outdated so existing projects regenerate; re-run `tailor setup` to pick it up.
23
+ - The `v2/seed-exec-to-cli-plugin` and `v2/sdk-skills-shim` codemods write the package-runner form when the invocation they produce goes through a runner that installs from the registry (`npx`, `bunx`, `pnpm`/`yarn dlx`, `npm exec`). A runner that resolves project binaries, such as `pnpm exec`, still gets the bare `tailor` binary.
24
+
3
25
  ## 0.4.0
4
26
 
5
27
  ### Minor Changes
@@ -1,9 +1,10 @@
1
1
  import * as path from "pathe";
2
2
  //#region codemods/v2/sdk-skills-shim/scripts/transform.ts
3
- const SHIM_PATTERN = /\btailor-sdk-skills(?:@[^\s'"`]+)?(?:[ \t]+install)?\b(?!-)/g;
4
- const REPLACEMENT = "tailor skills add";
3
+ const SHIM_PATTERN = new RegExp(`((?<![\\w.-])(?:npx|bunx|(?:pnpm|yarn)[ \\t]+dlx|npm[ \\t]+exec)(?:[ \\t]+-{1,2}[\\w-]*)*[ \\t]+)?\\btailor-sdk-skills(?:@[^\\s'"\`]+)?(?:[ \\t]+install)?\\b(?!-)`, "g");
4
+ const CLI_BINARY = "tailor";
5
+ const CLI_PACKAGE = "@tailor-platform/sdk";
5
6
  function replaceShim(value) {
6
- return value.replace(SHIM_PATTERN, REPLACEMENT);
7
+ return value.replace(SHIM_PATTERN, (_match, runner) => `${runner ?? ""}${runner == null ? CLI_BINARY : CLI_PACKAGE} skills add`);
7
8
  }
8
9
  function transformText(source) {
9
10
  if (!SHIM_PATTERN.test(source)) return null;
@@ -22,8 +22,17 @@ const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
22
22
  ]);
23
23
  const NODE_FLAG_PATTERN = new RegExp(`(${VALUE_NODE_FLAG})(?:=(${ARG_VALUE})|${SPACE}(${ARG_VALUE}))|(${BOOLEAN_NODE_FLAG})`, "g");
24
24
  const ENV_FILE_FLAG = /^--env-file(?:-if-exists)?$/;
25
- const RUNNER_PREFIX_PATTERN = new RegExp(`(?<![\\w.-])(?:pnpm|npm|yarn|bunx|bun|npx)(?:${SPACE}(?:run|exec|dlx))?${SPACE}$`);
25
+ const RUNNER_PREFIX_PATTERN = new RegExp(`(?<![\\w.-])(pnpm|npm|yarn|bunx|bun|npx)(?:${SPACE}(run|exec|dlx))?${SPACE}$`);
26
26
  const RUNNER_PREFIX_WINDOW = 64;
27
+ const CLI_BINARY = "tailor";
28
+ const CLI_PACKAGE = "@tailor-platform/sdk";
29
+ const PACKAGE_RUNNER = `npx ${CLI_PACKAGE}`;
30
+ /** Whether a runner installs names it cannot resolve from the project. */
31
+ function installsMissingNames(runner, subcommand) {
32
+ if (runner === "npx" || runner === "bunx") return true;
33
+ if (subcommand === "dlx") return true;
34
+ return runner === "npm" && subcommand === "exec";
35
+ }
27
36
  /** Translate the leading `node` flags into flags the CLI command accepts. */
28
37
  function carriedOverFlags(nodeFlags) {
29
38
  return [...nodeFlags.matchAll(NODE_FLAG_PATTERN)].filter((match) => match[1] != null && ENV_FILE_FLAG.test(match[1])).map((match) => ` ${match[1]} ${match[2] ?? match[3]}`).join("");
@@ -32,11 +41,12 @@ function carriedOverFlags(nodeFlags) {
32
41
  * Rewrite runner invocations. The runner spells validation as its first
33
42
  * positional argument, so a consumed `validate` selects the subcommand.
34
43
  */
35
- function rewrite(value, prefix = "") {
44
+ function rewrite(value, inventedHead = CLI_BINARY) {
36
45
  return value.replace(RUNNER_PATTERN, (_match, nodeFlags, _quote, validate, offset) => {
37
46
  const command = validate ? "validate" : "apply";
38
47
  const before = value.slice(Math.max(0, offset - RUNNER_PREFIX_WINDOW), offset);
39
- return `${RUNNER_PREFIX_PATTERN.test(before) ? "" : prefix}tailor seed ${command}${carriedOverFlags(nodeFlags)}`;
48
+ const existing = RUNNER_PREFIX_PATTERN.exec(before);
49
+ return `${existing ? installsMissingNames(existing[1], existing[2]) ? CLI_PACKAGE : CLI_BINARY : inventedHead} seed ${command}${carriedOverFlags(nodeFlags)}`;
40
50
  });
41
51
  }
42
52
  function transformText(source) {
@@ -49,7 +59,7 @@ function transformText(source) {
49
59
  * node_modules rather than the PATH.
50
60
  */
51
61
  function transformSourceText(source) {
52
- const updated = rewrite(source, "npx ");
62
+ const updated = rewrite(source, PACKAGE_RUNNER);
53
63
  if (FORK_PATTERN.test(source) && updated.includes("exec.mjs")) return null;
54
64
  return updated === source ? null : updated;
55
65
  }
@@ -106,7 +116,7 @@ function reviewFindings(source, filePath, relativePath) {
106
116
  return {
107
117
  file: relativePath,
108
118
  line: index + 1,
109
- message: "Replace the fork()-based seed runner call with execSync(\"npx tailor seed apply\"), forwarding env/stdio, and unwind the surrounding await/Promise plumbing.",
119
+ message: "Replace the fork()-based seed runner call with execSync(\"npx @tailor-platform/sdk seed apply\"), forwarding env/stdio, and unwind the surrounding await/Promise plumbing.",
110
120
  excerpt: lines[index].trim()
111
121
  };
112
122
  });
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { gte, lt, parse, valid } from "semver";
9
9
  import * as fs from "node:fs";
10
10
  import { realpathSync } from "node:fs";
11
11
  import { Lang, parse as parse$1 } from "@ast-grep/napi";
12
- import chalk from "chalk";
12
+ import { stripVTControlCharacters, styleText } from "node:util";
13
13
  import { structuredPatch } from "diff";
14
14
  import picomatch from "picomatch";
15
15
  import { execFileSync } from "node:child_process";
@@ -205,13 +205,16 @@ const allCodemods = [
205
205
  examples: [{
206
206
  lang: "sh",
207
207
  before: "npx tailor-sdk-skills",
208
- after: "tailor skills add"
208
+ after: "npx @tailor-platform/sdk skills add"
209
209
  }],
210
210
  prompt: [
211
211
  "The standalone tailor-sdk-skills binary is removed in v2; call the skills add",
212
212
  "subcommand on the main tailor CLI instead. Replace any remaining",
213
213
  "tailor-sdk-skills invocations the codemod did not rewrite with",
214
- "`tailor skills add`."
214
+ "`tailor skills add`, or `npx @tailor-platform/sdk skills add` when the",
215
+ "invocation runs through a package runner (npx, bunx, pnpm/yarn dlx, npm exec)",
216
+ "— those resolve a package name, and `npx tailor` reaches an unrelated",
217
+ "`tailor` package on npm."
215
218
  ].join("\n")
216
219
  },
217
220
  {
@@ -680,7 +683,7 @@ const allCodemods = [
680
683
  {
681
684
  id: "v2/idp-publish-events-rename",
682
685
  name: "defineIdp publishUserEvents → publishEvents",
683
- description: "Rename the `defineIdp` option `publishUserEvents` to `publishEvents`, matching the field name TailorDB types, resolvers, and workflows already use.",
686
+ description: "Rename the `defineIdp` option `publishUserEvents` to `publishEvents`, matching the field name that TailorDB tables, resolvers, and workflows already use.",
684
687
  since: "1.5.0",
685
688
  until: "2.0.0",
686
689
  prereleaseUntil: V2_NEXT_11,
@@ -1290,7 +1293,7 @@ const allCodemods = [
1290
1293
  " typically fork the runner and await a hand-rolled Promise around",
1291
1294
  " `child.on(\"close\", ...)`). The plugin is a CLI-dispatched binary rather",
1292
1295
  " than a forkable JS module, so call it synchronously instead —",
1293
- " `execSync(\"npx tailor seed apply\", { env, stdio: \"inherit\" })` — keeping",
1296
+ " `execSync(\"npx @tailor-platform/sdk seed apply\", { env, stdio: \"inherit\" })` — keeping",
1294
1297
  " the original `env` and `stdio` forwarding, and unwind the surrounding",
1295
1298
  " Promise wrapper (drop the now-unused `await`, and the `async` keyword when",
1296
1299
  " nothing else in the function awaits). Note that `execSync` throws on a",
@@ -1518,6 +1521,46 @@ function getApplicableCodemods(fromVersion, toVersion) {
1518
1521
  return allCodemods.filter((codemod) => gte(fromVersion, codemod.since) && lt(fromVersion, effectiveCodemodBoundary(codemod)) && reachesCodemodBoundary(toVersion, codemod));
1519
1522
  }
1520
1523
  //#endregion
1524
+ //#region ../shared/src/color.ts
1525
+ const style = (name) => (text) => styleText(name, text, { validateStream: false });
1526
+ /**
1527
+ * Style functions by name, so call sites read `color.bold(text)`. Styling is
1528
+ * always applied; `renderFor` drops it again when the destination stream has no
1529
+ * color support. Add a name here when a package needs one that is not listed.
1530
+ */
1531
+ const color = {
1532
+ bold: style("bold"),
1533
+ dim: style("dim"),
1534
+ italic: style("italic"),
1535
+ gray: style("gray"),
1536
+ white: style("white"),
1537
+ red: style("red"),
1538
+ green: style("green"),
1539
+ yellow: style("yellow"),
1540
+ cyan: style("cyan"),
1541
+ magenta: style("magenta"),
1542
+ redBright: style("redBright"),
1543
+ greenBright: style("greenBright"),
1544
+ cyanBright: style("cyanBright")
1545
+ };
1546
+ const supportsColor = (stream) => {
1547
+ const forced = process.env.FORCE_COLOR;
1548
+ if (forced !== void 0) return forced !== "0" && forced !== "false";
1549
+ if (process.env.NODE_DISABLE_COLORS !== void 0) return false;
1550
+ if ((process.env.NO_COLOR ?? "") !== "") return false;
1551
+ if (process.env.TERM === "dumb") return false;
1552
+ return stream.isTTY === true;
1553
+ };
1554
+ /**
1555
+ * Prepares styled text for the stream it is written to.
1556
+ * @param stream - Stream the text is written to
1557
+ * @param text - Styled text
1558
+ * @returns Text with styling removed when the stream has no color support
1559
+ */
1560
+ function renderFor(stream, text) {
1561
+ return supportsColor(stream) ? text : stripVTControlCharacters(text);
1562
+ }
1563
+ //#endregion
1521
1564
  //#region src/runner.ts
1522
1565
  /** Default file patterns for TypeScript files. */
1523
1566
  const DEFAULT_FILE_PATTERNS = ["**/*.{ts,tsx,mts,cts}"];
@@ -1589,6 +1632,9 @@ async function* walkFiles(root, relativeDir = "") {
1589
1632
  if (entry.isFile()) yield relative;
1590
1633
  }
1591
1634
  }
1635
+ function writeDiffLine(line, style) {
1636
+ process.stderr.write(renderFor(process.stderr, `${style ? style(line) : line}\n`));
1637
+ }
1592
1638
  /**
1593
1639
  * Print a colorized unified diff for a single file to stderr.
1594
1640
  * @param filePath - Absolute path to the file
@@ -1598,13 +1644,14 @@ async function* walkFiles(root, relativeDir = "") {
1598
1644
  function printDiff(filePath, before, after) {
1599
1645
  const patch = structuredPatch(filePath, filePath, before, after, "", "", { context: 3 });
1600
1646
  if (patch.hunks.length === 0) return;
1601
- process.stderr.write(`\n${chalk.bold(`--- ${filePath}`)}\n`);
1602
- process.stderr.write(`${chalk.bold(`+++ ${filePath}`)}\n`);
1647
+ writeDiffLine("");
1648
+ writeDiffLine(`--- ${filePath}`, color.bold);
1649
+ writeDiffLine(`+++ ${filePath}`, color.bold);
1603
1650
  for (const hunk of patch.hunks) {
1604
- process.stderr.write(chalk.cyan(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@\n`));
1605
- for (const line of hunk.lines) if (line.startsWith("+")) process.stderr.write(`${chalk.green(line)}\n`);
1606
- else if (line.startsWith("-")) process.stderr.write(`${chalk.red(line)}\n`);
1607
- else process.stderr.write(`${line}\n`);
1651
+ writeDiffLine(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`, color.cyan);
1652
+ for (const line of hunk.lines) if (line.startsWith("+")) writeDiffLine(line, color.green);
1653
+ else if (line.startsWith("-")) writeDiffLine(line, color.red);
1654
+ else writeDiffLine(line);
1608
1655
  }
1609
1656
  }
1610
1657
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk-codemod",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Codemod runner for Tailor Platform SDK upgrades",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,6 @@
17
17
  "type": "module",
18
18
  "dependencies": {
19
19
  "@ast-grep/napi": "0.45.0",
20
- "chalk": "5.6.2",
21
20
  "diff": "9.0.0",
22
21
  "pathe": "2.0.3",
23
22
  "picomatch": "4.0.5",
@@ -29,12 +28,17 @@
29
28
  "devDependencies": {
30
29
  "@types/node": "24.13.3",
31
30
  "@types/picomatch": "4.0.3",
32
- "@types/semver": "7.7.1",
33
- "eslint-plugin-zod": "4.7.0",
31
+ "@types/semver": "7.8.0",
32
+ "eslint-plugin-zod": "4.9.0",
34
33
  "oxlint": "1.76.0",
35
34
  "tsdown": "0.22.14",
36
35
  "typescript": "6.0.3",
37
- "vitest": "4.1.10"
36
+ "vitest": "4.1.10",
37
+ "@tailor-platform/shared": "^0.0.0"
38
+ },
39
+ "engines": {
40
+ "bun": ">=1.2.0",
41
+ "node": ">=22.15.0"
38
42
  },
39
43
  "scripts": {
40
44
  "build": "tsdown",