@archie/devtools 0.0.25 → 0.0.27
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/dist/chunk-4VGQJ3PW.mjs +577 -0
- package/dist/client/client.js +23 -29
- package/dist/client/client.mjs +23 -29
- package/dist/collection-binding.d.mts +156 -0
- package/dist/collection-binding.d.ts +156 -0
- package/dist/collection-binding.js +553 -0
- package/dist/collection-binding.mjs +521 -0
- package/dist/index.js +9 -10
- package/dist/index.mjs +7 -575
- package/dist/inspector.standalone.js +262 -10
- package/package.json +6 -1
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/babel-plugin-collection-binding.ts
|
|
21
|
+
var babel_plugin_collection_binding_exports = {};
|
|
22
|
+
__export(babel_plugin_collection_binding_exports, {
|
|
23
|
+
babelPluginCollectionBinding: () => babelPluginCollectionBinding
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(babel_plugin_collection_binding_exports);
|
|
26
|
+
var import_types = require("@babel/types");
|
|
27
|
+
|
|
28
|
+
// src/babel-plugin-editor-meta.ts
|
|
29
|
+
function meaningfulChildren(t, children) {
|
|
30
|
+
return children.filter((child) => {
|
|
31
|
+
if (t.isJSXText(child)) return child.value.trim() !== "";
|
|
32
|
+
if (t.isJSXExpressionContainer(child)) return !t.isJSXEmptyExpression(child.expression);
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/babel-plugin-collection-binding.ts
|
|
38
|
+
var ATTR_ENTITY = "data-agent-entity";
|
|
39
|
+
var ATTR_ROW = "data-agent-row";
|
|
40
|
+
var ATTR_FIELD = "data-agent-field";
|
|
41
|
+
var ATTR_FIELD_STATE = "data-agent-field-state";
|
|
42
|
+
var ATTR_FIELD_PARTS = "data-agent-field-parts";
|
|
43
|
+
var ATTR_FIELD_SLOT = "data-agent-field-slot";
|
|
44
|
+
var ATTR_COLLECTION_ORDER = "data-agent-collection-order";
|
|
45
|
+
var SLICE_ROOT_NAME = "slice";
|
|
46
|
+
var CHAIN_METHODS = /* @__PURE__ */ new Set(["filter", "slice", "sort", "map"]);
|
|
47
|
+
var MAX_SOURCE_CHAIN_HOPS = 4;
|
|
48
|
+
var MAX_PROJECTION_DEPTH = 3;
|
|
49
|
+
function babelPluginCollectionBinding({ types: t }, opts = {}) {
|
|
50
|
+
const { fileExclude = /node_modules/ } = opts;
|
|
51
|
+
function hasOwnAttr(elementPath, name) {
|
|
52
|
+
return elementPath.node.openingElement.attributes.some(
|
|
53
|
+
(a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name })
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function addAttr(elementPath, name, value) {
|
|
57
|
+
if (hasOwnAttr(elementPath, name)) return;
|
|
58
|
+
elementPath.node.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(name), value));
|
|
59
|
+
}
|
|
60
|
+
function getTagName(opening) {
|
|
61
|
+
const { name } = opening;
|
|
62
|
+
if (t.isJSXIdentifier(name)) return name.name;
|
|
63
|
+
if (t.isJSXMemberExpression(name)) {
|
|
64
|
+
const parts = [];
|
|
65
|
+
let current = name;
|
|
66
|
+
while (t.isJSXMemberExpression(current)) {
|
|
67
|
+
parts.unshift(current.property.name);
|
|
68
|
+
current = current.object;
|
|
69
|
+
}
|
|
70
|
+
if (t.isJSXIdentifier(current)) parts.unshift(current.name);
|
|
71
|
+
return parts.join(".");
|
|
72
|
+
}
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
function isLowercaseTag(tag) {
|
|
76
|
+
return tag.length > 0 && tag[0] === tag[0].toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
function getAttrName(attr) {
|
|
79
|
+
return t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
80
|
+
}
|
|
81
|
+
function isPageSliceBinding(scope) {
|
|
82
|
+
const binding = scope.getBinding(SLICE_ROOT_NAME);
|
|
83
|
+
if (!binding) return true;
|
|
84
|
+
return binding.scope === binding.scope.getProgramParent();
|
|
85
|
+
}
|
|
86
|
+
function isUseMemoCallee(callee) {
|
|
87
|
+
if (t.isIdentifier(callee, { name: "useMemo" })) return true;
|
|
88
|
+
return t.isMemberExpression(callee) && !callee.computed && t.isIdentifier(callee.property, { name: "useMemo" });
|
|
89
|
+
}
|
|
90
|
+
function resolveSliceSource(expr, scope, hops, hasSort) {
|
|
91
|
+
if (t.isCallExpression(expr)) {
|
|
92
|
+
const callee = expr.callee;
|
|
93
|
+
if (!t.isExpression(callee)) return null;
|
|
94
|
+
if (isUseMemoCallee(callee)) {
|
|
95
|
+
const [factory] = expr.arguments;
|
|
96
|
+
if (!factory || !t.isArrowFunctionExpression(factory)) return null;
|
|
97
|
+
if (!t.isExpression(factory.body)) return null;
|
|
98
|
+
return resolveSliceSource(factory.body, scope, hops, hasSort);
|
|
99
|
+
}
|
|
100
|
+
if (t.isMemberExpression(callee) && !callee.computed && t.isIdentifier(callee.property)) {
|
|
101
|
+
const method = callee.property.name;
|
|
102
|
+
if (!CHAIN_METHODS.has(method)) return null;
|
|
103
|
+
if (!t.isExpression(callee.object)) return null;
|
|
104
|
+
return resolveSliceSource(callee.object, scope, hops, hasSort || method === "sort");
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (t.isMemberExpression(expr)) {
|
|
109
|
+
if (!t.isIdentifier(expr.object, { name: SLICE_ROOT_NAME })) return null;
|
|
110
|
+
if (!isPageSliceBinding(scope)) return null;
|
|
111
|
+
if (!expr.computed && t.isIdentifier(expr.property)) {
|
|
112
|
+
return { entity: expr.property.name, hasSort };
|
|
113
|
+
}
|
|
114
|
+
if (expr.computed && t.isStringLiteral(expr.property)) {
|
|
115
|
+
return { entity: expr.property.value, hasSort };
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (t.isIdentifier(expr)) {
|
|
120
|
+
if (hops >= MAX_SOURCE_CHAIN_HOPS) return null;
|
|
121
|
+
const binding = scope.getBinding(expr.name);
|
|
122
|
+
if (!binding || !binding.constant) return null;
|
|
123
|
+
const declarator = binding.path;
|
|
124
|
+
if (!declarator.isVariableDeclarator()) return null;
|
|
125
|
+
const init = declarator.node.init;
|
|
126
|
+
if (!init || !t.isExpression(init)) return null;
|
|
127
|
+
return resolveSliceSource(init, declarator.scope, hops + 1, hasSort);
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
function buildScopeFromParam(param) {
|
|
132
|
+
if (t.isIdentifier(param)) {
|
|
133
|
+
return { identifiers: /* @__PURE__ */ new Map([[param.name, { kind: "self" }]]) };
|
|
134
|
+
}
|
|
135
|
+
if (t.isObjectPattern(param)) {
|
|
136
|
+
const identifiers = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const prop of param.properties) {
|
|
138
|
+
if (!t.isObjectProperty(prop) || prop.computed) continue;
|
|
139
|
+
const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;
|
|
140
|
+
if (!key || key.includes(",")) continue;
|
|
141
|
+
const value = prop.value;
|
|
142
|
+
let localName = null;
|
|
143
|
+
if (t.isIdentifier(value)) localName = value.name;
|
|
144
|
+
else if (t.isAssignmentPattern(value) && t.isIdentifier(value.left)) localName = value.left.name;
|
|
145
|
+
if (!localName) continue;
|
|
146
|
+
identifiers.set(localName, { kind: "field", field: key });
|
|
147
|
+
}
|
|
148
|
+
if (identifiers.size === 0) return null;
|
|
149
|
+
return { identifiers };
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function buildOptionalRowIdExpression(idValueExpr) {
|
|
154
|
+
return t.conditionalExpression(
|
|
155
|
+
t.binaryExpression("==", t.cloneNode(idValueExpr), t.nullLiteral()),
|
|
156
|
+
t.identifier("undefined"),
|
|
157
|
+
t.callExpression(t.identifier("String"), [idValueExpr])
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function computeRowIdExpression(scope) {
|
|
161
|
+
for (const [localName, binding] of scope.identifiers) {
|
|
162
|
+
if (binding.kind === "self") {
|
|
163
|
+
return buildOptionalRowIdExpression(
|
|
164
|
+
t.optionalMemberExpression(t.identifier(localName), t.identifier("id"), false, true)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const [localName, binding] of scope.identifiers) {
|
|
169
|
+
if (binding.kind === "field" && binding.field === "id") {
|
|
170
|
+
return buildOptionalRowIdExpression(t.identifier(localName));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
function isStaticLiteralExpr(node) {
|
|
176
|
+
if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node)) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return t.isTemplateLiteral(node) && node.expressions.length === 0;
|
|
180
|
+
}
|
|
181
|
+
function containsEvaluation(node) {
|
|
182
|
+
if (!node) return false;
|
|
183
|
+
if (t.isCallExpression(node) || t.isOptionalCallExpression(node) || t.isNewExpression(node) || t.isTaggedTemplateExpression(node)) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
const keys = import_types.VISITOR_KEYS[node.type] ?? [];
|
|
187
|
+
for (const key of keys) {
|
|
188
|
+
const value = node[key];
|
|
189
|
+
if (Array.isArray(value)) {
|
|
190
|
+
for (const child of value) {
|
|
191
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
192
|
+
if (containsEvaluation(child)) return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} else if (value && typeof value === "object" && "type" in value) {
|
|
196
|
+
if (containsEvaluation(value)) return true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
function classifyMemberField(expr, scope) {
|
|
202
|
+
if (!t.isIdentifier(expr.object)) return null;
|
|
203
|
+
const binding = scope.identifiers.get(expr.object.name);
|
|
204
|
+
if (!binding || binding.kind !== "self") return null;
|
|
205
|
+
if (!expr.computed) {
|
|
206
|
+
if (!t.isIdentifier(expr.property)) return null;
|
|
207
|
+
if (expr.property.name === "id") return null;
|
|
208
|
+
return { kind: "static", field: expr.property.name };
|
|
209
|
+
}
|
|
210
|
+
if (t.isStringLiteral(expr.property)) {
|
|
211
|
+
if (expr.property.value === "id") return null;
|
|
212
|
+
if (expr.property.value.includes(",")) return null;
|
|
213
|
+
return { kind: "static", field: expr.property.value };
|
|
214
|
+
}
|
|
215
|
+
return { kind: "unresolved-computed" };
|
|
216
|
+
}
|
|
217
|
+
function fieldNameForBranch(expr, scope) {
|
|
218
|
+
if (t.isIdentifier(expr)) {
|
|
219
|
+
const binding = scope.identifiers.get(expr.name);
|
|
220
|
+
return binding?.kind === "field" ? binding.field : null;
|
|
221
|
+
}
|
|
222
|
+
if (t.isMemberExpression(expr) || t.isOptionalMemberExpression(expr)) {
|
|
223
|
+
const verdict = classifyMemberField(expr, scope);
|
|
224
|
+
return verdict?.kind === "static" ? verdict.field : null;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
function flattenNullish(expr) {
|
|
229
|
+
const parts = [];
|
|
230
|
+
let current = expr;
|
|
231
|
+
while (t.isLogicalExpression(current) && current.operator === "??") {
|
|
232
|
+
parts.unshift(current.right);
|
|
233
|
+
current = current.left;
|
|
234
|
+
}
|
|
235
|
+
parts.unshift(current);
|
|
236
|
+
return parts;
|
|
237
|
+
}
|
|
238
|
+
function classifyNullishChain(expr, scope) {
|
|
239
|
+
const parts = flattenNullish(expr);
|
|
240
|
+
if (parts.length < 2) return null;
|
|
241
|
+
const last = parts[parts.length - 1];
|
|
242
|
+
if (parts.length === 2 && isStaticLiteralExpr(last)) {
|
|
243
|
+
const field = fieldNameForBranch(parts[0], scope);
|
|
244
|
+
return field ? { kind: "static", field } : null;
|
|
245
|
+
}
|
|
246
|
+
const fields = parts.map((p) => fieldNameForBranch(p, scope));
|
|
247
|
+
if (fields.some((f) => f === null)) return null;
|
|
248
|
+
const distinct = new Set(fields);
|
|
249
|
+
if (distinct.size === 1) return { kind: "static", field: fields[0] };
|
|
250
|
+
let acc = t.stringLiteral(fields[fields.length - 1]);
|
|
251
|
+
for (let i = parts.length - 2; i >= 0; i -= 1) {
|
|
252
|
+
acc = t.conditionalExpression(
|
|
253
|
+
t.binaryExpression("!=", t.cloneNode(parts[i]), t.nullLiteral()),
|
|
254
|
+
t.stringLiteral(fields[i]),
|
|
255
|
+
acc
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
return { kind: "runtime", expr: acc };
|
|
259
|
+
}
|
|
260
|
+
function classifySimpleLogicalOr(expr, scope) {
|
|
261
|
+
if (!isStaticLiteralExpr(expr.right)) return null;
|
|
262
|
+
const field = fieldNameForBranch(expr.left, scope);
|
|
263
|
+
return field ? { kind: "static", field } : null;
|
|
264
|
+
}
|
|
265
|
+
function classifyConditional(expr, scope) {
|
|
266
|
+
const { test, consequent, alternate } = expr;
|
|
267
|
+
if (!t.isExpression(test) || !t.isExpression(consequent) || !t.isExpression(alternate)) return null;
|
|
268
|
+
if (isStaticLiteralExpr(consequent) && isStaticLiteralExpr(alternate)) {
|
|
269
|
+
const testField = fieldNameForBranch(test, scope);
|
|
270
|
+
return testField ? { kind: "static", field: testField } : null;
|
|
271
|
+
}
|
|
272
|
+
const consField = fieldNameForBranch(consequent, scope);
|
|
273
|
+
const altField = fieldNameForBranch(alternate, scope);
|
|
274
|
+
if (!consField || !altField) return null;
|
|
275
|
+
if (consField === altField) return { kind: "static", field: consField };
|
|
276
|
+
if (containsEvaluation(test)) return null;
|
|
277
|
+
return {
|
|
278
|
+
kind: "runtime",
|
|
279
|
+
expr: t.conditionalExpression(t.cloneNode(test), t.stringLiteral(consField), t.stringLiteral(altField))
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function classifyFieldExpr(expr, scope) {
|
|
283
|
+
if (t.isIdentifier(expr)) {
|
|
284
|
+
const binding = scope.identifiers.get(expr.name);
|
|
285
|
+
return binding?.kind === "field" ? { kind: "static", field: binding.field } : null;
|
|
286
|
+
}
|
|
287
|
+
if (t.isMemberExpression(expr) || t.isOptionalMemberExpression(expr)) {
|
|
288
|
+
return classifyMemberField(expr, scope);
|
|
289
|
+
}
|
|
290
|
+
if (t.isLogicalExpression(expr) && expr.operator === "??") return classifyNullishChain(expr, scope);
|
|
291
|
+
if (t.isLogicalExpression(expr) && expr.operator === "||") return classifySimpleLogicalOr(expr, scope);
|
|
292
|
+
if (t.isConditionalExpression(expr)) return classifyConditional(expr, scope);
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function applyFieldVerdict(elementPath, verdict) {
|
|
296
|
+
if (!verdict) return;
|
|
297
|
+
if (verdict.kind === "unresolved-computed") {
|
|
298
|
+
addAttr(elementPath, ATTR_FIELD_STATE, t.stringLiteral("unresolved"));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (verdict.kind === "static") {
|
|
302
|
+
addAttr(elementPath, ATTR_FIELD, t.stringLiteral(verdict.field));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
addAttr(elementPath, ATTR_FIELD, t.jsxExpressionContainer(verdict.expr));
|
|
306
|
+
}
|
|
307
|
+
function meaningfulChildPaths(elementPath) {
|
|
308
|
+
const meaningfulSet = new Set(meaningfulChildren(t, elementPath.node.children));
|
|
309
|
+
const childPaths = elementPath.get("children");
|
|
310
|
+
return childPaths.filter((p) => meaningfulSet.has(p.node));
|
|
311
|
+
}
|
|
312
|
+
function isStaticExpressionContainer(container) {
|
|
313
|
+
if (t.isJSXEmptyExpression(container.expression)) return true;
|
|
314
|
+
return isStaticLiteralExpr(container.expression);
|
|
315
|
+
}
|
|
316
|
+
function isInvisibleRenderExpr(expr) {
|
|
317
|
+
if (t.isNullLiteral(expr)) return true;
|
|
318
|
+
if (t.isBooleanLiteral(expr)) return true;
|
|
319
|
+
if (t.isStringLiteral(expr) && expr.value === "") return true;
|
|
320
|
+
if (t.isTemplateLiteral(expr) && expr.expressions.length === 0 && expr.quasis.length === 1 && expr.quasis[0].value.cooked === "") {
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
function stampPureLeaf(elementPath, expr, scope) {
|
|
326
|
+
if (hasOwnAttr(elementPath, ATTR_FIELD) || hasOwnAttr(elementPath, ATTR_FIELD_STATE)) return;
|
|
327
|
+
if (t.isJSXEmptyExpression(expr) || !t.isExpression(expr)) return;
|
|
328
|
+
applyFieldVerdict(elementPath, classifyFieldExpr(expr, scope));
|
|
329
|
+
}
|
|
330
|
+
function stampLabelValueOrMixed(elementPath, childPaths, scope) {
|
|
331
|
+
if (hasOwnAttr(elementPath, ATTR_FIELD) || hasOwnAttr(elementPath, ATTR_FIELD_STATE)) return;
|
|
332
|
+
const hasInvisibleSibling = childPaths.some(
|
|
333
|
+
(p) => p.isJSXExpressionContainer() && t.isExpression(p.node.expression) && isInvisibleRenderExpr(p.node.expression)
|
|
334
|
+
);
|
|
335
|
+
if (hasInvisibleSibling) return;
|
|
336
|
+
const dynamicEntries = [];
|
|
337
|
+
childPaths.forEach((p, index) => {
|
|
338
|
+
if (!p.isJSXExpressionContainer()) return;
|
|
339
|
+
const container = p.node;
|
|
340
|
+
if (isStaticExpressionContainer(container)) return;
|
|
341
|
+
if (!t.isExpression(container.expression)) return;
|
|
342
|
+
dynamicEntries.push({ index, expr: container.expression });
|
|
343
|
+
});
|
|
344
|
+
if (dynamicEntries.length === 0) return;
|
|
345
|
+
if (dynamicEntries.length === 1) {
|
|
346
|
+
const { index, expr } = dynamicEntries[0];
|
|
347
|
+
const verdict = classifyFieldExpr(expr, scope);
|
|
348
|
+
if (!verdict) return;
|
|
349
|
+
applyFieldVerdict(elementPath, verdict);
|
|
350
|
+
if (verdict.kind !== "unresolved-computed") {
|
|
351
|
+
addAttr(elementPath, ATTR_FIELD_SLOT, t.stringLiteral(String(index)));
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const fields = [];
|
|
356
|
+
for (const { expr } of dynamicEntries) {
|
|
357
|
+
const verdict = classifyFieldExpr(expr, scope);
|
|
358
|
+
if (!verdict || verdict.kind !== "static") return;
|
|
359
|
+
fields.push(verdict.field);
|
|
360
|
+
}
|
|
361
|
+
if (new Set(fields).size <= 1) return;
|
|
362
|
+
addAttr(elementPath, ATTR_FIELD_STATE, t.stringLiteral("mixed"));
|
|
363
|
+
addAttr(elementPath, ATTR_FIELD_PARTS, t.stringLiteral(fields.join(",")));
|
|
364
|
+
}
|
|
365
|
+
function resolveComponentDefinition(tagName, fromPath) {
|
|
366
|
+
if (tagName.includes(".")) return null;
|
|
367
|
+
const binding = fromPath.scope.getBinding(tagName);
|
|
368
|
+
if (!binding) return null;
|
|
369
|
+
if (binding.scope !== binding.scope.getProgramParent()) return null;
|
|
370
|
+
const bp = binding.path;
|
|
371
|
+
if (bp.isFunctionDeclaration()) return bp;
|
|
372
|
+
if (bp.isVariableDeclarator()) {
|
|
373
|
+
const init = bp.get("init");
|
|
374
|
+
if (!Array.isArray(init) && (init.isArrowFunctionExpression() || init.isFunctionExpression())) {
|
|
375
|
+
return init;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
function buildCalleePropContext(fnPath) {
|
|
381
|
+
const [first] = fnPath.node.params;
|
|
382
|
+
if (!first || !t.isObjectPattern(first)) return null;
|
|
383
|
+
const propMap = /* @__PURE__ */ new Map();
|
|
384
|
+
for (const prop of first.properties) {
|
|
385
|
+
if (!t.isObjectProperty(prop) || prop.computed) continue;
|
|
386
|
+
const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;
|
|
387
|
+
if (!key) continue;
|
|
388
|
+
const value = prop.value;
|
|
389
|
+
let localName = null;
|
|
390
|
+
if (t.isIdentifier(value)) localName = value.name;
|
|
391
|
+
else if (t.isAssignmentPattern(value) && t.isIdentifier(value.left)) localName = value.left.name;
|
|
392
|
+
if (!localName) continue;
|
|
393
|
+
propMap.set(key, localName);
|
|
394
|
+
}
|
|
395
|
+
if (propMap.size === 0) return null;
|
|
396
|
+
return { propMap };
|
|
397
|
+
}
|
|
398
|
+
function findReturnedJsxPath(fnPath) {
|
|
399
|
+
const body = fnPath.get("body");
|
|
400
|
+
if (Array.isArray(body)) return null;
|
|
401
|
+
if (body.isBlockStatement()) {
|
|
402
|
+
const returnPaths = [];
|
|
403
|
+
body.traverse({
|
|
404
|
+
Function(inner) {
|
|
405
|
+
inner.skip();
|
|
406
|
+
},
|
|
407
|
+
ReturnStatement(rp) {
|
|
408
|
+
returnPaths.push(rp);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
if (returnPaths.length !== 1) return null;
|
|
412
|
+
const arg = returnPaths[0].get("argument");
|
|
413
|
+
if (Array.isArray(arg) || !arg.node) return null;
|
|
414
|
+
return arg.isJSXElement() ? arg : null;
|
|
415
|
+
}
|
|
416
|
+
return body.isJSXElement() ? body : null;
|
|
417
|
+
}
|
|
418
|
+
function findSelfForwardingLocalName(usagePath, scope, propCtx) {
|
|
419
|
+
for (const attr of usagePath.node.openingElement.attributes) {
|
|
420
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
421
|
+
const localName = propCtx.propMap.get(getAttrName(attr));
|
|
422
|
+
if (!localName) continue;
|
|
423
|
+
const value = attr.value;
|
|
424
|
+
if (!t.isJSXExpressionContainer(value)) continue;
|
|
425
|
+
const expr = value.expression;
|
|
426
|
+
if (!t.isIdentifier(expr)) continue;
|
|
427
|
+
const binding = scope.identifiers.get(expr.name);
|
|
428
|
+
if (binding?.kind === "self") return localName;
|
|
429
|
+
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
function resolveRowRoot(jsxPath, scope, depth) {
|
|
433
|
+
const tag = getTagName(jsxPath.node.openingElement);
|
|
434
|
+
if (isLowercaseTag(tag)) return { hostPath: jsxPath, scope };
|
|
435
|
+
if (depth >= MAX_PROJECTION_DEPTH) return null;
|
|
436
|
+
const fnPath = resolveComponentDefinition(tag, jsxPath);
|
|
437
|
+
if (!fnPath) return null;
|
|
438
|
+
const propCtx = buildCalleePropContext(fnPath);
|
|
439
|
+
if (!propCtx) return null;
|
|
440
|
+
const localName = findSelfForwardingLocalName(jsxPath, scope, propCtx);
|
|
441
|
+
if (!localName) return null;
|
|
442
|
+
const innerReturn = findReturnedJsxPath(fnPath);
|
|
443
|
+
if (!innerReturn) return null;
|
|
444
|
+
return resolveRowRoot(innerReturn, { identifiers: /* @__PURE__ */ new Map([[localName, { kind: "self" }]]) }, depth + 1);
|
|
445
|
+
}
|
|
446
|
+
function resolveFieldProjection(jsxPath, scope, depth) {
|
|
447
|
+
const tag = getTagName(jsxPath.node.openingElement);
|
|
448
|
+
if (isLowercaseTag(tag)) return { hostPath: jsxPath, scope };
|
|
449
|
+
if (depth >= MAX_PROJECTION_DEPTH) return null;
|
|
450
|
+
const fnPath = resolveComponentDefinition(tag, jsxPath);
|
|
451
|
+
if (!fnPath) return null;
|
|
452
|
+
const propCtx = buildCalleePropContext(fnPath);
|
|
453
|
+
if (!propCtx) return null;
|
|
454
|
+
const identifiers = /* @__PURE__ */ new Map();
|
|
455
|
+
for (const attr of jsxPath.node.openingElement.attributes) {
|
|
456
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
457
|
+
const localName = propCtx.propMap.get(getAttrName(attr));
|
|
458
|
+
if (!localName) continue;
|
|
459
|
+
const value = attr.value;
|
|
460
|
+
if (!t.isJSXExpressionContainer(value)) continue;
|
|
461
|
+
const expr = value.expression;
|
|
462
|
+
if (t.isJSXEmptyExpression(expr) || !t.isExpression(expr)) continue;
|
|
463
|
+
if (t.isIdentifier(expr)) {
|
|
464
|
+
const binding = scope.identifiers.get(expr.name);
|
|
465
|
+
if (binding?.kind === "self") {
|
|
466
|
+
identifiers.set(localName, { kind: "self" });
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const verdict = classifyFieldExpr(expr, scope);
|
|
471
|
+
if (verdict?.kind === "static") {
|
|
472
|
+
identifiers.set(localName, { kind: "field", field: verdict.field });
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (identifiers.size === 0) return null;
|
|
476
|
+
const innerReturn = findReturnedJsxPath(fnPath);
|
|
477
|
+
if (!innerReturn) return null;
|
|
478
|
+
return resolveFieldProjection(innerReturn, { identifiers }, depth + 1);
|
|
479
|
+
}
|
|
480
|
+
function walkFieldsWithinRow(elementPath, scope) {
|
|
481
|
+
const childPaths = meaningfulChildPaths(elementPath);
|
|
482
|
+
const hasElementChild = childPaths.some((p) => p.isJSXElement());
|
|
483
|
+
if (hasElementChild) {
|
|
484
|
+
for (const childPath of childPaths) {
|
|
485
|
+
if (!childPath.isJSXElement()) continue;
|
|
486
|
+
handleStructuralChild(childPath, scope);
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (childPaths.length === 0) return;
|
|
491
|
+
const exprChildren = childPaths.filter((p) => p.isJSXExpressionContainer());
|
|
492
|
+
if (childPaths.length === 1 && exprChildren.length === 1) {
|
|
493
|
+
stampPureLeaf(elementPath, exprChildren[0].node.expression, scope);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (childPaths.length > 1) {
|
|
497
|
+
stampLabelValueOrMixed(elementPath, childPaths, scope);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
function handleStructuralChild(childPath, scope) {
|
|
501
|
+
const tag = getTagName(childPath.node.openingElement);
|
|
502
|
+
if (isLowercaseTag(tag)) {
|
|
503
|
+
walkFieldsWithinRow(childPath, scope);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const projected = resolveFieldProjection(childPath, scope, 0);
|
|
507
|
+
if (!projected) return;
|
|
508
|
+
walkFieldsWithinRow(projected.hostPath, projected.scope);
|
|
509
|
+
}
|
|
510
|
+
function processSliceMap(callPath) {
|
|
511
|
+
const node = callPath.node;
|
|
512
|
+
const callee = node.callee;
|
|
513
|
+
if (!t.isMemberExpression(callee) || callee.computed) return;
|
|
514
|
+
if (!t.isIdentifier(callee.property, { name: "map" })) return;
|
|
515
|
+
if (!t.isExpression(callee.object)) return;
|
|
516
|
+
const source = resolveSliceSource(callee.object, callPath.scope, 0, false);
|
|
517
|
+
if (!source) return;
|
|
518
|
+
const [callback] = node.arguments;
|
|
519
|
+
if (!callback || !t.isArrowFunctionExpression(callback) && !t.isFunctionExpression(callback)) return;
|
|
520
|
+
if (callback.params.length === 0) return;
|
|
521
|
+
const callbackPath = callPath.get("arguments.0");
|
|
522
|
+
if (Array.isArray(callbackPath)) return;
|
|
523
|
+
if (!callbackPath.isArrowFunctionExpression() && !callbackPath.isFunctionExpression()) return;
|
|
524
|
+
const initialScope = buildScopeFromParam(callback.params[0]);
|
|
525
|
+
if (!initialScope) return;
|
|
526
|
+
const returnedJsx = findReturnedJsxPath(callbackPath);
|
|
527
|
+
if (!returnedJsx) return;
|
|
528
|
+
const resolvedRoot = resolveRowRoot(returnedJsx, initialScope, 0);
|
|
529
|
+
if (!resolvedRoot) return;
|
|
530
|
+
const rowIdExpr = computeRowIdExpression(resolvedRoot.scope);
|
|
531
|
+
if (!rowIdExpr) return;
|
|
532
|
+
const { hostPath, scope } = resolvedRoot;
|
|
533
|
+
if (hasOwnAttr(hostPath, ATTR_ENTITY)) return;
|
|
534
|
+
addAttr(hostPath, ATTR_ENTITY, t.stringLiteral(source.entity));
|
|
535
|
+
addAttr(hostPath, ATTR_ROW, t.jsxExpressionContainer(rowIdExpr));
|
|
536
|
+
addAttr(hostPath, ATTR_COLLECTION_ORDER, t.stringLiteral(source.hasSort ? "derived" : "stable"));
|
|
537
|
+
walkFieldsWithinRow(hostPath, scope);
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
name: "babel-plugin-collection-binding",
|
|
541
|
+
visitor: {
|
|
542
|
+
CallExpression(path, state) {
|
|
543
|
+
const filename = state.filename ?? "";
|
|
544
|
+
if (fileExclude.test(filename)) return;
|
|
545
|
+
processSliceMap(path);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
551
|
+
0 && (module.exports = {
|
|
552
|
+
babelPluginCollectionBinding
|
|
553
|
+
});
|