@tailor-platform/sdk-codemod 0.3.0-next.0 → 0.3.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/dist/codemods/v2/apply-to-deploy/scripts/transform.js +22 -4
- package/dist/codemods/v2/auth-invoker-unwrap/scripts/transform.js +99 -11
- package/dist/codemods/v2/cli-rename/scripts/transform.js +373 -14
- package/dist/codemods/v2/execute-script-arg/scripts/transform.js +60 -0
- package/dist/codemods/v2/principal-unify/scripts/transform.js +1131 -43
- package/dist/codemods/v2/tailordb-namespace/scripts/transform.js +5 -4
- package/dist/index.js +521 -37
- package/package.json +5 -5
|
@@ -3,14 +3,28 @@ import { Lang, parse } from "@ast-grep/napi";
|
|
|
3
3
|
const TYPE_RENAME_MAP = {
|
|
4
4
|
TailorUser: "TailorPrincipal",
|
|
5
5
|
TailorActor: "TailorPrincipal",
|
|
6
|
+
TailorActorType: "TailorPrincipal",
|
|
6
7
|
TailorInvoker: "TailorPrincipal"
|
|
7
8
|
};
|
|
8
9
|
const UNAUTHENTICATED = "unauthenticatedTailorUser";
|
|
9
10
|
const QUICK_FILTER_NEEDLES = [
|
|
10
11
|
...Object.keys(TYPE_RENAME_MAP),
|
|
11
12
|
UNAUTHENTICATED,
|
|
12
|
-
"
|
|
13
|
+
"userId",
|
|
14
|
+
"userType",
|
|
15
|
+
"createResolver",
|
|
16
|
+
".hooks",
|
|
17
|
+
".validate",
|
|
18
|
+
".parse"
|
|
13
19
|
];
|
|
20
|
+
const ACTOR_PROPERTY_RENAME_MAP = {
|
|
21
|
+
userId: "id",
|
|
22
|
+
userType: "type"
|
|
23
|
+
};
|
|
24
|
+
const ACTOR_TYPE_LITERAL_RENAME_MAP = {
|
|
25
|
+
USER_TYPE_USER: "user",
|
|
26
|
+
USER_TYPE_MACHINE_USER: "machine_user"
|
|
27
|
+
};
|
|
14
28
|
function quickFilter(source) {
|
|
15
29
|
if (!source.includes("@tailor-platform/sdk")) return false;
|
|
16
30
|
return QUICK_FILTER_NEEDLES.some((needle) => source.includes(needle));
|
|
@@ -23,14 +37,284 @@ function isInsideImportStatement(node) {
|
|
|
23
37
|
}
|
|
24
38
|
return false;
|
|
25
39
|
}
|
|
26
|
-
function
|
|
40
|
+
function memberObjectParent(node) {
|
|
27
41
|
const parent = node.parent();
|
|
28
|
-
if (!parent || parent.kind() !== "member_expression") return
|
|
42
|
+
if (!parent || parent.kind() !== "member_expression" && parent.kind() !== "subscript_expression") return null;
|
|
29
43
|
const obj = parent.field("object");
|
|
30
|
-
if (!obj) return
|
|
44
|
+
if (!obj) return null;
|
|
31
45
|
const r = node.range();
|
|
32
46
|
const or = obj.range();
|
|
33
|
-
|
|
47
|
+
if (r.start.index !== or.start.index || r.end.index !== or.end.index) return null;
|
|
48
|
+
return parent;
|
|
49
|
+
}
|
|
50
|
+
function isMemberExpressionObject(node) {
|
|
51
|
+
return memberObjectParent(node) !== null;
|
|
52
|
+
}
|
|
53
|
+
function optionalPrincipalReadKind(node) {
|
|
54
|
+
const parent = memberObjectParent(node);
|
|
55
|
+
if (!parent) return null;
|
|
56
|
+
if (parent.text().startsWith(`${node.text()}?.`)) return null;
|
|
57
|
+
if (isAssignmentTargetReference(node)) return null;
|
|
58
|
+
if (parent.kind() === "subscript_expression") return "computed";
|
|
59
|
+
return parent.field("property")?.kind() === "property_identifier" ? "property" : null;
|
|
60
|
+
}
|
|
61
|
+
function isOptionalizableMemberObject(node) {
|
|
62
|
+
return optionalPrincipalReadKind(node) !== null;
|
|
63
|
+
}
|
|
64
|
+
function principalIdentifierReplacement(node, name) {
|
|
65
|
+
const readKind = optionalPrincipalReadKind(node);
|
|
66
|
+
if (readKind === "computed") return `${name}?.`;
|
|
67
|
+
if (readKind === "property") return `${name}?`;
|
|
68
|
+
return name;
|
|
69
|
+
}
|
|
70
|
+
function principalPropertyReplacement(node, name) {
|
|
71
|
+
const parent = node.parent();
|
|
72
|
+
return parent ? principalIdentifierReplacement(parent, name) : name;
|
|
73
|
+
}
|
|
74
|
+
function isObjectDestructureInitializer(node) {
|
|
75
|
+
const parent = node.parent();
|
|
76
|
+
if (!parent || parent.kind() !== "variable_declarator") return false;
|
|
77
|
+
const value = parent.field("value");
|
|
78
|
+
if (!value) return false;
|
|
79
|
+
const valueRange = value.range();
|
|
80
|
+
const nodeRange = node.range();
|
|
81
|
+
if (valueRange.start.index !== nodeRange.start.index || valueRange.end.index !== nodeRange.end.index) return false;
|
|
82
|
+
return parent.field("name")?.kind() === "object_pattern";
|
|
83
|
+
}
|
|
84
|
+
function principalReadReplacement(node, name) {
|
|
85
|
+
return isObjectDestructureInitializer(node) ? `${name} ?? {}` : principalIdentifierReplacement(node, name);
|
|
86
|
+
}
|
|
87
|
+
function nodeRangeContains(outer, inner) {
|
|
88
|
+
const outerRange = outer.range();
|
|
89
|
+
const innerRange = inner.range();
|
|
90
|
+
return innerRange.start.index >= outerRange.start.index && innerRange.end.index <= outerRange.end.index;
|
|
91
|
+
}
|
|
92
|
+
function isAssignmentTargetReference(node) {
|
|
93
|
+
let current = node;
|
|
94
|
+
let parent = current.parent();
|
|
95
|
+
while (parent && (parent.kind() === "member_expression" || parent.kind() === "subscript_expression")) {
|
|
96
|
+
const object = parent.field("object");
|
|
97
|
+
if (!object || !nodeRangeContains(object, current)) break;
|
|
98
|
+
current = parent;
|
|
99
|
+
parent = current.parent();
|
|
100
|
+
}
|
|
101
|
+
if (!parent) return false;
|
|
102
|
+
if (parent.kind() === "update_expression") return true;
|
|
103
|
+
if (parent.kind() !== "assignment_expression" && parent.kind() !== "augmented_assignment_expression") return false;
|
|
104
|
+
const left = parent.field("left");
|
|
105
|
+
return !!left && nodeRangeContains(left, current);
|
|
106
|
+
}
|
|
107
|
+
function parseArgumentCall(node) {
|
|
108
|
+
if (node.kind() !== "shorthand_property_identifier") return null;
|
|
109
|
+
const object = node.parent();
|
|
110
|
+
if (!object || object.kind() !== "object") return null;
|
|
111
|
+
const args = object.parent();
|
|
112
|
+
if (!args || args.kind() !== "arguments") return null;
|
|
113
|
+
const call = args.parent();
|
|
114
|
+
return call && call.kind() === "call_expression" && findMemberCallName(call) === "parse" ? call : null;
|
|
115
|
+
}
|
|
116
|
+
function isSdkFieldParseArgumentShorthand(node, parseContext) {
|
|
117
|
+
const call = parseArgumentCall(node);
|
|
118
|
+
return call ? isSdkFieldMemberCall(call, parseContext.sdkFieldRootNames, parseContext.sdkFieldLocalBindings, parseContext.root) : false;
|
|
119
|
+
}
|
|
120
|
+
function addActorPropertyReplacement(property, edits, transformedActorPropertyStarts) {
|
|
121
|
+
const newName = ACTOR_PROPERTY_RENAME_MAP[property.text()];
|
|
122
|
+
if (!newName) return;
|
|
123
|
+
const start = property.range().start.index;
|
|
124
|
+
if (transformedActorPropertyStarts.has(start)) return;
|
|
125
|
+
transformedActorPropertyStarts.add(start);
|
|
126
|
+
edits.push(property.replace(newName));
|
|
127
|
+
}
|
|
128
|
+
function actorTypeLiteralReplacement(literal) {
|
|
129
|
+
const match = literal.text().match(/^(['"])(USER_TYPE_USER|USER_TYPE_MACHINE_USER|USER_TYPE_UNSPECIFIED)\1$/);
|
|
130
|
+
if (!match) return null;
|
|
131
|
+
const [, quote, value] = match;
|
|
132
|
+
if (value === "USER_TYPE_UNSPECIFIED") return "undefined";
|
|
133
|
+
return `${quote}${ACTOR_TYPE_LITERAL_RENAME_MAP[value]}${quote}`;
|
|
134
|
+
}
|
|
135
|
+
function addActorTypeLiteralReplacement(literal, edits, transformedLiteralStarts) {
|
|
136
|
+
if (literal.kind() !== "string") return;
|
|
137
|
+
const replacement = actorTypeLiteralReplacement(literal);
|
|
138
|
+
if (!replacement) return;
|
|
139
|
+
const start = literal.range().start.index;
|
|
140
|
+
if (transformedLiteralStarts.has(start)) return;
|
|
141
|
+
transformedLiteralStarts.add(start);
|
|
142
|
+
edits.push(literal.replace(replacement));
|
|
143
|
+
}
|
|
144
|
+
function transformActorTypeLiteralsInNode(node, edits, transformedLiteralStarts) {
|
|
145
|
+
if (node.kind() === "string") addActorTypeLiteralReplacement(node, edits, transformedLiteralStarts);
|
|
146
|
+
const literals = node.findAll({ rule: { kind: "string" } });
|
|
147
|
+
for (const literal of literals) addActorTypeLiteralReplacement(literal, edits, transformedLiteralStarts);
|
|
148
|
+
}
|
|
149
|
+
function isTransformedActorTypeMember(node, transformedActorPropertyStarts) {
|
|
150
|
+
if (node.kind() !== "member_expression") return false;
|
|
151
|
+
const property = node.field("property");
|
|
152
|
+
return property?.text() === "userType" && transformedActorPropertyStarts.has(property.range().start.index);
|
|
153
|
+
}
|
|
154
|
+
function nodeContainsTransformedActorTypeMember(node, transformedActorPropertyStarts) {
|
|
155
|
+
if (isTransformedActorTypeMember(node, transformedActorPropertyStarts)) return true;
|
|
156
|
+
return node.findAll({ rule: { kind: "member_expression" } }).some((member) => isTransformedActorTypeMember(member, transformedActorPropertyStarts));
|
|
157
|
+
}
|
|
158
|
+
function switchDiscriminant(node) {
|
|
159
|
+
return node.children().find((child) => child.kind() === "parenthesized_expression") ?? null;
|
|
160
|
+
}
|
|
161
|
+
function switchBody(node) {
|
|
162
|
+
return node.children().find((child) => child.kind() === "switch_body") ?? null;
|
|
163
|
+
}
|
|
164
|
+
function transformActorTypeComparisonLiterals(root, edits, transformedActorPropertyStarts) {
|
|
165
|
+
if (transformedActorPropertyStarts.size === 0) return;
|
|
166
|
+
const transformedLiteralStarts = /* @__PURE__ */ new Set();
|
|
167
|
+
const binaries = root.findAll({ rule: { kind: "binary_expression" } });
|
|
168
|
+
for (const binary of binaries) {
|
|
169
|
+
if (!binary.children().some((child) => isTransformedActorTypeMember(child, transformedActorPropertyStarts))) continue;
|
|
170
|
+
for (const child of binary.children()) addActorTypeLiteralReplacement(child, edits, transformedLiteralStarts);
|
|
171
|
+
}
|
|
172
|
+
const switches = root.findAll({ rule: { kind: "switch_statement" } });
|
|
173
|
+
for (const switchNode of switches) {
|
|
174
|
+
const discriminant = switchDiscriminant(switchNode);
|
|
175
|
+
if (!discriminant || !nodeContainsTransformedActorTypeMember(discriminant, transformedActorPropertyStarts)) continue;
|
|
176
|
+
const body = switchBody(switchNode);
|
|
177
|
+
if (!body) continue;
|
|
178
|
+
const cases = body.findAll({ rule: { kind: "switch_case" } });
|
|
179
|
+
for (const caseNode of cases) for (const child of caseNode.children()) addActorTypeLiteralReplacement(child, edits, transformedLiteralStarts);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function transformTailorActorTypeInitializerLiterals(root, actorTypeLocalNames, sdkNamespaceNames, edits) {
|
|
183
|
+
if (actorTypeLocalNames.size === 0 && sdkNamespaceNames.size === 0) return;
|
|
184
|
+
const transformedLiteralStarts = /* @__PURE__ */ new Set();
|
|
185
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
186
|
+
for (const decl of declarators) {
|
|
187
|
+
if (!isSdkTypeReference(decl, actorTypeLocalNames, "TailorActorType", sdkNamespaceNames, root)) continue;
|
|
188
|
+
const value = decl.field("value");
|
|
189
|
+
if (!value) continue;
|
|
190
|
+
transformActorTypeLiteralsInNode(value, edits, transformedLiteralStarts);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function transformActorTypeBindingComparisons(root, binding, edits) {
|
|
194
|
+
const refs = root.findAll({ rule: {
|
|
195
|
+
kind: "identifier",
|
|
196
|
+
regex: `^${escapeRegex(binding.name)}$`
|
|
197
|
+
} });
|
|
198
|
+
const transformedLiteralStarts = /* @__PURE__ */ new Set();
|
|
199
|
+
for (const ref of refs) {
|
|
200
|
+
const binary = ref.parent();
|
|
201
|
+
if (!binary || binary.kind() !== "binary_expression") continue;
|
|
202
|
+
if (isShadowedLocalReference(root, binding.name, ref.range().start.index, binding.bindingStart)) continue;
|
|
203
|
+
for (const child of binary.children()) addActorTypeLiteralReplacement(child, edits, transformedLiteralStarts);
|
|
204
|
+
}
|
|
205
|
+
const switches = root.findAll({ rule: { kind: "switch_statement" } });
|
|
206
|
+
for (const switchNode of switches) {
|
|
207
|
+
const discriminant = switchDiscriminant(switchNode);
|
|
208
|
+
if (!discriminant) continue;
|
|
209
|
+
if (!discriminant.findAll({ rule: {
|
|
210
|
+
kind: "identifier",
|
|
211
|
+
regex: `^${escapeRegex(binding.name)}$`
|
|
212
|
+
} }).some((ref) => !isShadowedLocalReference(root, binding.name, ref.range().start.index, binding.bindingStart))) continue;
|
|
213
|
+
const body = switchBody(switchNode);
|
|
214
|
+
if (!body) continue;
|
|
215
|
+
const cases = body.findAll({ rule: { kind: "switch_case" } });
|
|
216
|
+
for (const caseNode of cases) for (const child of caseNode.children()) addActorTypeLiteralReplacement(child, edits, transformedLiteralStarts);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function transformTailorActorTypeBindingComparisons(root, actorTypeLocalNames, sdkNamespaceNames, edits) {
|
|
220
|
+
if (actorTypeLocalNames.size === 0 && sdkNamespaceNames.size === 0) return;
|
|
221
|
+
for (const kind of NESTED_FN_KINDS) {
|
|
222
|
+
const fns = root.findAll({ rule: { kind } });
|
|
223
|
+
for (const fn of fns) {
|
|
224
|
+
const param = getFirstFunctionParam(fn);
|
|
225
|
+
if (!param || !isSdkTypeReference(param, actorTypeLocalNames, "TailorActorType", sdkNamespaceNames, root)) continue;
|
|
226
|
+
const pattern = getFunctionParamPattern(param);
|
|
227
|
+
const body = fn.field("body");
|
|
228
|
+
if (!pattern || pattern.kind() !== "identifier" || !body) continue;
|
|
229
|
+
transformActorTypeBindingComparisons(body, {
|
|
230
|
+
name: pattern.text(),
|
|
231
|
+
bindingStart: pattern.range().start.index
|
|
232
|
+
}, edits);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
236
|
+
for (const decl of declarators) {
|
|
237
|
+
if (!isSdkTypeReference(decl, actorTypeLocalNames, "TailorActorType", sdkNamespaceNames, root)) continue;
|
|
238
|
+
const name = decl.field("name");
|
|
239
|
+
if (!name || name.kind() !== "identifier") continue;
|
|
240
|
+
transformActorTypeBindingComparisons(root, {
|
|
241
|
+
name: name.text(),
|
|
242
|
+
bindingStart: name.range().start.index
|
|
243
|
+
}, edits);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function transformActorBindingMemberAccesses(root, binding, edits, transformedActorPropertyStarts) {
|
|
247
|
+
const refs = root.findAll({ rule: {
|
|
248
|
+
kind: "identifier",
|
|
249
|
+
regex: `^${escapeRegex(binding.name)}$`
|
|
250
|
+
} });
|
|
251
|
+
for (const ref of refs) {
|
|
252
|
+
const parent = ref.parent();
|
|
253
|
+
if (!parent || parent.kind() !== "member_expression") continue;
|
|
254
|
+
const object = parent.field("object");
|
|
255
|
+
if (!object || object.range().start.index !== ref.range().start.index) continue;
|
|
256
|
+
const property = parent.field("property");
|
|
257
|
+
if (!property || property.kind() !== "property_identifier") continue;
|
|
258
|
+
if (!ACTOR_PROPERTY_RENAME_MAP[property.text()]) continue;
|
|
259
|
+
const pos = ref.range().start.index;
|
|
260
|
+
if (isShadowedLocalReference(root, binding.name, pos, binding.bindingStart)) continue;
|
|
261
|
+
addActorPropertyReplacement(property, edits, transformedActorPropertyStarts);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function isSdkTypeReference(node, localNames, sdkTypeName, sdkNamespaceNames, root) {
|
|
265
|
+
const typeAnnotation = node.field("type");
|
|
266
|
+
if (!typeAnnotation) return false;
|
|
267
|
+
return typeAnnotation.findAll({ rule: { kind: "type_identifier" } }).some((id) => localNames.has(id.text()) || id.text() === sdkTypeName && isSdkNamespaceQualifiedTypeIdentifier(id, sdkNamespaceNames, root));
|
|
268
|
+
}
|
|
269
|
+
function transformTailorActorTypedMemberAccesses(root, actorTypeLocalNames, sdkNamespaceNames, edits, transformedActorPropertyStarts) {
|
|
270
|
+
if (actorTypeLocalNames.size === 0 && sdkNamespaceNames.size === 0) return;
|
|
271
|
+
for (const kind of NESTED_FN_KINDS) {
|
|
272
|
+
const fns = root.findAll({ rule: { kind } });
|
|
273
|
+
for (const fn of fns) {
|
|
274
|
+
const param = getFirstFunctionParam(fn);
|
|
275
|
+
if (!param || !isSdkTypeReference(param, actorTypeLocalNames, "TailorActor", sdkNamespaceNames, root)) continue;
|
|
276
|
+
const pattern = getFunctionParamPattern(param);
|
|
277
|
+
const body = fn.field("body");
|
|
278
|
+
if (!pattern || pattern.kind() !== "identifier" || !body) continue;
|
|
279
|
+
transformActorBindingMemberAccesses(body, {
|
|
280
|
+
name: pattern.text(),
|
|
281
|
+
bindingStart: pattern.range().start.index
|
|
282
|
+
}, edits, transformedActorPropertyStarts);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
286
|
+
for (const decl of declarators) {
|
|
287
|
+
if (!isSdkTypeReference(decl, actorTypeLocalNames, "TailorActor", sdkNamespaceNames, root)) continue;
|
|
288
|
+
const name = decl.field("name");
|
|
289
|
+
if (!name || name.kind() !== "identifier") continue;
|
|
290
|
+
transformActorBindingMemberAccesses(root, {
|
|
291
|
+
name: name.text(),
|
|
292
|
+
bindingStart: name.range().start.index
|
|
293
|
+
}, edits, transformedActorPropertyStarts);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function transformExecutorCtxActorAccesses(body, ctxName, ctxShadowRanges, edits, transformedActorPropertyStarts) {
|
|
297
|
+
const properties = body.findAll({ rule: {
|
|
298
|
+
kind: "property_identifier",
|
|
299
|
+
regex: "^(userId|userType)$"
|
|
300
|
+
} });
|
|
301
|
+
for (const property of properties) {
|
|
302
|
+
const parent = property.parent();
|
|
303
|
+
if (!parent || parent.kind() !== "member_expression") continue;
|
|
304
|
+
const object = parent.field("object");
|
|
305
|
+
if (!object || object.kind() !== "member_expression") continue;
|
|
306
|
+
if (object.field("property")?.text() !== "actor") continue;
|
|
307
|
+
const ctxObject = object.field("object");
|
|
308
|
+
if (!ctxObject || ctxObject.kind() !== "identifier" || ctxObject.text() !== ctxName) continue;
|
|
309
|
+
const pos = ctxObject.range().start.index;
|
|
310
|
+
if (isInsideAnyRange(pos, ctxShadowRanges)) continue;
|
|
311
|
+
addActorPropertyReplacement(property, edits, transformedActorPropertyStarts);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function renamedTypeIdentifierText(name) {
|
|
315
|
+
if (name === "TailorInvoker") return "(TailorPrincipal | null)";
|
|
316
|
+
if (name === "TailorActorType") return "(TailorPrincipal[\"type\"] | undefined)";
|
|
317
|
+
return TYPE_RENAME_MAP[name] ?? null;
|
|
34
318
|
}
|
|
35
319
|
function extractModuleSource(importText) {
|
|
36
320
|
return importText.match(/from\s+(["'])([^"']+)\1/)?.[2] ?? "@tailor-platform/sdk";
|
|
@@ -59,7 +343,7 @@ function* iterateImportSpecs(importStmt) {
|
|
|
59
343
|
};
|
|
60
344
|
}
|
|
61
345
|
}
|
|
62
|
-
function rebuildImportStatement(importStmt, globalEmittedRenamed, unauthenticatedLocalNames) {
|
|
346
|
+
function rebuildImportStatement(importStmt, globalEmittedRenamed, unauthenticatedLocalNames, nullableInvokerAliasLocalNames, actorTypeAliasLocalNames) {
|
|
63
347
|
const importText = importStmt.text();
|
|
64
348
|
const isImportType = /^\s*import\s+type\b/.test(importText);
|
|
65
349
|
const trailingSemi = importText.trimEnd().endsWith(";") ? ";" : "";
|
|
@@ -73,12 +357,17 @@ function rebuildImportStatement(importStmt, globalEmittedRenamed, unauthenticate
|
|
|
73
357
|
const renamed = TYPE_RENAME_MAP[importedName];
|
|
74
358
|
if (renamed) {
|
|
75
359
|
touched = true;
|
|
76
|
-
const
|
|
360
|
+
const dropsAliasForNullableInvoker = importedName === "TailorInvoker" && !!aliasNode;
|
|
361
|
+
const dropsAliasForActorType = importedName === "TailorActorType" && !!aliasNode;
|
|
362
|
+
const dropsAliasForExpandedType = dropsAliasForNullableInvoker || dropsAliasForActorType;
|
|
363
|
+
if (dropsAliasForNullableInvoker) nullableInvokerAliasLocalNames.add(localName);
|
|
364
|
+
if (dropsAliasForActorType) actorTypeAliasLocalNames.add(localName);
|
|
365
|
+
const finalLocal = dropsAliasForExpandedType ? renamed : aliasNode?.text() ?? renamed;
|
|
77
366
|
if (seenLocal.has(finalLocal)) continue;
|
|
78
|
-
if (!aliasNode && globalEmittedRenamed.has(renamed)) continue;
|
|
367
|
+
if ((!aliasNode || dropsAliasForExpandedType) && globalEmittedRenamed.has(renamed)) continue;
|
|
79
368
|
seenLocal.add(finalLocal);
|
|
80
|
-
if (!aliasNode) globalEmittedRenamed.add(renamed);
|
|
81
|
-
const asPart = aliasNode ? ` as ${aliasNode.text()}` : "";
|
|
369
|
+
if (!aliasNode || dropsAliasForExpandedType) globalEmittedRenamed.add(renamed);
|
|
370
|
+
const asPart = aliasNode && !dropsAliasForExpandedType ? ` as ${aliasNode.text()}` : "";
|
|
82
371
|
newSpecTexts.push(`${isTypeOnly ? "type " : ""}${renamed}${asPart}`);
|
|
83
372
|
} else if (importedName === UNAUTHENTICATED) {
|
|
84
373
|
touched = true;
|
|
@@ -160,6 +449,15 @@ function patternBindsName(pat, name) {
|
|
|
160
449
|
}
|
|
161
450
|
return false;
|
|
162
451
|
}
|
|
452
|
+
function hasNestedPropertyPattern(pat, name) {
|
|
453
|
+
if (pat.kind() !== "object_pattern") return false;
|
|
454
|
+
for (const child of pat.children()) {
|
|
455
|
+
if (child.kind() !== "pair_pattern") continue;
|
|
456
|
+
if (child.field("key")?.text() !== name) continue;
|
|
457
|
+
if (child.field("value")?.kind() !== "identifier") return true;
|
|
458
|
+
}
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
163
461
|
function functionRebindsName(fn, name) {
|
|
164
462
|
const single = fn.field("parameter");
|
|
165
463
|
if (single && patternBindsName(single, name)) return true;
|
|
@@ -235,6 +533,62 @@ function collectAllShadowRanges(root, name) {
|
|
|
235
533
|
}
|
|
236
534
|
return ranges;
|
|
237
535
|
}
|
|
536
|
+
function hasUnshadowedIdentifierReference(root, name) {
|
|
537
|
+
const shadowRanges = collectAllShadowRanges(root, name);
|
|
538
|
+
const refs = root.findAll({ rule: {
|
|
539
|
+
kind: "identifier",
|
|
540
|
+
regex: `^${escapeRegex(name)}$`
|
|
541
|
+
} });
|
|
542
|
+
for (const ref of refs) if (!isInsideAnyRange(ref.range().start.index, shadowRanges)) return true;
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
function hasPrincipalAssignmentTarget(root, name) {
|
|
546
|
+
const shadowRanges = collectAllShadowRanges(root, name);
|
|
547
|
+
const refs = root.findAll({ rule: {
|
|
548
|
+
kind: "identifier",
|
|
549
|
+
regex: `^${escapeRegex(name)}$`
|
|
550
|
+
} });
|
|
551
|
+
for (const ref of refs) {
|
|
552
|
+
const pos = ref.range().start.index;
|
|
553
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
554
|
+
if (isAssignmentTargetReference(ref)) return true;
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
function rewriteParseArgumentShorthands(root, localName, propertyName, parseContext, edits) {
|
|
559
|
+
const shadowRanges = collectAllShadowRanges(root, localName);
|
|
560
|
+
const shortRefs = root.findAll({ rule: {
|
|
561
|
+
kind: "shorthand_property_identifier",
|
|
562
|
+
regex: `^${escapeRegex(localName)}$`
|
|
563
|
+
} });
|
|
564
|
+
for (const ref of shortRefs) {
|
|
565
|
+
const pos = ref.range().start.index;
|
|
566
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
567
|
+
if (!isSdkFieldParseArgumentShorthand(ref, parseContext)) continue;
|
|
568
|
+
edits.push(ref.replace(`${propertyName}: ${localName}`));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function guardPrincipalMemberAccesses(root, binding, edits) {
|
|
572
|
+
const refs = root.findAll({ rule: {
|
|
573
|
+
kind: "identifier",
|
|
574
|
+
regex: `^${escapeRegex(binding.name)}$`
|
|
575
|
+
} });
|
|
576
|
+
for (const ref of refs) {
|
|
577
|
+
if (!isOptionalizableMemberObject(ref)) continue;
|
|
578
|
+
const pos = ref.range().start.index;
|
|
579
|
+
if (isShadowedLocalReference(root, binding.name, pos, binding.bindingStart)) continue;
|
|
580
|
+
edits.push(ref.replace(`${binding.name}?`));
|
|
581
|
+
}
|
|
582
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
583
|
+
for (const decl of declarators) {
|
|
584
|
+
const value = decl.field("value");
|
|
585
|
+
if (!value || value.kind() !== "identifier" || value.text() !== binding.name) continue;
|
|
586
|
+
if (!isObjectDestructureInitializer(value)) continue;
|
|
587
|
+
const pos = value.range().start.index;
|
|
588
|
+
if (isShadowedLocalReference(root, binding.name, pos, binding.bindingStart)) continue;
|
|
589
|
+
edits.push(value.replace(`${binding.name} ?? {}`));
|
|
590
|
+
}
|
|
591
|
+
}
|
|
238
592
|
function findResolverBodyArrow(call) {
|
|
239
593
|
const args = call.field("arguments");
|
|
240
594
|
if (!args) return null;
|
|
@@ -249,6 +603,45 @@ function findResolverBodyArrow(call) {
|
|
|
249
603
|
}
|
|
250
604
|
return null;
|
|
251
605
|
}
|
|
606
|
+
function* iterateNamespaceImportLocalNames(importStmt) {
|
|
607
|
+
const namespaceImports = importStmt.findAll({ rule: { kind: "namespace_import" } });
|
|
608
|
+
for (const namespaceImport of namespaceImports) {
|
|
609
|
+
const localName = namespaceImport.children().find((c) => c.kind() === "identifier");
|
|
610
|
+
if (localName) yield localName.text();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
function isUnshadowedNamespaceObject(node, namespaceNames, root) {
|
|
614
|
+
if (node.kind() !== "identifier" || !namespaceNames.has(node.text())) return false;
|
|
615
|
+
return !isInsideAnyRange(node.range().start.index, collectAllShadowRanges(root, node.text()));
|
|
616
|
+
}
|
|
617
|
+
function isSdkNamespaceQualifiedTypeIdentifier(typeId, namespaceNames, root) {
|
|
618
|
+
if (typeId.kind() !== "type_identifier") return false;
|
|
619
|
+
const parent = typeId.parent();
|
|
620
|
+
if (!parent || parent.kind() !== "nested_type_identifier") return false;
|
|
621
|
+
const namespaceObject = parent.children().find((c) => c.kind() === "identifier");
|
|
622
|
+
return !!namespaceObject && isUnshadowedNamespaceObject(namespaceObject, namespaceNames, root);
|
|
623
|
+
}
|
|
624
|
+
function namespaceQualifiedTypeReplacement(typeId, namespaceNames, root) {
|
|
625
|
+
if (typeId.kind() !== "type_identifier") return null;
|
|
626
|
+
const parent = typeId.parent();
|
|
627
|
+
if (!parent || parent.kind() !== "nested_type_identifier") return null;
|
|
628
|
+
const namespaceObject = parent.children().find((c) => c.kind() === "identifier");
|
|
629
|
+
if (!namespaceObject || !isUnshadowedNamespaceObject(namespaceObject, namespaceNames, root)) return null;
|
|
630
|
+
const namespace = namespaceObject.text();
|
|
631
|
+
if (typeId.text() === "TailorInvoker") return {
|
|
632
|
+
target: parent,
|
|
633
|
+
text: `(${namespace}.TailorPrincipal | null)`
|
|
634
|
+
};
|
|
635
|
+
if (typeId.text() === "TailorActorType") return {
|
|
636
|
+
target: parent,
|
|
637
|
+
text: `(${namespace}.TailorPrincipal["type"] | undefined)`
|
|
638
|
+
};
|
|
639
|
+
const renamed = TYPE_RENAME_MAP[typeId.text()];
|
|
640
|
+
return renamed ? {
|
|
641
|
+
target: typeId,
|
|
642
|
+
text: renamed
|
|
643
|
+
} : null;
|
|
644
|
+
}
|
|
252
645
|
/**
|
|
253
646
|
* Look for any binding named `caller` in the resolver body or pattern. When
|
|
254
647
|
* one exists, renaming `user` → `caller` would either shadow it, collide with
|
|
@@ -270,23 +663,20 @@ function hasCallerBindingConflict(pattern, body) {
|
|
|
270
663
|
if (inner && inner.text() === "caller") return true;
|
|
271
664
|
}
|
|
272
665
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
regex: "^caller$",
|
|
281
|
-
inside: { kind: "variable_declarator" }
|
|
282
|
-
} }).length > 0) return true;
|
|
666
|
+
const decls = body.findAll({ rule: { kind: "variable_declarator" } });
|
|
667
|
+
for (const decl of decls) {
|
|
668
|
+
const nameNode = decl.field("name");
|
|
669
|
+
if (nameNode && patternBindsName(nameNode, "caller")) return true;
|
|
670
|
+
}
|
|
671
|
+
const functionDecls = body.findAll({ rule: { kind: "function_declaration" } });
|
|
672
|
+
for (const fn of functionDecls) if (fn.field("name")?.text() === "caller") return true;
|
|
283
673
|
for (const k of NESTED_FN_KINDS) {
|
|
284
674
|
const fns = body.findAll({ rule: { kind: k } });
|
|
285
675
|
for (const fn of fns) if (functionRebindsName(fn, "caller")) return true;
|
|
286
676
|
}
|
|
287
677
|
return false;
|
|
288
678
|
}
|
|
289
|
-
function transformResolverBody(arrowNode, edits) {
|
|
679
|
+
function transformResolverBody(arrowNode, edits, parseContext) {
|
|
290
680
|
const params = arrowNode.field("parameters") ?? arrowNode.field("parameter") ?? arrowNode.children().find((c) => c.kind() === "formal_parameters");
|
|
291
681
|
const body = arrowNode.field("body");
|
|
292
682
|
if (!params || !body) return;
|
|
@@ -300,24 +690,52 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
300
690
|
}
|
|
301
691
|
if (!pattern) return;
|
|
302
692
|
if (pattern.kind() === "object_pattern") {
|
|
693
|
+
if (hasNestedPropertyPattern(pattern, "user")) return;
|
|
694
|
+
if (hasPrincipalAssignmentTarget(body, "user")) return;
|
|
303
695
|
if (hasCallerBindingConflict(pattern, body)) return;
|
|
696
|
+
const aliasRenamedUser = hasUnshadowedIdentifierReference(body, "caller");
|
|
697
|
+
let aliasedShorthandUser = false;
|
|
304
698
|
let renamedShorthandUser = false;
|
|
699
|
+
const principalAliasBindings = [];
|
|
305
700
|
for (const child of pattern.children()) {
|
|
306
701
|
const kind = child.kind();
|
|
307
|
-
if (kind === "shorthand_property_identifier_pattern" && child.text() === "user") {
|
|
702
|
+
if (kind === "shorthand_property_identifier_pattern" && child.text() === "user") if (aliasRenamedUser) {
|
|
703
|
+
edits.push(child.replace("caller: user"));
|
|
704
|
+
aliasedShorthandUser = true;
|
|
705
|
+
principalAliasBindings.push({
|
|
706
|
+
name: "user",
|
|
707
|
+
bindingStart: child.range().start.index
|
|
708
|
+
});
|
|
709
|
+
} else {
|
|
308
710
|
edits.push(child.replace("caller"));
|
|
309
711
|
renamedShorthandUser = true;
|
|
310
|
-
}
|
|
712
|
+
}
|
|
713
|
+
else if (kind === "pair_pattern") {
|
|
311
714
|
const key = child.field("key");
|
|
312
|
-
if (key && key.text() === "user")
|
|
715
|
+
if (key && key.text() === "user") {
|
|
716
|
+
edits.push(key.replace("caller"));
|
|
717
|
+
const value = child.field("value");
|
|
718
|
+
if (value?.kind() === "identifier") principalAliasBindings.push({
|
|
719
|
+
name: value.text(),
|
|
720
|
+
bindingStart: value.range().start.index
|
|
721
|
+
});
|
|
722
|
+
}
|
|
313
723
|
} else if (kind === "object_assignment_pattern") {
|
|
314
724
|
const inner = child.children().find((c) => c.kind() === "shorthand_property_identifier_pattern");
|
|
315
|
-
if (inner && inner.text() === "user") {
|
|
725
|
+
if (inner && inner.text() === "user") if (aliasRenamedUser) {
|
|
726
|
+
edits.push(inner.replace("caller: user"));
|
|
727
|
+
aliasedShorthandUser = true;
|
|
728
|
+
principalAliasBindings.push({
|
|
729
|
+
name: "user",
|
|
730
|
+
bindingStart: inner.range().start.index
|
|
731
|
+
});
|
|
732
|
+
} else {
|
|
316
733
|
edits.push(inner.replace("caller"));
|
|
317
734
|
renamedShorthandUser = true;
|
|
318
735
|
}
|
|
319
736
|
}
|
|
320
737
|
}
|
|
738
|
+
if (aliasedShorthandUser) rewriteParseArgumentShorthands(body, "user", "invoker", parseContext, edits);
|
|
321
739
|
if (renamedShorthandUser) {
|
|
322
740
|
const shadowRanges = collectAllShadowRanges(body, "user");
|
|
323
741
|
const refs = body.findAll({ rule: {
|
|
@@ -327,7 +745,7 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
327
745
|
for (const ref of refs) {
|
|
328
746
|
const pos = ref.range().start.index;
|
|
329
747
|
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
330
|
-
edits.push(ref.replace("caller"));
|
|
748
|
+
edits.push(ref.replace(principalIdentifierReplacement(ref, "caller")));
|
|
331
749
|
}
|
|
332
750
|
const shortRefs = body.findAll({ rule: {
|
|
333
751
|
kind: "shorthand_property_identifier",
|
|
@@ -336,9 +754,10 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
336
754
|
for (const ref of shortRefs) {
|
|
337
755
|
const pos = ref.range().start.index;
|
|
338
756
|
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
339
|
-
edits.push(ref.replace("user: caller"));
|
|
757
|
+
edits.push(ref.replace(isSdkFieldParseArgumentShorthand(ref, parseContext) ? "invoker: caller" : "user: caller"));
|
|
340
758
|
}
|
|
341
759
|
}
|
|
760
|
+
for (const binding of principalAliasBindings) guardPrincipalMemberAccesses(body, binding, edits);
|
|
342
761
|
return;
|
|
343
762
|
}
|
|
344
763
|
const ctxName = pattern.text();
|
|
@@ -354,7 +773,7 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
354
773
|
if (!(obj && obj.kind() === "identifier" && obj.text() === ctxName)) continue;
|
|
355
774
|
const pos = obj.range().start.index;
|
|
356
775
|
if (isInsideAnyRange(pos, ctxShadowRanges)) continue;
|
|
357
|
-
edits.push(propId.replace("caller"));
|
|
776
|
+
edits.push(propId.replace(principalPropertyReplacement(propId, "caller")));
|
|
358
777
|
}
|
|
359
778
|
const ctxDestructures = body.findAll({ rule: {
|
|
360
779
|
kind: "variable_declarator",
|
|
@@ -364,6 +783,7 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
364
783
|
regex: `^${escapeRegex(ctxName)}$`
|
|
365
784
|
}
|
|
366
785
|
} });
|
|
786
|
+
const principalAliasBindings = [];
|
|
367
787
|
for (const decl of ctxDestructures) {
|
|
368
788
|
const pos = decl.range().start.index;
|
|
369
789
|
if (isInsideAnyRange(pos, ctxShadowRanges)) continue;
|
|
@@ -371,13 +791,556 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
371
791
|
if (!pat || pat.kind() !== "object_pattern") continue;
|
|
372
792
|
for (const child of pat.children()) {
|
|
373
793
|
const k = child.kind();
|
|
374
|
-
if (k === "shorthand_property_identifier_pattern" && child.text() === "user")
|
|
375
|
-
|
|
794
|
+
if (k === "shorthand_property_identifier_pattern" && child.text() === "user") {
|
|
795
|
+
edits.push(child.replace("caller: user"));
|
|
796
|
+
principalAliasBindings.push({
|
|
797
|
+
name: "user",
|
|
798
|
+
bindingStart: child.range().start.index
|
|
799
|
+
});
|
|
800
|
+
} else if (k === "pair_pattern") {
|
|
376
801
|
const key = child.field("key");
|
|
377
|
-
|
|
802
|
+
const value = child.field("value");
|
|
803
|
+
if (key && key.text() === "user" && value?.kind() === "identifier") {
|
|
804
|
+
edits.push(key.replace("caller"));
|
|
805
|
+
principalAliasBindings.push({
|
|
806
|
+
name: value.text(),
|
|
807
|
+
bindingStart: value.range().start.index
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
for (const binding of principalAliasBindings) guardPrincipalMemberAccesses(body, binding, edits);
|
|
814
|
+
}
|
|
815
|
+
function findMemberCallName(call) {
|
|
816
|
+
const fn = call.field("function");
|
|
817
|
+
if (!fn || fn.kind() !== "member_expression") return null;
|
|
818
|
+
return fn.field("property")?.text() ?? null;
|
|
819
|
+
}
|
|
820
|
+
function findMemberCallObject(call) {
|
|
821
|
+
const fn = call.field("function");
|
|
822
|
+
if (!fn || fn.kind() !== "member_expression") return null;
|
|
823
|
+
return fn.field("object");
|
|
824
|
+
}
|
|
825
|
+
function isFunctionNode(node) {
|
|
826
|
+
return node.kind() === "arrow_function" || node.kind() === "function_declaration" || node.kind() === "function_expression" || node.kind() === "method_definition";
|
|
827
|
+
}
|
|
828
|
+
function propertyName(node) {
|
|
829
|
+
return node.field("key")?.text() ?? node.field("name")?.text() ?? null;
|
|
830
|
+
}
|
|
831
|
+
function getFirstFunctionParam(fn) {
|
|
832
|
+
const params = fn.field("parameters") ?? fn.field("parameter") ?? fn.children().find((c) => c.kind() === "formal_parameters");
|
|
833
|
+
if (!params) return null;
|
|
834
|
+
if (params.kind() === "object_pattern" || params.kind() === "identifier") return params;
|
|
835
|
+
return params.children().find((c) => c.kind() === "required_parameter" || c.kind() === "optional_parameter" || c.kind() === "identifier" || c.kind() === "object_pattern") ?? null;
|
|
836
|
+
}
|
|
837
|
+
function getFunctionParamPattern(param) {
|
|
838
|
+
if (param.kind() === "object_pattern" || param.kind() === "identifier") return param;
|
|
839
|
+
return param.field("pattern");
|
|
840
|
+
}
|
|
841
|
+
function findExecutorBodyFunctions(call) {
|
|
842
|
+
const objArg = call.field("arguments")?.children().find((c) => c.kind() === "object");
|
|
843
|
+
if (!objArg) return [];
|
|
844
|
+
const functions = [];
|
|
845
|
+
const visitObject = (object) => {
|
|
846
|
+
for (const child of object.children()) {
|
|
847
|
+
if (child.kind() === "method_definition") {
|
|
848
|
+
if (propertyName(child) === "body") functions.push(child);
|
|
849
|
+
continue;
|
|
850
|
+
}
|
|
851
|
+
if (child.kind() !== "pair") continue;
|
|
852
|
+
const value = child.field("value");
|
|
853
|
+
if (!value) continue;
|
|
854
|
+
if (child.field("key")?.text() === "body" && isFunctionNode(value)) functions.push(value);
|
|
855
|
+
else if (value.kind() === "object") visitObject(value);
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
visitObject(objArg);
|
|
859
|
+
return functions;
|
|
860
|
+
}
|
|
861
|
+
function transformExecutorBodyActorAccesses(fn, edits, transformedActorPropertyStarts) {
|
|
862
|
+
const param = getFirstFunctionParam(fn);
|
|
863
|
+
const pattern = param ? getFunctionParamPattern(param) : null;
|
|
864
|
+
const body = fn.field("body");
|
|
865
|
+
if (!pattern || !body) return;
|
|
866
|
+
if (pattern.kind() === "identifier") {
|
|
867
|
+
const ctxName = pattern.text();
|
|
868
|
+
transformExecutorCtxActorAccesses(body, ctxName, collectCtxShadowRanges(body, ctxName, fn), edits, transformedActorPropertyStarts);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
if (pattern.kind() !== "object_pattern") return;
|
|
872
|
+
for (const child of pattern.children()) {
|
|
873
|
+
const kind = child.kind();
|
|
874
|
+
if (kind === "shorthand_property_identifier_pattern" && child.text() === "actor") transformActorBindingMemberAccesses(body, {
|
|
875
|
+
name: "actor",
|
|
876
|
+
bindingStart: child.range().start.index
|
|
877
|
+
}, edits, transformedActorPropertyStarts);
|
|
878
|
+
else if (kind === "pair_pattern") {
|
|
879
|
+
const key = child.field("key");
|
|
880
|
+
const value = child.field("value");
|
|
881
|
+
if (key?.text() === "actor" && value?.kind() === "identifier") transformActorBindingMemberAccesses(body, {
|
|
882
|
+
name: value.text(),
|
|
883
|
+
bindingStart: value.range().start.index
|
|
884
|
+
}, edits, transformedActorPropertyStarts);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function nullableTailorUserTypeReplacement(typeId, typeContext) {
|
|
889
|
+
if (typeContext.tailorUserTypeLocalNames.has(typeId.text())) return typeId.text() === "TailorUser" ? "TailorPrincipal | null" : `${typeId.text()} | null`;
|
|
890
|
+
return isSdkNamespaceQualifiedTypeIdentifier(typeId, typeContext.sdkNamespaceNames, typeContext.root) ? "TailorPrincipal | null" : null;
|
|
891
|
+
}
|
|
892
|
+
function transformObjectTypeUserProperty(objectType, edits, typeContext) {
|
|
893
|
+
for (const child of objectType.children()) {
|
|
894
|
+
if (child.kind() !== "property_signature") continue;
|
|
895
|
+
const name = child.field("name");
|
|
896
|
+
if (name?.text() !== "user") continue;
|
|
897
|
+
edits.push(name.replace("invoker"));
|
|
898
|
+
const typeAnnotation = child.field("type");
|
|
899
|
+
if (!typeAnnotation || /\bnull\b/.test(typeAnnotation.text())) continue;
|
|
900
|
+
const typeIds = typeAnnotation.findAll({ rule: { kind: "type_identifier" } });
|
|
901
|
+
for (const typeId of typeIds) {
|
|
902
|
+
const replacement = nullableTailorUserTypeReplacement(typeId, typeContext);
|
|
903
|
+
if (!replacement) continue;
|
|
904
|
+
typeContext.transformedPrincipalTypeStarts.add(typeId.range().start.index);
|
|
905
|
+
edits.push(typeId.replace(replacement));
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function localCallbackTypeObject(declaration) {
|
|
910
|
+
return declaration.children().find((c) => c.kind() === "object_type" || c.kind() === "interface_body") ?? null;
|
|
911
|
+
}
|
|
912
|
+
function collectLocalCallbackTypeBindings(root) {
|
|
913
|
+
const rootScope = localBindingRootScope(root);
|
|
914
|
+
const bindings = [];
|
|
915
|
+
for (const kind of ["type_alias_declaration", "interface_declaration"]) {
|
|
916
|
+
const declarations = root.findAll({ rule: { kind } });
|
|
917
|
+
for (const declaration of declarations) {
|
|
918
|
+
if (!localCallbackTypeObject(declaration)) continue;
|
|
919
|
+
const name = declaration.field("name");
|
|
920
|
+
if (!name || name.kind() !== "type_identifier" && name.kind() !== "identifier") continue;
|
|
921
|
+
bindings.push({
|
|
922
|
+
name: name.text(),
|
|
923
|
+
declaration,
|
|
924
|
+
bindingStart: name.range().start.index,
|
|
925
|
+
scope: enclosingScopeRange(declaration) ?? rootScope
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return bindings;
|
|
930
|
+
}
|
|
931
|
+
function isShadowedLocalTypeReference(root, name, pos, bindingStart) {
|
|
932
|
+
for (const kind of ["type_alias_declaration", "interface_declaration"]) {
|
|
933
|
+
const declarations = root.findAll({ rule: { kind } });
|
|
934
|
+
for (const declaration of declarations) {
|
|
935
|
+
const nameNode = declaration.field("name");
|
|
936
|
+
if (!nameNode || nameNode.text() !== name) continue;
|
|
937
|
+
if (nameNode.range().start.index === bindingStart) continue;
|
|
938
|
+
const scope = enclosingScopeRange(declaration);
|
|
939
|
+
if (scope && rangeContains(scope, pos)) return true;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
function resolveLocalCallbackTypeBinding(node, context) {
|
|
945
|
+
const pos = node.range().start.index;
|
|
946
|
+
return context.bindings.find((binding) => binding.name === node.text() && rangeContains(binding.scope, pos) && !isShadowedLocalTypeReference(context.root, binding.name, pos, binding.bindingStart)) ?? null;
|
|
947
|
+
}
|
|
948
|
+
function transformNamedPrincipalCallbackType(typeName, edits, context) {
|
|
949
|
+
const binding = resolveLocalCallbackTypeBinding(typeName, context);
|
|
950
|
+
if (!binding) return;
|
|
951
|
+
const start = binding.declaration.range().start.index;
|
|
952
|
+
if (context.transformedTypeStarts.has(start)) return;
|
|
953
|
+
const objectType = localCallbackTypeObject(binding.declaration);
|
|
954
|
+
if (!objectType) return;
|
|
955
|
+
context.transformedTypeStarts.add(start);
|
|
956
|
+
transformObjectTypeUserProperty(objectType, edits, context);
|
|
957
|
+
}
|
|
958
|
+
function transformPrincipalCallbackParamType(param, edits, typeContext) {
|
|
959
|
+
const typeAnnotation = param.field("type");
|
|
960
|
+
const objectType = typeAnnotation?.children().find((c) => c.kind() === "object_type");
|
|
961
|
+
if (objectType) {
|
|
962
|
+
if (typeContext) transformObjectTypeUserProperty(objectType, edits, typeContext);
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const typeName = typeAnnotation?.children().find((c) => c.kind() === "type_identifier");
|
|
966
|
+
if (typeName && typeContext) transformNamedPrincipalCallbackType(typeName, edits, typeContext);
|
|
967
|
+
}
|
|
968
|
+
function transformPrincipalCallbackParam(fn, edits, typeContext) {
|
|
969
|
+
const param = getFirstFunctionParam(fn);
|
|
970
|
+
if (!param) return;
|
|
971
|
+
const pattern = getFunctionParamPattern(param);
|
|
972
|
+
const body = fn.field("body");
|
|
973
|
+
if (!pattern || !body) return;
|
|
974
|
+
if (pattern.kind() === "identifier") {
|
|
975
|
+
const ctxName = pattern.text();
|
|
976
|
+
const ctxShadowRanges = collectCtxShadowRanges(body, ctxName, fn);
|
|
977
|
+
const propertyAccesses = body.findAll({ rule: {
|
|
978
|
+
kind: "property_identifier",
|
|
979
|
+
regex: "^user$"
|
|
980
|
+
} });
|
|
981
|
+
for (const propId of propertyAccesses) {
|
|
982
|
+
const parent = propId.parent();
|
|
983
|
+
if (!parent || parent.kind() !== "member_expression") continue;
|
|
984
|
+
const obj = parent.field("object");
|
|
985
|
+
if (!(obj && obj.kind() === "identifier" && obj.text() === ctxName)) continue;
|
|
986
|
+
const pos = obj.range().start.index;
|
|
987
|
+
if (isInsideAnyRange(pos, ctxShadowRanges)) continue;
|
|
988
|
+
edits.push(propId.replace(principalPropertyReplacement(propId, "invoker")));
|
|
989
|
+
}
|
|
990
|
+
const ctxDestructures = body.findAll({ rule: {
|
|
991
|
+
kind: "variable_declarator",
|
|
992
|
+
has: {
|
|
993
|
+
field: "value",
|
|
994
|
+
kind: "identifier",
|
|
995
|
+
regex: `^${escapeRegex(ctxName)}$`
|
|
996
|
+
}
|
|
997
|
+
} });
|
|
998
|
+
const principalAliasBindings = [];
|
|
999
|
+
for (const decl of ctxDestructures) {
|
|
1000
|
+
const pos = decl.range().start.index;
|
|
1001
|
+
if (isInsideAnyRange(pos, ctxShadowRanges)) continue;
|
|
1002
|
+
const pat = decl.field("name");
|
|
1003
|
+
if (!pat || pat.kind() !== "object_pattern") continue;
|
|
1004
|
+
for (const child of pat.children()) {
|
|
1005
|
+
const kind = child.kind();
|
|
1006
|
+
if (kind === "shorthand_property_identifier_pattern" && child.text() === "user") {
|
|
1007
|
+
edits.push(child.replace("invoker: user"));
|
|
1008
|
+
principalAliasBindings.push({
|
|
1009
|
+
name: "user",
|
|
1010
|
+
bindingStart: child.range().start.index
|
|
1011
|
+
});
|
|
1012
|
+
} else if (kind === "pair_pattern") {
|
|
1013
|
+
const key = child.field("key");
|
|
1014
|
+
const value = child.field("value");
|
|
1015
|
+
if (key?.text() === "user" && value?.kind() === "identifier") {
|
|
1016
|
+
edits.push(key.replace("invoker"));
|
|
1017
|
+
principalAliasBindings.push({
|
|
1018
|
+
name: value.text(),
|
|
1019
|
+
bindingStart: value.range().start.index
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
for (const binding of principalAliasBindings) guardPrincipalMemberAccesses(body, binding, edits);
|
|
1026
|
+
transformPrincipalCallbackParamType(param, edits, typeContext);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (pattern.kind() !== "object_pattern") return;
|
|
1030
|
+
if (hasNestedPropertyPattern(pattern, "user")) return;
|
|
1031
|
+
let hasUserParamProperty = false;
|
|
1032
|
+
let renamesBinding = false;
|
|
1033
|
+
const principalAliasBindings = [];
|
|
1034
|
+
for (const child of pattern.children()) {
|
|
1035
|
+
const kind = child.kind();
|
|
1036
|
+
if (kind === "shorthand_property_identifier_pattern" && child.text() === "user") {
|
|
1037
|
+
hasUserParamProperty = true;
|
|
1038
|
+
renamesBinding = true;
|
|
1039
|
+
} else if (kind === "pair_pattern") {
|
|
1040
|
+
if (child.field("key")?.text() === "user") {
|
|
1041
|
+
hasUserParamProperty = true;
|
|
1042
|
+
const value = child.field("value");
|
|
1043
|
+
if (value?.kind() === "identifier") principalAliasBindings.push({
|
|
1044
|
+
name: value.text(),
|
|
1045
|
+
bindingStart: value.range().start.index
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
} else if (kind === "object_assignment_pattern") {
|
|
1049
|
+
if (child.children().find((c) => c.kind() === "shorthand_property_identifier_pattern")?.text() === "user") {
|
|
1050
|
+
hasUserParamProperty = true;
|
|
1051
|
+
renamesBinding = true;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
if (!hasUserParamProperty) return;
|
|
1056
|
+
if (renamesBinding && hasPrincipalAssignmentTarget(body, "user")) return;
|
|
1057
|
+
if (renamesBinding && patternBindsName(pattern, "invoker")) return;
|
|
1058
|
+
transformPrincipalCallbackParamType(param, edits, typeContext);
|
|
1059
|
+
const aliasRenamedUser = renamesBinding && (collectAllShadowRanges(body, "invoker").length > 0 || hasUnshadowedIdentifierReference(body, "invoker"));
|
|
1060
|
+
let aliasedShorthandUser = false;
|
|
1061
|
+
let renamedShorthandUser = false;
|
|
1062
|
+
for (const child of pattern.children()) {
|
|
1063
|
+
const kind = child.kind();
|
|
1064
|
+
if (kind === "shorthand_property_identifier_pattern" && child.text() === "user") if (aliasRenamedUser) {
|
|
1065
|
+
edits.push(child.replace("invoker: user"));
|
|
1066
|
+
aliasedShorthandUser = true;
|
|
1067
|
+
principalAliasBindings.push({
|
|
1068
|
+
name: "user",
|
|
1069
|
+
bindingStart: child.range().start.index
|
|
1070
|
+
});
|
|
1071
|
+
} else {
|
|
1072
|
+
edits.push(child.replace("invoker"));
|
|
1073
|
+
renamedShorthandUser = true;
|
|
1074
|
+
}
|
|
1075
|
+
else if (kind === "pair_pattern") {
|
|
1076
|
+
const key = child.field("key");
|
|
1077
|
+
if (key?.text() === "user") edits.push(key.replace("invoker"));
|
|
1078
|
+
} else if (kind === "object_assignment_pattern") {
|
|
1079
|
+
const inner = child.children().find((c) => c.kind() === "shorthand_property_identifier_pattern");
|
|
1080
|
+
if (inner?.text() === "user") if (aliasRenamedUser) {
|
|
1081
|
+
edits.push(inner.replace("invoker: user"));
|
|
1082
|
+
aliasedShorthandUser = true;
|
|
1083
|
+
principalAliasBindings.push({
|
|
1084
|
+
name: "user",
|
|
1085
|
+
bindingStart: inner.range().start.index
|
|
1086
|
+
});
|
|
1087
|
+
} else {
|
|
1088
|
+
edits.push(inner.replace("invoker"));
|
|
1089
|
+
renamedShorthandUser = true;
|
|
378
1090
|
}
|
|
379
1091
|
}
|
|
380
1092
|
}
|
|
1093
|
+
if (!renamedShorthandUser) {
|
|
1094
|
+
if (aliasedShorthandUser) rewriteParseArgumentShorthands(body, "user", "invoker", typeContext, edits);
|
|
1095
|
+
for (const binding of principalAliasBindings) guardPrincipalMemberAccesses(body, binding, edits);
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const shadowRanges = collectAllShadowRanges(body, "user");
|
|
1099
|
+
const refs = body.findAll({ rule: {
|
|
1100
|
+
kind: "identifier",
|
|
1101
|
+
regex: "^user$"
|
|
1102
|
+
} });
|
|
1103
|
+
for (const ref of refs) {
|
|
1104
|
+
const pos = ref.range().start.index;
|
|
1105
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
1106
|
+
edits.push(ref.replace(principalReadReplacement(ref, "invoker")));
|
|
1107
|
+
}
|
|
1108
|
+
const shortRefs = body.findAll({ rule: {
|
|
1109
|
+
kind: "shorthand_property_identifier",
|
|
1110
|
+
regex: "^user$"
|
|
1111
|
+
} });
|
|
1112
|
+
for (const ref of shortRefs) {
|
|
1113
|
+
const pos = ref.range().start.index;
|
|
1114
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
1115
|
+
edits.push(ref.replace(isSdkFieldParseArgumentShorthand(ref, typeContext) ? "invoker" : "user: invoker"));
|
|
1116
|
+
}
|
|
1117
|
+
for (const binding of principalAliasBindings) guardPrincipalMemberAccesses(body, binding, edits);
|
|
1118
|
+
}
|
|
1119
|
+
function rangeContains([start, end], pos) {
|
|
1120
|
+
return pos >= start && pos < end;
|
|
1121
|
+
}
|
|
1122
|
+
function isShadowedLocalReference(root, name, pos, bindingStart) {
|
|
1123
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
1124
|
+
for (const decl of declarators) {
|
|
1125
|
+
const nameNode = decl.field("name");
|
|
1126
|
+
if (!nameNode || !patternBindsName(nameNode, name)) continue;
|
|
1127
|
+
const nameRange = nameNode.range();
|
|
1128
|
+
if (bindingStart >= nameRange.start.index && bindingStart < nameRange.end.index) continue;
|
|
1129
|
+
const scope = enclosingScopeRange(decl);
|
|
1130
|
+
if (scope && rangeContains(scope, pos)) return true;
|
|
1131
|
+
}
|
|
1132
|
+
const functionDecls = root.findAll({ rule: { kind: "function_declaration" } });
|
|
1133
|
+
for (const fn of functionDecls) {
|
|
1134
|
+
const nameNode = fn.field("name");
|
|
1135
|
+
if (!nameNode || nameNode.text() !== name) continue;
|
|
1136
|
+
if (nameNode.range().start.index === bindingStart) continue;
|
|
1137
|
+
const scope = enclosingScopeRange(fn);
|
|
1138
|
+
if (scope && rangeContains(scope, pos)) return true;
|
|
1139
|
+
}
|
|
1140
|
+
for (const kind of NESTED_FN_KINDS) {
|
|
1141
|
+
const fns = root.findAll({ rule: { kind } });
|
|
1142
|
+
for (const fn of fns) {
|
|
1143
|
+
if (!functionRebindsName(fn, name)) continue;
|
|
1144
|
+
const range = fn.range();
|
|
1145
|
+
if (pos >= range.start.index && pos < range.end.index) return true;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
1150
|
+
function resolvesToSdkFieldLocal(node, bindings, root) {
|
|
1151
|
+
if (node.kind() !== "identifier") return false;
|
|
1152
|
+
const pos = node.range().start.index;
|
|
1153
|
+
return bindings.some((binding) => binding.name === node.text() && rangeContains(binding.scope, pos) && !isShadowedLocalReference(root, binding.name, pos, binding.bindingStart));
|
|
1154
|
+
}
|
|
1155
|
+
function isSdkFieldExpression(node, sdkFieldRootNames, sdkFieldLocalBindings, root) {
|
|
1156
|
+
if (node.kind() === "identifier") {
|
|
1157
|
+
const pos = node.range().start.index;
|
|
1158
|
+
return sdkFieldRootNames.has(node.text()) && !isInsideAnyRange(pos, collectAllShadowRanges(root, node.text())) || resolvesToSdkFieldLocal(node, sdkFieldLocalBindings, root);
|
|
1159
|
+
}
|
|
1160
|
+
if (node.kind() === "member_expression") {
|
|
1161
|
+
const object = node.field("object");
|
|
1162
|
+
return object ? isSdkFieldExpression(object, sdkFieldRootNames, sdkFieldLocalBindings, root) : false;
|
|
1163
|
+
}
|
|
1164
|
+
if (node.kind() === "call_expression") {
|
|
1165
|
+
const object = findMemberCallObject(node);
|
|
1166
|
+
return object ? isSdkFieldExpression(object, sdkFieldRootNames, sdkFieldLocalBindings, root) : false;
|
|
1167
|
+
}
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
function collectSdkFieldLocalBindings(root, sdkFieldRootNames) {
|
|
1171
|
+
const bindings = [];
|
|
1172
|
+
let changed = true;
|
|
1173
|
+
while (changed) {
|
|
1174
|
+
changed = false;
|
|
1175
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
1176
|
+
for (const decl of declarators) {
|
|
1177
|
+
const name = decl.field("name");
|
|
1178
|
+
const value = decl.field("value");
|
|
1179
|
+
if (!name || name.kind() !== "identifier" || !value) continue;
|
|
1180
|
+
const bindingStart = name.range().start.index;
|
|
1181
|
+
if (bindings.some((binding) => binding.bindingStart === bindingStart)) continue;
|
|
1182
|
+
if (!isSdkFieldExpression(value, sdkFieldRootNames, bindings, root)) continue;
|
|
1183
|
+
const rootRange = root.range();
|
|
1184
|
+
const scope = enclosingScopeRange(decl) ?? [rootRange.start.index, rootRange.end.index];
|
|
1185
|
+
bindings.push({
|
|
1186
|
+
name: name.text(),
|
|
1187
|
+
bindingStart,
|
|
1188
|
+
scope
|
|
1189
|
+
});
|
|
1190
|
+
changed = true;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return bindings;
|
|
1194
|
+
}
|
|
1195
|
+
function isSdkFieldMemberCall(call, sdkFieldRootNames, sdkFieldLocalBindings, root) {
|
|
1196
|
+
const object = findMemberCallObject(call);
|
|
1197
|
+
return object ? isSdkFieldExpression(object, sdkFieldRootNames, sdkFieldLocalBindings, root) : false;
|
|
1198
|
+
}
|
|
1199
|
+
function localBindingRootScope(root) {
|
|
1200
|
+
const rootRange = root.range();
|
|
1201
|
+
return [rootRange.start.index, rootRange.end.index];
|
|
1202
|
+
}
|
|
1203
|
+
function collectLocalCallbackBindings(root) {
|
|
1204
|
+
const rootScope = localBindingRootScope(root);
|
|
1205
|
+
const bindings = [];
|
|
1206
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
1207
|
+
for (const decl of declarators) {
|
|
1208
|
+
const name = decl.field("name");
|
|
1209
|
+
const value = decl.field("value");
|
|
1210
|
+
if (!name || name.kind() !== "identifier" || !value || !isFunctionNode(value)) continue;
|
|
1211
|
+
bindings.push({
|
|
1212
|
+
name: name.text(),
|
|
1213
|
+
fn: value,
|
|
1214
|
+
bindingStart: name.range().start.index,
|
|
1215
|
+
scope: enclosingScopeRange(decl) ?? rootScope
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
const functionDecls = root.findAll({ rule: { kind: "function_declaration" } });
|
|
1219
|
+
for (const fn of functionDecls) {
|
|
1220
|
+
const name = fn.field("name");
|
|
1221
|
+
if (!name || name.kind() !== "identifier") continue;
|
|
1222
|
+
bindings.push({
|
|
1223
|
+
name: name.text(),
|
|
1224
|
+
fn,
|
|
1225
|
+
bindingStart: name.range().start.index,
|
|
1226
|
+
scope: enclosingScopeRange(fn) ?? rootScope
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
return bindings;
|
|
1230
|
+
}
|
|
1231
|
+
function collectLocalObjectBindings(root) {
|
|
1232
|
+
const rootScope = localBindingRootScope(root);
|
|
1233
|
+
const bindings = [];
|
|
1234
|
+
const declarators = root.findAll({ rule: { kind: "variable_declarator" } });
|
|
1235
|
+
for (const decl of declarators) {
|
|
1236
|
+
const name = decl.field("name");
|
|
1237
|
+
const value = decl.field("value");
|
|
1238
|
+
if (!name || name.kind() !== "identifier" || value?.kind() !== "object") continue;
|
|
1239
|
+
bindings.push({
|
|
1240
|
+
name: name.text(),
|
|
1241
|
+
object: value,
|
|
1242
|
+
bindingStart: name.range().start.index,
|
|
1243
|
+
scope: enclosingScopeRange(decl) ?? rootScope
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
return bindings;
|
|
1247
|
+
}
|
|
1248
|
+
function resolveLocalCallbackBinding(node, bindings, root) {
|
|
1249
|
+
if (node.kind() !== "identifier") return null;
|
|
1250
|
+
const pos = node.range().start.index;
|
|
1251
|
+
return bindings.find((binding) => binding.name === node.text() && rangeContains(binding.scope, pos) && !isShadowedLocalReference(root, binding.name, pos, binding.bindingStart)) ?? null;
|
|
1252
|
+
}
|
|
1253
|
+
function resolveLocalObjectBinding(node, bindings, root) {
|
|
1254
|
+
if (node.kind() !== "identifier") return null;
|
|
1255
|
+
const pos = node.range().start.index;
|
|
1256
|
+
return bindings.find((binding) => binding.name === node.text() && rangeContains(binding.scope, pos) && !isShadowedLocalReference(root, binding.name, pos, binding.bindingStart)) ?? null;
|
|
1257
|
+
}
|
|
1258
|
+
function transformPrincipalCallbackNode(node, edits, callbackBindings, transformedCallbackStarts, typeContext, root) {
|
|
1259
|
+
if (isFunctionNode(node)) {
|
|
1260
|
+
transformPrincipalCallbackParam(node, edits, typeContext);
|
|
1261
|
+
return true;
|
|
1262
|
+
}
|
|
1263
|
+
const binding = resolveLocalCallbackBinding(node, callbackBindings, root);
|
|
1264
|
+
if (!binding) return false;
|
|
1265
|
+
const start = binding.fn.range().start.index;
|
|
1266
|
+
if (!transformedCallbackStarts.has(start)) {
|
|
1267
|
+
transformedCallbackStarts.add(start);
|
|
1268
|
+
transformPrincipalCallbackParam(binding.fn, edits, typeContext);
|
|
1269
|
+
}
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
function transformHookCallbackObject(node, edits, callbackBindings, transformedCallbackStarts, typeContext, root) {
|
|
1273
|
+
if (node.kind() !== "object") return;
|
|
1274
|
+
for (const child of node.children()) {
|
|
1275
|
+
if (child.kind() === "method_definition") {
|
|
1276
|
+
const key = propertyName(child);
|
|
1277
|
+
if (key === "create" || key === "update") transformPrincipalCallbackParam(child, edits, typeContext);
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
if (child.kind() !== "pair") continue;
|
|
1281
|
+
const key = child.field("key")?.text();
|
|
1282
|
+
const value = child.field("value");
|
|
1283
|
+
if (!value) continue;
|
|
1284
|
+
if (key === "create" || key === "update") {
|
|
1285
|
+
if (!transformPrincipalCallbackNode(value, edits, callbackBindings, transformedCallbackStarts, typeContext, root) && value.kind() === "object") transformHookCallbackObject(value, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1286
|
+
} else if (value.kind() === "object") transformHookCallbackObject(value, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
function transformHookCallbackConfigNode(node, edits, callbackBindings, objectBindings, transformedCallbackStarts, transformedObjectStarts, typeContext, root) {
|
|
1290
|
+
if (node.kind() === "object") {
|
|
1291
|
+
transformHookCallbackObject(node, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1292
|
+
return true;
|
|
1293
|
+
}
|
|
1294
|
+
const binding = resolveLocalObjectBinding(node, objectBindings, root);
|
|
1295
|
+
if (!binding) return false;
|
|
1296
|
+
const start = binding.object.range().start.index;
|
|
1297
|
+
if (!transformedObjectStarts.has(start)) {
|
|
1298
|
+
transformedObjectStarts.add(start);
|
|
1299
|
+
transformHookCallbackObject(binding.object, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1300
|
+
}
|
|
1301
|
+
return true;
|
|
1302
|
+
}
|
|
1303
|
+
function transformValidateCallbackNode(node, edits, callbackBindings, transformedCallbackStarts, typeContext, root) {
|
|
1304
|
+
if (transformPrincipalCallbackNode(node, edits, callbackBindings, transformedCallbackStarts, typeContext, root)) return;
|
|
1305
|
+
if (node.kind() === "array") {
|
|
1306
|
+
for (const child of node.children()) transformValidateCallbackNode(child, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
if (node.kind() !== "object") return;
|
|
1310
|
+
for (const child of node.children()) {
|
|
1311
|
+
if (child.kind() === "method_definition") {
|
|
1312
|
+
transformPrincipalCallbackParam(child, edits, typeContext);
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
if (child.kind() !== "pair") continue;
|
|
1316
|
+
const value = child.field("value");
|
|
1317
|
+
if (value) transformValidateCallbackNode(value, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
function transformPrincipalCallbacksInCall(call, edits, sdkFieldRootNames, sdkFieldLocalBindings, callbackBindings, objectBindings, transformedCallbackStarts, transformedObjectStarts, typeContext, root) {
|
|
1321
|
+
const memberName = findMemberCallName(call);
|
|
1322
|
+
if (memberName !== "hooks" && memberName !== "validate") return;
|
|
1323
|
+
if (!isSdkFieldMemberCall(call, sdkFieldRootNames, sdkFieldLocalBindings, root)) return;
|
|
1324
|
+
const args = call.field("arguments");
|
|
1325
|
+
if (!args) return;
|
|
1326
|
+
if (memberName === "hooks") {
|
|
1327
|
+
for (const arg of args.children()) if (transformHookCallbackConfigNode(arg, edits, callbackBindings, objectBindings, transformedCallbackStarts, transformedObjectStarts, typeContext, root)) break;
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
for (const arg of args.children()) transformValidateCallbackNode(arg, edits, callbackBindings, transformedCallbackStarts, typeContext, root);
|
|
1331
|
+
}
|
|
1332
|
+
function transformParseArgsObject(call, edits, sdkFieldRootNames, sdkFieldLocalBindings, root) {
|
|
1333
|
+
if (findMemberCallName(call) !== "parse") return;
|
|
1334
|
+
if (!isSdkFieldMemberCall(call, sdkFieldRootNames, sdkFieldLocalBindings, root)) return;
|
|
1335
|
+
const objArg = call.field("arguments")?.children().find((c) => c.kind() === "object");
|
|
1336
|
+
if (!objArg) return;
|
|
1337
|
+
for (const child of objArg.children()) {
|
|
1338
|
+
const kind = child.kind();
|
|
1339
|
+
if (kind === "pair") {
|
|
1340
|
+
const key = child.field("key");
|
|
1341
|
+
if (key?.text() === "user") edits.push(key.replace("invoker"));
|
|
1342
|
+
} else if (kind === "shorthand_property_identifier" && child.text() === "user") edits.push(child.replace("invoker: user"));
|
|
1343
|
+
}
|
|
381
1344
|
}
|
|
382
1345
|
/**
|
|
383
1346
|
* Migrate user/actor/invoker types and identifiers to the unified TailorPrincipal.
|
|
@@ -388,10 +1351,13 @@ function transformResolverBody(arrowNode, edits) {
|
|
|
388
1351
|
* - Replaces standalone references to `unauthenticatedTailorUser` with `null`. Member-access
|
|
389
1352
|
* forms like `unauthenticatedTailorUser.id` are left alone on purpose so the resulting TS
|
|
390
1353
|
* error after the import is removed points the author at the broken access.
|
|
1354
|
+
* - Rewrites actor member accesses from `userId` / `userType` to `id` / `type`.
|
|
391
1355
|
* - Renames `user` to `caller` for top-level destructured resolver bodies (`{ input, user }`),
|
|
392
1356
|
* handles aliased pairs (`{ user: currentUser }`) by rewriting only the property name, and
|
|
393
1357
|
* rewrites `<ctx>.user` for non-destructured single-param bodies — respecting variable
|
|
394
1358
|
* shadowing in both directions.
|
|
1359
|
+
* - Renames TailorDB hook/validator callback `user` parameters to `invoker`, and rewrites
|
|
1360
|
+
* `.parse({ user: ... })` arguments to `.parse({ invoker: ... })`.
|
|
395
1361
|
* @param source - TypeScript source text.
|
|
396
1362
|
* @returns Transformed source or null when nothing matched.
|
|
397
1363
|
*/
|
|
@@ -407,21 +1373,32 @@ function transform(source) {
|
|
|
407
1373
|
}
|
|
408
1374
|
} });
|
|
409
1375
|
const sdkRenameSourceNames = /* @__PURE__ */ new Set();
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
|
|
1376
|
+
const tailorUserTypeLocalNames = /* @__PURE__ */ new Set();
|
|
1377
|
+
const nullableInvokerAliasLocalNames = /* @__PURE__ */ new Set();
|
|
1378
|
+
const actorTypeAliasLocalNames = /* @__PURE__ */ new Set();
|
|
1379
|
+
const actorTypeLocalNames = /* @__PURE__ */ new Set();
|
|
1380
|
+
const actorTypeValueLocalNames = /* @__PURE__ */ new Set();
|
|
1381
|
+
const sdkNamespaceNames = /* @__PURE__ */ new Set();
|
|
1382
|
+
for (const importStmt of sdkImports) {
|
|
1383
|
+
for (const namespaceName of iterateNamespaceImportLocalNames(importStmt)) sdkNamespaceNames.add(namespaceName);
|
|
1384
|
+
for (const { importedName, aliasNode, localName } of iterateImportSpecs(importStmt)) {
|
|
1385
|
+
if (TYPE_RENAME_MAP[importedName] && !aliasNode) sdkRenameSourceNames.add(importedName);
|
|
1386
|
+
if (importedName === "TailorUser") tailorUserTypeLocalNames.add(localName);
|
|
1387
|
+
if (importedName === "TailorActor") actorTypeLocalNames.add(localName);
|
|
1388
|
+
if (importedName === "TailorActorType") actorTypeValueLocalNames.add(localName);
|
|
1389
|
+
if (importedName === "TailorInvoker" && aliasNode) nullableInvokerAliasLocalNames.add(localName);
|
|
1390
|
+
if (importedName === "TailorActorType" && aliasNode) actorTypeAliasLocalNames.add(localName);
|
|
1391
|
+
}
|
|
419
1392
|
}
|
|
1393
|
+
const transformedActorPropertyStarts = /* @__PURE__ */ new Set();
|
|
1394
|
+
transformTailorActorTypedMemberAccesses(tree, actorTypeLocalNames, sdkNamespaceNames, edits, transformedActorPropertyStarts);
|
|
1395
|
+
transformTailorActorTypeInitializerLiterals(tree, actorTypeValueLocalNames, sdkNamespaceNames, edits);
|
|
1396
|
+
transformTailorActorTypeBindingComparisons(tree, actorTypeValueLocalNames, sdkNamespaceNames, edits);
|
|
420
1397
|
let importRemoved = false;
|
|
421
1398
|
const globalEmittedRenamed = /* @__PURE__ */ new Set();
|
|
422
1399
|
const unauthenticatedLocalNames = /* @__PURE__ */ new Set();
|
|
423
1400
|
for (const importStmt of sdkImports) {
|
|
424
|
-
const { newText, touched } = rebuildImportStatement(importStmt, globalEmittedRenamed, unauthenticatedLocalNames);
|
|
1401
|
+
const { newText, touched } = rebuildImportStatement(importStmt, globalEmittedRenamed, unauthenticatedLocalNames, nullableInvokerAliasLocalNames, actorTypeAliasLocalNames);
|
|
425
1402
|
if (!touched) continue;
|
|
426
1403
|
edits.push(importStmt.replace(newText));
|
|
427
1404
|
if (newText === "") importRemoved = true;
|
|
@@ -441,7 +1418,20 @@ function transform(source) {
|
|
|
441
1418
|
}
|
|
442
1419
|
}
|
|
443
1420
|
const createResolverLocalNames = /* @__PURE__ */ new Set();
|
|
444
|
-
|
|
1421
|
+
const createExecutorLocalNames = /* @__PURE__ */ new Set();
|
|
1422
|
+
const sdkFieldRootNames = /* @__PURE__ */ new Set();
|
|
1423
|
+
for (const namespaceName of sdkNamespaceNames) sdkFieldRootNames.add(namespaceName);
|
|
1424
|
+
for (const importStmt of sdkImports) for (const { importedName, localName } of iterateImportSpecs(importStmt)) {
|
|
1425
|
+
if (importedName === "createResolver") createResolverLocalNames.add(localName);
|
|
1426
|
+
if (importedName === "createExecutor") createExecutorLocalNames.add(localName);
|
|
1427
|
+
if (importedName === "t" || importedName === "db") sdkFieldRootNames.add(localName);
|
|
1428
|
+
}
|
|
1429
|
+
const sdkFieldLocalBindings = collectSdkFieldLocalBindings(tree, sdkFieldRootNames);
|
|
1430
|
+
const parseContext = {
|
|
1431
|
+
sdkFieldRootNames,
|
|
1432
|
+
sdkFieldLocalBindings,
|
|
1433
|
+
root: tree
|
|
1434
|
+
};
|
|
445
1435
|
for (const localName of createResolverLocalNames) {
|
|
446
1436
|
const shadowRanges = collectAllShadowRanges(tree, localName);
|
|
447
1437
|
const calls = tree.findAll({ rule: {
|
|
@@ -458,8 +1448,106 @@ function transform(source) {
|
|
|
458
1448
|
const pos = callee.range().start.index;
|
|
459
1449
|
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
460
1450
|
const arrow = findResolverBodyArrow(call);
|
|
461
|
-
if (arrow) transformResolverBody(arrow, edits);
|
|
1451
|
+
if (arrow) transformResolverBody(arrow, edits, parseContext);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
for (const namespaceName of sdkNamespaceNames) {
|
|
1455
|
+
const shadowRanges = collectAllShadowRanges(tree, namespaceName);
|
|
1456
|
+
const calls = tree.findAll({ rule: {
|
|
1457
|
+
kind: "call_expression",
|
|
1458
|
+
has: {
|
|
1459
|
+
field: "function",
|
|
1460
|
+
kind: "member_expression",
|
|
1461
|
+
has: {
|
|
1462
|
+
field: "property",
|
|
1463
|
+
kind: "property_identifier",
|
|
1464
|
+
regex: "^createResolver$"
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
} });
|
|
1468
|
+
for (const call of calls) {
|
|
1469
|
+
const object = call.field("function")?.field("object");
|
|
1470
|
+
if (!object || object.kind() !== "identifier" || object.text() !== namespaceName) continue;
|
|
1471
|
+
const pos = object.range().start.index;
|
|
1472
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
1473
|
+
const arrow = findResolverBodyArrow(call);
|
|
1474
|
+
if (arrow) transformResolverBody(arrow, edits, parseContext);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
for (const localName of createExecutorLocalNames) {
|
|
1478
|
+
const shadowRanges = collectAllShadowRanges(tree, localName);
|
|
1479
|
+
const calls = tree.findAll({ rule: {
|
|
1480
|
+
kind: "call_expression",
|
|
1481
|
+
has: {
|
|
1482
|
+
field: "function",
|
|
1483
|
+
kind: "identifier",
|
|
1484
|
+
regex: `^${escapeRegex(localName)}$`
|
|
1485
|
+
}
|
|
1486
|
+
} });
|
|
1487
|
+
for (const call of calls) {
|
|
1488
|
+
const callee = call.field("function");
|
|
1489
|
+
if (!callee) continue;
|
|
1490
|
+
const pos = callee.range().start.index;
|
|
1491
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
1492
|
+
for (const fn of findExecutorBodyFunctions(call)) transformExecutorBodyActorAccesses(fn, edits, transformedActorPropertyStarts);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
for (const namespaceName of sdkNamespaceNames) {
|
|
1496
|
+
const shadowRanges = collectAllShadowRanges(tree, namespaceName);
|
|
1497
|
+
const calls = tree.findAll({ rule: {
|
|
1498
|
+
kind: "call_expression",
|
|
1499
|
+
has: {
|
|
1500
|
+
field: "function",
|
|
1501
|
+
kind: "member_expression",
|
|
1502
|
+
has: {
|
|
1503
|
+
field: "property",
|
|
1504
|
+
kind: "property_identifier",
|
|
1505
|
+
regex: "^createExecutor$"
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
} });
|
|
1509
|
+
for (const call of calls) {
|
|
1510
|
+
const object = call.field("function")?.field("object");
|
|
1511
|
+
if (!object || object.kind() !== "identifier" || object.text() !== namespaceName) continue;
|
|
1512
|
+
const pos = object.range().start.index;
|
|
1513
|
+
if (isInsideAnyRange(pos, shadowRanges)) continue;
|
|
1514
|
+
for (const fn of findExecutorBodyFunctions(call)) transformExecutorBodyActorAccesses(fn, edits, transformedActorPropertyStarts);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
transformActorTypeComparisonLiterals(tree, edits, transformedActorPropertyStarts);
|
|
1518
|
+
const callbackBindings = collectLocalCallbackBindings(tree);
|
|
1519
|
+
const objectBindings = collectLocalObjectBindings(tree);
|
|
1520
|
+
const typeContext = {
|
|
1521
|
+
bindings: collectLocalCallbackTypeBindings(tree),
|
|
1522
|
+
transformedTypeStarts: /* @__PURE__ */ new Set(),
|
|
1523
|
+
transformedPrincipalTypeStarts: /* @__PURE__ */ new Set(),
|
|
1524
|
+
tailorUserTypeLocalNames,
|
|
1525
|
+
sdkNamespaceNames,
|
|
1526
|
+
sdkFieldRootNames,
|
|
1527
|
+
sdkFieldLocalBindings,
|
|
1528
|
+
root: tree
|
|
1529
|
+
};
|
|
1530
|
+
const transformedCallbackStarts = /* @__PURE__ */ new Set();
|
|
1531
|
+
const transformedObjectStarts = /* @__PURE__ */ new Set();
|
|
1532
|
+
const memberCalls = tree.findAll({ rule: { kind: "call_expression" } });
|
|
1533
|
+
for (const call of memberCalls) {
|
|
1534
|
+
transformPrincipalCallbacksInCall(call, edits, sdkFieldRootNames, sdkFieldLocalBindings, callbackBindings, objectBindings, transformedCallbackStarts, transformedObjectStarts, typeContext, tree);
|
|
1535
|
+
transformParseArgsObject(call, edits, sdkFieldRootNames, sdkFieldLocalBindings, tree);
|
|
1536
|
+
}
|
|
1537
|
+
const typeIdents = tree.findAll({ rule: {
|
|
1538
|
+
kind: "type_identifier",
|
|
1539
|
+
not: { inside: { kind: "import_statement" } }
|
|
1540
|
+
} });
|
|
1541
|
+
for (const id of typeIdents) {
|
|
1542
|
+
if (typeContext.transformedPrincipalTypeStarts.has(id.range().start.index)) continue;
|
|
1543
|
+
const qualifiedReplacement = namespaceQualifiedTypeReplacement(id, sdkNamespaceNames, tree);
|
|
1544
|
+
if (qualifiedReplacement) {
|
|
1545
|
+
edits.push(qualifiedReplacement.target.replace(qualifiedReplacement.text));
|
|
1546
|
+
continue;
|
|
462
1547
|
}
|
|
1548
|
+
const newName = sdkRenameSourceNames.has(id.text()) ? renamedTypeIdentifierText(id.text()) : nullableInvokerAliasLocalNames.has(id.text()) ? renamedTypeIdentifierText("TailorInvoker") : actorTypeAliasLocalNames.has(id.text()) ? renamedTypeIdentifierText("TailorActorType") : null;
|
|
1549
|
+
if (!newName) continue;
|
|
1550
|
+
edits.push(id.replace(newName));
|
|
463
1551
|
}
|
|
464
1552
|
if (edits.length === 0) return null;
|
|
465
1553
|
let result = tree.commitEdits(edits);
|