@nocobase/flow-engine 2.0.36 → 2.0.38
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/lib/utils/runjsValue.js +41 -11
- package/package.json +4 -4
- package/src/utils/__tests__/runjsValue.test.ts +11 -0
- package/src/utils/runjsValue.ts +50 -11
package/lib/utils/runjsValue.js
CHANGED
|
@@ -231,6 +231,34 @@ function normalizeSubPath(raw) {
|
|
|
231
231
|
return { subPath: s, wildcard: false };
|
|
232
232
|
}
|
|
233
233
|
__name(normalizeSubPath, "normalizeSubPath");
|
|
234
|
+
function extractCtxRootUsage(expr) {
|
|
235
|
+
const raw = String(expr || "").trim();
|
|
236
|
+
if (!raw || raw === "ctx") return null;
|
|
237
|
+
const dotMatch = raw.match(/^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)([\s\S]*)$/);
|
|
238
|
+
if (dotMatch) {
|
|
239
|
+
const varName = dotMatch[1] || "";
|
|
240
|
+
const rest = dotMatch[2] || "";
|
|
241
|
+
const normalized = normalizeSubPath(rest);
|
|
242
|
+
return {
|
|
243
|
+
varName,
|
|
244
|
+
subPath: normalized.subPath,
|
|
245
|
+
wildcard: normalized.wildcard
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const bracketMatch = raw.match(/^ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]([\s\S]*)$/);
|
|
249
|
+
if (bracketMatch) {
|
|
250
|
+
const varName = bracketMatch[2] || "";
|
|
251
|
+
const rest = bracketMatch[3] || "";
|
|
252
|
+
const normalized = normalizeSubPath(rest);
|
|
253
|
+
return {
|
|
254
|
+
varName,
|
|
255
|
+
subPath: normalized.subPath,
|
|
256
|
+
wildcard: normalized.wildcard
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
__name(extractCtxRootUsage, "extractCtxRootUsage");
|
|
234
262
|
function extractUsedVariablePathsFromRunJS(code) {
|
|
235
263
|
if (typeof code !== "string" || !code.trim()) return {};
|
|
236
264
|
const src = stripStringsAndComments(code);
|
|
@@ -242,23 +270,25 @@ function extractUsedVariablePathsFromRunJS(code) {
|
|
|
242
270
|
set.add(subPath || "");
|
|
243
271
|
usage.set(varName, set);
|
|
244
272
|
}, "add");
|
|
273
|
+
const addCtxUsage = /* @__PURE__ */ __name((expr) => {
|
|
274
|
+
const hit = extractCtxRootUsage(expr);
|
|
275
|
+
if (!(hit == null ? void 0 : hit.varName)) return;
|
|
276
|
+
add(hit.varName, hit.wildcard ? "" : hit.subPath);
|
|
277
|
+
}, "addCtxUsage");
|
|
245
278
|
const dotRe = /ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*(?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
|
|
246
279
|
let match;
|
|
247
280
|
while (match = dotRe.exec(src)) {
|
|
248
|
-
|
|
249
|
-
const firstKeyMatch = pathAfterCtx.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
|
|
250
|
-
if (!firstKeyMatch) continue;
|
|
251
|
-
const firstKey = firstKeyMatch[1];
|
|
252
|
-
const rest = pathAfterCtx.slice(firstKey.length);
|
|
253
|
-
const { subPath, wildcard } = normalizeSubPath(rest);
|
|
254
|
-
add(firstKey, wildcard ? "" : subPath);
|
|
281
|
+
addCtxUsage(`ctx.${match[1] || ""}`);
|
|
255
282
|
}
|
|
256
283
|
const bracketRootRe = /ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]((?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
|
|
257
284
|
while (match = bracketRootRe.exec(srcWithStrings)) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
285
|
+
addCtxUsage(`ctx['${match[2] || ""}']${match[3] || ""}`);
|
|
286
|
+
}
|
|
287
|
+
const getVarRe = /ctx\.getVar\s*\(\s*(['"])((?:\\.|(?!\1)[\s\S])*)\1\s*\)/g;
|
|
288
|
+
while (match = getVarRe.exec(srcWithStrings)) {
|
|
289
|
+
const expr = String(match[2] || "").replace(/\\'/g, "'").replace(/\\"/g, '"').trim();
|
|
290
|
+
if (!expr.startsWith("ctx")) continue;
|
|
291
|
+
addCtxUsage(expr);
|
|
262
292
|
}
|
|
263
293
|
const out = {};
|
|
264
294
|
for (const [k, set] of usage.entries()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/flow-engine",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.38",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@formily/antd-v5": "1.x",
|
|
10
10
|
"@formily/reactive": "2.x",
|
|
11
|
-
"@nocobase/sdk": "2.0.
|
|
12
|
-
"@nocobase/shared": "2.0.
|
|
11
|
+
"@nocobase/sdk": "2.0.38",
|
|
12
|
+
"@nocobase/shared": "2.0.38",
|
|
13
13
|
"ahooks": "^3.7.2",
|
|
14
14
|
"axios": "^1.7.0",
|
|
15
15
|
"dayjs": "^1.11.9",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
],
|
|
38
38
|
"author": "NocoBase Team",
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "965dc05b53b2303e58dfc2c80fea91168d9ca794"
|
|
41
41
|
}
|
|
@@ -41,4 +41,15 @@ describe('runjsValue utils', () => {
|
|
|
41
41
|
expect(out.someVar).toContain('');
|
|
42
42
|
expect(out.user).toContain('name');
|
|
43
43
|
});
|
|
44
|
+
|
|
45
|
+
it('extractUsedVariablePathsFromRunJS: extracts ctx.getVar string paths', () => {
|
|
46
|
+
const code = `
|
|
47
|
+
const phone = await ctx.getVar('ctx.item.value.phone');
|
|
48
|
+
const assignee = await ctx.getVar("ctx.user.profile.name");
|
|
49
|
+
return [phone, assignee];
|
|
50
|
+
`;
|
|
51
|
+
const out = extractUsedVariablePathsFromRunJS(code);
|
|
52
|
+
expect(out.item).toContain('value.phone');
|
|
53
|
+
expect(out.user).toContain('profile.name');
|
|
54
|
+
});
|
|
44
55
|
});
|
package/src/utils/runjsValue.ts
CHANGED
|
@@ -236,6 +236,37 @@ function normalizeSubPath(raw: string): { subPath: string; wildcard: boolean } {
|
|
|
236
236
|
return { subPath: s, wildcard: false };
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
function extractCtxRootUsage(expr: string): { varName: string; subPath: string; wildcard: boolean } | null {
|
|
240
|
+
const raw = String(expr || '').trim();
|
|
241
|
+
if (!raw || raw === 'ctx') return null;
|
|
242
|
+
|
|
243
|
+
const dotMatch = raw.match(/^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)([\s\S]*)$/);
|
|
244
|
+
if (dotMatch) {
|
|
245
|
+
const varName = dotMatch[1] || '';
|
|
246
|
+
const rest = dotMatch[2] || '';
|
|
247
|
+
const normalized = normalizeSubPath(rest);
|
|
248
|
+
return {
|
|
249
|
+
varName,
|
|
250
|
+
subPath: normalized.subPath,
|
|
251
|
+
wildcard: normalized.wildcard,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const bracketMatch = raw.match(/^ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]([\s\S]*)$/);
|
|
256
|
+
if (bracketMatch) {
|
|
257
|
+
const varName = bracketMatch[2] || '';
|
|
258
|
+
const rest = bracketMatch[3] || '';
|
|
259
|
+
const normalized = normalizeSubPath(rest);
|
|
260
|
+
return {
|
|
261
|
+
varName,
|
|
262
|
+
subPath: normalized.subPath,
|
|
263
|
+
wildcard: normalized.wildcard,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
239
270
|
/**
|
|
240
271
|
* Heuristic extraction of ctx variable usage from RunJS code.
|
|
241
272
|
*
|
|
@@ -256,27 +287,35 @@ export function extractUsedVariablePathsFromRunJS(code: string): Record<string,
|
|
|
256
287
|
usage.set(varName, set);
|
|
257
288
|
};
|
|
258
289
|
|
|
290
|
+
const addCtxUsage = (expr: string) => {
|
|
291
|
+
const hit = extractCtxRootUsage(expr);
|
|
292
|
+
if (!hit?.varName) return;
|
|
293
|
+
add(hit.varName, hit.wildcard ? '' : hit.subPath);
|
|
294
|
+
};
|
|
295
|
+
|
|
259
296
|
// dot form: ctx.foo.bar / ctx.foo[0].bar (excluding ctx.method(...))
|
|
260
297
|
const dotRe = /ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*(?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
|
|
261
298
|
let match: RegExpExecArray | null;
|
|
262
299
|
while ((match = dotRe.exec(src))) {
|
|
263
|
-
|
|
264
|
-
const firstKeyMatch = pathAfterCtx.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
|
|
265
|
-
if (!firstKeyMatch) continue;
|
|
266
|
-
const firstKey = firstKeyMatch[1];
|
|
267
|
-
const rest = pathAfterCtx.slice(firstKey.length);
|
|
268
|
-
const { subPath, wildcard } = normalizeSubPath(rest);
|
|
269
|
-
add(firstKey, wildcard ? '' : subPath);
|
|
300
|
+
addCtxUsage(`ctx.${match[1] || ''}`);
|
|
270
301
|
}
|
|
271
302
|
|
|
272
303
|
// bracket root: ctx['foo'].bar / ctx["foo"][0] (excluding ctx['method'](...))
|
|
273
304
|
const bracketRootRe =
|
|
274
305
|
/ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]((?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
|
|
275
306
|
while ((match = bracketRootRe.exec(srcWithStrings))) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
307
|
+
addCtxUsage(`ctx['${match[2] || ''}']${match[3] || ''}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// async-safe helper form: await ctx.getVar('ctx.foo.bar')
|
|
311
|
+
const getVarRe = /ctx\.getVar\s*\(\s*(['"])((?:\\.|(?!\1)[\s\S])*)\1\s*\)/g;
|
|
312
|
+
while ((match = getVarRe.exec(srcWithStrings))) {
|
|
313
|
+
const expr = String(match[2] || '')
|
|
314
|
+
.replace(/\\'/g, "'")
|
|
315
|
+
.replace(/\\"/g, '"')
|
|
316
|
+
.trim();
|
|
317
|
+
if (!expr.startsWith('ctx')) continue;
|
|
318
|
+
addCtxUsage(expr);
|
|
280
319
|
}
|
|
281
320
|
|
|
282
321
|
const out: Record<string, string[]> = {};
|