@uni_toolkit/uniapp-miniprogram-devtool 0.1.1-alpha.1778855349600
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/LICENSE +21 -0
- package/README.md +176 -0
- package/bin/umpd.js +16 -0
- package/dist/automator-inspector.cjs +172 -0
- package/dist/automator-inspector.cjs.map +1 -0
- package/dist/automator-inspector.d.cts +35 -0
- package/dist/chunk-CKQMccvm.cjs +28 -0
- package/dist/cli.cjs +33 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +5 -0
- package/dist/core.cjs +593 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +71 -0
- package/dist/html-report.cjs +75 -0
- package/dist/html-report.cjs.map +1 -0
- package/dist/html-report.d.cts +7 -0
- package/dist/one-click.cjs +223 -0
- package/dist/one-click.cjs.map +1 -0
- package/dist/one-click.d.cts +5 -0
- package/dist/runtime-snippet.cjs +116 -0
- package/dist/runtime-snippet.cjs.map +1 -0
- package/dist/runtime-snippet.d.cts +7 -0
- package/dist/web-panel.cjs +882 -0
- package/dist/web-panel.cjs.map +1 -0
- package/dist/web-panel.d.cts +50 -0
- package/package.json +60 -0
package/dist/core.cjs
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_chunk = require("./chunk-CKQMccvm.cjs");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
node_fs = require_chunk.__toESM(node_fs);
|
|
5
|
+
let node_path = require("node:path");
|
|
6
|
+
node_path = require_chunk.__toESM(node_path);
|
|
7
|
+
//#region src/core.ts
|
|
8
|
+
const TEMPLATE_EXTENSIONS = [".wxml"];
|
|
9
|
+
const NATIVE_TEMPLATE_TAGS = new Set([
|
|
10
|
+
"view",
|
|
11
|
+
"text",
|
|
12
|
+
"image",
|
|
13
|
+
"button",
|
|
14
|
+
"input",
|
|
15
|
+
"textarea",
|
|
16
|
+
"scroll-view",
|
|
17
|
+
"swiper",
|
|
18
|
+
"swiper-item",
|
|
19
|
+
"icon",
|
|
20
|
+
"progress",
|
|
21
|
+
"rich-text",
|
|
22
|
+
"checkbox",
|
|
23
|
+
"checkbox-group",
|
|
24
|
+
"radio",
|
|
25
|
+
"radio-group",
|
|
26
|
+
"switch",
|
|
27
|
+
"slider",
|
|
28
|
+
"picker",
|
|
29
|
+
"picker-view",
|
|
30
|
+
"picker-view-column",
|
|
31
|
+
"navigator",
|
|
32
|
+
"form",
|
|
33
|
+
"label",
|
|
34
|
+
"map",
|
|
35
|
+
"canvas",
|
|
36
|
+
"camera",
|
|
37
|
+
"video",
|
|
38
|
+
"live-player",
|
|
39
|
+
"live-pusher",
|
|
40
|
+
"movable-area",
|
|
41
|
+
"movable-view",
|
|
42
|
+
"cover-view",
|
|
43
|
+
"cover-image",
|
|
44
|
+
"slot",
|
|
45
|
+
"block",
|
|
46
|
+
"template",
|
|
47
|
+
"ad",
|
|
48
|
+
"open-data",
|
|
49
|
+
"official-account",
|
|
50
|
+
"editor",
|
|
51
|
+
"page-meta",
|
|
52
|
+
"navigation-bar",
|
|
53
|
+
"match-media",
|
|
54
|
+
"sticky-section",
|
|
55
|
+
"sticky-header"
|
|
56
|
+
]);
|
|
57
|
+
const GENERATED_PATTERNS = [
|
|
58
|
+
{
|
|
59
|
+
re: /\bsei\s*\(\s*common_vendor\.gei|common_vendor\.sei\s*\(\s*common_vendor\.gei|\bgei\s*\(/,
|
|
60
|
+
name: "generated element id",
|
|
61
|
+
kind: "element-id"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
re: /common_assets\._imports_\d+|\b_imports_\d+\b/,
|
|
65
|
+
name: "generated static asset",
|
|
66
|
+
kind: "static-asset"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
re: /u_s_b_h/,
|
|
70
|
+
name: "generated CSS var --status-bar-height",
|
|
71
|
+
kind: "css-var"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
re: /u_s_a_i_b/,
|
|
75
|
+
name: "generated CSS var --uni-safe-area-inset-bottom",
|
|
76
|
+
kind: "css-var"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
re: /virtualHostClass/,
|
|
80
|
+
name: "generated virtualHostClass",
|
|
81
|
+
kind: "virtual-host-class"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
re: /virtualHostStyle/,
|
|
85
|
+
name: "generated virtualHostStyle",
|
|
86
|
+
kind: "virtual-host-style"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
re: /virtualHostHidden/,
|
|
90
|
+
name: "generated virtualHostHidden",
|
|
91
|
+
kind: "virtual-host-hidden"
|
|
92
|
+
}
|
|
93
|
+
];
|
|
94
|
+
function walkFiles(root, predicate) {
|
|
95
|
+
const output = [];
|
|
96
|
+
function walk(dir) {
|
|
97
|
+
if (!node_fs.default.existsSync(dir)) return;
|
|
98
|
+
for (const name of node_fs.default.readdirSync(dir)) {
|
|
99
|
+
const full = node_path.default.join(dir, name);
|
|
100
|
+
if (node_fs.default.statSync(full).isDirectory()) walk(full);
|
|
101
|
+
else if (!predicate || predicate(full)) output.push(full);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
walk(root);
|
|
105
|
+
return output;
|
|
106
|
+
}
|
|
107
|
+
function normalizeSlashes(value) {
|
|
108
|
+
return value.split(node_path.default.sep).join("/");
|
|
109
|
+
}
|
|
110
|
+
function stripJsComments(input) {
|
|
111
|
+
let output = "";
|
|
112
|
+
let state = "normal";
|
|
113
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
114
|
+
const ch = input[index];
|
|
115
|
+
const next = input[index + 1];
|
|
116
|
+
if (state === "normal") if (ch === "/" && next === "/") {
|
|
117
|
+
state = "line";
|
|
118
|
+
output += " ";
|
|
119
|
+
index += 1;
|
|
120
|
+
} else if (ch === "/" && next === "*") {
|
|
121
|
+
state = "block";
|
|
122
|
+
output += " ";
|
|
123
|
+
index += 1;
|
|
124
|
+
} else if (ch === "\"" || ch === "'" || ch === "`") {
|
|
125
|
+
state = ch;
|
|
126
|
+
output += ch;
|
|
127
|
+
} else output += ch;
|
|
128
|
+
else if (state === "line") if (ch === "\n") {
|
|
129
|
+
state = "normal";
|
|
130
|
+
output += ch;
|
|
131
|
+
} else output += " ";
|
|
132
|
+
else if (state === "block") if (ch === "*" && next === "/") {
|
|
133
|
+
state = "normal";
|
|
134
|
+
output += " ";
|
|
135
|
+
index += 1;
|
|
136
|
+
} else output += ch === "\n" ? "\n" : " ";
|
|
137
|
+
else {
|
|
138
|
+
output += ch;
|
|
139
|
+
if (ch === "\\") {
|
|
140
|
+
index += 1;
|
|
141
|
+
output += input[index] || "";
|
|
142
|
+
} else if (ch === state) state = "normal";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return output;
|
|
146
|
+
}
|
|
147
|
+
function findMatchingBrace(input, openIndex) {
|
|
148
|
+
let depth = 0;
|
|
149
|
+
let state = "normal";
|
|
150
|
+
for (let index = openIndex; index < input.length; index += 1) {
|
|
151
|
+
const ch = input[index];
|
|
152
|
+
if (state === "normal") {
|
|
153
|
+
if (ch === "\"" || ch === "'" || ch === "`") state = ch;
|
|
154
|
+
else if (ch === "{") depth += 1;
|
|
155
|
+
else if (ch === "}") {
|
|
156
|
+
depth -= 1;
|
|
157
|
+
if (depth === 0) return index;
|
|
158
|
+
}
|
|
159
|
+
} else if (ch === "\\") index += 1;
|
|
160
|
+
else if (ch === state) state = "normal";
|
|
161
|
+
}
|
|
162
|
+
return -1;
|
|
163
|
+
}
|
|
164
|
+
function extractReturnedObject(js) {
|
|
165
|
+
const start = js.indexOf("const __returned__ =");
|
|
166
|
+
if (start !== -1) {
|
|
167
|
+
const open = js.indexOf("{", start + 20);
|
|
168
|
+
if (open === -1) return null;
|
|
169
|
+
const close = findMatchingBrace(js, open);
|
|
170
|
+
if (close === -1) return null;
|
|
171
|
+
return js.slice(open + 1, close);
|
|
172
|
+
}
|
|
173
|
+
return extractRenderReturnObject(js) || extractSetupRenderReturnObject(js);
|
|
174
|
+
}
|
|
175
|
+
function extractRenderReturnObject(js) {
|
|
176
|
+
const start = js.indexOf("function _sfc_render");
|
|
177
|
+
if (start === -1) return null;
|
|
178
|
+
const open = js.indexOf("{", start + 20);
|
|
179
|
+
if (open === -1) return null;
|
|
180
|
+
const close = findMatchingBrace(js, open);
|
|
181
|
+
if (close === -1) return null;
|
|
182
|
+
const body = js.slice(open + 1, close);
|
|
183
|
+
let state = "normal";
|
|
184
|
+
let depthParen = 0;
|
|
185
|
+
let depthBracket = 0;
|
|
186
|
+
let depthBrace = 0;
|
|
187
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
188
|
+
const ch = body[index];
|
|
189
|
+
if (state === "normal") {
|
|
190
|
+
if (ch === "\"" || ch === "'" || ch === "`") state = ch;
|
|
191
|
+
else if (ch === "(") depthParen += 1;
|
|
192
|
+
else if (ch === ")") depthParen -= 1;
|
|
193
|
+
else if (ch === "[") depthBracket += 1;
|
|
194
|
+
else if (ch === "]") depthBracket -= 1;
|
|
195
|
+
else if (ch === "{") depthBrace += 1;
|
|
196
|
+
else if (ch === "}") depthBrace -= 1;
|
|
197
|
+
else if (depthParen === 0 && depthBracket === 0 && depthBrace === 0 && body.startsWith("return", index) && !/[A-Za-z0-9_$]/.test(body[index - 1] || "") && !/[A-Za-z0-9_$]/.test(body[index + 6] || "")) {
|
|
198
|
+
let probe = index + 6;
|
|
199
|
+
while (/\s/.test(body[probe] || "")) probe += 1;
|
|
200
|
+
if (body[probe] !== "{") return null;
|
|
201
|
+
const returnClose = findMatchingBrace(body, probe);
|
|
202
|
+
if (returnClose === -1) return null;
|
|
203
|
+
return body.slice(probe + 1, returnClose);
|
|
204
|
+
}
|
|
205
|
+
} else if (ch === "\\") index += 1;
|
|
206
|
+
else if (ch === state) state = "normal";
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
function extractSetupRenderReturnObject(js) {
|
|
211
|
+
const re = /return\s*\([^)]*\)\s*=>\s*\{/g;
|
|
212
|
+
let match = re.exec(js);
|
|
213
|
+
while (match) {
|
|
214
|
+
const currentMatch = match;
|
|
215
|
+
match = re.exec(js);
|
|
216
|
+
const open = js.indexOf("{", currentMatch.index);
|
|
217
|
+
if (open === -1) continue;
|
|
218
|
+
const close = findMatchingBrace(js, open);
|
|
219
|
+
if (close === -1) continue;
|
|
220
|
+
const returned = extractTopLevelReturnObject(js.slice(open + 1, close));
|
|
221
|
+
if (returned) return returned;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
function extractTopLevelReturnObject(body) {
|
|
226
|
+
let state = "normal";
|
|
227
|
+
let depthParen = 0;
|
|
228
|
+
let depthBracket = 0;
|
|
229
|
+
let depthBrace = 0;
|
|
230
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
231
|
+
const ch = body[index];
|
|
232
|
+
if (state === "normal") {
|
|
233
|
+
if (ch === "\"" || ch === "'" || ch === "`") state = ch;
|
|
234
|
+
else if (ch === "(") depthParen += 1;
|
|
235
|
+
else if (ch === ")") depthParen -= 1;
|
|
236
|
+
else if (ch === "[") depthBracket += 1;
|
|
237
|
+
else if (ch === "]") depthBracket -= 1;
|
|
238
|
+
else if (ch === "{") depthBrace += 1;
|
|
239
|
+
else if (ch === "}") depthBrace -= 1;
|
|
240
|
+
else if (depthParen === 0 && depthBracket === 0 && depthBrace === 0 && body.startsWith("return", index) && !/[A-Za-z0-9_$]/.test(body[index - 1] || "") && !/[A-Za-z0-9_$]/.test(body[index + 6] || "")) {
|
|
241
|
+
let probe = index + 6;
|
|
242
|
+
while (/\s/.test(body[probe] || "")) probe += 1;
|
|
243
|
+
if (body[probe] !== "{") continue;
|
|
244
|
+
const returnClose = findMatchingBrace(body, probe);
|
|
245
|
+
if (returnClose === -1) return null;
|
|
246
|
+
return body.slice(probe + 1, returnClose);
|
|
247
|
+
}
|
|
248
|
+
} else if (ch === "\\") index += 1;
|
|
249
|
+
else if (ch === state) state = "normal";
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
function splitTopLevelProperties(body) {
|
|
254
|
+
const props = [];
|
|
255
|
+
let state = "normal";
|
|
256
|
+
let depthParen = 0;
|
|
257
|
+
let depthBrace = 0;
|
|
258
|
+
let depthBracket = 0;
|
|
259
|
+
let start = 0;
|
|
260
|
+
function push(end) {
|
|
261
|
+
const part = body.slice(start, end).trim();
|
|
262
|
+
if (part) props.push(part);
|
|
263
|
+
start = end + 1;
|
|
264
|
+
}
|
|
265
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
266
|
+
const ch = body[index];
|
|
267
|
+
if (state === "normal") {
|
|
268
|
+
if (ch === "\"" || ch === "'" || ch === "`") state = ch;
|
|
269
|
+
else if (ch === "(") depthParen += 1;
|
|
270
|
+
else if (ch === ")") depthParen -= 1;
|
|
271
|
+
else if (ch === "{") depthBrace += 1;
|
|
272
|
+
else if (ch === "}") depthBrace -= 1;
|
|
273
|
+
else if (ch === "[") depthBracket += 1;
|
|
274
|
+
else if (ch === "]") depthBracket -= 1;
|
|
275
|
+
else if (ch === "," && depthParen === 0 && depthBrace === 0 && depthBracket === 0) push(index);
|
|
276
|
+
} else if (ch === "\\") index += 1;
|
|
277
|
+
else if (ch === state) state = "normal";
|
|
278
|
+
}
|
|
279
|
+
push(body.length);
|
|
280
|
+
return props;
|
|
281
|
+
}
|
|
282
|
+
function parseProperty(part) {
|
|
283
|
+
let state = "normal";
|
|
284
|
+
let depthParen = 0;
|
|
285
|
+
let depthBrace = 0;
|
|
286
|
+
let depthBracket = 0;
|
|
287
|
+
for (let index = 0; index < part.length; index += 1) {
|
|
288
|
+
const ch = part[index];
|
|
289
|
+
if (state === "normal") {
|
|
290
|
+
if (ch === "\"" || ch === "'" || ch === "`") state = ch;
|
|
291
|
+
else if (ch === "(") depthParen += 1;
|
|
292
|
+
else if (ch === ")") depthParen -= 1;
|
|
293
|
+
else if (ch === "{") depthBrace += 1;
|
|
294
|
+
else if (ch === "}") depthBrace -= 1;
|
|
295
|
+
else if (ch === "[") depthBracket += 1;
|
|
296
|
+
else if (ch === "]") depthBracket -= 1;
|
|
297
|
+
else if (ch === ":" && depthParen === 0 && depthBrace === 0 && depthBracket === 0) return {
|
|
298
|
+
key: part.slice(0, index).trim().replace(/^['"]|['"]$/g, ""),
|
|
299
|
+
expression: part.slice(index + 1).trim()
|
|
300
|
+
};
|
|
301
|
+
} else if (ch === "\\") index += 1;
|
|
302
|
+
else if (ch === state) state = "normal";
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
function extractSetupBindings(js) {
|
|
307
|
+
const names = /* @__PURE__ */ new Set();
|
|
308
|
+
const blocked = new Set([
|
|
309
|
+
"__returned__",
|
|
310
|
+
"common_vendor",
|
|
311
|
+
"_sfc_main"
|
|
312
|
+
]);
|
|
313
|
+
const variableRe = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/g;
|
|
314
|
+
const functionRe = /\bfunction\s+([A-Za-z_$][\w$]*)\s*\(/g;
|
|
315
|
+
let match = variableRe.exec(js);
|
|
316
|
+
while (match) {
|
|
317
|
+
if (!blocked.has(match[1])) names.add(match[1]);
|
|
318
|
+
match = variableRe.exec(js);
|
|
319
|
+
}
|
|
320
|
+
match = functionRe.exec(js);
|
|
321
|
+
while (match) {
|
|
322
|
+
if (!blocked.has(match[1])) names.add(match[1]);
|
|
323
|
+
match = functionRe.exec(js);
|
|
324
|
+
}
|
|
325
|
+
return names;
|
|
326
|
+
}
|
|
327
|
+
function inferFromExpression(expression, setupBindings) {
|
|
328
|
+
const normalized = expression.replace(/\s+/g, " ");
|
|
329
|
+
for (const item of GENERATED_PATTERNS) if (item.re.test(expression)) return {
|
|
330
|
+
sourceName: null,
|
|
331
|
+
generatedName: item.name,
|
|
332
|
+
kind: item.kind,
|
|
333
|
+
confidence: "generated",
|
|
334
|
+
expressionSummary: normalized
|
|
335
|
+
};
|
|
336
|
+
const eventMatch = expression.match(/(?:common_vendor\.)?o\s*\(\s*([A-Za-z_$][\w$]*)/);
|
|
337
|
+
if (eventMatch) return {
|
|
338
|
+
sourceName: eventMatch[1],
|
|
339
|
+
generatedName: null,
|
|
340
|
+
kind: "event-handler",
|
|
341
|
+
confidence: "high",
|
|
342
|
+
expressionSummary: normalized
|
|
343
|
+
};
|
|
344
|
+
const unrefMatch = expression.match(/(?:common_vendor\.)?unref\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/);
|
|
345
|
+
if (unrefMatch) return {
|
|
346
|
+
sourceName: unrefMatch[1],
|
|
347
|
+
generatedName: null,
|
|
348
|
+
kind: "binding",
|
|
349
|
+
confidence: "high",
|
|
350
|
+
expressionSummary: normalized
|
|
351
|
+
};
|
|
352
|
+
const refValueMatch = expression.match(/\b([A-Za-z_$][\w$]*)\.value\b/);
|
|
353
|
+
if (refValueMatch && setupBindings.has(refValueMatch[1])) return {
|
|
354
|
+
sourceName: refValueMatch[1],
|
|
355
|
+
generatedName: null,
|
|
356
|
+
kind: "binding",
|
|
357
|
+
confidence: "high",
|
|
358
|
+
expressionSummary: normalized
|
|
359
|
+
};
|
|
360
|
+
const instanceValueMatch = expression.match(/\$(?:data|setup|props|options)\.([A-Za-z_$][\w$]*)/);
|
|
361
|
+
if (instanceValueMatch) return {
|
|
362
|
+
sourceName: instanceValueMatch[1],
|
|
363
|
+
generatedName: null,
|
|
364
|
+
kind: "binding",
|
|
365
|
+
confidence: "high",
|
|
366
|
+
expressionSummary: normalized
|
|
367
|
+
};
|
|
368
|
+
const directNames = [];
|
|
369
|
+
for (const name of setupBindings) if (new RegExp(`(^|[^\\w$])${escapeRegExp(name)}([^\\w$]|$)`).test(expression)) directNames.push(name);
|
|
370
|
+
if (directNames.length === 1) return {
|
|
371
|
+
sourceName: directNames[0],
|
|
372
|
+
generatedName: null,
|
|
373
|
+
kind: "binding",
|
|
374
|
+
confidence: "medium",
|
|
375
|
+
expressionSummary: normalized
|
|
376
|
+
};
|
|
377
|
+
if (directNames.length > 1) return {
|
|
378
|
+
sourceName: directNames.join(", "),
|
|
379
|
+
generatedName: null,
|
|
380
|
+
kind: "expression",
|
|
381
|
+
confidence: "medium",
|
|
382
|
+
expressionSummary: normalized
|
|
383
|
+
};
|
|
384
|
+
return {
|
|
385
|
+
sourceName: null,
|
|
386
|
+
generatedName: null,
|
|
387
|
+
kind: "unknown",
|
|
388
|
+
confidence: "low",
|
|
389
|
+
expressionSummary: normalized
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function escapeRegExp(value) {
|
|
393
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
394
|
+
}
|
|
395
|
+
function findWxmlUsages(wxml, key) {
|
|
396
|
+
if (!wxml) return [];
|
|
397
|
+
const usages = [];
|
|
398
|
+
const re = new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(key)}([^A-Za-z0-9_$]|$)`, "g");
|
|
399
|
+
let match = re.exec(wxml);
|
|
400
|
+
while (match) {
|
|
401
|
+
const index = match.index + match[1].length;
|
|
402
|
+
const start = Math.max(0, index - 45);
|
|
403
|
+
const end = Math.min(wxml.length, index + key.length + 45);
|
|
404
|
+
const snippet = wxml.slice(start, end).replace(/\s+/g, " ").trim();
|
|
405
|
+
usages.push({
|
|
406
|
+
index,
|
|
407
|
+
snippet
|
|
408
|
+
});
|
|
409
|
+
if (usages.length >= 8) break;
|
|
410
|
+
match = re.exec(wxml);
|
|
411
|
+
}
|
|
412
|
+
return usages;
|
|
413
|
+
}
|
|
414
|
+
function extractTemplateKeyRefs(source, keys) {
|
|
415
|
+
const matched = /* @__PURE__ */ new Set();
|
|
416
|
+
for (const key of keys) if (new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(key)}([^A-Za-z0-9_$]|$)`).test(source)) matched.add(key);
|
|
417
|
+
return Array.from(matched);
|
|
418
|
+
}
|
|
419
|
+
function normalizeSnippet(value, limit = 120) {
|
|
420
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
421
|
+
return normalized.length > limit ? `${normalized.slice(0, limit - 1)}...` : normalized;
|
|
422
|
+
}
|
|
423
|
+
function classifyTemplateTag(tag) {
|
|
424
|
+
return NATIVE_TEMPLATE_TAGS.has(tag) ? "element" : "component";
|
|
425
|
+
}
|
|
426
|
+
function parseTemplateAttributes(source) {
|
|
427
|
+
const attrs = [];
|
|
428
|
+
const attrSource = source.replace(/^<[^/\s>]+/, "").replace(/\/?>$/, "");
|
|
429
|
+
const re = /([:@A-Za-z0-9._-]+)(?:=(?:"([^"]*)"|'([^']*)'))?/g;
|
|
430
|
+
let match = re.exec(attrSource);
|
|
431
|
+
while (match) {
|
|
432
|
+
attrs.push({
|
|
433
|
+
name: match[1],
|
|
434
|
+
value: match[2] ?? match[3] ?? ""
|
|
435
|
+
});
|
|
436
|
+
match = re.exec(attrSource);
|
|
437
|
+
}
|
|
438
|
+
return attrs;
|
|
439
|
+
}
|
|
440
|
+
function parseTemplateTree(wxml, keys) {
|
|
441
|
+
if (!wxml.trim()) return null;
|
|
442
|
+
const keyNames = keys.map((item) => item.key);
|
|
443
|
+
const root = {
|
|
444
|
+
id: "root",
|
|
445
|
+
tag: "page",
|
|
446
|
+
kind: "element",
|
|
447
|
+
snippet: "page",
|
|
448
|
+
keyRefs: [],
|
|
449
|
+
attrs: [],
|
|
450
|
+
text: null,
|
|
451
|
+
children: []
|
|
452
|
+
};
|
|
453
|
+
const stack = [root];
|
|
454
|
+
const tokenRe = /<!--[\s\S]*?-->|<\/?[^>]+>|[^<]+/g;
|
|
455
|
+
let match = tokenRe.exec(wxml);
|
|
456
|
+
let counter = 0;
|
|
457
|
+
while (match) {
|
|
458
|
+
const token = match[0];
|
|
459
|
+
if (!token || token.startsWith("<!--")) {
|
|
460
|
+
match = tokenRe.exec(wxml);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (token.startsWith("</")) {
|
|
464
|
+
if (stack.length > 1) stack.pop();
|
|
465
|
+
match = tokenRe.exec(wxml);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (token.startsWith("<")) {
|
|
469
|
+
const tagMatch = token.match(/^<\s*([^\s/>]+)/);
|
|
470
|
+
if (!tagMatch) {
|
|
471
|
+
match = tokenRe.exec(wxml);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const tag = tagMatch[1];
|
|
475
|
+
counter += 1;
|
|
476
|
+
const node = {
|
|
477
|
+
id: `node-${counter}`,
|
|
478
|
+
tag,
|
|
479
|
+
kind: classifyTemplateTag(tag),
|
|
480
|
+
snippet: normalizeSnippet(token),
|
|
481
|
+
keyRefs: extractTemplateKeyRefs(token, keyNames),
|
|
482
|
+
attrs: parseTemplateAttributes(token),
|
|
483
|
+
text: null,
|
|
484
|
+
children: []
|
|
485
|
+
};
|
|
486
|
+
stack[stack.length - 1].children.push(node);
|
|
487
|
+
if (!/\/>$/.test(token) && !token.startsWith("<input")) stack.push(node);
|
|
488
|
+
match = tokenRe.exec(wxml);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const text = normalizeSnippet(token, 80);
|
|
492
|
+
if (!text) {
|
|
493
|
+
match = tokenRe.exec(wxml);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
counter += 1;
|
|
497
|
+
stack[stack.length - 1].children.push({
|
|
498
|
+
id: `node-${counter}`,
|
|
499
|
+
tag: "#text",
|
|
500
|
+
kind: "text",
|
|
501
|
+
snippet: text,
|
|
502
|
+
keyRefs: extractTemplateKeyRefs(token, keyNames),
|
|
503
|
+
attrs: [],
|
|
504
|
+
text,
|
|
505
|
+
children: []
|
|
506
|
+
});
|
|
507
|
+
match = tokenRe.exec(wxml);
|
|
508
|
+
}
|
|
509
|
+
return root;
|
|
510
|
+
}
|
|
511
|
+
function readSourceMap(targetRoot, jsFile) {
|
|
512
|
+
const match = node_fs.default.readFileSync(jsFile, "utf8").match(/\/\/# sourceMappingURL=(.+)$/m);
|
|
513
|
+
if (!match) return null;
|
|
514
|
+
const mapPath = node_path.default.resolve(node_path.default.dirname(jsFile), match[1]);
|
|
515
|
+
if (!mapPath.startsWith(node_path.default.dirname(targetRoot)) || !node_fs.default.existsSync(mapPath)) return null;
|
|
516
|
+
try {
|
|
517
|
+
const map = JSON.parse(node_fs.default.readFileSync(mapPath, "utf8"));
|
|
518
|
+
return {
|
|
519
|
+
path: normalizeSlashes(node_path.default.relative(targetRoot, mapPath)),
|
|
520
|
+
sources: Array.isArray(map.sources) ? map.sources : [],
|
|
521
|
+
sourcesContent: Array.isArray(map.sourcesContent) ? map.sourcesContent : [],
|
|
522
|
+
names: Array.isArray(map.names) ? map.names : []
|
|
523
|
+
};
|
|
524
|
+
} catch (_error) {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function findTemplateFile(jsFile) {
|
|
529
|
+
for (const extension of TEMPLATE_EXTENSIONS) {
|
|
530
|
+
const file = jsFile.replace(/\.js$/, extension);
|
|
531
|
+
if (node_fs.default.existsSync(file)) return file;
|
|
532
|
+
}
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
function analyzePage(targetRoot, jsFile) {
|
|
536
|
+
const jsNoComments = stripJsComments(node_fs.default.readFileSync(jsFile, "utf8"));
|
|
537
|
+
const relJs = normalizeSlashes(node_path.default.relative(targetRoot, jsFile));
|
|
538
|
+
const page = relJs.replace(/\.js$/, "");
|
|
539
|
+
const wxmlFile = findTemplateFile(jsFile);
|
|
540
|
+
const wxml = wxmlFile ? node_fs.default.readFileSync(wxmlFile, "utf8") : "";
|
|
541
|
+
const sourceMap = readSourceMap(targetRoot, jsFile);
|
|
542
|
+
const setupBindings = extractSetupBindings(jsNoComments);
|
|
543
|
+
const body = extractReturnedObject(jsNoComments);
|
|
544
|
+
const keys = [];
|
|
545
|
+
if (body) for (const part of splitTopLevelProperties(body)) {
|
|
546
|
+
const parsed = parseProperty(part);
|
|
547
|
+
if (!parsed || !parsed.key) continue;
|
|
548
|
+
const inferred = inferFromExpression(parsed.expression, setupBindings);
|
|
549
|
+
keys.push({
|
|
550
|
+
key: parsed.key,
|
|
551
|
+
...inferred,
|
|
552
|
+
expression: parsed.expression,
|
|
553
|
+
wxmlUsages: findWxmlUsages(wxml, parsed.key)
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
const templateTree = parseTemplateTree(wxml, keys);
|
|
557
|
+
return {
|
|
558
|
+
page,
|
|
559
|
+
jsFile: relJs,
|
|
560
|
+
wxmlFile: wxmlFile ? normalizeSlashes(node_path.default.relative(targetRoot, wxmlFile)) : null,
|
|
561
|
+
sourceMap,
|
|
562
|
+
keys,
|
|
563
|
+
templateTree
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function analyzeProject(targetRoot) {
|
|
567
|
+
if (!node_fs.default.existsSync(targetRoot)) throw new Error(`Target does not exist: ${targetRoot}`);
|
|
568
|
+
const pageFiles = walkFiles(targetRoot, (file) => file.endsWith(".js") && !file.includes(`${node_path.default.sep}common${node_path.default.sep}`)).filter((file) => {
|
|
569
|
+
const js = node_fs.default.readFileSync(file, "utf8");
|
|
570
|
+
return js.includes("const __returned__ =") || js.includes("function _sfc_render") || !!findTemplateFile(file);
|
|
571
|
+
});
|
|
572
|
+
const pages = {};
|
|
573
|
+
for (const file of pageFiles) {
|
|
574
|
+
const page = analyzePage(targetRoot, file);
|
|
575
|
+
pages[page.page] = page;
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
tool: "uniappx-keymap-devtools",
|
|
579
|
+
version: "0.1.0",
|
|
580
|
+
targetRoot,
|
|
581
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
582
|
+
pages
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
//#endregion
|
|
586
|
+
exports.analyzePage = analyzePage;
|
|
587
|
+
exports.analyzeProject = analyzeProject;
|
|
588
|
+
exports.extractReturnedObject = extractReturnedObject;
|
|
589
|
+
exports.inferFromExpression = inferFromExpression;
|
|
590
|
+
exports.parseProperty = parseProperty;
|
|
591
|
+
exports.splitTopLevelProperties = splitTopLevelProperties;
|
|
592
|
+
|
|
593
|
+
//# sourceMappingURL=core.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.cjs","names":["fs","path"],"sources":["../src/core.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nexport type Confidence = 'high' | 'medium' | 'low' | 'generated';\n\nexport interface SourceMapInfo {\n path: string;\n sources: string[];\n sourcesContent: string[];\n names: string[];\n}\n\nexport interface WxmlUsage {\n index: number;\n snippet: string;\n}\n\nexport interface TemplateAttribute {\n name: string;\n value: string;\n}\n\nexport interface TemplateNode {\n id: string;\n tag: string;\n kind: 'element' | 'component' | 'text';\n snippet: string;\n keyRefs: string[];\n attrs: TemplateAttribute[];\n text: string | null;\n children: TemplateNode[];\n}\n\nexport interface KeyMapItem {\n key: string;\n sourceName: string | null;\n generatedName: string | null;\n kind: string;\n confidence: Confidence;\n expressionSummary: string;\n expression: string;\n wxmlUsages: WxmlUsage[];\n}\n\nexport interface PageAnalysis {\n page: string;\n jsFile: string;\n wxmlFile: string | null;\n sourceMap: SourceMapInfo | null;\n keys: KeyMapItem[];\n templateTree: TemplateNode | null;\n}\n\nexport interface ProjectAnalysis {\n tool: 'uniappx-keymap-devtools';\n version: string;\n targetRoot: string;\n generatedAt: string;\n pages: Record<string, PageAnalysis>;\n}\n\ninterface GeneratedPattern {\n re: RegExp;\n name: string;\n kind: string;\n}\n\ninterface ParsedProperty {\n key: string;\n expression: string;\n}\n\ninterface InferredExpression {\n sourceName: string | null;\n generatedName: string | null;\n kind: string;\n confidence: Confidence;\n expressionSummary: string;\n}\n\nconst TEMPLATE_EXTENSIONS = ['.wxml'];\nconst NATIVE_TEMPLATE_TAGS = new Set([\n 'view',\n 'text',\n 'image',\n 'button',\n 'input',\n 'textarea',\n 'scroll-view',\n 'swiper',\n 'swiper-item',\n 'icon',\n 'progress',\n 'rich-text',\n 'checkbox',\n 'checkbox-group',\n 'radio',\n 'radio-group',\n 'switch',\n 'slider',\n 'picker',\n 'picker-view',\n 'picker-view-column',\n 'navigator',\n 'form',\n 'label',\n 'map',\n 'canvas',\n 'camera',\n 'video',\n 'live-player',\n 'live-pusher',\n 'movable-area',\n 'movable-view',\n 'cover-view',\n 'cover-image',\n 'slot',\n 'block',\n 'template',\n 'ad',\n 'open-data',\n 'official-account',\n 'editor',\n 'page-meta',\n 'navigation-bar',\n 'match-media',\n 'sticky-section',\n 'sticky-header',\n]);\n\nconst GENERATED_PATTERNS: GeneratedPattern[] = [\n {\n re: /\\bsei\\s*\\(\\s*common_vendor\\.gei|common_vendor\\.sei\\s*\\(\\s*common_vendor\\.gei|\\bgei\\s*\\(/,\n name: 'generated element id',\n kind: 'element-id',\n },\n { re: /common_assets\\._imports_\\d+|\\b_imports_\\d+\\b/, name: 'generated static asset', kind: 'static-asset' },\n { re: /u_s_b_h/, name: 'generated CSS var --status-bar-height', kind: 'css-var' },\n { re: /u_s_a_i_b/, name: 'generated CSS var --uni-safe-area-inset-bottom', kind: 'css-var' },\n { re: /virtualHostClass/, name: 'generated virtualHostClass', kind: 'virtual-host-class' },\n { re: /virtualHostStyle/, name: 'generated virtualHostStyle', kind: 'virtual-host-style' },\n { re: /virtualHostHidden/, name: 'generated virtualHostHidden', kind: 'virtual-host-hidden' },\n];\n\nfunction walkFiles(root: string, predicate?: (file: string) => boolean): string[] {\n const output: string[] = [];\n function walk(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const name of fs.readdirSync(dir)) {\n const full = path.join(dir, name);\n const stat = fs.statSync(full);\n if (stat.isDirectory()) walk(full);\n else if (!predicate || predicate(full)) output.push(full);\n }\n }\n walk(root);\n return output;\n}\n\nfunction normalizeSlashes(value: string): string {\n return value.split(path.sep).join('/');\n}\n\nfunction stripJsComments(input: string): string {\n let output = '';\n let state: 'normal' | 'line' | 'block' | '\"' | \"'\" | '`' = 'normal';\n\n for (let index = 0; index < input.length; index += 1) {\n const ch = input[index];\n const next = input[index + 1];\n\n if (state === 'normal') {\n if (ch === '/' && next === '/') {\n state = 'line';\n output += ' ';\n index += 1;\n } else if (ch === '/' && next === '*') {\n state = 'block';\n output += ' ';\n index += 1;\n } else if (ch === '\"' || ch === \"'\" || ch === '`') {\n state = ch;\n output += ch;\n } else {\n output += ch;\n }\n } else if (state === 'line') {\n if (ch === '\\n') {\n state = 'normal';\n output += ch;\n } else {\n output += ' ';\n }\n } else if (state === 'block') {\n if (ch === '*' && next === '/') {\n state = 'normal';\n output += ' ';\n index += 1;\n } else {\n output += ch === '\\n' ? '\\n' : ' ';\n }\n } else {\n output += ch;\n if (ch === '\\\\') {\n index += 1;\n output += input[index] || '';\n } else if (ch === state) {\n state = 'normal';\n }\n }\n }\n return output;\n}\n\nfunction findMatchingBrace(input: string, openIndex: number): number {\n let depth = 0;\n let state: 'normal' | '\"' | \"'\" | '`' = 'normal';\n\n for (let index = openIndex; index < input.length; index += 1) {\n const ch = input[index];\n if (state === 'normal') {\n if (ch === '\"' || ch === \"'\" || ch === '`') state = ch;\n else if (ch === '{') depth += 1;\n else if (ch === '}') {\n depth -= 1;\n if (depth === 0) return index;\n }\n } else if (ch === '\\\\') {\n index += 1;\n } else if (ch === state) {\n state = 'normal';\n }\n }\n return -1;\n}\n\nexport function extractReturnedObject(js: string): string | null {\n const marker = 'const __returned__ =';\n const start = js.indexOf(marker);\n if (start !== -1) {\n const open = js.indexOf('{', start + marker.length);\n if (open === -1) return null;\n const close = findMatchingBrace(js, open);\n if (close === -1) return null;\n return js.slice(open + 1, close);\n }\n return extractRenderReturnObject(js) || extractSetupRenderReturnObject(js);\n}\n\nfunction extractRenderReturnObject(js: string): string | null {\n const marker = 'function _sfc_render';\n const start = js.indexOf(marker);\n if (start === -1) return null;\n\n const open = js.indexOf('{', start + marker.length);\n if (open === -1) return null;\n const close = findMatchingBrace(js, open);\n if (close === -1) return null;\n\n const body = js.slice(open + 1, close);\n let state: 'normal' | '\"' | \"'\" | '`' = 'normal';\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n\n for (let index = 0; index < body.length; index += 1) {\n const ch = body[index];\n if (state === 'normal') {\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n state = ch;\n } else if (ch === '(') {\n depthParen += 1;\n } else if (ch === ')') {\n depthParen -= 1;\n } else if (ch === '[') {\n depthBracket += 1;\n } else if (ch === ']') {\n depthBracket -= 1;\n } else if (ch === '{') {\n depthBrace += 1;\n } else if (ch === '}') {\n depthBrace -= 1;\n } else if (\n depthParen === 0 &&\n depthBracket === 0 &&\n depthBrace === 0 &&\n body.startsWith('return', index) &&\n !/[A-Za-z0-9_$]/.test(body[index - 1] || '') &&\n !/[A-Za-z0-9_$]/.test(body[index + 6] || '')\n ) {\n let probe = index + 6;\n while (/\\s/.test(body[probe] || '')) probe += 1;\n if (body[probe] !== '{') return null;\n const returnClose = findMatchingBrace(body, probe);\n if (returnClose === -1) return null;\n return body.slice(probe + 1, returnClose);\n }\n } else if (ch === '\\\\') {\n index += 1;\n } else if (ch === state) {\n state = 'normal';\n }\n }\n\n return null;\n}\n\nfunction extractSetupRenderReturnObject(js: string): string | null {\n const re = /return\\s*\\([^)]*\\)\\s*=>\\s*\\{/g;\n let match: RegExpExecArray | null = re.exec(js);\n\n while (match) {\n const currentMatch = match;\n match = re.exec(js);\n const open = js.indexOf('{', currentMatch.index);\n if (open === -1) continue;\n const close = findMatchingBrace(js, open);\n if (close === -1) continue;\n const body = js.slice(open + 1, close);\n const returned = extractTopLevelReturnObject(body);\n if (returned) return returned;\n }\n\n return null;\n}\n\nfunction extractTopLevelReturnObject(body: string): string | null {\n let state: 'normal' | '\"' | \"'\" | '`' = 'normal';\n let depthParen = 0;\n let depthBracket = 0;\n let depthBrace = 0;\n\n for (let index = 0; index < body.length; index += 1) {\n const ch = body[index];\n if (state === 'normal') {\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n state = ch;\n } else if (ch === '(') {\n depthParen += 1;\n } else if (ch === ')') {\n depthParen -= 1;\n } else if (ch === '[') {\n depthBracket += 1;\n } else if (ch === ']') {\n depthBracket -= 1;\n } else if (ch === '{') {\n depthBrace += 1;\n } else if (ch === '}') {\n depthBrace -= 1;\n } else if (\n depthParen === 0 &&\n depthBracket === 0 &&\n depthBrace === 0 &&\n body.startsWith('return', index) &&\n !/[A-Za-z0-9_$]/.test(body[index - 1] || '') &&\n !/[A-Za-z0-9_$]/.test(body[index + 6] || '')\n ) {\n let probe = index + 6;\n while (/\\s/.test(body[probe] || '')) probe += 1;\n if (body[probe] !== '{') continue;\n const returnClose = findMatchingBrace(body, probe);\n if (returnClose === -1) return null;\n return body.slice(probe + 1, returnClose);\n }\n } else if (ch === '\\\\') {\n index += 1;\n } else if (ch === state) {\n state = 'normal';\n }\n }\n\n return null;\n}\n\nexport function splitTopLevelProperties(body: string): string[] {\n const props: string[] = [];\n let state: 'normal' | '\"' | \"'\" | '`' = 'normal';\n let depthParen = 0;\n let depthBrace = 0;\n let depthBracket = 0;\n let start = 0;\n\n function push(end: number): void {\n const part = body.slice(start, end).trim();\n if (part) props.push(part);\n start = end + 1;\n }\n\n for (let index = 0; index < body.length; index += 1) {\n const ch = body[index];\n if (state === 'normal') {\n if (ch === '\"' || ch === \"'\" || ch === '`') state = ch;\n else if (ch === '(') depthParen += 1;\n else if (ch === ')') depthParen -= 1;\n else if (ch === '{') depthBrace += 1;\n else if (ch === '}') depthBrace -= 1;\n else if (ch === '[') depthBracket += 1;\n else if (ch === ']') depthBracket -= 1;\n else if (ch === ',' && depthParen === 0 && depthBrace === 0 && depthBracket === 0) push(index);\n } else if (ch === '\\\\') {\n index += 1;\n } else if (ch === state) {\n state = 'normal';\n }\n }\n push(body.length);\n return props;\n}\n\nexport function parseProperty(part: string): ParsedProperty | null {\n let state: 'normal' | '\"' | \"'\" | '`' = 'normal';\n let depthParen = 0;\n let depthBrace = 0;\n let depthBracket = 0;\n\n for (let index = 0; index < part.length; index += 1) {\n const ch = part[index];\n if (state === 'normal') {\n if (ch === '\"' || ch === \"'\" || ch === '`') state = ch;\n else if (ch === '(') depthParen += 1;\n else if (ch === ')') depthParen -= 1;\n else if (ch === '{') depthBrace += 1;\n else if (ch === '}') depthBrace -= 1;\n else if (ch === '[') depthBracket += 1;\n else if (ch === ']') depthBracket -= 1;\n else if (ch === ':' && depthParen === 0 && depthBrace === 0 && depthBracket === 0) {\n const rawKey = part.slice(0, index).trim();\n const key = rawKey.replace(/^['\"]|['\"]$/g, '');\n return { key, expression: part.slice(index + 1).trim() };\n }\n } else if (ch === '\\\\') {\n index += 1;\n } else if (ch === state) {\n state = 'normal';\n }\n }\n return null;\n}\n\nfunction extractSetupBindings(js: string): Set<string> {\n const names = new Set<string>();\n const blocked = new Set(['__returned__', 'common_vendor', '_sfc_main']);\n const variableRe = /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\b/g;\n const functionRe = /\\bfunction\\s+([A-Za-z_$][\\w$]*)\\s*\\(/g;\n let match: RegExpExecArray | null = variableRe.exec(js);\n\n while (match) {\n if (!blocked.has(match[1])) names.add(match[1]);\n match = variableRe.exec(js);\n }\n match = functionRe.exec(js);\n while (match) {\n if (!blocked.has(match[1])) names.add(match[1]);\n match = functionRe.exec(js);\n }\n return names;\n}\n\nexport function inferFromExpression(expression: string, setupBindings: Set<string>): InferredExpression {\n const normalized = expression.replace(/\\s+/g, ' ');\n for (const item of GENERATED_PATTERNS) {\n if (item.re.test(expression)) {\n return {\n sourceName: null,\n generatedName: item.name,\n kind: item.kind,\n confidence: 'generated',\n expressionSummary: normalized,\n };\n }\n }\n\n const eventMatch = expression.match(/(?:common_vendor\\.)?o\\s*\\(\\s*([A-Za-z_$][\\w$]*)/);\n if (eventMatch) {\n return {\n sourceName: eventMatch[1],\n generatedName: null,\n kind: 'event-handler',\n confidence: 'high',\n expressionSummary: normalized,\n };\n }\n\n const unrefMatch = expression.match(/(?:common_vendor\\.)?unref\\s*\\(\\s*([A-Za-z_$][\\w$]*)\\s*\\)/);\n if (unrefMatch) {\n return {\n sourceName: unrefMatch[1],\n generatedName: null,\n kind: 'binding',\n confidence: 'high',\n expressionSummary: normalized,\n };\n }\n\n const refValueMatch = expression.match(/\\b([A-Za-z_$][\\w$]*)\\.value\\b/);\n if (refValueMatch && setupBindings.has(refValueMatch[1])) {\n return {\n sourceName: refValueMatch[1],\n generatedName: null,\n kind: 'binding',\n confidence: 'high',\n expressionSummary: normalized,\n };\n }\n\n const instanceValueMatch = expression.match(/\\$(?:data|setup|props|options)\\.([A-Za-z_$][\\w$]*)/);\n if (instanceValueMatch) {\n return {\n sourceName: instanceValueMatch[1],\n generatedName: null,\n kind: 'binding',\n confidence: 'high',\n expressionSummary: normalized,\n };\n }\n\n const directNames: string[] = [];\n for (const name of setupBindings) {\n const re = new RegExp(`(^|[^\\\\w$])${escapeRegExp(name)}([^\\\\w$]|$)`);\n if (re.test(expression)) directNames.push(name);\n }\n\n if (directNames.length === 1) {\n return {\n sourceName: directNames[0],\n generatedName: null,\n kind: 'binding',\n confidence: 'medium',\n expressionSummary: normalized,\n };\n }\n\n if (directNames.length > 1) {\n return {\n sourceName: directNames.join(', '),\n generatedName: null,\n kind: 'expression',\n confidence: 'medium',\n expressionSummary: normalized,\n };\n }\n\n return {\n sourceName: null,\n generatedName: null,\n kind: 'unknown',\n confidence: 'low',\n expressionSummary: normalized,\n };\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction findWxmlUsages(wxml: string, key: string): WxmlUsage[] {\n if (!wxml) return [];\n const usages: WxmlUsage[] = [];\n const re = new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(key)}([^A-Za-z0-9_$]|$)`, 'g');\n let match: RegExpExecArray | null = re.exec(wxml);\n\n while (match) {\n const index = match.index + match[1].length;\n const start = Math.max(0, index - 45);\n const end = Math.min(wxml.length, index + key.length + 45);\n const snippet = wxml.slice(start, end).replace(/\\s+/g, ' ').trim();\n usages.push({ index, snippet });\n if (usages.length >= 8) break;\n match = re.exec(wxml);\n }\n return usages;\n}\n\nfunction extractTemplateKeyRefs(source: string, keys: string[]): string[] {\n const matched = new Set<string>();\n for (const key of keys) {\n const re = new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(key)}([^A-Za-z0-9_$]|$)`);\n if (re.test(source)) matched.add(key);\n }\n return Array.from(matched);\n}\n\nfunction normalizeSnippet(value: string, limit = 120): string {\n const normalized = value.replace(/\\s+/g, ' ').trim();\n return normalized.length > limit ? `${normalized.slice(0, limit - 1)}...` : normalized;\n}\n\nfunction classifyTemplateTag(tag: string): 'element' | 'component' {\n return NATIVE_TEMPLATE_TAGS.has(tag) ? 'element' : 'component';\n}\n\nfunction parseTemplateAttributes(source: string): TemplateAttribute[] {\n const attrs: TemplateAttribute[] = [];\n const attrSource = source.replace(/^<[^/\\s>]+/, '').replace(/\\/?>$/, '');\n const re = /([:@A-Za-z0-9._-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'))?/g;\n let match: RegExpExecArray | null = re.exec(attrSource);\n while (match) {\n attrs.push({\n name: match[1],\n value: match[2] ?? match[3] ?? '',\n });\n match = re.exec(attrSource);\n }\n return attrs;\n}\n\nfunction parseTemplateTree(wxml: string, keys: KeyMapItem[]): TemplateNode | null {\n if (!wxml.trim()) return null;\n\n const keyNames = keys.map((item) => item.key);\n const root: TemplateNode = {\n id: 'root',\n tag: 'page',\n kind: 'element',\n snippet: 'page',\n keyRefs: [],\n attrs: [],\n text: null,\n children: [],\n };\n const stack: TemplateNode[] = [root];\n const tokenRe = /<!--[\\s\\S]*?-->|<\\/?[^>]+>|[^<]+/g;\n let match: RegExpExecArray | null = tokenRe.exec(wxml);\n let counter = 0;\n\n while (match) {\n const token = match[0];\n if (!token || token.startsWith('<!--')) {\n match = tokenRe.exec(wxml);\n continue;\n }\n\n if (token.startsWith('</')) {\n if (stack.length > 1) stack.pop();\n match = tokenRe.exec(wxml);\n continue;\n }\n\n if (token.startsWith('<')) {\n const tagMatch = token.match(/^<\\s*([^\\s/>]+)/);\n if (!tagMatch) {\n match = tokenRe.exec(wxml);\n continue;\n }\n const tag = tagMatch[1];\n counter += 1;\n const node: TemplateNode = {\n id: `node-${counter}`,\n tag,\n kind: classifyTemplateTag(tag),\n snippet: normalizeSnippet(token),\n keyRefs: extractTemplateKeyRefs(token, keyNames),\n attrs: parseTemplateAttributes(token),\n text: null,\n children: [],\n };\n stack[stack.length - 1].children.push(node);\n if (!/\\/>$/.test(token) && !token.startsWith('<input')) stack.push(node);\n match = tokenRe.exec(wxml);\n continue;\n }\n\n const text = normalizeSnippet(token, 80);\n if (!text) {\n match = tokenRe.exec(wxml);\n continue;\n }\n counter += 1;\n stack[stack.length - 1].children.push({\n id: `node-${counter}`,\n tag: '#text',\n kind: 'text',\n snippet: text,\n keyRefs: extractTemplateKeyRefs(token, keyNames),\n attrs: [],\n text,\n children: [],\n });\n match = tokenRe.exec(wxml);\n }\n\n return root;\n}\n\nfunction readSourceMap(targetRoot: string, jsFile: string): SourceMapInfo | null {\n const js = fs.readFileSync(jsFile, 'utf8');\n const match = js.match(/\\/\\/# sourceMappingURL=(.+)$/m);\n if (!match) return null;\n\n const mapPath = path.resolve(path.dirname(jsFile), match[1]);\n if (!mapPath.startsWith(path.dirname(targetRoot)) || !fs.existsSync(mapPath)) return null;\n\n try {\n const map = JSON.parse(fs.readFileSync(mapPath, 'utf8')) as Partial<SourceMapInfo>;\n return {\n path: normalizeSlashes(path.relative(targetRoot, mapPath)),\n sources: Array.isArray(map.sources) ? map.sources : [],\n sourcesContent: Array.isArray(map.sourcesContent) ? map.sourcesContent : [],\n names: Array.isArray(map.names) ? map.names : [],\n };\n } catch (_error) {\n return null;\n }\n}\n\nfunction findTemplateFile(jsFile: string): string | null {\n for (const extension of TEMPLATE_EXTENSIONS) {\n const file = jsFile.replace(/\\.js$/, extension);\n if (fs.existsSync(file)) return file;\n }\n return null;\n}\n\nexport function analyzePage(targetRoot: string, jsFile: string): PageAnalysis {\n const js = fs.readFileSync(jsFile, 'utf8');\n const jsNoComments = stripJsComments(js);\n const relJs = normalizeSlashes(path.relative(targetRoot, jsFile));\n const page = relJs.replace(/\\.js$/, '');\n const wxmlFile = findTemplateFile(jsFile);\n const wxml = wxmlFile ? fs.readFileSync(wxmlFile, 'utf8') : '';\n const sourceMap = readSourceMap(targetRoot, jsFile);\n const setupBindings = extractSetupBindings(jsNoComments);\n const body = extractReturnedObject(jsNoComments);\n const keys: KeyMapItem[] = [];\n\n if (body) {\n for (const part of splitTopLevelProperties(body)) {\n const parsed = parseProperty(part);\n if (!parsed || !parsed.key) continue;\n const inferred = inferFromExpression(parsed.expression, setupBindings);\n keys.push({\n key: parsed.key,\n ...inferred,\n expression: parsed.expression,\n wxmlUsages: findWxmlUsages(wxml, parsed.key),\n });\n }\n }\n\n const templateTree = parseTemplateTree(wxml, keys);\n\n return {\n page,\n jsFile: relJs,\n wxmlFile: wxmlFile ? normalizeSlashes(path.relative(targetRoot, wxmlFile)) : null,\n sourceMap,\n keys,\n templateTree,\n };\n}\n\nexport function analyzeProject(targetRoot: string): ProjectAnalysis {\n if (!fs.existsSync(targetRoot)) throw new Error(`Target does not exist: ${targetRoot}`);\n\n const jsFiles = walkFiles(\n targetRoot,\n (file) => file.endsWith('.js') && !file.includes(`${path.sep}common${path.sep}`),\n );\n const pageFiles = jsFiles.filter((file) => {\n const js = fs.readFileSync(file, 'utf8');\n return js.includes('const __returned__ =') || js.includes('function _sfc_render') || !!findTemplateFile(file);\n });\n\n const pages: Record<string, PageAnalysis> = {};\n for (const file of pageFiles) {\n const page = analyzePage(targetRoot, file);\n pages[page.page] = page;\n }\n\n return {\n tool: 'uniappx-keymap-devtools',\n version: '0.1.0',\n targetRoot,\n generatedAt: new Date().toISOString(),\n pages,\n };\n}\n"],"mappings":"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"}
|