tackbox 0.1.96 → 0.1.98
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/README.md +46 -31
- package/bin/tackbox-eslint.js +7 -0
- package/js/README.md +7 -0
- package/js/omp/index.js +2 -2
- package/js/rules/_shared.js +47 -19
- package/js/rules/no-broad-notify.js +4 -3
- package/js/rules/no-parse-fallback.js +2 -3
- package/js/rules/no-skipped-test.js +3 -5
- package/js/rules/no-swallow-allsettled.js +2 -3
- package/js/rules/no-swallow-catch.js +2 -3
- package/js/rules/no-swallow-promise-catch.js +2 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,12 +163,12 @@ past (argparse misuse, and the per-command cases below).
|
|
|
163
163
|
`--draft` is a generator, not a gate: `0` when every uncovered
|
|
164
164
|
marker was drafted (an orphan-only tree included), `2` only when
|
|
165
165
|
unresolvable files leave the draft incomplete.
|
|
166
|
-
- **hook** - `0` a no-op, a clean event, or a JSON decision (
|
|
167
|
-
|
|
166
|
+
- **hook** - `0` a no-op, a clean event, or a JSON pre decision (an
|
|
167
|
+
approval prompt or a refusal before an unrelated edit); `1` a
|
|
168
168
|
non-blocking infra error (unreadable stdin, a git failure); `2` a
|
|
169
|
-
PostToolUse finding on
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
PostToolUse finding on edited lines, a non-compiling Go package, or
|
|
170
|
+
session approvals debt in a touched file. A post error reports a
|
|
171
|
+
mutation that already landed; it does not block or undo the write.
|
|
172
172
|
- **hook-protocol** - `0` whenever a decision was reached, whatever the
|
|
173
173
|
decision says (it rides the JSON on stdout, never the exit code); `1`
|
|
174
174
|
plus one stderr line when none was: unreadable stdin, or a request
|
|
@@ -473,8 +473,8 @@ scopes (lambdas, arrows, IIFEs) appear as 8-hex content hashes; Java
|
|
|
473
473
|
overloads carry a parameter-type signature; same-name siblings take
|
|
474
474
|
an `@k` ordinal. Repeat the line for each identical occurrence.
|
|
475
475
|
|
|
476
|
-
|
|
477
|
-
marker without a covering entry and an entry without a live marker
|
|
476
|
+
For `tackbox lint` and `tackbox approvals`, the bidirectional check covers the whole tree:
|
|
477
|
+
a marker without a covering entry and an entry without a live marker
|
|
478
478
|
(an orphan) are both findings, reported by `tackbox lint` under the
|
|
479
479
|
`approvals (whole tree):` header whatever the lint scope.
|
|
480
480
|
`tackbox approvals` runs the same check standalone;
|
|
@@ -488,11 +488,19 @@ Approving is adding the line. In an agent session the edit that adds
|
|
|
488
488
|
a manifest line draws the PreToolUse ask quoting the entry (several
|
|
489
489
|
lines in one edit draw one all-or-nothing ask), so the only route to
|
|
490
490
|
a green check passes through a visible diff and a human decision.
|
|
491
|
-
Writing a marker itself never asks - by any channel, Edit or shell
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
491
|
+
Writing a marker itself never asks - by any channel, Edit or shell.
|
|
492
|
+
New session debt blocks the next edit outside the affected marker files
|
|
493
|
+
and `.tackbox/approvals`; post-edit feedback reports debt only in touched
|
|
494
|
+
files. Bash and eval run no approvals checks. `dev.py check` and CI still
|
|
495
|
+
report all tree inconsistencies. Removing a manifest line is free; a
|
|
496
|
+
marker whose text, scope, or count changes needs its entry updated.
|
|
497
|
+
|
|
498
|
+
Approvals messages carry the suppressed rule's text, or say the marker
|
|
499
|
+
suppresses nothing when no finding is available, such as in the standalone
|
|
500
|
+
`approvals` command. Each inconsistency takes one line; no message supplies
|
|
501
|
+
an approval entry to copy. Suppressed findings stay out of ordinary lint
|
|
502
|
+
output, its exit status, and codequality. See D020 in
|
|
503
|
+
[rules/DECISIONS.md](rules/DECISIONS.md) for the session boundary.
|
|
496
504
|
|
|
497
505
|
## Generated and vendored code
|
|
498
506
|
|
|
@@ -575,15 +583,18 @@ specified in [docs/report-contracts.md](docs/report-contracts.md).
|
|
|
575
583
|
|
|
576
584
|
## Agent hook
|
|
577
585
|
|
|
578
|
-
The rules wire into a coding agent's edit loop through one shared core:
|
|
579
|
-
approval gates,
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
586
|
+
The rules wire into a coding agent's edit loop through one shared core:
|
|
587
|
+
approval gates, diff-scoped lint, and session approvals debt have the same
|
|
588
|
+
semantics whichever host drives them. Session means the worktree difference
|
|
589
|
+
from HEAD, including staged changes and untracked files; without a commit,
|
|
590
|
+
the whole tree is added. Existing debt is left to `dev.py check` and CI.
|
|
591
|
+
|
|
592
|
+
- **Post-edit** re-lints touched files (Go: their package). A finding on
|
|
593
|
+
added lines or session approvals debt in a touched file becomes a tool
|
|
594
|
+
error carrying the findings. The mutation has already landed; this is
|
|
595
|
+
not a block or rollback. Debt includes a new uncovered marker, a new
|
|
596
|
+
orphaned approval, and an approval whose marker was deleted.
|
|
597
|
+
A verified violation is always a tool error. A post event
|
|
587
598
|
that cannot be verified reports three facts: the mutation may already have
|
|
588
599
|
landed, why verification did not complete, and that the mutation must not be
|
|
589
600
|
repeated before `dev.py check`. OMP appends that warning to the model-facing
|
|
@@ -596,6 +607,10 @@ are the same whichever host drives them. In host-neutral terms:
|
|
|
596
607
|
A known target whose content is ambiguous asks when it reaches a bypass
|
|
597
608
|
surface. An unclassifiable file mutation or a failed policy dependency blocks
|
|
598
609
|
before it can run; it is never weakened into an approval prompt.
|
|
610
|
+
Session approvals debt also blocks an edit if any target is outside the
|
|
611
|
+
repair set: files of the debt's markers and `.tackbox/approvals`.
|
|
612
|
+
A multi-file edit with one unrelated target is refused as a whole.
|
|
613
|
+
The existing approval gates still apply to every permitted repair.
|
|
599
614
|
|
|
600
615
|
Only markers in files an engine would lint participate in the check
|
|
601
616
|
(D012): a marker in a Go `testdata/` path or a non-lintable fixture
|
|
@@ -658,17 +673,17 @@ the current file.
|
|
|
658
673
|
three-fact warning, omits an `isError` override so OMP preserves the host
|
|
659
674
|
state, and tells the model not to repeat the mutation before `dev.py check`.
|
|
660
675
|
- an opaque write channel (`xd://` tool devices, archive members, SQLite rows),
|
|
661
|
-
every `bash` call, and every `eval` call name no file, so they run
|
|
662
|
-
|
|
676
|
+
every `bash` call, and every `eval` call name no file, so they run
|
|
677
|
+
neither approvals checks nor targeted lint.
|
|
663
678
|
- MCP tool names are not enumerated by this extension. Their file mutations are
|
|
664
|
-
an explicit residual outside its pre gate and post
|
|
665
|
-
run `dev.py check`.
|
|
679
|
+
an explicit residual outside its pre gate and targeted post checks;
|
|
680
|
+
review their diff and run `dev.py check`.
|
|
666
681
|
- the post adapter consumes each result-detail record independently. It falls
|
|
667
682
|
back to a snapshot only for that record when the record is pruned; failed
|
|
668
683
|
records do not widen the scope of successful landed records. OMP 18.x does
|
|
669
684
|
not identify a landed subset for a single aggregate error without per-file
|
|
670
|
-
details, so Tackbox
|
|
671
|
-
|
|
685
|
+
details, so Tackbox preserves the host error and cannot safely perform
|
|
686
|
+
targeted lint for that residual. It does not run a whole-tree approvals check.
|
|
672
687
|
|
|
673
688
|
The extension runs `uvx tackbox@<npm package version> hook-protocol`. A tagged
|
|
674
689
|
wheel is built and protocol-canary tested, published to PyPI, then a successful
|
|
@@ -711,16 +726,16 @@ one JSON decision on stdout:
|
|
|
711
726
|
landed). Pre requests omit `succeeded`; post requests require the boolean
|
|
712
727
|
`succeeded`, so a failed tool is not misreported as a missing landed file.
|
|
713
728
|
- `tool` is one of `edit`, `apply_patch`, `write`, `bash`, or `eval`. `bash` and
|
|
714
|
-
`eval` are target-free
|
|
729
|
+
`eval` are target-free channels and run no approvals or targeted lint.
|
|
715
730
|
- a **target** is one file mutation with an absolute `path`, `op`, and
|
|
716
731
|
`expectedPresent`. `edit` and `write` expect the path to exist, `delete`
|
|
717
732
|
expects it absent, and a move reports an absent source plus a present
|
|
718
733
|
destination. `content` is a full replacement; otherwise `added` and
|
|
719
734
|
`removed` are text fragments. `content` and fragments are mutually exclusive.
|
|
720
735
|
`ambiguous: true` means a known target needs whole-file treatment.
|
|
721
|
-
- **zero targets** is the opaque channel:
|
|
722
|
-
|
|
723
|
-
|
|
736
|
+
- **zero targets** is the opaque channel: no approvals or targeted lint runs.
|
|
737
|
+
`unknown` is a non-empty reason only when no concrete target can be named;
|
|
738
|
+
it blocks pre and warns post.
|
|
724
739
|
- the wire decisions are `allow`, `ask`, `block`, and `warn`. The semantic
|
|
725
740
|
outcomes are inactive, allow, approval-required, violation, and unverified:
|
|
726
741
|
unverified maps to `block` pre and `warn` post. Hosts must make a post warning
|
package/bin/tackbox-eslint.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const { ESLint } = require('eslint')
|
|
5
|
+
const { setSuppressedReporter } = require('../js/rules/_shared')
|
|
5
6
|
|
|
6
7
|
const REPORTERS_FLAG = '--reporters='
|
|
7
8
|
|
|
@@ -129,6 +130,12 @@ async function main() {
|
|
|
129
130
|
process.stderr.write('tackbox-eslint: no files supplied\n')
|
|
130
131
|
process.exit(2)
|
|
131
132
|
}
|
|
133
|
+
if (machine) {
|
|
134
|
+
setSuppressedReporter(finding => {
|
|
135
|
+
const file = path.relative(process.cwd(), finding.file).split(path.sep).join('/')
|
|
136
|
+
process.stdout.write(JSON.stringify({ ...finding, file }) + '\n')
|
|
137
|
+
})
|
|
138
|
+
}
|
|
132
139
|
validateDeclarations(decls)
|
|
133
140
|
const eslint = new ESLint({
|
|
134
141
|
// Inline directives (eslint-disable ... tackbox/<rule>) would be an
|
package/js/README.md
CHANGED
|
@@ -146,6 +146,13 @@ siblings still report. Recognition reads the enclosing element's
|
|
|
146
146
|
preceding `SvelteHTMLComment` sibling; `/* ... */` block comments
|
|
147
147
|
are never markers.
|
|
148
148
|
|
|
149
|
+
The wrapper's `--machine` output retains suppressed findings with the
|
|
150
|
+
same rule text plus `suppressed`, `marker_kind`, and `marker_line`.
|
|
151
|
+
Human ESLint output and its exit status ignore them. Only the shared
|
|
152
|
+
approvals renderer presents them (D020 in
|
|
153
|
+
[../rules/DECISIONS.md](../rules/DECISIONS.md)); a marker that excuses
|
|
154
|
+
no violation produces no suppressed finding.
|
|
155
|
+
|
|
149
156
|
## Markdown
|
|
150
157
|
|
|
151
158
|
The CLI also lints `.md` files through `tackbox-mdlint`, a thin markdownlint
|
package/js/omp/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const HEADLESS_NOTE =
|
|
|
9
9
|
'tackbox cannot ask here (no interactive session), so the call is blocked' +
|
|
10
10
|
' instead of approved. Re-issue it interactively, or drop the gated line.'
|
|
11
11
|
const DENIED = 'tackbox: approval denied.'
|
|
12
|
-
const
|
|
12
|
+
const FINDINGS = 'tackbox found issues after this change:'
|
|
13
13
|
|
|
14
14
|
module.exports = function tackbox(pi) {
|
|
15
15
|
pi.setLabel('tackbox')
|
|
@@ -61,7 +61,7 @@ function applyPost(decision, event) {
|
|
|
61
61
|
const kind = decision && decision.kind
|
|
62
62
|
if (kind === hook.BLOCK) {
|
|
63
63
|
return {
|
|
64
|
-
content: appended(event, `${
|
|
64
|
+
content: appended(event, `${FINDINGS}\n${decision.reason}`),
|
|
65
65
|
isError: true,
|
|
66
66
|
}
|
|
67
67
|
}
|
package/js/rules/_shared.js
CHANGED
|
@@ -392,12 +392,18 @@ function blockHasReport(context, block, errName) {
|
|
|
392
392
|
return found
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
// Multiline HTML comments locate approval identity at the keyword, not the delimiter.
|
|
396
|
+
function markerLine(comment, prefix) {
|
|
397
|
+
const raw = comment.value
|
|
398
398
|
const text = raw.trim()
|
|
399
|
-
|
|
400
|
-
|
|
399
|
+
const marker = prefix + ':'
|
|
400
|
+
if (!text.startsWith(marker) || text.slice(marker.length).trim().length < MIN_REASON) return null
|
|
401
|
+
let line = comment.loc.start.line
|
|
402
|
+
const offset = raw.indexOf(marker)
|
|
403
|
+
for (let i = 0; i < offset; i++) {
|
|
404
|
+
if (raw[i] === '\n') line++
|
|
405
|
+
}
|
|
406
|
+
return line
|
|
401
407
|
}
|
|
402
408
|
|
|
403
409
|
// precedingSvelteSibling returns the template node immediately before `el` among
|
|
@@ -416,30 +422,51 @@ function precedingSvelteSibling(el) {
|
|
|
416
422
|
return null
|
|
417
423
|
}
|
|
418
424
|
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
// reason can be followed by human context, a blank line breaking the block - and,
|
|
423
|
-
// in a Svelte template, an HTML comment `<!-- ... -->` immediately above an
|
|
424
|
-
// enclosing element, which covers the whole element (residual A8: an inline
|
|
425
|
-
// handler can span lines). getAllComments omits SvelteHTMLComment nodes, so the
|
|
426
|
-
// template form is read off the element's preceding sibling.
|
|
427
|
-
function hasMarkerAbove(context, node, prefix) {
|
|
428
|
-
if (!node || !node.loc) return false
|
|
425
|
+
// Svelte HTML comments cover the following element, not just its first line.
|
|
426
|
+
function markerAbove(context, node, prefix) {
|
|
427
|
+
if (!node || !node.loc) return null
|
|
429
428
|
const sourceCode = context.sourceCode || context.getSourceCode()
|
|
430
429
|
const byEndLine = new Map()
|
|
431
430
|
for (const c of sourceCode.getAllComments()) {
|
|
432
431
|
if (c.type === 'Line') byEndLine.set(c.loc.end.line, c)
|
|
433
432
|
}
|
|
434
433
|
for (let line = node.loc.start.line - 1; byEndLine.has(line); line--) {
|
|
435
|
-
|
|
434
|
+
const comment = byEndLine.get(line)
|
|
435
|
+
const marker = markerLine(comment, prefix)
|
|
436
|
+
if (marker !== null) return marker
|
|
436
437
|
}
|
|
437
438
|
for (let cur = node.parent; cur; cur = cur.parent) {
|
|
438
439
|
if (cur.type !== 'SvelteElement') continue
|
|
439
440
|
const sib = precedingSvelteSibling(cur)
|
|
440
|
-
if (sib && sib.type === 'SvelteHTMLComment'
|
|
441
|
+
if (sib && sib.type === 'SvelteHTMLComment') {
|
|
442
|
+
const marker = markerLine(sib, prefix)
|
|
443
|
+
if (marker !== null) return marker
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return null
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
let suppressedReporter = null
|
|
450
|
+
|
|
451
|
+
function setSuppressedReporter(reporter) {
|
|
452
|
+
suppressedReporter = reporter
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function reportWithMarker(context, descriptor, anchor, kind, messages) {
|
|
456
|
+
const line = markerAbove(context, anchor, kind)
|
|
457
|
+
if (line === null) {
|
|
458
|
+
context.report(descriptor)
|
|
459
|
+
} else if (suppressedReporter) {
|
|
460
|
+
suppressedReporter({
|
|
461
|
+
file: context.filename || context.getFilename(),
|
|
462
|
+
line: descriptor.node.loc.start.line,
|
|
463
|
+
rule: context.id,
|
|
464
|
+
message: messages[descriptor.messageId],
|
|
465
|
+
suppressed: true,
|
|
466
|
+
marker_kind: kind,
|
|
467
|
+
marker_line: line,
|
|
468
|
+
})
|
|
441
469
|
}
|
|
442
|
-
return false
|
|
443
470
|
}
|
|
444
471
|
|
|
445
472
|
// --- F2b: path-sensitive no-swallow analysis -----------------------------
|
|
@@ -835,7 +862,8 @@ module.exports = {
|
|
|
835
862
|
walk,
|
|
836
863
|
blockHasThrow,
|
|
837
864
|
blockHasReport,
|
|
838
|
-
|
|
865
|
+
reportWithMarker,
|
|
866
|
+
setSuppressedReporter,
|
|
839
867
|
enclosingFn,
|
|
840
868
|
fnReturnsResultLike,
|
|
841
869
|
someNode,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { reportWithMarker, walk, isTier1Notify, argFlows, isTestFile } = require('./_shared')
|
|
2
2
|
|
|
3
3
|
// guarded: `call` sits under an additional condition strictly inside the catch
|
|
4
4
|
// body - an if-branch (consequent/alternate) or a switch case. A notify
|
|
@@ -35,11 +35,12 @@ module.exports = {
|
|
|
35
35
|
if (errName == null) return
|
|
36
36
|
const body = node.body
|
|
37
37
|
if (!body || body.type !== 'BlockStatement') return
|
|
38
|
-
if (hasMarkerAbove(context, node.parent, 'no-report')) return
|
|
39
38
|
walk(body, call => {
|
|
40
39
|
if (call.type !== 'CallExpression') return
|
|
41
40
|
if (!isTier1Notify(context, call) || !argFlows(call, errName)) return
|
|
42
|
-
if (!guarded(call, body))
|
|
41
|
+
if (!guarded(call, body)) {
|
|
42
|
+
reportWithMarker(context, { node: call, messageId: 'broad' }, node.parent, 'no-report', module.exports.meta.messages)
|
|
43
|
+
}
|
|
43
44
|
})
|
|
44
45
|
},
|
|
45
46
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const {
|
|
2
|
-
|
|
2
|
+
reportWithMarker,
|
|
3
3
|
enclosingFn,
|
|
4
4
|
fnReturnsResultLike,
|
|
5
5
|
errObjectFlows,
|
|
@@ -139,11 +139,10 @@ module.exports = {
|
|
|
139
139
|
if (!tryBlockParses(node.block)) return
|
|
140
140
|
const handler = node.handler
|
|
141
141
|
if (!handler || !handler.body || handler.body.type !== 'BlockStatement') return
|
|
142
|
-
if (hasMarkerAbove(context, node, 'parse-skip')) return
|
|
143
142
|
const errName = handler.param && handler.param.type === 'Identifier' ? handler.param.name : null
|
|
144
143
|
const allowBoundary = fnReturnsResultLike(enclosingFn(node))
|
|
145
144
|
if (catchPropagates(handler.body, errName, allowBoundary)) return
|
|
146
|
-
context
|
|
145
|
+
reportWithMarker(context, { node: handler, messageId: 'fallback' }, node, 'parse-skip', module.exports.meta.messages)
|
|
147
146
|
},
|
|
148
147
|
}
|
|
149
148
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { reportWithMarker, matchesTestModifier, isStaticString, staticStringValue, TEST_ROOTS } = require('./_shared')
|
|
2
2
|
|
|
3
3
|
const SKIP_PROPS = new Set(['skip', 'todo', 'skipIf', 'fixme'])
|
|
4
4
|
const BARE = new Set(['xit', 'xdescribe', 'xtest'])
|
|
@@ -80,14 +80,12 @@ module.exports = {
|
|
|
80
80
|
CallExpression(node) {
|
|
81
81
|
if (matchesTestModifier(node.callee, BARE, n => SKIP_PROPS.has(n))) {
|
|
82
82
|
if (hasInCallReason(node)) return
|
|
83
|
-
|
|
84
|
-
context.report({ node, messageId: 'skipped' })
|
|
83
|
+
reportWithMarker(context, { node, messageId: 'skipped' }, outermostCall(node), 'test-skip', module.exports.meta.messages)
|
|
85
84
|
return
|
|
86
85
|
}
|
|
87
86
|
if (node.callee.type === 'Identifier' && TEST_ROOTS.has(node.callee.name)) {
|
|
88
87
|
if (optionsSkipVerdict(node) !== 'flag') return
|
|
89
|
-
|
|
90
|
-
context.report({ node, messageId: 'skipped' })
|
|
88
|
+
reportWithMarker(context, { node, messageId: 'skipped' }, outermostCall(node), 'test-skip', module.exports.meta.messages)
|
|
91
89
|
}
|
|
92
90
|
},
|
|
93
91
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { reportWithMarker, enclosingFn, someNode } = require('./_shared')
|
|
2
2
|
|
|
3
3
|
// isAllSettledCall: syntactic `Promise.allSettled(...)`. Matched by shape, not
|
|
4
4
|
// resolution - Promise is a global and allSettled is unambiguous.
|
|
@@ -43,9 +43,8 @@ module.exports = {
|
|
|
43
43
|
return {
|
|
44
44
|
CallExpression(node) {
|
|
45
45
|
if (!isAllSettledCall(node)) return
|
|
46
|
-
if (hasMarkerAbove(context, node, 'no-report')) return
|
|
47
46
|
if (refsReason(enclosingFn(node) || sc.ast)) return
|
|
48
|
-
context
|
|
47
|
+
reportWithMarker(context, { node, messageId: 'swallow' }, node, 'no-report', module.exports.meta.messages)
|
|
49
48
|
},
|
|
50
49
|
}
|
|
51
50
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const {
|
|
2
|
-
|
|
2
|
+
reportWithMarker,
|
|
3
3
|
enclosingFn,
|
|
4
4
|
fnReturnsResultLike,
|
|
5
5
|
makeHandledAnalysis,
|
|
@@ -20,11 +20,10 @@ module.exports = {
|
|
|
20
20
|
const body = node.body
|
|
21
21
|
if (!body || body.type !== 'BlockStatement') return
|
|
22
22
|
const tryStmt = node.parent
|
|
23
|
-
if (tryStmt && hasMarkerAbove(context, tryStmt, 'no-report')) return
|
|
24
23
|
const errName = node.param && node.param.type === 'Identifier' ? node.param.name : null
|
|
25
24
|
const allowBoundary = fnReturnsResultLike(enclosingFn(node))
|
|
26
25
|
if (makeHandledAnalysis({ context, errName, allowBoundary }).handled(body)) return
|
|
27
|
-
context
|
|
26
|
+
reportWithMarker(context, { node, messageId: 'swallow' }, tryStmt, 'no-report', module.exports.meta.messages)
|
|
28
27
|
},
|
|
29
28
|
}
|
|
30
29
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { reportWithMarker, makeHandledAnalysis } = require('./_shared')
|
|
2
2
|
|
|
3
3
|
// rejectionHandler returns the rejection-handler argument of a promise
|
|
4
4
|
// method: `.catch(onErr)` -> arg 0, `.then(onOk, onErr)` -> arg 1. A single-arg
|
|
@@ -28,10 +28,9 @@ module.exports = {
|
|
|
28
28
|
const handler = rejectionHandler(node)
|
|
29
29
|
if (!handler) return
|
|
30
30
|
if (handler.type !== 'ArrowFunctionExpression' && handler.type !== 'FunctionExpression') return
|
|
31
|
-
if (hasMarkerAbove(context, node, 'no-report')) return
|
|
32
31
|
const errName = handler.params[0] && handler.params[0].type === 'Identifier' ? handler.params[0].name : null
|
|
33
32
|
if (makeHandledAnalysis({ context, errName, allowBoundary: false, returnIdentity: true }).handled(handler.body)) return
|
|
34
|
-
context
|
|
33
|
+
reportWithMarker(context, { node, messageId: 'swallow' }, node, 'no-report', module.exports.meta.messages)
|
|
35
34
|
},
|
|
36
35
|
}
|
|
37
36
|
},
|
package/package.json
CHANGED