Skip to content

Commit 2255280

Browse files
committed
fix(scripts): 判据的实参窗口排除左括号,嵌套调用不再算作读取调用
`[^)'"`]{0,80}` 排除了右括号却没排除左括号,于是 `find(wrap('sys_user_position'))` 会被判为「read call 读取该表」—— 表名其实是内层调用的实参,不是这次读取的。 与该正则自己注释里的声明(「是这次调用的靠前实参,而非嵌套在其中之物」)不符。 改为 `[^()'"`]{0,80}`。真实语料命中面不变(仍是规范解析器 + explain-engine 两个,门禁真实运行仍绿),这是精度修正而非收窄结果。 self-test 补上 11 条读取调用拼法断言,把召回侧钉死: - 肯定式(会红):member 调用、helper 调用带前置实参(规范解析器用的正是 tryFind 这种拼法,丢了它阳性对照本身就会塌)、双引号、模板字面量、实参换行; - 否定式(平凡成立,仅备案):注释、常量表、无引号对象键、Set 字面量、 页面元数据,以及本次修的嵌套调用。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
1 parent c2c25bd commit 2255280

1 file changed

Lines changed: 30 additions & 1 deletion

File tree

scripts/check-single-authz-resolver.mjs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ const READ_VERBS = 'find|query|select|count|aggregate';
247247
function readCallPattern(table) {
248248
return new RegExp(
249249
'[\\w$.]*(?:' + READ_VERBS + ')[\\w$]*\\s*\\(\\s*' + // callee + open paren
250-
'[^)\'"`]{0,80}' + // earlier plain arguments, if any
250+
'[^()\'"`]{0,80}' + // earlier plain arguments, if any
251251
'[\'"`]' + table + '[\'"`]', // the table, quoted
252252
'i',
253253
);
@@ -613,6 +613,35 @@ function selfTest() {
613613
expect(`querying only ${t} is not a resolver`, queriesAllGrantTables(resolverFixtureBody([t])), false);
614614
}
615615

616+
// --- The read-call spellings the criterion must recognise (POSITIVE polarity). ---
617+
// These go red if READ_VERBS is narrowed or the argument pattern regresses — the
618+
// recall side of the criterion, which no fixture above can reach because
619+
// `resolverFixtureBody` only ever emits `ql.find`. The canonical resolver uses the
620+
// `tryFind` HELPER spelling, so losing it would break the positive control itself.
621+
const t0 = GRANT_TABLES[0];
622+
for (const [label, src] of [
623+
['member call', `ql.find('${t0}', { where: {} })`],
624+
['helper call with a leading argument', `await tryFind(ql, '${t0}', { user_id }, 200)`],
625+
['double quotes', `ql.find("${t0}")`],
626+
['template literal', 'dataEngine.findOne(`' + t0 + '`)'],
627+
['argument on the next line', `this.ql.find(\n '${t0}',\n { limit: 1 })`],
628+
]) {
629+
expect(`a read call is recognised — ${label}`, queriesGrantTable(src, t0), true);
630+
}
631+
// ...and the shapes that merely CONTAIN the name are not read calls (negative
632+
// polarity, listed for the record). The nested-call case is the sharp one: the table
633+
// must be an argument of the READ call, not of something nested inside it.
634+
for (const [label, src] of [
635+
['a comment', `// we read ${t0} here`],
636+
['a constant list', `const NAMES = ['${t0}'];`],
637+
['an unquoted object key', `${t0}: { allowRead: true },`],
638+
['a Set literal', `new Set(['${t0}'])`],
639+
['page metadata', `objectName: '${t0}',`],
640+
['a nested call inside a read call', `find(wrap('${t0}'))`],
641+
]) {
642+
expect(`not a read call — ${label}`, queriesGrantTable(src, t0), false);
643+
}
644+
616645
// (1) — a second file reading rows from every grant table is a duplicate resolver.
617646
write('packages/rest/src/my-own-resolver.ts', resolverFixtureBody());
618647
const dupErrors = audit(dir);

0 commit comments

Comments
 (0)