@mertcreates/eslint-plugin-mv3
v1.0.0
Published
ESLint rules for Manifest V3 extension safety (e.g., catching executeScript closure traps).
Downloads
37
Maintainers
Readme
eslint-plugin-mv3
ESLint rule(s) for MV3-safe scripting.executeScript usage.
It enforces that injected func code is self-contained, statically analyzable, and safe across Main World boundaries.
Contents
- The Problem
- Features
- Install
- Usage (eslintrc)
- Usage (flat config)
- Rules
- Options
- Compatibility
- Benchmarks
- License
The Problem
When using Manifest V3 scripting.executeScript({ func }), the injected
function is serialized and executed in Main World. Outer-scope values are not
carried with it.
If injected code references variables outside its own scope, it can fail at
runtime with ReferenceError: ... is not defined. This plugin catches those
closure traps statically at lint time.
Features
- Detects closure capture inside
executeScript({ func }) - Rejects imported/non-local
funcreferences - Enforces
args: [...]when injected functions have parameters - Rejects dynamic/spread options that break static enforcement
- Supports
chromeandbrowserhosts - Supports alias/destructure/computed access,
.call,.apply,.bind,Reflect.apply
Install
npm i -D @mertcreates/eslint-plugin-mv3
# or
yarn add -D @mertcreates/eslint-plugin-mv3
# or
pnpm add -D @mertcreates/eslint-plugin-mv3
# or
bun add -D @mertcreates/eslint-plugin-mv3Usage (eslintrc)
{
"plugins": ["@mertcreates/mv3"],
"rules": {
"@mertcreates/mv3/no-execute-script-closure": "error"
}
}Or use recommended config:
{
"extends": ["plugin:@mertcreates/mv3/recommended"]
}Usage (flat config)
import mv3Plugin from '@mertcreates/eslint-plugin-mv3';
export default [
mv3Plugin.configs.recommended,
];Rules
The recommended config enables this rule.
@mertcreates/mv3/no-execute-script-closure
Validates that:
funcis local and resolvable in the same filefuncdoes not capture outer-scope variablesargsis present and array-literal when function parameters exist- invocation/config shape stays statically analyzable
Incorrect:
const TOP = 'outer';
function installBridge() {
return TOP;
}
chrome.scripting.executeScript({
target: { tabId: 1 },
func: installBridge,
});Correct:
function installBridge(source) {
return source;
}
chrome.scripting.executeScript({
target: { tabId: 1 },
func: installBridge,
args: ['outer'],
});Options
No rule options right now. The rule is intentionally strict and zero-config.
Compatibility
- ESLint:
>=8.50.0 <10 - Node: versions supported by your ESLint runtime
Benchmarks
Benchmarks separate:
- ESLint core overhead
- Rule-on cost
- Net rule cost (
rule-on - overhead)
Latest run highlights (BENCH_SCALE=1 BENCH_WARMUP=2 BENCH_RUNS=5):
noise-baseline-5k: net median rule cost ~2.96msmixed-worst-case(30k lines): net median rule cost ~16.19ms
See details in BENCHMARK.md.
License
MIT.
