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

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,28 @@
1
1
  # @tailor-platform/sdk-codemod
2
2
 
3
+ ## 0.3.0-next.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1693](https://github.com/tailor-platform/sdk/pull/1693) [`4751214`](https://github.com/tailor-platform/sdk/commit/4751214c0923e094a844f9ce322279a47e871075) Thanks [@dqn](https://github.com/dqn)! - Rename the TailorDB schema builder from `db.type()` to `db.table()`.
8
+
9
+ Update TailorDB definitions:
10
+
11
+ ```diff
12
+ import { db } from "@tailor-platform/sdk";
13
+
14
+ -export const user = db.type("User", {
15
+ +export const user = db.table("User", {
16
+ name: db.string(),
17
+ });
18
+ ```
19
+
20
+ - [#1704](https://github.com/tailor-platform/sdk/pull/1704) [`9c81d9c`](https://github.com/tailor-platform/sdk/commit/9c81d9c18b1d29b3e9307ea17fe54c8ce55f4dda) Thanks [@dqn](https://github.com/dqn)! - Remove flat value and default exports from `@tailor-platform/sdk/runtime/*` subpath modules. Import each subpath through its self-named namespace export instead, for example `import { iconv } from "@tailor-platform/sdk/runtime/iconv"`.
21
+
22
+ The aggregate `@tailor-platform/sdk/runtime` entry remains named-only, and its deprecated `file.deleteFile` alias is removed in favor of `file.delete`. The v2 codemod rewrites straightforward namespace-star subpath imports, flat named value imports, and aggregate `file.deleteFile` calls to the new namespace-object style.
23
+
24
+ `TailorContextAPI` and `TailorWorkflowAPI` now describe the SDK wrapper objects. Code that types the platform-provided `globalThis.tailor.context` or `globalThis.tailor.workflow` objects directly must use `PlatformContextAPI` or `PlatformWorkflowAPI` instead.
25
+
3
26
  ## 0.3.0-next.3
4
27
 
5
28
  ### Patch Changes
@@ -168,4 +168,4 @@ function localDeclarationNames(root) {
168
168
  return names;
169
169
  }
170
170
  //#endregion
171
- export { importSpecNames as a, importSource as i, findImportStatements as n, isTypeOnlyImport as o, importBindings as r, localDeclarationNames as s, buildAddNamedImportEdit as t };
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 };
@@ -1,4 +1,4 @@
1
- import { a as importSpecNames, i as importSource, n as findImportStatements, o as isTypeOnlyImport, r as importBindings, s as localDeclarationNames, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-Bfn39biW.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-D3FXAKNz.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";
@@ -0,0 +1,383 @@
1
+ import { a as importSource, i as importBindings, r as findImportStatements } from "../../../ast-grep-helpers-D3FXAKNz.js";
2
+ import { Lang, parse } from "@ast-grep/napi";
3
+ //#region codemods/v2/db-type-to-table/scripts/transform.ts
4
+ const SDK_MODULE = "@tailor-platform/sdk";
5
+ function sourceLang(filePath, source) {
6
+ return filePath.endsWith(".tsx") || filePath.endsWith(".jsx") || source.includes("</") ? Lang.Tsx : Lang.TypeScript;
7
+ }
8
+ function namespaceImportNames(importStmt) {
9
+ return importStmt.findAll({ rule: { kind: "namespace_import" } }).flatMap((node) => node.children().filter((child) => child.kind() === "identifier")).map((node) => node.text());
10
+ }
11
+ function isInsideImportStatement(node) {
12
+ let current = node.parent();
13
+ while (current) {
14
+ if (current.kind() === "import_statement") return true;
15
+ current = current.parent();
16
+ }
17
+ return false;
18
+ }
19
+ function isBindingLeafKind(kind) {
20
+ return kind === "identifier" || kind === "shorthand_property_identifier_pattern";
21
+ }
22
+ function isBindingPatternKind(kind) {
23
+ return isBindingLeafKind(kind) || kind === "object_pattern" || kind === "array_pattern" || kind === "rest_pattern";
24
+ }
25
+ function collectBindingNodes(node, names, result) {
26
+ if (isBindingLeafKind(node.kind())) {
27
+ if (names.has(node.text())) result.push(node);
28
+ return;
29
+ }
30
+ for (const child of node.children()) {
31
+ if (child.kind() === "property_identifier") continue;
32
+ if (child.kind() === "=") break;
33
+ collectBindingNodes(child, names, result);
34
+ }
35
+ }
36
+ function bindingNodes(node, names) {
37
+ const result = [];
38
+ collectBindingNodes(node, names, result);
39
+ return result;
40
+ }
41
+ function directBindingNodes(node, names) {
42
+ const result = [];
43
+ for (const child of node.children()) {
44
+ if (child.kind() === "=") break;
45
+ if (isBindingPatternKind(child.kind())) collectBindingNodes(child, names, result);
46
+ }
47
+ return result;
48
+ }
49
+ function firstDeclaratorChild(node) {
50
+ return node.children().find((child) => child.kind() !== "=") ?? null;
51
+ }
52
+ function declaratorValue(node) {
53
+ const children = node.children();
54
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
55
+ if (equalsIndex === -1) return null;
56
+ return children.slice(equalsIndex + 1).find((child) => child.kind() !== "comment") ?? null;
57
+ }
58
+ function assignmentTarget(node) {
59
+ const children = node.children();
60
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
61
+ if (equalsIndex === -1) return null;
62
+ return children.slice(0, equalsIndex).find((child) => child.kind() !== "comment") ?? null;
63
+ }
64
+ function assignmentValue(node) {
65
+ const children = node.children();
66
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
67
+ if (equalsIndex === -1) return null;
68
+ return children.slice(equalsIndex + 1).find((child) => child.kind() !== "comment") ?? null;
69
+ }
70
+ function parameterDefaultTarget(node) {
71
+ const children = node.children();
72
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
73
+ if (equalsIndex === -1) return null;
74
+ return children.slice(0, equalsIndex).find((child) => isBindingPatternKind(child.kind())) ?? null;
75
+ }
76
+ function parameterDefaultValue(node) {
77
+ const children = node.children();
78
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
79
+ if (equalsIndex === -1) return null;
80
+ return children.slice(equalsIndex + 1).find((child) => child.kind() !== "comment") ?? null;
81
+ }
82
+ function addShadowedRange(shadowedRanges, name, scopeNode) {
83
+ const range = scopeNode.range();
84
+ if (!shadowedRanges.has(name)) shadowedRanges.set(name, []);
85
+ shadowedRanges.get(name).push({
86
+ start: range.start.index,
87
+ end: range.end.index
88
+ });
89
+ }
90
+ function nearestScope(node) {
91
+ let current = node.parent();
92
+ while (current) {
93
+ const kind = current.kind();
94
+ if (kind === "statement_block" || kind === "program" || kind === "switch_body" || kind === "for_statement" || kind === "for_in_statement") return current;
95
+ current = current.parent();
96
+ }
97
+ return node;
98
+ }
99
+ function functionScope(node) {
100
+ let current = node.parent();
101
+ while (current) {
102
+ const kind = current.kind();
103
+ if (kind === "function_declaration" || kind === "function_expression" || kind === "arrow_function" || kind === "method_definition" || kind === "program") return current;
104
+ current = current.parent();
105
+ }
106
+ return node;
107
+ }
108
+ function variableDeclarationScope(node) {
109
+ const declaration = node.parent();
110
+ if (/^var\b/.test(declaration?.text().trimStart() ?? "")) return functionScope(node);
111
+ return nearestScope(node);
112
+ }
113
+ function parameterScope(node) {
114
+ let current = node.parent();
115
+ while (current) {
116
+ const kind = current.kind();
117
+ if (kind === "formal_parameters") {
118
+ current = current.parent();
119
+ continue;
120
+ }
121
+ if (kind === "function_declaration" || kind === "function_expression" || kind === "arrow_function" || kind === "method_definition") return current;
122
+ break;
123
+ }
124
+ return nearestScope(node);
125
+ }
126
+ function buildShadowedRanges(root, names) {
127
+ const shadowedRanges = /* @__PURE__ */ new Map();
128
+ for (const decl of root.findAll({ rule: { kind: "variable_declarator" } })) {
129
+ if (isInsideImportStatement(decl)) continue;
130
+ const binding = firstDeclaratorChild(decl);
131
+ if (!binding) continue;
132
+ for (const name of bindingNodes(binding, names)) addShadowedRange(shadowedRanges, name.text(), variableDeclarationScope(decl));
133
+ }
134
+ for (const decl of root.findAll({ rule: { any: [
135
+ { kind: "function_declaration" },
136
+ { kind: "class_declaration" },
137
+ { kind: "enum_declaration" }
138
+ ] } })) {
139
+ const name = decl.children().find((child) => child.kind() === "identifier" && names.has(child.text()));
140
+ if (name) addShadowedRange(shadowedRanges, name.text(), nearestScope(decl));
141
+ }
142
+ for (const param of root.findAll({ rule: { any: [{ kind: "required_parameter" }, { kind: "optional_parameter" }] } })) for (const name of directBindingNodes(param, names)) addShadowedRange(shadowedRanges, name.text(), parameterScope(param));
143
+ for (const arrow of root.findAll({ rule: { kind: "arrow_function" } })) {
144
+ const children = arrow.children();
145
+ const arrowIndex = children.findIndex((child) => child.kind() === "=>");
146
+ if (arrowIndex === -1) continue;
147
+ for (const child of children.slice(0, arrowIndex)) {
148
+ if (child.kind() === "=") break;
149
+ if (!isBindingPatternKind(child.kind())) continue;
150
+ for (const name of bindingNodes(child, names)) addShadowedRange(shadowedRanges, name.text(), arrow);
151
+ }
152
+ }
153
+ for (const catchClause of root.findAll({ rule: { kind: "catch_clause" } })) for (const name of directBindingNodes(catchClause, names)) addShadowedRange(shadowedRanges, name.text(), catchClause);
154
+ for (const loop of root.findAll({ rule: { kind: "for_in_statement" } })) {
155
+ const children = loop.children();
156
+ const keywordIndex = children.findIndex((child) => child.kind() === "in" || child.kind() === "of");
157
+ if (keywordIndex === -1) continue;
158
+ for (const child of children.slice(0, keywordIndex)) for (const name of bindingNodes(child, names)) addShadowedRange(shadowedRanges, name.text(), loop);
159
+ }
160
+ return shadowedRanges;
161
+ }
162
+ function isShadowed(node, shadowedRanges) {
163
+ const ranges = shadowedRanges.get(node.text());
164
+ if (!ranges) return false;
165
+ const position = node.range().start.index;
166
+ return ranges.some((range) => position >= range.start && position < range.end);
167
+ }
168
+ function unwrapExpression(node) {
169
+ let current = node;
170
+ while (current) {
171
+ const kind = current.kind();
172
+ if (kind === "parenthesized_expression") {
173
+ current = current.children().find((child) => child.kind() !== "(" && child.kind() !== ")") ?? null;
174
+ continue;
175
+ }
176
+ if (kind === "as_expression" || kind === "satisfies_expression" || kind === "non_null_expression") {
177
+ current = current.children()[0] ?? null;
178
+ continue;
179
+ }
180
+ if (kind === "type_assertion") {
181
+ current = current.children().find((child) => child.kind() !== "type_arguments") ?? null;
182
+ continue;
183
+ }
184
+ return current;
185
+ }
186
+ return null;
187
+ }
188
+ function isSdkDbMember(object, dbNames, namespaceNames, shadowedRanges) {
189
+ const unwrapped = unwrapExpression(object);
190
+ if (!unwrapped) return false;
191
+ if (unwrapped.kind() === "identifier") return dbNames.has(unwrapped.text()) && !isShadowed(unwrapped, shadowedRanges);
192
+ if (unwrapped.kind() !== "member_expression") return false;
193
+ const base = unwrapExpression(unwrapped.field("object"));
194
+ const property = memberProperty(unwrapped);
195
+ return base?.kind() === "identifier" && namespaceNames.has(base.text()) && !isShadowed(base, shadowedRanges) && property?.text() === "db";
196
+ }
197
+ function memberProperty(member) {
198
+ const children = member.children();
199
+ for (let index = children.length - 1; index >= 0; index -= 1) {
200
+ const child = children[index];
201
+ if (child.kind() === "property_identifier") return child;
202
+ }
203
+ return member.field("property");
204
+ }
205
+ function typeStringLiteral(node) {
206
+ if (!node) return null;
207
+ const kind = node.kind();
208
+ if (kind !== "string" && kind !== "template_string") return null;
209
+ const fragments = node.children().filter((child) => child.kind() === "string_fragment");
210
+ return fragments.length === 1 && fragments[0].text() === "type" ? node : null;
211
+ }
212
+ function replaceStringLiteralValue(node, value) {
213
+ const text = node.text();
214
+ const quote = text.startsWith("'") ? "'" : text.startsWith("`") ? "`" : "\"";
215
+ return node.replace(`${quote}${value}${quote}`);
216
+ }
217
+ function hasTypeBuilderUse(root, name, afterIndex) {
218
+ for (const member of root.findAll({ rule: { kind: "member_expression" } })) {
219
+ if (member.range().start.index <= afterIndex) continue;
220
+ if (memberProperty(member)?.text() !== "type") continue;
221
+ const object = unwrapExpression(member.field("object"));
222
+ if (object?.kind() === "identifier" && object.text() === name) return true;
223
+ }
224
+ for (const subscript of root.findAll({ rule: { kind: "subscript_expression" } })) {
225
+ if (subscript.range().start.index <= afterIndex) continue;
226
+ if (!typeStringLiteral(subscript.field("index"))) continue;
227
+ const object = unwrapExpression(subscript.field("object"));
228
+ if (object?.kind() === "identifier" && object.text() === name) return true;
229
+ }
230
+ return false;
231
+ }
232
+ function transform(source, filePath) {
233
+ if (!source.includes("type") || !source.includes(SDK_MODULE)) return null;
234
+ let root;
235
+ try {
236
+ root = parse(sourceLang(filePath, source), source).root();
237
+ } catch {
238
+ return null;
239
+ }
240
+ const imports = findImportStatements(root).filter((importStmt) => importSource(importStmt) === SDK_MODULE);
241
+ if (imports.length === 0) return null;
242
+ const dbNames = /* @__PURE__ */ new Set();
243
+ const namespaceNames = /* @__PURE__ */ new Set();
244
+ for (const importStmt of imports) {
245
+ for (const binding of importBindings(importStmt)) if (binding.importedName === "db") dbNames.add(binding.localName);
246
+ for (const name of namespaceImportNames(importStmt)) namespaceNames.add(name);
247
+ }
248
+ if (dbNames.size === 0 && namespaceNames.size === 0) return null;
249
+ const shadowedRanges = buildShadowedRanges(root, /* @__PURE__ */ new Set([...dbNames, ...namespaceNames]));
250
+ const edits = [];
251
+ for (const member of root.findAll({ rule: { kind: "member_expression" } })) {
252
+ const property = memberProperty(member);
253
+ if (property?.text() !== "type") continue;
254
+ if (!isSdkDbMember(member.field("object"), dbNames, namespaceNames, shadowedRanges)) continue;
255
+ edits.push(property.replace("table"));
256
+ }
257
+ for (const subscript of root.findAll({ rule: { kind: "subscript_expression" } })) {
258
+ const index = typeStringLiteral(subscript.field("index"));
259
+ if (!index) continue;
260
+ if (!isSdkDbMember(subscript.field("object"), dbNames, namespaceNames, shadowedRanges)) continue;
261
+ edits.push(replaceStringLiteralValue(index, "table"));
262
+ }
263
+ return edits.length > 0 ? root.commitEdits(edits) : null;
264
+ }
265
+ function lineForIndex(source, index) {
266
+ return source.slice(0, index).split(/\r\n|\r|\n/).length;
267
+ }
268
+ function excerptAtIndex(source, index) {
269
+ const lineStart = Math.max(source.lastIndexOf("\n", index - 1) + 1, 0);
270
+ const lineEnd = source.indexOf("\n", index);
271
+ return source.slice(lineStart, lineEnd === -1 ? source.length : lineEnd).trim();
272
+ }
273
+ function objectPatternHasTypeProperty(pattern) {
274
+ return pattern.findAll({ rule: { any: [{
275
+ kind: "property_identifier",
276
+ regex: "^type$"
277
+ }, {
278
+ kind: "shorthand_property_identifier_pattern",
279
+ regex: "^type$"
280
+ }] } }).some((node) => node.text() === "type");
281
+ }
282
+ function namespaceDbAliasBindings(pattern) {
283
+ const aliases = [];
284
+ for (const child of pattern.children()) {
285
+ if (child.kind() === "shorthand_property_identifier_pattern" && child.text() === "db") {
286
+ aliases.push(child);
287
+ continue;
288
+ }
289
+ if (child.kind() !== "pair_pattern") continue;
290
+ if (child.field("key")?.text() !== "db") continue;
291
+ const value = child.field("value");
292
+ if (value?.kind() === "identifier") aliases.push(value);
293
+ }
294
+ return aliases;
295
+ }
296
+ function isSdkNamespaceMember(node, namespaceNames, shadowedRanges) {
297
+ const unwrapped = unwrapExpression(node);
298
+ return unwrapped?.kind() === "identifier" && namespaceNames.has(unwrapped.text()) && !isShadowed(unwrapped, shadowedRanges);
299
+ }
300
+ function reviewFindings(source, filePath, relativePath) {
301
+ if (!source.includes("type") || !source.includes(SDK_MODULE)) return [];
302
+ let root;
303
+ try {
304
+ root = parse(sourceLang(filePath, source), source).root();
305
+ } catch {
306
+ return [];
307
+ }
308
+ const imports = findImportStatements(root).filter((importStmt) => importSource(importStmt) === SDK_MODULE);
309
+ if (imports.length === 0) return [];
310
+ const dbNames = /* @__PURE__ */ new Set();
311
+ const namespaceNames = /* @__PURE__ */ new Set();
312
+ for (const importStmt of imports) {
313
+ for (const binding of importBindings(importStmt)) if (binding.importedName === "db") dbNames.add(binding.localName);
314
+ for (const name of namespaceImportNames(importStmt)) namespaceNames.add(name);
315
+ }
316
+ if (dbNames.size === 0 && namespaceNames.size === 0) return [];
317
+ const shadowedRanges = buildShadowedRanges(root, /* @__PURE__ */ new Set([...dbNames, ...namespaceNames]));
318
+ const findings = [];
319
+ for (const decl of root.findAll({ rule: { kind: "variable_declarator" } })) {
320
+ const binding = firstDeclaratorChild(decl);
321
+ if (binding?.kind() !== "object_pattern" || !objectPatternHasTypeProperty(binding)) continue;
322
+ if (!isSdkDbMember(declaratorValue(decl), dbNames, namespaceNames, shadowedRanges)) continue;
323
+ findings.push({
324
+ file: relativePath,
325
+ line: lineForIndex(source, binding.range().start.index),
326
+ message: "Review destructured db.type builder usage and migrate it to db.table.",
327
+ excerpt: excerptAtIndex(source, binding.range().start.index)
328
+ });
329
+ }
330
+ for (const decl of root.findAll({ rule: { kind: "variable_declarator" } })) {
331
+ const binding = firstDeclaratorChild(decl);
332
+ if (binding?.kind() !== "object_pattern") continue;
333
+ if (!isSdkNamespaceMember(declaratorValue(decl), namespaceNames, shadowedRanges)) continue;
334
+ for (const alias of namespaceDbAliasBindings(binding)) {
335
+ if (!hasTypeBuilderUse(root, alias.text(), decl.range().end.index)) continue;
336
+ findings.push({
337
+ file: relativePath,
338
+ line: lineForIndex(source, binding.range().start.index),
339
+ message: "Review SDK db alias usage and migrate db.type builder calls to db.table.",
340
+ excerpt: excerptAtIndex(source, binding.range().start.index)
341
+ });
342
+ }
343
+ }
344
+ for (const decl of root.findAll({ rule: { kind: "variable_declarator" } })) {
345
+ const binding = firstDeclaratorChild(decl);
346
+ if (binding?.kind() !== "identifier") continue;
347
+ if (!isSdkDbMember(declaratorValue(decl), dbNames, namespaceNames, shadowedRanges)) continue;
348
+ if (!hasTypeBuilderUse(root, binding.text(), decl.range().end.index)) continue;
349
+ findings.push({
350
+ file: relativePath,
351
+ line: lineForIndex(source, binding.range().start.index),
352
+ message: "Review SDK db alias usage and migrate db.type builder calls to db.table.",
353
+ excerpt: excerptAtIndex(source, binding.range().start.index)
354
+ });
355
+ }
356
+ for (const assignment of root.findAll({ rule: { kind: "assignment_expression" } })) {
357
+ const target = assignmentTarget(assignment);
358
+ if (target?.kind() !== "identifier") continue;
359
+ if (!isSdkDbMember(assignmentValue(assignment), dbNames, namespaceNames, shadowedRanges)) continue;
360
+ if (!hasTypeBuilderUse(root, target.text(), assignment.range().end.index)) continue;
361
+ findings.push({
362
+ file: relativePath,
363
+ line: lineForIndex(source, assignment.range().start.index),
364
+ message: "Review SDK db alias usage and migrate db.type builder calls to db.table.",
365
+ excerpt: excerptAtIndex(source, assignment.range().start.index)
366
+ });
367
+ }
368
+ for (const param of root.findAll({ rule: { any: [{ kind: "required_parameter" }, { kind: "optional_parameter" }] } })) {
369
+ const target = parameterDefaultTarget(param);
370
+ if (target?.kind() !== "identifier") continue;
371
+ if (!isSdkDbMember(parameterDefaultValue(param), dbNames, namespaceNames, shadowedRanges)) continue;
372
+ if (!hasTypeBuilderUse(root, target.text(), param.range().end.index)) continue;
373
+ findings.push({
374
+ file: relativePath,
375
+ line: lineForIndex(source, param.range().start.index),
376
+ message: "Review SDK db alias usage and migrate db.type builder calls to db.table.",
377
+ excerpt: excerptAtIndex(source, param.range().start.index)
378
+ });
379
+ }
380
+ return findings;
381
+ }
382
+ //#endregion
383
+ export { transform as default, reviewFindings };
@@ -1,4 +1,4 @@
1
- import { n as findImportStatements, r as importBindings, s as localDeclarationNames, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-Bfn39biW.js";
1
+ import { c as localDeclarationNames, i as importBindings, r as findImportStatements, t as buildAddNamedImportEdit } from "../../../ast-grep-helpers-D3FXAKNz.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";
@@ -0,0 +1,792 @@
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";
2
+ import { Lang, parse } from "@ast-grep/napi";
3
+ //#region codemods/v2/runtime-subpath-namespace/scripts/transform.ts
4
+ const MODULES_BY_SOURCE = new Map([
5
+ {
6
+ namespace: "iconv",
7
+ source: "@tailor-platform/sdk/runtime/iconv",
8
+ members: {
9
+ convert: "convert",
10
+ convertBuffer: "convertBuffer",
11
+ decode: "decode",
12
+ encode: "encode",
13
+ encodings: "encodings",
14
+ Iconv: "Iconv"
15
+ }
16
+ },
17
+ {
18
+ namespace: "secretmanager",
19
+ source: "@tailor-platform/sdk/runtime/secretmanager",
20
+ members: {
21
+ getSecrets: "getSecrets",
22
+ getSecret: "getSecret"
23
+ }
24
+ },
25
+ {
26
+ namespace: "authconnection",
27
+ source: "@tailor-platform/sdk/runtime/authconnection",
28
+ members: { getConnectionToken: "getConnectionToken" }
29
+ },
30
+ {
31
+ namespace: "idp",
32
+ source: "@tailor-platform/sdk/runtime/idp",
33
+ members: { Client: "Client" }
34
+ },
35
+ {
36
+ namespace: "workflow",
37
+ source: "@tailor-platform/sdk/runtime/workflow",
38
+ members: {
39
+ triggerWorkflow: "triggerWorkflow",
40
+ resumeWorkflow: "resumeWorkflow",
41
+ triggerJobFunction: "triggerJobFunction",
42
+ wait: "wait",
43
+ resolve: "resolve"
44
+ }
45
+ },
46
+ {
47
+ namespace: "context",
48
+ source: "@tailor-platform/sdk/runtime/context",
49
+ members: { getInvoker: "getInvoker" }
50
+ },
51
+ {
52
+ namespace: "file",
53
+ source: "@tailor-platform/sdk/runtime/file",
54
+ members: {
55
+ upload: "upload",
56
+ download: "download",
57
+ downloadAsBase64: "downloadAsBase64",
58
+ delete: "delete",
59
+ deleteFile: "delete",
60
+ getMetadata: "getMetadata",
61
+ downloadStream: "downloadStream",
62
+ uploadStream: "uploadStream"
63
+ }
64
+ },
65
+ {
66
+ namespace: "aigateway",
67
+ source: "@tailor-platform/sdk/runtime/aigateway",
68
+ members: { get: "get" }
69
+ }
70
+ ].map((mod) => [mod.source, mod]));
71
+ const AGGREGATE_RUNTIME_SOURCE = "@tailor-platform/sdk/runtime";
72
+ const JSX_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
73
+ const JS_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
74
+ ".js",
75
+ ".mjs",
76
+ ".cjs"
77
+ ]);
78
+ function quickFilter(source) {
79
+ return source.includes(AGGREGATE_RUNTIME_SOURCE);
80
+ }
81
+ function sourceLang(filePath, source) {
82
+ const lower = filePath.toLowerCase();
83
+ const extension = lower.slice(lower.lastIndexOf("."));
84
+ if (JSX_FILE_EXTENSIONS.has(extension)) return Lang.Tsx;
85
+ if (JS_FILE_EXTENSIONS.has(extension) && /<>|<\/>|<[A-Za-z][\w.$:-]/.test(source)) return Lang.Tsx;
86
+ return Lang.TypeScript;
87
+ }
88
+ function importClause(importStmt) {
89
+ return importStmt.children().find((child) => child.kind() === "import_clause") ?? null;
90
+ }
91
+ function hasDefaultImport(importStmt) {
92
+ return importClause(importStmt)?.children().some((child) => child.kind() === "identifier") ?? false;
93
+ }
94
+ function namespaceImportName(importStmt) {
95
+ return importClause(importStmt)?.children().find((child) => child.kind() === "namespace_import")?.children().find((child) => child.kind() === "identifier")?.text() ?? null;
96
+ }
97
+ function formatImport(source, namedSpecs, typeOnly = false, attributeText = "") {
98
+ const importKeyword = typeOnly ? "import type" : "import";
99
+ const named = namedSpecs.length > 0 ? `{ ${namedSpecs.join(", ")} }` : null;
100
+ const attributes = attributeText === "" ? "" : ` ${attributeText}`;
101
+ if (named) return `${importKeyword} ${named} from "${source}"${attributes};`;
102
+ return "";
103
+ }
104
+ function importAttributeText(importStmt) {
105
+ return importStmt.children().find((child) => child.kind() === "import_attribute")?.text() ?? "";
106
+ }
107
+ function replaceImportStatement(importStmt, nextText, sourceText) {
108
+ if (nextText !== "") return importStmt.replace(nextText);
109
+ const range = importStmt.range();
110
+ let endPos = range.end.index;
111
+ if (sourceText[endPos] === "\r" && sourceText[endPos + 1] === "\n") endPos += 2;
112
+ else if (sourceText[endPos] === "\n") endPos += 1;
113
+ return {
114
+ startPos: range.start.index,
115
+ endPos,
116
+ insertedText: ""
117
+ };
118
+ }
119
+ function isInsideImportStatement(node) {
120
+ let current = node.parent();
121
+ while (current) {
122
+ if (current.kind() === "import_statement") return true;
123
+ current = current.parent();
124
+ }
125
+ return false;
126
+ }
127
+ function isInsideExportSpecifier(node) {
128
+ let current = node.parent();
129
+ while (current) {
130
+ if (current.kind() === "export_specifier") return true;
131
+ if (current.kind() === "export_statement") return false;
132
+ current = current.parent();
133
+ }
134
+ return false;
135
+ }
136
+ function isInsideTypeQuery(node) {
137
+ let current = node.parent();
138
+ while (current) {
139
+ if (current.kind() === "type_query") return true;
140
+ if (current.kind() === "statement_block" || current.kind() === "program") return false;
141
+ current = current.parent();
142
+ }
143
+ return false;
144
+ }
145
+ function isJsxTagName(node) {
146
+ const parentKind = node.parent()?.kind();
147
+ return parentKind === "jsx_opening_element" || parentKind === "jsx_self_closing_element" || parentKind === "jsx_closing_element";
148
+ }
149
+ function sameNode(left, right) {
150
+ if (!left) return false;
151
+ const leftRange = left.range();
152
+ const rightRange = right.range();
153
+ return leftRange.start.index === rightRange.start.index && leftRange.end.index === rightRange.end.index;
154
+ }
155
+ function typeParameterName(typeParameter) {
156
+ return typeParameter.children().find((child) => child.kind() === "type_identifier") ?? null;
157
+ }
158
+ function typeParametersDeclare(typeParameters, name) {
159
+ return typeParameters.children().some((child) => child.kind() === "type_parameter" && typeParameterName(child)?.text() === name);
160
+ }
161
+ function isTypeParameterScoped(node) {
162
+ let current = node.parent();
163
+ while (current) {
164
+ if (current.kind() === "type_parameter" && sameNode(typeParameterName(current), node)) return true;
165
+ const typeParameters = current.children().find((child) => child.kind() === "type_parameters");
166
+ if (typeParameters && typeParametersDeclare(typeParameters, node.text())) return true;
167
+ current = current.parent();
168
+ }
169
+ return false;
170
+ }
171
+ function isNestedTypeMember(node) {
172
+ const parent = node.parent();
173
+ if (parent?.kind() !== "nested_type_identifier") return false;
174
+ return !sameNode(parent.children().find((child) => child.kind() === "identifier" || child.kind() === "type_identifier"), node);
175
+ }
176
+ function localTypeScopeDeclarationNames(root) {
177
+ const names = /* @__PURE__ */ new Set();
178
+ for (const node of root.findAll({ rule: { any: [
179
+ { kind: "type_parameter" },
180
+ { kind: "infer_type" },
181
+ { kind: "mapped_type_clause" }
182
+ ] } })) {
183
+ const name = node.children().find((child) => child.kind() === "type_identifier");
184
+ if (name) names.add(name.text());
185
+ }
186
+ return names;
187
+ }
188
+ function hasExportSpecifierReference(root, names) {
189
+ return root.findAll({ rule: { kind: "export_specifier" } }).some((specifier) => specifier.children().some((child) => child.kind() === "identifier" && names.has(child.text())));
190
+ }
191
+ function hasNonTypeQueryTypeReference(root, names) {
192
+ return root.findAll({ rule: { kind: "type_identifier" } }).some((node) => {
193
+ if (!names.has(node.text())) return false;
194
+ if (isInsideImportStatement(node)) return false;
195
+ if (isInsideExportSpecifier(node)) return false;
196
+ if (isTypeParameterScoped(node)) return false;
197
+ if (isNestedTypeMember(node)) return false;
198
+ return !isInsideTypeQuery(node);
199
+ });
200
+ }
201
+ function hasNamespaceTypeMemberReference(root, namespaceLocal) {
202
+ return root.findAll({ rule: { kind: "nested_type_identifier" } }).some((node) => {
203
+ return node.children().find((child) => child.kind() === "identifier" || child.kind() === "type_identifier")?.text() === namespaceLocal;
204
+ });
205
+ }
206
+ function findExportStatements(root) {
207
+ return root.findAll({ rule: { kind: "export_statement" } }).filter((stmt) => stmt.parent()?.kind() === "program").toSorted((a, b) => a.range().start.index - b.range().start.index);
208
+ }
209
+ function aggregateFileImportLocals(imports) {
210
+ const locals = /* @__PURE__ */ new Set();
211
+ for (const importStmt of imports) {
212
+ if (importSource(importStmt) !== AGGREGATE_RUNTIME_SOURCE) continue;
213
+ for (const binding of importBindings(importStmt)) if (!binding.typeOnly && binding.importedName === "file") locals.add(binding.localName);
214
+ }
215
+ return locals;
216
+ }
217
+ function isValueBindingLeafKind(kind) {
218
+ return kind === "identifier" || kind === "shorthand_property_identifier_pattern";
219
+ }
220
+ function isValueBindingPatternKind(kind) {
221
+ return isValueBindingLeafKind(kind) || kind === "object_pattern" || kind === "array_pattern" || kind === "rest_pattern";
222
+ }
223
+ function collectValueBindingNames(node, names, result) {
224
+ if (isValueBindingLeafKind(node.kind())) {
225
+ if (names.has(node.text())) result.add(node.text());
226
+ return;
227
+ }
228
+ for (const child of node.children()) {
229
+ if (child.kind() === "property_identifier") continue;
230
+ if (child.kind() === "=") break;
231
+ collectValueBindingNames(child, names, result);
232
+ }
233
+ }
234
+ function valueBindingNames(node, names) {
235
+ const result = /* @__PURE__ */ new Set();
236
+ collectValueBindingNames(node, names, result);
237
+ return result;
238
+ }
239
+ function directValueBindingNames(node, names) {
240
+ const result = /* @__PURE__ */ new Set();
241
+ for (const child of node.children()) {
242
+ if (child.kind() === "=") break;
243
+ if (isValueBindingPatternKind(child.kind())) collectValueBindingNames(child, names, result);
244
+ }
245
+ return result;
246
+ }
247
+ function firstDeclaratorChild(node) {
248
+ return node.children().find((child) => child.kind() !== "=") ?? null;
249
+ }
250
+ function addShadowedRange(ranges, name, scope) {
251
+ const range = scope.range();
252
+ const existing = ranges.get(name) ?? [];
253
+ existing.push({
254
+ start: range.start.index,
255
+ end: range.end.index
256
+ });
257
+ ranges.set(name, existing);
258
+ }
259
+ function nearestValueScope(node) {
260
+ let current = node.parent();
261
+ while (current) {
262
+ const kind = current.kind();
263
+ if (kind === "statement_block" || kind === "program" || kind === "switch_body" || kind === "for_statement" || kind === "for_in_statement") return current;
264
+ current = current.parent();
265
+ }
266
+ return node;
267
+ }
268
+ function functionValueScope(node) {
269
+ let current = node.parent();
270
+ while (current) {
271
+ const kind = current.kind();
272
+ if (kind === "function_declaration" || kind === "function_expression" || kind === "arrow_function" || kind === "method_definition" || kind === "program") return current;
273
+ current = current.parent();
274
+ }
275
+ return node;
276
+ }
277
+ function variableValueScope(node) {
278
+ const declaration = node.parent();
279
+ return /^var\b/.test(declaration?.text().trimStart() ?? "") ? functionValueScope(node) : nearestValueScope(node);
280
+ }
281
+ function parameterValueScope(node) {
282
+ let current = node.parent();
283
+ while (current) {
284
+ const kind = current.kind();
285
+ if (kind === "formal_parameters") {
286
+ current = current.parent();
287
+ continue;
288
+ }
289
+ if (kind === "function_declaration" || kind === "function_expression" || kind === "arrow_function" || kind === "method_definition") return current;
290
+ break;
291
+ }
292
+ return nearestValueScope(node);
293
+ }
294
+ function buildShadowedRanges(root, names) {
295
+ const ranges = /* @__PURE__ */ new Map();
296
+ for (const decl of root.findAll({ rule: { kind: "variable_declarator" } })) {
297
+ if (isInsideImportStatement(decl)) continue;
298
+ const binding = firstDeclaratorChild(decl);
299
+ if (!binding) continue;
300
+ for (const name of valueBindingNames(binding, names)) addShadowedRange(ranges, name, variableValueScope(decl));
301
+ }
302
+ for (const decl of root.findAll({ rule: { any: [
303
+ { kind: "function_declaration" },
304
+ { kind: "class_declaration" },
305
+ { kind: "enum_declaration" }
306
+ ] } })) {
307
+ const name = decl.children().find((child) => child.kind() === "identifier" && names.has(child.text()));
308
+ if (name) addShadowedRange(ranges, name.text(), nearestValueScope(decl));
309
+ }
310
+ for (const expression of root.findAll({ rule: { any: [{ kind: "function_expression" }, { kind: "class" }] } })) {
311
+ const name = expression.children().find((child) => (child.kind() === "identifier" || child.kind() === "type_identifier") && names.has(child.text()));
312
+ if (name) addShadowedRange(ranges, name.text(), expression);
313
+ }
314
+ for (const param of root.findAll({ rule: { any: [{ kind: "required_parameter" }, { kind: "optional_parameter" }] } })) for (const name of directValueBindingNames(param, names)) addShadowedRange(ranges, name, parameterValueScope(param));
315
+ for (const arrow of root.findAll({ rule: { kind: "arrow_function" } })) {
316
+ const children = arrow.children();
317
+ const arrowIndex = children.findIndex((child) => child.kind() === "=>");
318
+ if (arrowIndex === -1) continue;
319
+ for (const child of children.slice(0, arrowIndex)) {
320
+ if (child.kind() === "=") break;
321
+ if (!isValueBindingPatternKind(child.kind())) continue;
322
+ for (const name of valueBindingNames(child, names)) addShadowedRange(ranges, name, arrow);
323
+ }
324
+ }
325
+ for (const catchClause of root.findAll({ rule: { kind: "catch_clause" } })) for (const name of directValueBindingNames(catchClause, names)) addShadowedRange(ranges, name, catchClause);
326
+ for (const loop of root.findAll({ rule: { kind: "for_in_statement" } })) {
327
+ const children = loop.children();
328
+ const keywordIndex = children.findIndex((child) => child.kind() === "in" || child.kind() === "of");
329
+ if (keywordIndex === -1) continue;
330
+ for (const child of children.slice(0, keywordIndex)) for (const name of valueBindingNames(child, names)) addShadowedRange(ranges, name, loop);
331
+ }
332
+ return ranges;
333
+ }
334
+ function isShadowed(node, ranges) {
335
+ const candidates = ranges.get(node.text());
336
+ if (!candidates) return false;
337
+ const position = node.range().start.index;
338
+ return candidates.some((range) => position >= range.start && position < range.end);
339
+ }
340
+ function isAggregateFileReceiver(node, fileLocals, shadowedRanges) {
341
+ return node?.kind() === "identifier" && fileLocals.has(node.text()) && !isShadowed(node, shadowedRanges);
342
+ }
343
+ function aggregateFileDeleteAccesses(root, imports) {
344
+ const fileLocals = aggregateFileImportLocals(imports);
345
+ if (fileLocals.size === 0) return [];
346
+ const shadowedRanges = buildShadowedRanges(root, fileLocals);
347
+ const accesses = [];
348
+ for (const member of root.findAll({ rule: { kind: "member_expression" } })) {
349
+ const receiver = member.field("object");
350
+ const property = member.children().find((child) => child.kind() === "property_identifier");
351
+ if (isAggregateFileReceiver(receiver, fileLocals, shadowedRanges) && property?.text() === "deleteFile") accesses.push({
352
+ node: member,
353
+ property,
354
+ computed: false
355
+ });
356
+ }
357
+ for (const subscript of root.findAll({ rule: { kind: "subscript_expression" } })) {
358
+ const receiver = subscript.field("object");
359
+ const property = subscript.field("index");
360
+ if (isAggregateFileReceiver(receiver, fileLocals, shadowedRanges) && property?.kind() === "string" && property.text().slice(1, -1) === "deleteFile") accesses.push({
361
+ node: subscript,
362
+ property,
363
+ computed: true
364
+ });
365
+ }
366
+ return accesses;
367
+ }
368
+ function aggregateFileDeleteEdits(root, imports) {
369
+ return aggregateFileDeleteAccesses(root, imports).map(({ property, computed }) => {
370
+ if (!computed) return property.replace("delete");
371
+ const quote = property.text()[0] ?? "\"";
372
+ return property.replace(`${quote}delete${quote}`);
373
+ });
374
+ }
375
+ function declaratorSides(node) {
376
+ const children = node.children();
377
+ const equalsIndex = children.findIndex((child) => child.kind() === "=");
378
+ if (equalsIndex === -1) return null;
379
+ const binding = children.slice(0, equalsIndex).find((child) => child.kind() !== "comment");
380
+ const value = children.slice(equalsIndex + 1).find((child) => child.kind() !== "comment");
381
+ return binding && value ? {
382
+ binding,
383
+ value
384
+ } : null;
385
+ }
386
+ function aggregateFileDeleteDestructures(root, imports) {
387
+ const fileLocals = aggregateFileImportLocals(imports);
388
+ if (fileLocals.size === 0) return [];
389
+ const shadowedRanges = buildShadowedRanges(root, fileLocals);
390
+ return root.findAll({ rule: { kind: "variable_declarator" } }).filter((declarator) => {
391
+ const sides = declaratorSides(declarator);
392
+ if (!sides || sides.binding.kind() !== "object_pattern" || !isAggregateFileReceiver(sides.value, fileLocals, shadowedRanges)) return false;
393
+ return sides.binding.findAll({ rule: { any: [{ kind: "property_identifier" }, { kind: "shorthand_property_identifier_pattern" }] } }).some((property) => property.text() === "deleteFile");
394
+ });
395
+ }
396
+ function aggregateFileDeleteFindingNodes(root, imports) {
397
+ return [...aggregateFileDeleteAccesses(root, imports).map((access) => access.node), ...aggregateFileDeleteDestructures(root, imports)];
398
+ }
399
+ function usedNames(root, imports, removedNames) {
400
+ const names = localDeclarationNames(root);
401
+ for (const importStmt of imports) for (const binding of importBindings(importStmt)) if (!removedNames.has(binding.localName)) names.add(binding.localName);
402
+ return names;
403
+ }
404
+ function uniqueNamespaceLocal(mod, root, imports, removedNames) {
405
+ const names = usedNames(root, imports, removedNames);
406
+ if (!names.has(mod.namespace)) return mod.namespace;
407
+ const base = `${mod.namespace}Runtime`;
408
+ if (!names.has(base)) return base;
409
+ for (let i = 2;; i++) {
410
+ const candidate = `${base}${i}`;
411
+ if (!names.has(candidate)) return candidate;
412
+ }
413
+ }
414
+ function selfNamespaceSpec(mod, localName) {
415
+ return localName === mod.namespace ? mod.namespace : `${mod.namespace} as ${localName}`;
416
+ }
417
+ function typeOnlySelfNamespaceSpec(mod, localName) {
418
+ return `type ${selfNamespaceSpec(mod, localName)}`;
419
+ }
420
+ function existingSelfNamespaceImport(importStmt, mod, statementTypeOnly) {
421
+ for (const spec of importStmt.findAll({ rule: { kind: "import_specifier" } })) {
422
+ const names = importSpecNames(spec);
423
+ if (!names || names.importedName !== mod.namespace) continue;
424
+ return {
425
+ localName: names.localName,
426
+ typeOnly: statementTypeOnly || names.typeOnly
427
+ };
428
+ }
429
+ return null;
430
+ }
431
+ function flatImportsFor(importStmt, mod) {
432
+ const statementTypeOnly = isTypeOnlyImport(importStmt);
433
+ const flatImports = [];
434
+ for (const spec of importStmt.findAll({ rule: { kind: "import_specifier" } })) {
435
+ const names = importSpecNames(spec);
436
+ if (!names) continue;
437
+ const memberName = mod.members[names.importedName];
438
+ if (!memberName) continue;
439
+ flatImports.push({
440
+ localName: names.localName,
441
+ memberName,
442
+ typeOnly: statementTypeOnly || names.typeOnly
443
+ });
444
+ }
445
+ return flatImports;
446
+ }
447
+ function plannedValueNamespaceLocal(importStmt, mod, root, imports) {
448
+ const source = importSource(importStmt);
449
+ if (!source) return null;
450
+ for (const candidate of imports) {
451
+ if (sameNode(candidate, importStmt)) continue;
452
+ if (importSource(candidate) !== source || isTypeOnlyImport(candidate)) continue;
453
+ const namespaceName = namespaceImportName(candidate);
454
+ if (namespaceName) return namespaceName;
455
+ const existingSelf = existingSelfNamespaceImport(candidate, mod, false);
456
+ if (existingSelf && !existingSelf.typeOnly) return existingSelf.localName;
457
+ const valueFlatImports = flatImportsFor(candidate, mod).filter((binding) => !binding.typeOnly);
458
+ if (valueFlatImports.length === 0) continue;
459
+ const removedNames = new Set(valueFlatImports.map((binding) => binding.localName));
460
+ const declaredNames = /* @__PURE__ */ new Set([...localDeclarationNames(root), ...localTypeScopeDeclarationNames(root)]);
461
+ if (valueFlatImports.some((binding) => declaredNames.has(binding.localName))) continue;
462
+ if (hasExportSpecifierReference(root, removedNames)) continue;
463
+ return uniqueNamespaceLocal(mod, root, imports, removedNames);
464
+ }
465
+ return null;
466
+ }
467
+ function buildImportReplacement(importStmt, mod, root, imports, sourceText, emittedNamespaceSpecifiers) {
468
+ const source = importSource(importStmt);
469
+ if (!source) return null;
470
+ const statementTypeOnly = isTypeOnlyImport(importStmt);
471
+ const attributes = importAttributeText(importStmt);
472
+ const namespaceName = namespaceImportName(importStmt);
473
+ if (namespaceName) {
474
+ if (hasNamespaceTypeMemberReference(root, namespaceName)) return null;
475
+ return {
476
+ edit: importStmt.replace(formatImport(source, [selfNamespaceSpec(mod, namespaceName)], statementTypeOnly, attributes)),
477
+ flatImports: [],
478
+ namespaceLocal: namespaceName
479
+ };
480
+ }
481
+ if (hasDefaultImport(importStmt)) return null;
482
+ const existingSelf = existingSelfNamespaceImport(importStmt, mod, statementTypeOnly);
483
+ const flatImports = [];
484
+ const keptSpecs = [];
485
+ for (const spec of importStmt.findAll({ rule: { kind: "import_specifier" } })) {
486
+ const names = importSpecNames(spec);
487
+ if (!names) continue;
488
+ const memberName = mod.members[names.importedName];
489
+ if (memberName) {
490
+ flatImports.push({
491
+ localName: names.localName,
492
+ memberName,
493
+ typeOnly: statementTypeOnly || names.typeOnly
494
+ });
495
+ continue;
496
+ }
497
+ keptSpecs.push(spec.text());
498
+ }
499
+ if (flatImports.length === 0) return null;
500
+ const removedNames = new Set(flatImports.map((binding) => binding.localName));
501
+ const declaredNames = /* @__PURE__ */ new Set([...localDeclarationNames(root), ...localTypeScopeDeclarationNames(root)]);
502
+ if (flatImports.some((binding) => declaredNames.has(binding.localName))) return null;
503
+ if (hasExportSpecifierReference(root, removedNames)) return null;
504
+ if (hasNonTypeQueryTypeReference(root, removedNames)) return null;
505
+ const flatImportsAreTypeOnly = flatImports.every((binding) => binding.typeOnly);
506
+ const canUseExistingSelf = existingSelf != null && (!existingSelf.typeOnly || flatImportsAreTypeOnly);
507
+ const plannedValueLocal = flatImportsAreTypeOnly ? plannedValueNamespaceLocal(importStmt, mod, root, imports) : null;
508
+ const namespaceLocal = plannedValueLocal ?? (canUseExistingSelf ? existingSelf.localName : uniqueNamespaceLocal(mod, root, imports, removedNames));
509
+ const namespaceSpecifierKey = [
510
+ source,
511
+ namespaceLocal,
512
+ flatImportsAreTypeOnly ? "type" : "value"
513
+ ].join("\0");
514
+ const namespaceAlreadyEmitted = emittedNamespaceSpecifiers.has(namespaceSpecifierKey);
515
+ const needsNamespaceSpecifier = plannedValueLocal == null && !canUseExistingSelf && !namespaceAlreadyEmitted;
516
+ if (needsNamespaceSpecifier) emittedNamespaceSpecifiers.add(namespaceSpecifierKey);
517
+ const namespaceSpecifier = flatImportsAreTypeOnly && !statementTypeOnly ? typeOnlySelfNamespaceSpec(mod, namespaceLocal) : selfNamespaceSpec(mod, namespaceLocal);
518
+ return {
519
+ edit: replaceImportStatement(importStmt, formatImport(source, needsNamespaceSpecifier ? [namespaceSpecifier, ...keptSpecs] : keptSpecs, statementTypeOnly, attributes), sourceText),
520
+ flatImports,
521
+ namespaceLocal
522
+ };
523
+ }
524
+ function referenceEdits(root, replacements) {
525
+ const byLocalName = /* @__PURE__ */ new Map();
526
+ for (const replacement of replacements) for (const binding of replacement.flatImports) byLocalName.set(binding.localName, {
527
+ namespaceLocal: replacement.namespaceLocal,
528
+ memberName: binding.memberName,
529
+ typeOnly: binding.typeOnly
530
+ });
531
+ const edits = [];
532
+ const replacementFor = (name) => {
533
+ const binding = byLocalName.get(name);
534
+ return binding ? `${binding.namespaceLocal}.${binding.memberName}` : null;
535
+ };
536
+ for (const node of root.findAll({ rule: { kind: "identifier" } })) {
537
+ if (isInsideImportStatement(node)) continue;
538
+ if (isInsideExportSpecifier(node)) continue;
539
+ if (isJsxTagName(node)) continue;
540
+ if (byLocalName.get(node.text())?.typeOnly && !isInsideTypeQuery(node)) continue;
541
+ const replacement = replacementFor(node.text());
542
+ if (!replacement) continue;
543
+ edits.push(node.replace(replacement));
544
+ }
545
+ for (const node of root.findAll({ rule: { kind: "type_identifier" } })) {
546
+ if (isInsideImportStatement(node)) continue;
547
+ if (isInsideExportSpecifier(node)) continue;
548
+ if (!isInsideTypeQuery(node)) continue;
549
+ if (isTypeParameterScoped(node)) continue;
550
+ if (isNestedTypeMember(node)) continue;
551
+ const replacement = replacementFor(node.text());
552
+ if (!replacement) continue;
553
+ edits.push(node.replace(replacement));
554
+ }
555
+ for (const node of root.findAll({ rule: { kind: "shorthand_property_identifier" } })) {
556
+ if (byLocalName.get(node.text())?.typeOnly) continue;
557
+ const replacement = replacementFor(node.text());
558
+ if (!replacement) continue;
559
+ edits.push(node.replace(`${node.text()}: ${replacement}`));
560
+ }
561
+ return edits;
562
+ }
563
+ /**
564
+ * Rewrite v1 runtime subpath imports to the v2 namespace object exports.
565
+ * @param source - File contents
566
+ * @param filePath - Absolute path to the file
567
+ * @returns Transformed source or null when nothing matched.
568
+ */
569
+ function transform(source, filePath) {
570
+ if (!quickFilter(source)) return null;
571
+ const root = parse(sourceLang(filePath, source), source).root();
572
+ const imports = findImportStatements(root);
573
+ const replacements = [];
574
+ const emittedNamespaceSpecifiers = /* @__PURE__ */ new Set();
575
+ for (const importStmt of imports) {
576
+ const sourceName = importSource(importStmt);
577
+ if (!sourceName) continue;
578
+ const mod = MODULES_BY_SOURCE.get(sourceName);
579
+ if (!mod) continue;
580
+ const replacement = buildImportReplacement(importStmt, mod, root, imports, source, emittedNamespaceSpecifiers);
581
+ if (replacement) replacements.push(replacement);
582
+ }
583
+ const aggregateEdits = aggregateFileDeleteEdits(root, imports);
584
+ if (replacements.length === 0 && aggregateEdits.length === 0) return null;
585
+ const edits = [
586
+ ...replacements.map((replacement) => replacement.edit),
587
+ ...referenceEdits(root, replacements),
588
+ ...aggregateEdits
589
+ ];
590
+ const result = root.commitEdits(edits);
591
+ return result === source ? null : result;
592
+ }
593
+ function hasRemovedFlatSpecifier(node, mod) {
594
+ return node.findAll({ rule: { any: [{ kind: "import_specifier" }, { kind: "export_specifier" }] } }).some((spec) => {
595
+ const names = importSpecNames(spec);
596
+ return names != null && mod.members[names.importedName] != null;
597
+ });
598
+ }
599
+ function isExportStar(node) {
600
+ if (node.children().some((child) => child.kind() === "*")) return true;
601
+ return node.children().find((child) => child.kind() === "namespace_export")?.children().some((child) => child.kind() === "*") ?? false;
602
+ }
603
+ function literalModuleSource(node) {
604
+ if (node.kind() === "string") return importSource(node);
605
+ if (node.kind() !== "template_string") return null;
606
+ if (node.children().some((child) => child.kind() === "template_substitution")) return null;
607
+ const text = node.text();
608
+ return text.startsWith("`") && text.endsWith("`") ? text.slice(1, -1) : null;
609
+ }
610
+ function isSourceScopeNode(node) {
611
+ const kind = node.kind();
612
+ return kind === "program" || kind === "statement_block" || kind === "function_declaration" || kind === "arrow_function" || kind === "method_definition";
613
+ }
614
+ function nearestSourceScope(node) {
615
+ let current = node.parent();
616
+ while (current) {
617
+ if (isSourceScopeNode(current)) return current;
618
+ current = current.parent();
619
+ }
620
+ return null;
621
+ }
622
+ function sameRange(left, right) {
623
+ if (!left) return false;
624
+ const leftRange = left.range();
625
+ const rightRange = right.range();
626
+ return leftRange.start.index === rightRange.start.index && leftRange.end.index === rightRange.end.index;
627
+ }
628
+ function isConstVariableDeclarator(node) {
629
+ return node.parent()?.children().some((child) => child.kind() === "const") ?? false;
630
+ }
631
+ function sourceConstInitializerContent(node) {
632
+ const directValue = literalModuleSource(node);
633
+ if (directValue != null) return directValue;
634
+ if (node.kind() !== "as_expression" && node.kind() !== "satisfies_expression" && node.kind() !== "parenthesized_expression") return null;
635
+ for (const child of node.children()) {
636
+ const childValue = sourceConstInitializerContent(child);
637
+ if (childValue != null) return childValue;
638
+ }
639
+ return null;
640
+ }
641
+ function sourceConstVariableDeclaratorContent(node, name) {
642
+ if (!isConstVariableDeclarator(node)) return null;
643
+ const names = /* @__PURE__ */ new Set();
644
+ collectBindingNames(node, names);
645
+ if (!names.has(name)) return null;
646
+ const initializer = node.children().findLast((child) => sourceConstInitializerContent(child) != null);
647
+ return initializer == null ? null : sourceConstInitializerContent(initializer);
648
+ }
649
+ function bindingNames(node) {
650
+ const names = /* @__PURE__ */ new Set();
651
+ collectBindingNames(node, names);
652
+ return names;
653
+ }
654
+ function sourceStringVariableInScope(scope, name, before) {
655
+ const bindings = scope.findAll({ rule: { any: [
656
+ { kind: "variable_declarator" },
657
+ { kind: "required_parameter" },
658
+ { kind: "optional_parameter" },
659
+ { kind: "catch_clause" }
660
+ ] } }).filter((node) => node.range().start.index < before && sameRange(nearestSourceScope(node), scope)).toSorted((a, b) => b.range().start.index - a.range().start.index);
661
+ for (const binding of bindings) {
662
+ if (!bindingNames(binding).has(name)) continue;
663
+ return binding.kind() === "variable_declarator" ? sourceConstVariableDeclaratorContent(binding, name) : null;
664
+ }
665
+ }
666
+ function sourceScopedStringVariableContent(identifier) {
667
+ const name = identifier.text();
668
+ const before = identifier.range().start.index;
669
+ let current = identifier.parent();
670
+ while (current) {
671
+ if (isSourceScopeNode(current)) {
672
+ const value = sourceStringVariableInScope(current, name, before);
673
+ if (value !== void 0) return value;
674
+ }
675
+ current = current.parent();
676
+ }
677
+ return null;
678
+ }
679
+ function isDynamicImportCall(node) {
680
+ return node.kind() === "call_expression" && node.children().some((child) => child.kind() === "import");
681
+ }
682
+ function isRequireCall(node) {
683
+ return node.kind() === "call_expression" && node.children().some((child) => child.kind() === "identifier" && child.text() === "require");
684
+ }
685
+ function isArgumentSyntaxNode(node) {
686
+ const kind = node.kind();
687
+ return kind === "(" || kind === ")" || kind === "," || kind === "comment";
688
+ }
689
+ function firstCallArgument(callExpression) {
690
+ return callExpression.children().find((child) => child.kind() === "arguments")?.children().find((child) => !isArgumentSyntaxNode(child)) ?? null;
691
+ }
692
+ function moduleCallSourceName(callExpression) {
693
+ const sourceArg = firstCallArgument(callExpression);
694
+ if (!sourceArg) return null;
695
+ const sourceName = literalModuleSource(sourceArg);
696
+ if (sourceName != null) return sourceName;
697
+ return sourceArg.kind() === "identifier" ? sourceScopedStringVariableContent(sourceArg) : null;
698
+ }
699
+ function dynamicImportSourceName(callExpression) {
700
+ return moduleCallSourceName(callExpression);
701
+ }
702
+ function dynamicImportExcerptNode(callExpression) {
703
+ let current = callExpression;
704
+ while (current.parent()) {
705
+ const parent = current.parent();
706
+ if (!parent) break;
707
+ if (parent.kind() !== "await_expression" && parent.kind() !== "parenthesized_expression" && parent.kind() !== "member_expression") break;
708
+ current = parent;
709
+ }
710
+ return current;
711
+ }
712
+ function dynamicRuntimeImportFindings(root, relativePath) {
713
+ const findings = [];
714
+ for (const callExpression of root.findAll({ rule: { kind: "call_expression" } })) {
715
+ if (!isDynamicImportCall(callExpression)) continue;
716
+ const sourceName = dynamicImportSourceName(callExpression);
717
+ if (!sourceName || !MODULES_BY_SOURCE.has(sourceName)) continue;
718
+ const excerptNode = dynamicImportExcerptNode(callExpression);
719
+ findings.push({
720
+ file: relativePath,
721
+ line: excerptNode.range().start.line + 1,
722
+ message: "Dynamic runtime subpath import may still access a removed flat value export.",
723
+ excerpt: excerptNode.text().trim()
724
+ });
725
+ }
726
+ return findings;
727
+ }
728
+ function runtimeRequireFindings(root, relativePath) {
729
+ const findings = [];
730
+ for (const callExpression of root.findAll({ rule: { kind: "call_expression" } })) {
731
+ if (isInsideImportStatement(callExpression)) continue;
732
+ if (!isRequireCall(callExpression)) continue;
733
+ const sourceName = moduleCallSourceName(callExpression);
734
+ if (!sourceName || !MODULES_BY_SOURCE.has(sourceName)) continue;
735
+ findings.push({
736
+ file: relativePath,
737
+ line: callExpression.range().start.line + 1,
738
+ message: "CommonJS runtime subpath require may still access a removed flat value export.",
739
+ excerpt: callExpression.text().trim()
740
+ });
741
+ }
742
+ return findings;
743
+ }
744
+ function isImportRequireStatement(importStmt) {
745
+ return importStmt.children().some((child) => child.kind() === "import_require_clause");
746
+ }
747
+ function reviewFindings(source, filePath, relativePath) {
748
+ if (!quickFilter(source)) return [];
749
+ const root = parse(sourceLang(filePath, source), source).root();
750
+ const imports = findImportStatements(root);
751
+ const findings = [];
752
+ findings.push(...dynamicRuntimeImportFindings(root, relativePath));
753
+ findings.push(...runtimeRequireFindings(root, relativePath));
754
+ for (const access of aggregateFileDeleteFindingNodes(root, imports)) findings.push({
755
+ file: relativePath,
756
+ line: access.range().start.line + 1,
757
+ message: "Aggregate runtime file namespace still uses the removed deleteFile alias.",
758
+ excerpt: access.text().trim()
759
+ });
760
+ for (const importStmt of imports) {
761
+ const sourceName = importSource(importStmt);
762
+ if (!sourceName) continue;
763
+ const mod = MODULES_BY_SOURCE.get(sourceName);
764
+ if (!mod) continue;
765
+ const hasImportRequire = isImportRequireStatement(importStmt);
766
+ const hasRemovedDefaultImport = hasDefaultImport(importStmt);
767
+ const hasNamespaceImport = namespaceImportName(importStmt) != null;
768
+ const hasRemovedFlatImport = hasRemovedFlatSpecifier(importStmt, mod);
769
+ if (!hasImportRequire && !hasRemovedDefaultImport && !hasNamespaceImport && !hasRemovedFlatImport) continue;
770
+ findings.push({
771
+ file: relativePath,
772
+ line: importStmt.range().start.line + 1,
773
+ message: hasImportRequire ? "TypeScript runtime subpath import-equals may still access a removed flat value export." : "Runtime subpath import still uses a removed default, namespace-star, or flat value import.",
774
+ excerpt: importStmt.text().trim()
775
+ });
776
+ }
777
+ for (const exportStmt of findExportStatements(root)) {
778
+ const sourceName = importSource(exportStmt);
779
+ if (!sourceName) continue;
780
+ const mod = MODULES_BY_SOURCE.get(sourceName);
781
+ if (!mod || !hasRemovedFlatSpecifier(exportStmt, mod) && !isExportStar(exportStmt)) continue;
782
+ findings.push({
783
+ file: relativePath,
784
+ line: exportStmt.range().start.line + 1,
785
+ message: "Runtime subpath re-export still uses a removed flat value export.",
786
+ excerpt: exportStmt.text().trim()
787
+ });
788
+ }
789
+ return findings;
790
+ }
791
+ //#endregion
792
+ export { transform as default, reviewFindings };
package/dist/index.js CHANGED
@@ -116,6 +116,7 @@ const RENAME_BIN_QUOTED_LEGACY_COMMAND_PATTERN = new RegExp([
116
116
  ].join(""));
