eslint-plugin-greasemonkey
v1.8.0
Published
ESLint rules for Greasemonkey/Tampermonkey userscripts
Maintainers
Readme
eslint-plugin-greasemonkey
ESLint rules for Greasemonkey userscripts.
Installation
From your project root:
npm i -D eslint-plugin-greasemonkeyAdd a bundled config to your eslint.config.*js:
...
import greasemonkey from 'eslint-plugin-greasemonkey'
export default [
// other configs
{
files: ['**/*.user.js'], plugins: { greasemonkey }
rules: {
...greasemonkey.configs.recommended.rules,
'greasemonkey/no-unused-resources': 'off', // selectively disable rule
'greasemonkey/meta-spacing': ['error', { spaces: 2 }] // selectively tweak rule
}
}
]Available bundles: recommended, strict, problem, tampermonkey, violentmonkey, greasemonkey, scriptcat, adguard
Note: Rule config is either a severity string ('off', 'warn', 'error') or an array [severity, options] when the rule accepts options.
Options
order(default[]) – metadata keys in custom order (e.g.['license', 'namespace']) to selectively override built-in order with
Incorrect code
// ==UserScript==
// @name My Script
! // @version 1.0.0
// @description A script
! // @namespace example.com
// @author John Doe
// @license MIT
// ==/UserScript==Correct code
// ==UserScript==
// @name My Script
- // @version 1.0.0
// @description A script
- // @namespace example.com
// @author John Doe
+ // @namespace example.com
+ // @version 1.0.0
// @license MIT
// ==/UserScript==When not to use it
If you don't care about the order of metadata fields.
Introduced in
v1.5.0 (September 15, 2026)
See also
Options
spaces(default3) – minimum spaces after the longest key
Incorrect code
/* eslint greasemonkey/meta-spacing: ['error', { spaces: 1 }] */
// ==UserScript==
! // @name My Script
// @namespace example.com
! // @version 1.0.0
// ==/UserScript==Correct code
/* eslint greasemonkey/meta-spacing: ['error', { spaces: 1 }] */
// ==UserScript==
- // @name My Script
+ // @name My Script
// @namespace example.com
- // @version 1.0.0
+ // @version 1.0.0
// ==/UserScript==When not to use it
If you don't care about visual alignment in metadata blocks.
Introduced in
v1.0.0 (September 9, 2026)
See also
Incorrect code
// ==UserScript==
! // @name Foo
! // @name Bar
! // @version 1.0.0
! // @version 2.0.0
// @match https://a.example.com/*
// @match https://b.example.com/*
// ==/UserScript==Correct code
// ==UserScript==
- // @name Foo
- // @name Bar
+ // @name My Script
- // @version 1.0.0
- // @version 2.0.0
+ // @version 1.0.0
// @match https://a.example.com/*
// @match https://b.example.com/*
// ==/UserScript==When not to use it
If you intentionally repeat single-value keys.
Introduced in
v1.2.0 (September 11, 2026)
See also
Options
target(default'all') – manager(s) whose grants to validate against ('all','tampermonkey','violentmonkey','greasemonkey','scriptcat','adguard'), as a single string or arrayallowedGrants(default[]) – additional@grantvalues to allow beyond the built-in list (covering Tampermonkey, Violentmonkey, Greasemonkey, ScriptCat and AdGuard), as a single string or array
Incorrect code
/* eslint greasemonkey/no-invalid-grants: ['error', { target: 'tampermonkey' }] */
// ==UserScript==
// @grant GM_getTab
! // @grant CAT.agent.dom
// ==/UserScript==
/* eslint greasemonkey/no-invalid-grants: ['error', { target: 'scriptcat' }] */
// ==UserScript==
! // @grant GM_getTab
// @grant CAT.agent.dom
// ==/UserScript==Correct code
/* eslint greasemonkey/no-invalid-grants: ['error', { target: 'tampermonkey' }] */
// ==UserScript==
// @grant GM_getTab
- // @grant CAT.agent.dom
// ==/UserScript==
/* eslint greasemonkey/no-invalid-grants: ['error', { target: 'scriptcat' }] */
// ==UserScript==
- // @grant GM_getTab
// @grant CAT.agent.dom
// ==/UserScript==When not to use it
If you don't want @grant validation at all. For individual uncovered grants, prefer whitelisting via allowedGrants over disabling the rule.
Introduced in
v1.2.0 (September 11, 2026) as valid-grants
Renamed in
v1.5.2 (September 16, 2026) to no-invalid-grants
See also
Options
target(default'all') – manager(s) whose headers to validate against ('all','tampermonkey','violentmonkey','greasemonkey','scriptcat','adguard'), as a single string or arrayallowedHeaders(default[]) – additional headers to allow (strings or regexes), as a single value or array
Incorrect code
/* eslint greasemonkey/no-invalid-headers: ['error', { target: 'tampermonkey', allowedHeaders: /^\w*url$/i }] */
// ==UserScript==
// @name My Script
! // @runin normal-tabs
! // @customURI https://example.com
! // @inject-into page
// ==/UserScript==Correct code
/* eslint greasemonkey/no-invalid-headers: ['error', { target: 'tampermonkey', allowedHeaders: /^\w*url$/i }] */
// ==UserScript==
// @name My Script
- // @runin normal-tabs
+ // @run-in normal-tabs
- // @customURI https://example.com
+ // @customURL https://example.com
- // @inject-into page
// ==/UserScript==When not to use it
If your script relies heavily on custom headers and you'd rather not maintain allowedHeaders.
Introduced in
v1.0.0 (September 9, 2026)
See also
Incorrect code
// ==UserScript==
// @name My Script
// ==/UserScript==
! GM_setValue('key', 'value')Correct code
// ==UserScript==
// @name My Script
+ // @grant GM_setValue
// ==/UserScript==
GM_setValue('key', 'value')When not to use it
If you use APIs through aliases or wrappers that obscure the original call site.
Introduced in
v1.3.0 (September 12, 2026)
See also
Incorrect code
// ==UserScript==
// @name My Script
// ==/UserScript==
! const css = GM_getResourceText('myCSS')Correct code
// ==UserScript==
// @name My Script
+ // @resource myCSS https://example.com/style.css
// ==/UserScript==
const css = GM_getResourceText('myCSS')When not to use it
If you reference resources through an alias or computed pattern that obscures the call site.
Introduced in
v1.4.0 (September 13, 2026)
See also
Incorrect code
// ==UserScript==
! // @grant GM_setValue
// ==/UserScript==Correct code
// ==UserScript==
// @grant GM_setValue
// ==/UserScript==
+ GM_setValue('key', 'value')When not to use it
If you access the granted API through an alias or computed property rather than calling it directly.
Introduced in
v1.0.0 (September 9, 2026)
See also
Incorrect code
// ==UserScript==
! // @resource myCSS https://example.com/style.css
// ==/UserScript==Correct code
// ==UserScript==
// @resource myCSS https://example.com/style.css
// ==/UserScript==
+ const css = GM_getResourceText('myCSS')When not to use it
If you pass resource names through variables or aliases rather than use them literally.
Introduced in
v1.0.0 (September 9, 2026)
See also
Incorrect code
// ==UserScript==
! // @include https://example.com/*
// ==/UserScript==Correct code
// ==UserScript==
- // @include https://example.com/*
+ // @match https://example.com/*
// ==/UserScript==When not to use it
If you rely on @include patterns that cannot be expressed using @match.
Introduced in
v1.3.0 (September 12, 2026)
See also
- Tampermonkey —
@match - Tampermonkey —
@include
Incorrect code
// ==UserScript==
// @name My Script
// ==/UserScript==
! console.log('hi')Correct code
// ==UserScript==
// @name My Script
// ==/UserScript==
+
console.log('hi')When not to use it
If you don't care about visual separation between metadata and code.
Introduced in
v1.3.0 (September 12, 2026) as require-meta-newline
Renamed in
v1.4.0 (September 13, 2026) to require-blank-line-after-meta-block
See also
Incorrect code
// ==UserScript==
! // @homepage https://example.com
// ==/UserScript==Correct code
// ==UserScript==
// @homepage https://example.com
+ // @homepageURL https://example.com
// ==/UserScript==When not to use it
If you don't care about ensuring homepage URL compatibility across different managers.
Introduced in
v1.3.0 (September 12, 2026)
See also
require-update-download-pair- Tampermonkey
@homepage,@homepageURL,@website,@source - ScriptCat
@homepage,@homepageURL,@website
Options
ignoreLanguages(default[]) – language code(s) to skip (e.g.'de'or['es', 'fr'])
Incorrect code
/* eslint greasemonkey/require-matching-localized-fields: ['error', { ignoreLanguages: ['fr'] }] */
// ==UserScript==
// @name:en My Script
! // @name:de Mein Skript
// @name:fr Mon Script
// @description:en Does something
// ==/UserScript==Correct code
/* eslint greasemonkey/require-matching-localized-fields: ['error', { ignoreLanguages: ['fr'] }] */
// ==UserScript==
// @name:en My Script
// @name:de Mein Skript
// @name:fr Mon Script
// @description:en Does something
+ // @description:de Tut etwas
// ==/UserScript==When not to use it
If you intentionally provide localized names without descriptions (or vice versa).
Introduced in
v1.0.0 (September 9, 2026)
See also
Options
fields(default['name', 'version']) – override the required field listrequireMatchOrInclude(defaulttrue) – require@matchor@include
Incorrect code
/* eslint greasemonkey/require-required-fields: ['error', { fields: ['name', 'version', 'license'] }] */
// ==UserScript==
// @name My Script
// ==/UserScript==Correct code
/* eslint greasemonkey/require-required-fields: ['error', { fields: ['name', 'version', 'license'] }] */
// ==UserScript==
// @name My Script
+ // @version 1.0.0
+ // @license MIT
+ // @match https://example.com/*
// ==/UserScript==When not to use it
If your script is a work-in-progress, or metadata is injected at build time.
Introduced in
v1.0.0 (September 9, 2026)
See also
Incorrect code
// ==UserScript==
! //@name My Script
// @version 1.0.0
// ==/UserScript==Correct code
// ==UserScript==
- //@name My Script
+ // @name My Script
// @version 1.0.0
// ==/UserScript==When not to use it
If you intentionally use a different prefix style.
Introduced in
v1.3.0 (September 12, 2026)
See also
Options
algorithm(default'sha256') – SRI hash algorithm(s) to enforce ('md5','sha1','sha256','sha384','sha512'), as a single string or array
Incorrect code
/* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
// ==UserScript==
! // @require https://example.com/library.js
// @resource css https://example.com/styles.css#sha384-h/TTEs...
! // @resource logo https://example.com/logo.png#sha256-xUj+3O...
// ==/UserScript==Correct code
/* eslint greasemonkey/require-sri-hashing: ['error', { algorithm: 'sha384' }] */
// ==UserScript==
- // @require https://example.com/library.js
+ // @require https://example.com/library.js#sha384-fTbBOw...
// @resource css https://example.com/styles.css#sha384-h/TTEs...
- // @resource logo https://example.com/logo.png#sha256-xUj+3O...
+ // @resource logo https://example.com/logo.png#sha384-mQ3Slt...
// ==/UserScript==When not to use it
If you prefer shorter URLs, or don't support users who strictly enforce subresource integrity via manager settings.
Introduced in
v1.5.0 (September 15, 2026)
See also
no-invalid-headersrequire-required-fields- Tampermonkey — Subresource Integrity
- ScriptCat — Resource Integrity Verification
Incorrect code
// ==UserScript==
! // @downloadURL https://example.com/script.user.js
// ==/UserScript==Correct code
// ==UserScript==
// @downloadURL https://example.com/script.user.js
+ // @updateURL https://example.com/script.meta.js
// ==/UserScript==When not to use it
If you don't target Tampermonkey or ScriptCat (where @updateURL avoids re-downloading the full script on every update check).
Introduced in
v1.3.0 (September 12, 2026)
See also
require-homepage-pair- Tampermonkey —
@updateURL - ScriptCat —
@updateURL
Incorrect filename
! /my-userscript.jsCorrect filename
- /my-userscript.js
+ /my-userscript.user.jsWhen not to use it
If you intentionally name your userscripts something other than *.user.js.
Introduced in
v1.2.0 (September 11, 2026)
Options
versionType(default'semver') – version format to enforce ('semver','date')allowFutureDate(defaultfalse) – allow@versiondates later than the current datetimezone(default'') – IANA timezone used to determine the current date (when omitted, only year/month are enforced)
Incorrect code
/* eslint greasemonkey/valid-field-values: ['error', { versionType: 'semver' }] */
// ==UserScript==
! // @version abc
! // @homepage not-a-url
// ==/UserScript==Correct code
/* eslint greasemonkey/valid-field-values: ['error', { versionType: 'semver' }] */
// ==UserScript==
- // @version abc
+ // @version 1.0.0
- // @homepage not-a-url
+ // @homepage https://example.com
// ==/UserScript==When not to use it
If you use a custom versioning scheme or URLs that aren't standard.
Introduced in
v1.0.0 (September 9, 2026)
See also
Shield embed
HTML
<a href="https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme">
<img height=32 alt="[Linted by eslint-plugin-greasemonkey]" src="https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge"></a>Markdown
[![[Linted by eslint-plugin-greasemonkey]](https://img.shields.io/badge/Linted_by-eslint--plugin--greasemonkey-black?logo=eslint&logoColor=white&labelColor=464646&style=for-the-badge)](https://codeberg.org/adamlui/eslint-plugin-greasemonkey/#readme)License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
Related
eslint-plugin-constructors
Install / Readme / Supported rules
Latest releases / Report a bug / More packages by author / Back to top ↑
