@tailor-platform/sdk-codemod 0.3.0-next.2 → 0.3.0-next.3

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.
@@ -0,0 +1,103 @@
1
+ import { n as findImportStatements, r as importBindings, s as localDeclarationNames, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-Bfn39biW.js";
2
+ import { Lang, parse } from "@ast-grep/napi";
3
+ //#region codemods/v2/runtime-globals-opt-in/scripts/transform.ts
4
+ const RUNTIME_MODULE = "@tailor-platform/sdk/runtime";
5
+ const TAILOR_IDP_CLIENT = "tailor.idp.Client";
6
+ const NON_ARGUMENT_KINDS = /* @__PURE__ */ new Set([
7
+ "(",
8
+ ")",
9
+ ",",
10
+ "comment"
11
+ ]);
12
+ function quickFilter(source) {
13
+ return source.includes(TAILOR_IDP_CLIENT);
14
+ }
15
+ function sourceLang(filePath, source) {
16
+ return filePath.endsWith(".tsx") || filePath.endsWith(".jsx") || source.includes("</") ? Lang.Tsx : Lang.TypeScript;
17
+ }
18
+ function runtimeIdpLocalName(imports) {
19
+ for (const importStmt of imports) for (const binding of importBindings(importStmt)) if (binding.source === RUNTIME_MODULE && binding.importedName === "idp" && !binding.typeOnly) return binding.localName;
20
+ return null;
21
+ }
22
+ function isRuntimeIdpBinding(binding) {
23
+ return binding.source === RUNTIME_MODULE && binding.importedName === "idp";
24
+ }
25
+ function hasCollision(imports, localNames, idpLocal, injectingNewIdpName) {
26
+ if (localNames.has("tailor") || injectingNewIdpName && localNames.has("idp") || localNames.has(idpLocal)) return true;
27
+ for (const importStmt of imports) for (const binding of importBindings(importStmt)) {
28
+ if (binding.localName === "tailor") return true;
29
+ if (binding.localName !== "idp") continue;
30
+ if (isRuntimeIdpBinding(binding)) continue;
31
+ return true;
32
+ }
33
+ return false;
34
+ }
35
+ function isDirectiveStatement(node) {
36
+ return node.kind() === "expression_statement" && node.children()[0]?.kind() === "string";
37
+ }
38
+ function importInsertionIndex(root, imports, source) {
39
+ const lastImport = imports.at(-1);
40
+ if (lastImport) return lastImport.range().end.index;
41
+ let pos = 0;
42
+ if (source.startsWith("#!")) {
43
+ const newlineIndex = source.indexOf("\n");
44
+ pos = newlineIndex === -1 ? source.length : newlineIndex + 1;
45
+ }
46
+ for (const child of root.children()) {
47
+ if (child.range().start.index < pos) continue;
48
+ if (child.kind() === "comment") {
49
+ pos = child.range().end.index;
50
+ continue;
51
+ }
52
+ if (!isDirectiveStatement(child)) break;
53
+ pos = child.range().end.index;
54
+ }
55
+ return pos;
56
+ }
57
+ function buildAddRuntimeImportEdit(root, source, imports) {
58
+ return buildAddNamedImportEdit({
59
+ importName: "idp",
60
+ imports,
61
+ insertionIndex: importInsertionIndex,
62
+ moduleName: RUNTIME_MODULE,
63
+ root,
64
+ source
65
+ });
66
+ }
67
+ function argumentExpressions(args) {
68
+ return args.children().filter((child) => !NON_ARGUMENT_KINDS.has(child.kind()));
69
+ }
70
+ function hasConstructorArguments(newExpression) {
71
+ const args = newExpression.field("arguments");
72
+ return args ? argumentExpressions(args).length > 0 : false;
73
+ }
74
+ function findTailorIdpClientConstructors(root) {
75
+ return root.findAll({ rule: { kind: "new_expression" } }).filter(hasConstructorArguments).map((node) => node.field("constructor")).filter((node) => node?.text() === TAILOR_IDP_CLIENT);
76
+ }
77
+ /**
78
+ * Rewrite direct `new tailor.idp.Client(...)` calls to the typed runtime
79
+ * wrapper. Files with local `tailor` or conflicting `idp` bindings are left
80
+ * unchanged for the runtime-globals review prompt.
81
+ * @param source - File contents
82
+ * @param filePath - Absolute path to the file
83
+ * @returns Transformed source or null when nothing matched.
84
+ */
85
+ function transform(source, filePath) {
86
+ if (!quickFilter(source)) return null;
87
+ const root = parse(sourceLang(filePath, source), source).root();
88
+ const constructors = findTailorIdpClientConstructors(root);
89
+ if (constructors.length === 0) return null;
90
+ const imports = findImportStatements(root);
91
+ const existingIdpLocal = runtimeIdpLocalName(imports);
92
+ const idpLocal = existingIdpLocal ?? "idp";
93
+ if (hasCollision(imports, localDeclarationNames(root), idpLocal, existingIdpLocal === null)) return null;
94
+ const edits = constructors.map((constructor) => constructor.replace(`${idpLocal}.Client`));
95
+ if (!existingIdpLocal) {
96
+ if (filePath.endsWith(".cts")) return null;
97
+ edits.push(buildAddRuntimeImportEdit(root, source, imports));
98
+ }
99
+ const result = root.commitEdits(edits);
100
+ return result === source ? null : result;
101
+ }
102
+ //#endregion
103
+ export { transform as default };
@@ -1,7 +1,7 @@
1
1
  import * as path from "pathe";
2
2
  //#region codemods/v2/sdk-skills-shim/scripts/transform.ts
3
3
  const SHIM_PATTERN = /\btailor-sdk-skills(?:@[^\s'"`]+)?(?:[ \t]+install)?\b(?!-)/g;
4
- const REPLACEMENT = "tailor-sdk skills install";
4
+ const REPLACEMENT = "tailor skills add";
5
5
  function replaceShim(value) {
6
6
  return value.replace(SHIM_PATTERN, REPLACEMENT);
7
7
  }
@@ -34,10 +34,10 @@ function transformPackageJson(source) {
34
34
  return JSON.stringify(parsed, null, 2) + trailing;
35
35
  }
36
36
  /**
37
- * Replace `tailor-sdk-skills` invocations with `tailor-sdk skills install`.
37
+ * Replace `tailor-sdk-skills` invocations with `tailor skills add`.
38
38
  *
39
39
  * The standalone `tailor-sdk-skills` binary is removed in v2; users must call
40
- * the subcommand on the main `tailor-sdk` CLI instead.
40
+ * the subcommand on the main `tailor` CLI instead.
41
41
  * @param source - File contents
42
42
  * @param filePath - Absolute path to the file (used to dispatch package.json vs text)
43
43
  * @returns Transformed source or null when nothing matched.
@@ -0,0 +1,14 @@
1
+ //#region codemods/v2/tailor-output-ignore-dir/scripts/transform.ts
2
+ const GENERATED_DIR_IGNORE_ENTRY_RE = /^(!?\/?)\.tailor-sdk(\/?)([ \t]*)$/gm;
3
+ /**
4
+ * Rewrite exact ignore-file entries for the generated SDK output directory.
5
+ * @param source - File contents
6
+ * @returns Transformed source or null when nothing matched.
7
+ */
8
+ function transform(source) {
9
+ if (!source.includes(".tailor-sdk")) return null;
10
+ const updated = source.replace(GENERATED_DIR_IGNORE_ENTRY_RE, (_match, prefix, slash, trailingWhitespace) => `${prefix}.tailor${slash}${trailingWhitespace}`);
11
+ return updated === source ? null : updated;
12
+ }
13
+ //#endregion
14
+ export { transform as default };
@@ -0,0 +1,126 @@
1
+ import { Lang, parse } from "@ast-grep/napi";
2
+ //#region codemods/v2/wait-point-rename/scripts/transform.ts
3
+ const SDK_MODULE = "@tailor-platform/sdk";
4
+ const RENAMES = {
5
+ defineWaitPoint: "createWaitPoint",
6
+ defineWaitPoints: "createWaitPoints"
7
+ };
8
+ function isInsideImportStatement(node) {
9
+ let current = node.parent();
10
+ while (current) {
11
+ if (current.kind() === "import_statement") return true;
12
+ current = current.parent();
13
+ }
14
+ return false;
15
+ }
16
+ /**
17
+ * Rename `defineWaitPoint` and `defineWaitPoints` imported from `@tailor-platform/sdk`
18
+ * to `createWaitPoint` and `createWaitPoints`, updating both the import specifiers
19
+ * and all usages in the file body.
20
+ * @param source - File contents
21
+ * @param filePath - Absolute path to the file (kept for the runner signature)
22
+ * @returns Transformed source or null when nothing matched.
23
+ */
24
+ function transform(source, _filePath) {
25
+ if (!Object.keys(RENAMES).some((name) => source.includes(name))) return null;
26
+ if (!source.includes(SDK_MODULE)) return null;
27
+ const root = parse(source.includes("</") || source.includes("/>") ? Lang.Tsx : Lang.TypeScript, source).root();
28
+ const edits = [];
29
+ const needsBodyRename = /* @__PURE__ */ new Set();
30
+ const importStmts = root.findAll({ rule: {
31
+ kind: "import_statement",
32
+ has: {
33
+ kind: "string",
34
+ regex: `^["']${SDK_MODULE}["']$`
35
+ }
36
+ } });
37
+ for (const importStmt of importStmts) {
38
+ const specs = importStmt.findAll({ rule: { kind: "import_specifier" } });
39
+ for (const spec of specs) {
40
+ const idents = spec.children().filter((c) => c.kind() === "identifier");
41
+ if (idents.length === 0) continue;
42
+ const importedName = idents[0].text();
43
+ const newName = RENAMES[importedName];
44
+ if (!newName) continue;
45
+ const isAliased = idents.length > 1;
46
+ edits.push(idents[0].replace(newName));
47
+ if (!isAliased) needsBodyRename.add(importedName);
48
+ }
49
+ }
50
+ if (edits.length === 0) return null;
51
+ if (needsBodyRename.size > 0) {
52
+ const shadowedRanges = /* @__PURE__ */ new Map();
53
+ const addShadowedRange = (name, scopeNode) => {
54
+ const r = scopeNode.range();
55
+ if (!shadowedRanges.has(name)) shadowedRanges.set(name, []);
56
+ shadowedRanges.get(name).push({
57
+ start: r.start.index,
58
+ end: r.end.index
59
+ });
60
+ };
61
+ const localDecls = root.findAll({ rule: { any: [{ kind: "function_declaration" }, { kind: "variable_declarator" }] } });
62
+ for (const decl of localDecls) {
63
+ if (isInsideImportStatement(decl)) continue;
64
+ const nameChild = decl.children().filter((c) => c.kind() === "identifier").find((c) => needsBodyRename.has(c.text())) ?? decl.children().find((c) => c.kind() === "object_pattern")?.children().find((c) => c.kind() === "shorthand_property_identifier_pattern" && needsBodyRename.has(c.text()));
65
+ if (!nameChild || !needsBodyRename.has(nameChild.text())) continue;
66
+ let scopeNode = root;
67
+ let p = decl.parent();
68
+ while (p) {
69
+ const k = p.kind();
70
+ if (k === "statement_block" || k === "program" || k === "for_statement" || k === "for_in_statement") {
71
+ scopeNode = p;
72
+ break;
73
+ }
74
+ p = p.parent();
75
+ }
76
+ addShadowedRange(nameChild.text(), scopeNode);
77
+ }
78
+ const paramNodes = root.findAll({ rule: { any: [{ kind: "required_parameter" }, { kind: "optional_parameter" }] } });
79
+ for (const param of paramNodes) {
80
+ if (isInsideImportStatement(param)) continue;
81
+ const nameChild = param.children().flatMap((c) => c.kind() === "rest_pattern" ? c.children().filter((cc) => cc.kind() === "identifier") : c.kind() === "identifier" ? [c] : []).find((c) => needsBodyRename.has(c.text()));
82
+ if (!nameChild) continue;
83
+ let scopeNode = root;
84
+ let p = param.parent();
85
+ while (p) {
86
+ const k = p.kind();
87
+ if (k === "formal_parameters") {
88
+ p = p.parent();
89
+ continue;
90
+ }
91
+ if (k === "function_declaration" || k === "function_expression" || k === "arrow_function" || k === "method_definition") {
92
+ scopeNode = p;
93
+ break;
94
+ }
95
+ break;
96
+ }
97
+ addShadowedRange(nameChild.text(), scopeNode);
98
+ }
99
+ const forInStmts = root.findAll({ rule: { kind: "for_in_statement" } });
100
+ for (const stmt of forInStmts) {
101
+ const children = stmt.children();
102
+ const keywordIdx = children.findIndex((c) => c.kind() === "of" || c.kind() === "in");
103
+ if (keywordIdx < 0) continue;
104
+ for (let i = 0; i < keywordIdx; i++) {
105
+ const child = children[i];
106
+ if (child.kind() === "identifier" && needsBodyRename.has(child.text())) addShadowedRange(child.text(), stmt);
107
+ }
108
+ }
109
+ const renameNode = (node) => {
110
+ const name = node.text();
111
+ if (!needsBodyRename.has(name)) return;
112
+ if (isInsideImportStatement(node)) return;
113
+ const ranges = shadowedRanges.get(name);
114
+ if (ranges) {
115
+ const pos = node.range().start.index;
116
+ if (ranges.some((r) => pos >= r.start && pos < r.end)) return;
117
+ }
118
+ edits.push(node.replace(RENAMES[name]));
119
+ };
120
+ for (const ident of root.findAll({ rule: { kind: "identifier" } })) renameNode(ident);
121
+ for (const prop of root.findAll({ rule: { kind: "shorthand_property_identifier" } })) renameNode(prop);
122
+ }
123
+ return root.commitEdits(edits);
124
+ }
125
+ //#endregion
126
+ export { transform as default };