117
117
  const V2_NEXT_1 = "2.0.0-next.1";
118
118
  const V2_NEXT_2 = "2.0.0-next.2";
119
+ const V2_NEXT_3 = "2.0.0-next.3";
119
120
  /** All registered codemods, in registration order. */
120
121
  const allCodemods = [
121
122
  {
@@ -494,6 +495,54 @@ const allCodemods = [
494
495
  "wrapper or global tailor.authconnection."
495
496
  ].join("\n")
496
497
  },
498
+ {
499
+ id: "v2/runtime-subpath-namespace",
500
+ name: "Runtime subpath imports use namespace objects",
501
+ description: "Rewrite `@tailor-platform/sdk/runtime/*` namespace-star and flat value imports to self-named namespace imports, and aggregate `file.deleteFile` calls to `file.delete`. `TailorContextAPI` and `TailorWorkflowAPI` now describe SDK wrappers; direct platform globals use `PlatformContextAPI` and `PlatformWorkflowAPI`.",
502
+ since: "1.0.0",
503
+ until: "2.0.0",
504
+ prereleaseUntil: V2_NEXT_3,
505
+ scriptPath: "v2/runtime-subpath-namespace/scripts/transform.js",
506
+ filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
507
+ legacyPatterns: [
508
+ "@tailor-platform/sdk/runtime/iconv",
509
+ "@tailor-platform/sdk/runtime/secretmanager",
510
+ "@tailor-platform/sdk/runtime/authconnection",
511
+ "@tailor-platform/sdk/runtime/idp",
512
+ "@tailor-platform/sdk/runtime/workflow",
513
+ "@tailor-platform/sdk/runtime/context",
514
+ "@tailor-platform/sdk/runtime/file",
515
+ "@tailor-platform/sdk/runtime/aigateway"
516
+ ],
517
+ examples: [
518
+ {
519
+ before: "import * as iconv from \"@tailor-platform/sdk/runtime/iconv\";\niconv.convert(value, \"UTF-8\", \"Shift_JIS\");",
520
+ after: "import { iconv } from \"@tailor-platform/sdk/runtime/iconv\";\niconv.convert(value, \"UTF-8\", \"Shift_JIS\");"
521
+ },
522
+ {
523
+ before: "import { get } from \"@tailor-platform/sdk/runtime/aigateway\";\nconst gateway = await get(\"main\");",
524
+ after: "import { aigateway } from \"@tailor-platform/sdk/runtime/aigateway\";\nconst gateway = await aigateway.get(\"main\");"
525
+ },
526
+ {
527
+ before: "import { file } from \"@tailor-platform/sdk/runtime\";\nawait file.deleteFile(\"ns\", \"Doc\", \"blob\", \"record-id\");",
528
+ after: "import { file } from \"@tailor-platform/sdk/runtime\";\nawait file.delete(\"ns\", \"Doc\", \"blob\", \"record-id\");"
529
+ }
530
+ ],
531
+ prompt: [
532
+ "In Tailor SDK v2, runtime subpath modules export only a self-named namespace",
533
+ "object (for example, `iconv` from `@tailor-platform/sdk/runtime/iconv`).",
534
+ "Default and flat value imports such as",
535
+ "`import { get } from \"@tailor-platform/sdk/runtime/aigateway\"` are removed.",
536
+ "The codemod rewrites straightforward namespace-star imports and flat named value",
537
+ "imports. It also rewrites direct `file.deleteFile` calls on the aggregate runtime",
538
+ "namespace to `file.delete`. Destructured aggregate `deleteFile` references require",
539
+ "manual migration. Review any remaining runtime imports manually, especially when",
540
+ "a local binding or nested scope shadows an imported value, or when",
541
+ "type-position namespace member references need explicit top-level type imports.",
542
+ "For direct platform globals, replace `TailorContextAPI` and `TailorWorkflowAPI`",
543
+ "type references with `PlatformContextAPI` and `PlatformWorkflowAPI` respectively."
544
+ ].join("\n")
545
+ },
497
546
  {
498
547
  id: "v2/tailordb-namespace",
499
548
  name: "Tailordb → tailordb (lowercase ambient namespace)",
@@ -518,6 +567,32 @@ const allCodemods = [
518
567
  "declarations automatically on SDK import."
519
568
  ].join("\n")
520
569
  },
570
+ {
571
+ id: "v2/db-type-to-table",
572
+ name: "db.type() → db.table()",
573
+ description: "Rename TailorDB schema builder calls from `db.type()` to `db.table()`. TailorDB schema definitions now use table terminology in SDK projects.",
574
+ since: "1.0.0",
575
+ until: "2.0.0",
576
+ prereleaseUntil: V2_NEXT_3,
577
+ scriptPath: "v2/db-type-to-table/scripts/transform.js",
578
+ filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
579
+ legacyPatterns: ["db.type"],
580
+ examples: [{
581
+ before: "import { db } from \"@tailor-platform/sdk\";\n\nexport const user = db.type(\"User\", {\n name: db.string(),\n});",
582
+ after: "import { db } from \"@tailor-platform/sdk\";\n\nexport const user = db.table(\"User\", {\n name: db.string(),\n});"
583
+ }],
584
+ prompt: [
585
+ "In Tailor SDK v2, TailorDB schema definitions use db.table(...) instead of",
586
+ "db.type(...). The codemod rewrites member accesses on db imported from",
587
+ "@tailor-platform/sdk, including aliases such as `import { db as schema }`.",
588
+ "It flags destructured builder aliases such as `const { type } = db` and",
589
+ "local builder aliases such as `const schema = db`, `schema = db`, or",
590
+ "`function make(schema = db) { ... }` for manual review because the local",
591
+ "alias may require call-site renaming.",
592
+ "Review any remaining db.type references and rename SDK TailorDB schema builder",
593
+ "calls to db.table. Leave unrelated local objects with a .type() method unchanged."
594
+ ].join("\n")
595
+ },
521
596
  {
522
597
  id: "v2/execute-script-arg",
523
598
  name: "executeScript arg JSON.stringify → value",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk-codemod",
3
- "version": "0.3.0-next.3",
3
+ "version": "0.3.0-next.4",
4
4
  "description": "Codemod runner for Tailor Platform SDK upgrades",
5
5
  "license": "MIT",
6
6
  "repository": {