@tailor-platform/sdk-codemod 0.3.0-next.4 → 0.3.0-next.6

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,30 @@
1
1
  # @tailor-platform/sdk-codemod
2
2
 
3
+ ## 0.3.0-next.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1789](https://github.com/tailor-platform/sdk/pull/1789) [`e4db171`](https://github.com/tailor-platform/sdk/commit/e4db171e2a0138ea1a0ba1a972bf895fd0616a28) Thanks [@toiroakr](https://github.com/toiroakr)! - Flag `tailor generate --watch` / `-W` invocations and programmatic `generate({ watch })` usage for manual review as part of the v2 migration (the flag and its dependency watcher are removed in `@tailor-platform/sdk` v2).
8
+
9
+ ## 0.3.0-next.5
10
+
11
+ ### Patch Changes
12
+
13
+ - [#1719](https://github.com/tailor-platform/sdk/pull/1719) [`4a05aec`](https://github.com/tailor-platform/sdk/commit/4a05aecfb100a1ea7292a6ae5809a2d1e6eddbfe) Thanks [@dqn](https://github.com/dqn)! - Derive default TailorDB forward relation names from the relation field name by removing a trailing `ID`, `Id`, or `id`, instead of deriving them from the target table name.
14
+
15
+ The v2 migration review identifies non-self relations without `toward.as`. Add an explicit name to preserve the v1 GraphQL field name, or update consumers to use the new field-based name.
16
+
17
+ - [#1678](https://github.com/tailor-platform/sdk/pull/1678) [`e0e768d`](https://github.com/tailor-platform/sdk/commit/e0e768d77470d13806ed7b2ee2117fe374d51d40) Thanks [@toiroakr](https://github.com/toiroakr)! - Redesign TailorDB hooks and validators with several breaking changes:
18
+
19
+ - Add shared `now` timestamp to all hooks — multiple fields stamped with the same `Date`
20
+ - Field-level hooks: `{ value, data, invoker }` → create `{ input, invoker, now }` / update `{ input, oldValue, invoker, now }` (`data` removed, `oldValue` added for update only)
21
+ - Type-level hooks: per-field mapping (`Hooks<F>`) → single `{ create, update }` object (`TypeHook<F>`) returning partial field overrides
22
+ - Type-level create hooks no longer receive `oldRecord`; update hooks receive non-nullable `oldRecord`
23
+ - Field-level validators: return type changed from `boolean` to `string | void` (return error message or void to pass); `[fn, message]` tuple form removed
24
+ - Type-level validators: `Validators<F>` per-field record → `TypeValidateFn<F>` single function with `issues(field, message)` callback
25
+ - Add `.default(value)` on fields to set a create-time default (makes required fields optional in create input)
26
+ - Remove exported types: `Hooks<F>`, `Validators<F>`, `ValidateConfig`
27
+
3
28
  ## 0.3.0-next.4
4
29
 
5
30
  ### Patch Changes
@@ -175,6 +200,18 @@
175
200
 
176
201
  - [#1435](https://github.com/tailor-platform/sdk/pull/1435) [`49c0cc9`](https://github.com/tailor-platform/sdk/commit/49c0cc99171d7e317a50a18804a21067d89f9493) Thanks [@dqn](https://github.com/dqn)! - Add the `v2/plugin-cli-import` codemod so `tailor-sdk upgrade` rewrites deprecated plugin imports from `@tailor-platform/sdk/cli` (`kyselyTypePlugin`, `enumConstantsPlugin`, `fileUtilsPlugin`, `seedPlugin`) to their dedicated `@tailor-platform/sdk/plugin/*` subpaths, splitting any non-plugin specifiers onto a separate import.
177
202
 
203
+ ## 0.3.7
204
+
205
+ ### Patch Changes
206
+
207
+ - [#1744](https://github.com/tailor-platform/sdk/pull/1744) [`3ca5b48`](https://github.com/tailor-platform/sdk/commit/3ca5b48fca4e8e1f0878350afc11d42d36bf3cab) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency politty to v0.11.2
208
+
209
+ ## 0.3.6
210
+
211
+ ### Patch Changes
212
+
213
+ - [#1688](https://github.com/tailor-platform/sdk/pull/1688) [`7f67996`](https://github.com/tailor-platform/sdk/commit/7f679963adc1df438e49200f1170415629817f44) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency @ast-grep/napi to v0.44.1
214
+
178
215
  ## 0.3.5
179
216
 
180
217
  ### Patch Changes
@@ -168,4 +168,4 @@ function localDeclarationNames(root) {
168
168
  return names;
169
169
  }
170
170
  //#endregion
171
- export { importSource as a, localDeclarationNames as c, importBindings as i, collectBindingNames as n, importSpecNames as o, findImportStatements as r, isTypeOnlyImport as s, buildAddNamedImportEdit as t };
171
+ export { importSource as a, localDeclarationNames as c, importBindings as i, stringValue as l, collectBindingNames as n, importSpecNames as o, findImportStatements as r, isTypeOnlyImport as s, buildAddNamedImportEdit as t };
@@ -1,4 +1,4 @@
1
- import { a as importSource, c as localDeclarationNames, i as importBindings, o as importSpecNames, r as findImportStatements, s as isTypeOnlyImport, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-D3FXAKNz.js";
1
+ import { a as importSource, c as localDeclarationNames, i as importBindings, o as importSpecNames, r as findImportStatements, s as isTypeOnlyImport, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-CXtWn3RB.js";
2
2
  import { Lang, parse } from "@ast-grep/napi";
3
3
  //#region codemods/v2/auth-connection-token-helper/scripts/transform.ts
4
4
  const RUNTIME_MODULE = "@tailor-platform/sdk/runtime";
@@ -1,4 +1,4 @@
1
- import { a as importSource, i as importBindings, r as findImportStatements } from "../../../ast-grep-helpers-D3FXAKNz.js";
1
+ import { a as importSource, i as importBindings, r as findImportStatements } from "../../../ast-grep-helpers-CXtWn3RB.js";
2
2
  import { Lang, parse } from "@ast-grep/napi";
3
3
  //#region codemods/v2/db-type-to-table/scripts/transform.ts
4
4
  const SDK_MODULE = "@tailor-platform/sdk";
@@ -0,0 +1,115 @@
1
+ import { l as stringValue } from "../../../ast-grep-helpers-CXtWn3RB.js";
2
+ import { Lang, parse } from "@ast-grep/napi";
3
+ //#region codemods/v2/forward-relation-name/scripts/transform.ts
4
+ function sourceLang(filePath, source) {
5
+ const lowerPath = filePath.toLowerCase();
6
+ if (/\.(?:ts|mts|cts)$/u.test(lowerPath)) return Lang.TypeScript;
7
+ if (/\.(?:tsx|jsx|js)$/u.test(lowerPath)) return Lang.Tsx;
8
+ return source.includes("</") ? Lang.Tsx : Lang.TypeScript;
9
+ }
10
+ function isRelationCall(call, aliases) {
11
+ const callee = call.children()[0];
12
+ if (!callee) return false;
13
+ if (callee.kind() === "identifier") return aliases.has(callee.text());
14
+ if (callee.kind() === "subscript_expression") {
15
+ const property = literalStringValue(callee.field("index"));
16
+ return property === null || property === "relation";
17
+ }
18
+ if (callee.kind() !== "member_expression") return false;
19
+ return callee.children().findLast((child) => child.kind() === "property_identifier" || child.kind() === "identifier")?.text() === "relation";
20
+ }
21
+ function relationBindingName(pattern) {
22
+ if (pattern.kind() !== "object_pattern") return null;
23
+ for (const child of pattern.children()) {
24
+ if (child.kind() === "shorthand_property_identifier_pattern" && child.text() === "relation") return child.text();
25
+ if (child.kind() === "pair_pattern" && stringValue(child.field("key")) === "relation") {
26
+ const value = child.field("value");
27
+ return value?.kind() === "identifier" ? value.text() : null;
28
+ }
29
+ if (child.kind() === "object_assignment_pattern") {
30
+ const binding = child.children().find((node) => node.kind() === "shorthand_property_identifier_pattern");
31
+ if (binding?.text() === "relation") return binding.text();
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ function relationAliases(root) {
37
+ const aliases = /* @__PURE__ */ new Set();
38
+ for (const pattern of root.findAll({ rule: { kind: "object_pattern" } })) {
39
+ const name = relationBindingName(pattern);
40
+ if (name) aliases.add(name);
41
+ }
42
+ return aliases;
43
+ }
44
+ function callArgument(call) {
45
+ const args = call.children().find((child) => child.kind() === "arguments");
46
+ if (!args) return null;
47
+ const values = args.children().filter((child) => {
48
+ const kind = child.kind();
49
+ return kind !== "(" && kind !== ")" && kind !== "," && kind !== "comment";
50
+ });
51
+ return values.length === 1 ? values[0] : null;
52
+ }
53
+ function pairKey(pair) {
54
+ const key = pair.children()[0];
55
+ return stringValue(key ?? null);
56
+ }
57
+ function pairValue(pair) {
58
+ const children = pair.children();
59
+ const colonIndex = children.findIndex((child) => child.kind() === ":");
60
+ if (colonIndex === -1) return null;
61
+ return children.slice(colonIndex + 1).find((child) => child.kind() !== "comment") ?? null;
62
+ }
63
+ function objectPair(object, key) {
64
+ return object.children().find((child) => child.kind() === "pair" && pairKey(child) === key) ?? null;
65
+ }
66
+ function literalStringValue(node) {
67
+ if (node?.kind() !== "string") return null;
68
+ return stringValue(node);
69
+ }
70
+ function hasDynamicProperties(object) {
71
+ return object.children().some((child) => {
72
+ const kind = child.kind();
73
+ if (kind === "{" || kind === "}" || kind === "," || kind === "comment") return false;
74
+ if (kind !== "pair") return true;
75
+ const keyKind = child.children()[0]?.kind();
76
+ return keyKind !== "property_identifier" && keyKind !== "string";
77
+ });
78
+ }
79
+ function needsReview(call) {
80
+ const config = callArgument(call);
81
+ if (config?.kind() !== "object") return config != null;
82
+ if (hasDynamicProperties(config)) return true;
83
+ const relationType = objectPair(config, "type");
84
+ const toward = objectPair(config, "toward");
85
+ if (!relationType || !toward) return false;
86
+ if (literalStringValue(pairValue(relationType)) === "keyOnly") return false;
87
+ const towardConfig = pairValue(toward);
88
+ if (towardConfig?.kind() !== "object") return towardConfig != null;
89
+ if (hasDynamicProperties(towardConfig)) return true;
90
+ const targetType = objectPair(towardConfig, "type");
91
+ if (targetType && literalStringValue(pairValue(targetType)) === "self") return false;
92
+ const as = objectPair(towardConfig, "as");
93
+ if (as) {
94
+ const explicitName = literalStringValue(pairValue(as));
95
+ return explicitName === null || explicitName.length === 0;
96
+ }
97
+ if (!targetType) return false;
98
+ return true;
99
+ }
100
+ function transform(_source, _filePath) {
101
+ return null;
102
+ }
103
+ function reviewFindings(source, filePath, relativePath) {
104
+ if (!source.includes("relation")) return [];
105
+ const root = parse(sourceLang(filePath, source), source).root();
106
+ const aliases = relationAliases(root);
107
+ return root.findAll({ rule: { kind: "call_expression" } }).filter((call) => isRelationCall(call, aliases) && needsReview(call)).map((call) => ({
108
+ file: relativePath,
109
+ line: call.range().start.line + 1,
110
+ message: "Review the v2 forward GraphQL field name or add an explicit toward.as.",
111
+ excerpt: call.text().split("\n", 1)[0].trim()
112
+ }));
113
+ }
114
+ //#endregion
115
+ export { transform as default, reviewFindings };
@@ -1,4 +1,4 @@
1
- import { c as localDeclarationNames, i as importBindings, r as findImportStatements, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-D3FXAKNz.js";
1
+ import { c as localDeclarationNames, i as importBindings, r as findImportStatements, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-CXtWn3RB.js";
2
2
  import { Lang, parse } from "@ast-grep/napi";
3
3
  //#region codemods/v2/runtime-globals-opt-in/scripts/transform.ts
4
4
  const RUNTIME_MODULE = "@tailor-platform/sdk/runtime";
@@ -1,4 +1,4 @@
1
- import { a as importSource, c as localDeclarationNames, i as importBindings, n as collectBindingNames, o as importSpecNames, r as findImportStatements, s as isTypeOnlyImport } from "../../../ast-grep-helpers-D3FXAKNz.js";
1
+ import { a as importSource, c as localDeclarationNames, i as importBindings, n as collectBindingNames, o as importSpecNames, r as findImportStatements, s as isTypeOnlyImport } from "../../../ast-grep-helpers-CXtWn3RB.js";
2
2
  import { Lang, parse } from "@ast-grep/napi";
3
3
  //#region codemods/v2/runtime-subpath-namespace/scripts/transform.ts
4
4
  const MODULES_BY_SOURCE = new Map([
package/dist/index.js CHANGED
@@ -117,6 +117,7 @@ const RENAME_BIN_QUOTED_LEGACY_COMMAND_PATTERN = new RegExp([
117
117
  const V2_NEXT_1 = "2.0.0-next.1";
118
118
  const V2_NEXT_2 = "2.0.0-next.2";
119
119
  const V2_NEXT_3 = "2.0.0-next.3";
120
+ const V2_NEXT_4 = "2.0.0-next.4";
120
121
  /** All registered codemods, in registration order. */
121
122
  const allCodemods = [
122
123
  {
@@ -593,6 +594,52 @@ const allCodemods = [
593
594
  "calls to db.table. Leave unrelated local objects with a .type() method unchanged."
594
595
  ].join("\n")
595
596
  },
597
+ {
598
+ id: "v2/forward-relation-name",
599
+ name: "TailorDB forward relation names derive from field names",
600
+ description: "Review TailorDB relations that omit `toward.as`. Their forward GraphQL field names now derive from the relation field name with a trailing `ID`, `Id`, or `id` removed, instead of from the target table name.",
601
+ since: "1.0.0",
602
+ until: "2.0.0",
603
+ prereleaseUntil: V2_NEXT_4,
604
+ scriptPath: "v2/forward-relation-name/scripts/transform.js",
605
+ filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
606
+ suspiciousPatterns: [
607
+ /\.relation\b(?!\s*\()/,
608
+ /\{[^}\n]*\brelation\b[^}\n]*\}\s*=/,
609
+ /\[\s*["']relation["']\s*\]/
610
+ ],
611
+ examples: [{
612
+ caption: "Preserve the v1 GraphQL field name by making it explicit:",
613
+ before: [
614
+ "ownerId: db.uuid().relation({",
615
+ " type: \"n-1\",",
616
+ " toward: { type: user },",
617
+ "}),"
618
+ ].join("\n"),
619
+ after: [
620
+ "ownerId: db.uuid().relation({",
621
+ " type: \"n-1\",",
622
+ " toward: { type: user, as: \"user\" },",
623
+ "}),"
624
+ ].join("\n")
625
+ }],
626
+ prompt: [
627
+ "Tailor SDK v2 derives a default forward GraphQL relation name from the source",
628
+ "field name by removing a trailing ID, Id, or id. V1 derived it from the target",
629
+ "table name. Review each reported non-self relation that omits toward.as.",
630
+ "",
631
+ "If consumers must keep using the v1 GraphQL field name, inspect the v1 schema and",
632
+ "copy that exact field name into toward.as. Otherwise, update GraphQL operations",
633
+ "and consumer code to use the new field-based name. No change is needed when the old",
634
+ "and new names are identical. Relations with a guaranteed non-empty toward.as,",
635
+ "self-relations, and keyOnly relations are unchanged. For an empty or dynamic",
636
+ "toward.as, determine whether its runtime value can be falsy; if so, treat the",
637
+ "relation as using the default name.",
638
+ "",
639
+ "A relation field without a trailing ID, Id, or id would default to its own scalar",
640
+ "field name and therefore conflict. Give that relation an explicit toward.as."
641
+ ].join("\n")
642
+ },
596
643
  {
597
644
  id: "v2/execute-script-arg",
598
645
  name: "executeScript arg JSON.stringify → value",
@@ -845,6 +892,138 @@ const allCodemods = [
845
892
  after: ".tailor/"
846
893
  }]
847
894
  },
895
+ {
896
+ id: "v2/tailordb-validate-simplify",
897
+ name: "ValidateFn simplification and type-level validate",
898
+ description: "Field-level `ValidateFn` is simplified from `(args: { value, data, invoker }) => boolean` to `(args: { value }) => string | void` — the function now returns the error message directly instead of a separate `[fn, message]` tuple. The `ValidateConfig` tuple form and `Validators<F>` record syntax on `db.type().validate()` are removed. Type-level validation uses `db.type().validate((args, issues) => void)` with `{ newRecord, oldRecord, invoker }` args and an `issues(field, message)` callback for cross-field rules.",
899
+ since: "1.0.0",
900
+ until: "2.0.0",
901
+ prereleaseUntil: V2_NEXT_4,
902
+ suspiciousPatterns: [
903
+ "ValidateConfig",
904
+ "Validators<",
905
+ "ValidatorsBase",
906
+ ".validate("
907
+ ],
908
+ examples: [{
909
+ caption: "Field-level validate: return an error message string instead of a boolean (tuple form removed):",
910
+ before: ".validate(\n [({ value }) => value.length > 5, \"Name must be longer than 5 characters\"],\n)",
911
+ after: ".validate(({ value }) =>\n value.length <= 5 ? \"Name must be longer than 5 characters\" : undefined,\n)"
912
+ }, {
913
+ caption: "Type-level validate: per-field record syntax replaced by a single function with `issues()` callback:",
914
+ before: ".validate({\n name: [({ value }) => value.length > 5, \"Name must be longer than 5\"],\n})",
915
+ after: ".validate(({ newRecord }, issues) => {\n if (newRecord.name && newRecord.name.length <= 5) {\n issues(\"name\", \"Name must be longer than 5\");\n }\n})"
916
+ }],
917
+ prompt: [
918
+ "The v2 SDK simplifies field validation and introduces type-level validation.",
919
+ "",
920
+ "Field-level `.validate()` changes:",
921
+ "- Signature: `(args: { value, data, invoker }) => boolean` → `(args: { value }) => string | void`",
922
+ "- The function now returns the error message string directly (or undefined/void to pass)",
923
+ " instead of returning a boolean with the message in a separate tuple.",
924
+ "- The `[fn, errorMessage]` tuple form (`ValidateConfig`) is removed.",
925
+ "- `data` and `invoker` are no longer available in field-level validators.",
926
+ " Use type-level `.validate()` for cross-field or invoker-dependent rules.",
927
+ "",
928
+ "Type-level `.validate()` on `db.type()` changes:",
929
+ "- Old: `.validate({ fieldName: fn | [fn, msg] | fn[] })` (per-field record, `Validators<F>` type)",
930
+ "- New: `.validate((args, issues) => void)` (single function, `TypeValidateFn<F>` type)",
931
+ "- Args: `{ newRecord, oldRecord, invoker }` — `newRecord` is the record after hooks run",
932
+ "- Call `issues(field, message)` to report validation errors; `field` supports dotted paths",
933
+ "- Move per-field validators that need `data`/`invoker` to the type-level function",
934
+ "",
935
+ "For each remaining `ValidateConfig`, `Validators<`, or old-signature `.validate()` usage:",
936
+ "1. Rewrite field-level validators to return the error string directly",
937
+ "2. Move cross-field / invoker-dependent validators to the type-level function",
938
+ "3. Remove unused `ValidateConfig` / `Validators` type imports"
939
+ ].join("\n")
940
+ },
941
+ {
942
+ id: "v2/tailordb-hook-redesign",
943
+ name: "TailorDB hook redesign: field-level args and type-level hooks",
944
+ description: "Field-level `HookFn` args change from `{ value, data, invoker }` to create `{ input, invoker, now }` / update `{ input, oldValue, invoker, now }` — `value` is renamed to `input`, matching the `input` arg on type-level hooks (same pre-hook data, narrowed to one field); `data` (the full record) is removed; `oldValue` (previous field value) is added for update hooks only; `now` (operation timestamp) is shared across all hooks. Type-level hooks on `db.type().hooks()` change from per-field mapping `{ fieldName: { create, update } }` (`Hooks<F>`) to a single `{ create, update }` object (`TypeHook<F>`) — create hooks take `{ input, invoker, now }`, update hooks take `{ input, oldRecord, invoker, now }` (oldRecord is always non-null). Both return partial field overrides.",
945
+ since: "1.0.0",
946
+ until: "2.0.0",
947
+ prereleaseUntil: V2_NEXT_4,
948
+ suspiciousPatterns: [
949
+ "Hooks<",
950
+ "HookFn<",
951
+ "Hook<",
952
+ ".hooks("
953
+ ],
954
+ examples: [{
955
+ caption: "Field-level hooks: `value` renamed to `input`, `data` replaced by `oldValue` and `now`; use `now` instead of `new Date()`:",
956
+ before: "db.datetime().hooks({\n create: ({ value }) => value ?? new Date(),\n update: () => new Date(),\n})",
957
+ after: "db.datetime().hooks({\n create: ({ input, now }) => input ?? now,\n update: ({ now }) => now,\n})"
958
+ }, {
959
+ caption: "Type-level hooks: per-field mapping replaced by single create/update functions:",
960
+ before: ".hooks({\n fullAddress: {\n create: ({ data }) => `${data.postalCode} ${data.address}`,\n update: ({ data }) => `${data.postalCode} ${data.address}`,\n },\n})",
961
+ after: ".hooks({\n create: ({ input }) => ({\n fullAddress: `${input.postalCode} ${input.address}`,\n }),\n update: ({ input }) => ({\n fullAddress: `${input.postalCode} ${input.address}`,\n }),\n})"
962
+ }],
963
+ prompt: [
964
+ "The v2 SDK redesigns TailorDB hooks at both field and type levels.",
965
+ "",
966
+ "Field-level `.hooks()` on individual fields:",
967
+ "- Create args: `{ value, data, invoker }` → `{ input, invoker, now }` (no `oldValue`)",
968
+ "- Update args: `{ value, data, invoker }` → `{ input, oldValue, invoker, now }`",
969
+ "- `value` is renamed to `input`, matching the type-level hook's `input` arg — both are",
970
+ " the same pre-hook data, at different granularity",
971
+ "- `data` (full record) is removed; update hooks get `oldValue` (previous field value) instead",
972
+ "- `now` provides the operation timestamp — use `now` instead of `new Date()`",
973
+ "- If a field-level hook needs the full record (other fields), move it to a type-level hook",
974
+ "",
975
+ "Type-level `.hooks()` on `db.type()`:",
976
+ "- Old: `.hooks({ fieldName: { create: fn, update: fn } })` (per-field mapping, `Hooks<F>` type)",
977
+ "- New: `.hooks({ create: fn, update: fn })` (single object, `TypeHook<F>` type)",
978
+ "- Each function: `({ input, oldRecord, invoker, now }) => ({ fieldName: value, ... })`",
979
+ "- `input` is the pre-hook input (may have nullish values for optional/defaulted fields)",
980
+ "- Create hooks do not receive `oldRecord`; update hooks receive `oldRecord` (always non-null)",
981
+ "- Return an object with only the fields to override; unmentioned fields are unchanged",
982
+ "",
983
+ "Migration steps for each `.hooks()` call on a `db.type()`:",
984
+ "1. If the old per-field hooks only use `value`/`invoker` and don't reference `data`,",
985
+ " convert them to field-level hooks with the new args (`value` → `input`, plus `oldValue`, `now`)",
986
+ "2. If the old hooks reference `data` (cross-field access), convert to a type-level hook",
987
+ " using `input`/`oldRecord`",
988
+ "3. Remove unused `Hooks<F>` / `HookFn<>` type imports"
989
+ ].join("\n")
990
+ },
991
+ {
992
+ id: "v2/generate-watch-flag",
993
+ name: "generate --watch flag removed",
994
+ description: "Review and remove `tailor generate --watch` / `-W` invocations and the `watch` option on `GenerateOptions`. The flag, its dependency watcher, and the self-restart-on-change logic are removed; `generate` now always performs a single generation pass.",
995
+ since: "1.0.0",
996
+ until: "2.0.0",
997
+ prereleaseUntil: "2.0.0-next.6",
998
+ filePatterns: [
999
+ "**/package.json",
1000
+ "**/*.{sh,bash,zsh,yml,yaml}",
1001
+ "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}",
1002
+ "**/*.md"
1003
+ ],
1004
+ suspiciousPatterns: [/\bgenerate\b[^\n]*(?:--watch\b|\s-W\b)/, [/\bgenerate\s*\(/, /\bwatch\s*:/]],
1005
+ examples: [{
1006
+ lang: "sh",
1007
+ caption: "The --watch/-W flag no longer exists; re-run generate after each change:",
1008
+ before: "tailor generate --watch",
1009
+ after: "tailor generate"
1010
+ }],
1011
+ prompt: [
1012
+ "Tailor SDK v2 removes the `generate --watch` (`-W`) flag along with the",
1013
+ "dependency watcher and self-restart logic that powered it. `tailor generate`",
1014
+ "now always runs a single generation pass and exits.",
1015
+ "",
1016
+ "For each flagged `tailor generate ... --watch` / `-W` invocation (package.json",
1017
+ "scripts, shell scripts, CI configs, or docs), drop the flag and re-run",
1018
+ "`tailor generate` after each change instead. If automatic regeneration on file",
1019
+ "change is still needed, wrap the command with a general-purpose file watcher",
1020
+ "(e.g. `chokidar-cli`, `nodemon`) at the project level.",
1021
+ "",
1022
+ "For programmatic use of `generate()` from `@tailor-platform/sdk/cli`, remove the",
1023
+ "`watch` field from the `GenerateOptions` argument — the function now performs a",
1024
+ "single generation pass and resolves once it completes."
1025
+ ].join("\n")
1026
+ },
848
1027
  {
849
1028
  id: "v2/node-minimum-22-15-0",
850
1029
  name: "Node.js minimum version raised to 22.15.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk-codemod",
3
- "version": "0.3.0-next.4",
3
+ "version": "0.3.0-next.6",
4
4
  "description": "Codemod runner for Tailor Platform SDK upgrades",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,25 +16,25 @@
16
16
  ],
17
17
  "type": "module",
18
18
  "dependencies": {
19
- "@ast-grep/napi": "0.44.0",
19
+ "@ast-grep/napi": "0.44.1",
20
20
  "chalk": "5.6.2",
21
21
  "diff": "9.0.0",
22
22
  "pathe": "2.0.3",
23
23
  "picomatch": "4.0.5",
24
24
  "pkg-types": "2.3.1",
25
- "politty": "0.11.0",
25
+ "politty": "0.11.2",
26
26
  "semver": "7.8.5",
27
27
  "zod": "4.4.3"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/node": "24.13.2",
30
+ "@types/node": "24.13.3",
31
31
  "@types/picomatch": "4.0.3",
32
32
  "@types/semver": "7.7.1",
33
33
  "eslint-plugin-zod": "4.7.0",
34
- "oxlint": "1.72.0",
35
- "tsdown": "0.22.3",
34
+ "oxlint": "1.73.0",
35
+ "tsdown": "0.22.5",
36
36
  "typescript": "6.0.3",
37
- "vitest": "4.1.9"
37
+ "vitest": "4.1.10"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "tsdown",