initial commit of actions

This commit is contained in:
Dominik Polakovics Polakovics 2026-01-31 18:56:04 +01:00
commit 949ece5785
44660 changed files with 12034344 additions and 0 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Keith Cirkel
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.

View file

@ -0,0 +1,179 @@
# eslint-plugin-escompat
This plugin will report eslint errors for code which - if left untranspiled -
will not work in some browsers.
This is useful if you intend to ship code without first using a transpiler, such
as [Babel](https://babeljs.io).
This _won't_ lint for features that can be polyfilled. For that you can use
[eslint-plugin-compat][epc].
## Installation
```bash
npm install --save-dev eslint-plugin-escompat
```
## Usage for Flat Configs (eslint.config.js) - ESLint >= 8
```js
// eslint.config.js
import globals from 'globals';
import escompat from 'eslint-plugin-escompat';
export default [
{
plugins: {
escompat
},
languageOptions: {
globals: globals.browser
},
rules: {
// Configure the individual `"escompat/*"` rules, e.g.:
'escompat/no-async-generator': ['error'],
'escompat/no-numeric-separators': ['error']
}
}
];
```
Alternatively, you can use the `recommended` configuration which will do the
plugins for you, with all recommended `"escompat/*"` rules reporting errors.
```js
import globals from 'globals';
import escompat from 'eslint-plugin-escompat';
export default [
{
languageOptions: {
globals: globals.browser
}
},
escompat.configs['flat/recommended']
];
```
## Usage for .eslintrc configs - ESLint < 9
Add `"escompat"` to `.eslintrc` `"plugins"` section, add `"browser": true` to
`"env"`, then configure the individual `"escompat/*"` rules.
Alternatively, you can use the `recommended` configuration which will do this
for you, with the `"escompat/*"` rules reporting errors (as in the snippet
above).
```js
// .eslintrc
{
"extends": ["plugin:escompat/recommended"]
}
```
### TypeScript Users
Aside from the `recommended` config, there are also multiple `typescript`
configs which can be used if you're using TypeScript. The TypeScript configs
only enable some of the rules, avoiding enabling rules for which `typescript`
safely transpiles down to a more compatible syntax. Extend the typescript config
that matches your `tsconfig.json` `target` value.
For flat configs:
```js
import globals from 'globals';
import escompat from 'eslint-plugin-escompat';
export default [
{
languageOptions: {
globals: globals.browser
}
},
// The TypeScript configs are in array form, so we need to
// spread them out here
...escompat.configs['flat/typescript-2016']
];
```
or for `.eslintrc`:
```js
{
"extends": ["plugin:escompat/typescript-2016"]
}
```
## Targeting Browsers
`eslint-plugin-escompat` uses the `browserslist` configuration in `package.json`
If you have a browserslist, it is safe to enable all of these rules - as any that
do not coincide with your chosen browsers will be turned off automatically.
See [browserslist/browserslist](https://github.com/browserslist/browserslist)
for configuration. Here's some examples:
```js
// Simple configuration (package.json)
{
// ...
"browserslist": ["last 1 versions", "not ie <= 8"],
}
```
```js
// Use development and production configurations (package.json)
{
// ...
"browserslist": {
"development": ["last 2 versions"],
"production": ["last 4 versions"]
}
}
```
:bulb: You can also define browsers in a
[separate browserslist file](https://github.com/browserslist/browserslist#config-file)
## Rules
- [no-async-generator](./docs/no-async-generator.md)
- [no-async-iteration](./docs/no-async-iteration.md)
- [no-bigint](./docs/no-bigint.md)
- [no-bind-operator](./docs/no-bind-operator.md)
- [no-class-static-blocks](./docs/no-class-static-blocks.md)
- [no-computed-public-class-fields](./docs/no-computed-public-class-fields.md)
- [no-do-expression](./docs/no-do-expression.md)
- [no-dynamic-imports](./docs/no-dynamic-imports.md)
- [no-edge-destructure-bug](./docs/no-edge-destructure-bug.md)
- [no-exponentiation-operator](./docs/no-exponentiation-operator.md)
- [no-hashbang-comment](./docs/no-hashbang-comment.md)
- [no-logical-assignment-operator](./docs/no-logical-assignment-operator.md)
- [no-nullish-coalescing](./docs/no-nullish-coalescing.md)
- [no-numeric-separators](./docs/no-numeric-separators.md)
- [no-object-rest-spread](./docs/no-object-rest-spread.md)
- [no-optional-catch](./docs/no-optional-catch.md)
- [no-optional-chaining](./docs/no-optional-chaining.md)
- [no-pipeline-operator](./docs/no-pipeline-operator.md)
- [no-private-class-fields](./docs/no-private-class-fields.md)
- [no-public-instance-class-fields](./docs/no-public-instance-class-fields.md)
- [no-public-static-class-fields](./docs/no-public-static-class-fields.md)
- [no-regexp-duplicate-named-groups](./docs/no-regexp-duplicate-named-groups.md)
- [no-regexp-lookbehind](./docs/no-regexp-lookbehind.md)
- [no-regexp-named-group](./docs/no-regexp-named-group.md)
- [no-regexp-s-flag](./docs/no-regexp-s-flag.md)
- [no-regexp-v-flag](./docs/no-regexp-v-flag.md)
- [no-top-level-await](./docs/no-top-level-await.md)
## Inspiration
This project was largely inspired by the great [eslint-plugin-compat][epc]
library.
[epc]: https://github.com/amilajack/eslint-plugin-compat

View file

@ -0,0 +1,288 @@
'use strict';
const path = require("path");
const browserslist = require("browserslist");
const { version, homepage } = require("../package.json");
const flatTypeScriptConfigs = {};
const createRule = (name, browserstring, description, { ts = null } = {}) => {
const rule = require(`./rules/${name}`);
module.exports.rules[name] = {
meta: Object.assign(
{
type: "problem",
docs: {
description,
recommended: true,
url: `${homepage}/blob/v${version}/docs/${name}.md`,
},
fixable: false,
schema: [],
deprecated: false,
replacedBy: null,
},
rule.meta || {}
),
create(context) {
let browsers = browserslist(browserstring);
const config = browserslist.findConfig(path.dirname(
context.filename ?? context.getFilename()
)) || {
defaults: "defaults",
};
const desiredBrowsers = browserslist(config.defaults);
const badBrowsers = desiredBrowsers
.filter((browser) => browsers.includes(browser))
.join(", ");
if (globalThis.ESLINT_TESTING || badBrowsers) {
const create = typeof rule === "function" ? rule : rule.create;
return create(context, globalThis.ESLINT_TESTING ? undefined : badBrowsers);
}
return {};
},
};
const configName = `typescript-${ts || "base"}`;
const flatConfigName = `flat/${configName}`;
if (!module.exports.configs[configName]) {
flatTypeScriptConfigs[configName] = [{
name: `escompat/${configName}`,
plugins: {
escompat: module.exports
},
rules: {}
}];
const config = { rules: {} };
if (ts === 2016) {
config.extends = [`plugin:escompat/typescript-base`];
flatTypeScriptConfigs[configName].unshift(
...flatTypeScriptConfigs['typescript-base']
);
} else if (ts) {
let previous = ts - 1;
while (!module.exports.configs[`typescript-${previous}`]) previous -= 1;
config.extends = [`plugin:escompat/typescript-${previous}`];
flatTypeScriptConfigs[configName].unshift(
...flatTypeScriptConfigs[`typescript-${previous}`]
);
}
module.exports.configs[configName] = config;
module.exports.configs[flatConfigName] = flatTypeScriptConfigs[configName];
}
module.exports.configs[`typescript-base`].rules[`escompat/${name}`] = "off";
module.exports.configs[`flat/typescript-base`].at(-1).rules[`escompat/${name}`] = "off";
module.exports.configs[configName].rules[`escompat/${name}`] = "error";
module.exports.configs[flatConfigName].at(-1).rules[`escompat/${name}`] = "error";
};
module.exports = { rules: {}, configs: {} };
// ES2015
createRule(
"no-edge-destructure-bug",
"edge < 18",
"disallow the use of specific destructuring patterns that cause bugs in old Edge"
);
// ES2016
createRule(
"no-exponentiation-operator",
"chrome < 52, edge < 14, firefox < 52, safari < 10.1",
"disallow use of exponentiation operator (**)",
{ ts: 2016 }
);
// ES2018
createRule(
"no-async-iteration",
"edge < 79, safari < 12, firefox < 57, chrome < 63",
"disallow the use of `for await of` style loops",
{ ts: 2018 }
);
createRule(
"no-async-generator",
"edge < 79, safari < 12, firefox < 57, chrome < 63",
"disallow the use of async generator functions",
{ ts: 2018 }
);
createRule(
"no-object-rest-spread",
"edge < 79, safari < 11.1, firefox < 55, chrome < 60",
"disallow object rest/spread patterns",
{ ts: 2018 }
);
createRule(
"no-regexp-s-flag",
"edge < 79, safari < 11.1, firefox < 78, chrome < 62",
"disallow the use of the RegExp `s` flag"
);
createRule(
"no-regexp-lookbehind",
"edge < 79, safari < 16.4, firefox < 78, chrome < 62",
"disallow the use of RegExp lookbehinds"
);
createRule(
"no-regexp-named-group",
"edge < 79, safari 11.1, firefox < 78, chrome < 64",
"disallow the use of RegExp named groups"
);
// ES2019
createRule(
"no-optional-catch",
"edge < 79, safari < 11.1, firefox < 58, chrome < 66",
"always require catch() to have an argument",
{ ts: 2019 }
);
// ES2020
createRule(
"no-dynamic-imports",
"edge < 79, safari < 11, firefox < 67, chrome < 63",
"disallow dynamic import statements"
);
createRule(
"no-optional-chaining",
"edge < 80, safari < 13.1, firefox < 72, chrome < 80",
"disallow the .? optional chaining operator",
{ ts: 2020 }
);
createRule(
"no-nullish-coalescing",
"edge < 80, safari < 13.1, firefox < 72, chrome < 80",
"disallow the ?? nullish coalescing operator",
{ ts: 2020 }
);
createRule(
"no-bigint",
"edge < 79, safari < 14, firefox < 68, chrome < 67",
"disallow bigints"
);
// ES2021
createRule(
"no-numeric-separators",
"edge < 79, safari < 13, firefox < 68, chrome < 75",
"disallow use of numeric separators like 1_000_000",
{ ts: 2021 }
);
createRule(
"no-logical-assignment-operator",
"edge < 85, safari < 14, firefox < 79, chrome < 85",
"disallow logical assignment operators like &&=",
{ ts: 2021 }
);
// ES2022
createRule(
"no-public-static-class-fields",
"edge < 79, safari < 14.5, firefox < 75, chrome < 72",
"disallow public static class fields like foo = 1",
{ ts: 2022 }
);
createRule(
"no-public-instance-class-fields",
"edge < 79, safari < 14.5, firefox < 69, chrome < 72",
"disallow public class fields like foo = 1",
{ ts: 2022 }
);
createRule(
"no-computed-public-class-fields",
"edge < 79, safari < 14.5, firefox < 69, chrome < 74",
"disallow computed public static or instance class fields like [foo] = 1",
{ ts: 2022 }
);
createRule(
"no-private-class-fields",
"edge < 79, safari < 14.5, firefox < 90, chrome < 74",
"disallow private class fields like #foo = 1",
{ ts: 2022 }
);
createRule(
"no-class-static-blocks",
"edge < 94, safari < 16.4, firefox < 93, chrome < 94",
"disallow static blocks like `static { x = 1 }`",
{ ts: 2022 }
);
createRule(
"no-top-level-await",
"edge < 89, safari < 15, firefox < 89, chrome < 89",
"disallow await keyword outside of async function context",
{ ts: 2022 }
);
// ES2023
createRule(
"no-hashbang-comment",
"edge < 79, safari < 13.1, firefox < 67, chrome < 74",
"disallow hashbang comments",
{ ts: 2023 }
);
// ES2024
createRule(
"no-regexp-v-flag",
"edge > 0, safari < 17, firefox < 116, chrome < 112",
"disallow the use of the RegExp `v` flag",
{ ts: 2024 }
);
// ES2025
createRule(
"no-regexp-duplicate-named-groups",
"edge < 125, safari < 17, firefox < 129, chrome < 125",
"disallow the use of RegExp duplicate named groups",
{ ts: 2025 }
);
// Proposals...
createRule(
"no-do-expression",
"edge > 0, safari > 0, firefox > 0, chrome > 0",
'disallow "do" expressions'
);
createRule(
"no-bind-operator",
"edge > 0, safari > 0, firefox > 0, chrome > 0",
"disallow the :: bind operator"
);
createRule(
"no-pipeline-operator",
"edge > 0, safari > 0, firefox > 0, chrome > 0",
"disallow the > pipeline operator"
);
module.exports.configs.recommended = {
plugins: ["escompat"],
parserOptions: { ecmaVersion: 2025 },
rules: Object.keys(module.exports.rules).reduce(
(o, r) => ((o["escompat/" + r] = ["error"]), o),
{}
),
};
module.exports.configs["flat/recommended"] = {
name: 'escompat/flat/recommended',
plugins: {
escompat: module.exports
},
languageOptions: {
ecmaVersion: 2025
},
rules: Object.keys(module.exports.rules).reduce(
(o, r) => ((o["escompat/" + r] = ["error"]), o),
{}
),
};
module.exports.configs.typescript = {
extends: ["plugin:escompat/typescript-2025"],
};
module.exports.configs['flat/typescript'] = flatTypeScriptConfigs[
'typescript-2025'
];
if (require.main === module) {
console.log(require("util").inspect(module.exports, { depth: Infinity }));
}

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
':function[async=true][generator=true]'(node) {
context.report(node, `Async Generators are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'ForOfStatement[await=true]'(node) {
context.report(node, `Async Iteration is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'Literal[bigint]'(node) {
context.report(node, `BigInts are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
BindExpression(node) {
context.report(node, `The Bind Operator is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,10 @@
'use strict';
module.exports = (context, badBrowser) => ({
StaticBlock(node) {
context.report(
node,
`Class Static Blocks are not supported in ${badBrowser}`
);
},
});

View file

@ -0,0 +1,11 @@
'use strict';
module.exports = (context, badBrowser) => ({
// Ignore type annotations that don't assign
'ClassProperty[computed=true]:not([typeAnnotation]:not([value]))'(node) {
context.report(node, `Computed Class Fields are not supported in ${badBrowser}`)
},
'PropertyDefinition[computed=true]:not([typeAnnotation]:not([value]))'(node) {
context.report(node, `Computed Class Fields are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
DoExpression(node) {
context.report(node, `Do Expressions are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'ImportExpression, CallExpression[callee.type="Import"]'(node) {
context.report(node, `Dynamic import is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,31 @@
'use strict';
const objectPatternHasDefaults = node =>
node.type === 'ObjectPattern' && node.properties.some(prop => prop.value.type === 'AssignmentPattern')
module.exports = function(context) {
return {
ArrowFunctionExpression(node) {
// Unary functions don't trip on this bug
if (node.params.length < 2) return
// This bug only occurs when some arguments use Object destructuring
if (!node.params.some(param => param.type === 'ObjectPattern')) return
const objectPatternArgs = node.params.filter(node => node.type === 'ObjectPattern')
// This bug is only occurs when an argument uses Object Destructuring with Default assignment
if (!objectPatternArgs.some(objectPatternHasDefaults)) return
// This bug gets fixed if the first argument uses Object destructuring with default assignments!
if (node.params[0].type === 'ObjectPattern' && objectPatternHasDefaults(node.params[0])) return
context.report(
node,
'There is an Edge 15-17 bug which causes second argument destructuring to fail. See https://git.io/fhd7N for more'
)
}
}
}
module.exports.schema = []

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'AssignmentExpression[operator="**="], BinaryExpression[operator="**"]'(node) {
context.report(node, `Exponentiation Operator is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,13 @@
'use strict';
module.exports = (context, badBrowser) => {
const { sourceCode = context.getSourceCode() } = context;
return {
'Program:exit' (node) {
const [comment] = sourceCode.getAllComments();
if (comment && comment.type === 'Shebang') {
context.report(node, `Hashbang comments are not supported in ${badBrowser}`)
}
}
}
}

View file

@ -0,0 +1,13 @@
'use strict';
module.exports = (context, badBrowser) => ({
'AssignmentExpression[operator="||="]'(node) {
context.report(node, `Logical assignment operators are not supported in ${badBrowser}`)
},
'AssignmentExpression[operator="&&="]'(node) {
context.report(node, `Logical assignment operators are not supported in ${badBrowser}`)
},
'AssignmentExpression[operator="??="]'(node) {
context.report(node, `Logical assignment operators are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'LogicalExpression[operator="??"]'(node) {
context.report(node, `the Nullish Coalescing Operator is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,16 @@
'use strict';
module.exports = {
meta: {
fixable: 'code'
},
create: (context, badBrowser) => ({
'Literal[raw=/_/][value>=0], Literal[raw=/_/][value<=0]'(node) {
context.report({
node,
message: `Numeric Separators are not supported in ${badBrowser}`,
fix: fixer => fixer.replaceText(node, String(node.value))
})
}
})
}

View file

@ -0,0 +1,18 @@
'use strict';
module.exports = (context, badBrowser) => ({
'ObjectExpression > SpreadElement'(node) {
context.report(node, `Object Rest/Spread is not supported in ${badBrowser}`)
},
'ObjectPattern > RestElement'(node) {
context.report(node, `Object Rest/Spread is not supported in ${badBrowser}`)
},
// Catch older versions of eslint and babel-eslint
ExperimentalRestProperty(node) {
context.report(node, `Object Rest/Spread is not supported in ${badBrowser}`)
},
ExperimentalSpreadProperty(node) {
context.report(node, `Object Rest/Spread is not supported in ${badBrowser}`)
},
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'CatchClause:not([param])'(node) {
context.report(node, `Optional Catch Parameters are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,10 @@
'use strict';
module.exports = (context, badBrowser) => ({
OptionalMemberExpression(node) {
context.report(node, `Optional Chaining is not supported in ${badBrowser}`)
},
ChainExpression(node) {
context.report(node, `Optional Chaining is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,7 @@
'use strict';
module.exports = (context, badBrowser) => ({
'BinaryExpression[operator="|>"]'(node) {
context.report(node, `The Pipeline Operator is not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,10 @@
'use strict';
module.exports = (context, badBrowser) => ({
ClassPrivateProperty(node) {
context.report(node, `Private Class Fields are not supported in ${badBrowser}`)
},
PrivateIdentifier(node) {
context.report(node, `Private Class Fields are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,13 @@
'use strict';
module.exports = (context, badBrowser) => ({
// Ignore type annotations that don't assign
'ClassProperty[static=false]:not([typeAnnotation]:not([value]))'(node) {
if (node.value === null) return
context.report(node, `Instance Class Fields are not supported in ${badBrowser}`)
},
'PropertyDefinition[static=false]:not([typeAnnotation]:not([value]))'(node) {
if (node.value === null) return
context.report(node, `Instance Class Fields are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,11 @@
'use strict';
module.exports = (context, badBrowser) => ({
// Ignore type annotations that don't assign
'ClassProperty[static=true]:not([typeAnnotation]:not([value]))'(node) {
context.report(node, `Static Class Fields are not supported in ${badBrowser}`)
},
'PropertyDefinition[static=true]:not([typeAnnotation]:not([value]))'(node) {
context.report(node, `Static Class Fields are not supported in ${badBrowser}`)
}
})

View file

@ -0,0 +1,30 @@
'use strict';
const hasDuplicateNamedGroups = s => /(\(\?<[_$\w]*?)>.*?\1>/.test(s)
module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (hasDuplicateNamedGroups(node.regex.pattern)) {
context.report(node, `RegExp duplicate named groups are not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [source] = node.arguments;
if (
source &&
(
(
source.type === 'Literal' &&
typeof source.value === 'string' &&
hasDuplicateNamedGroups(source.value)
) ||
(
source.type === 'TemplateLiteral' &&
source.quasis.some(({value: {raw}}) => hasDuplicateNamedGroups(raw))
)
)
) {
context.report(node, `RegExp duplicate named groups are not supported in ${badBrowser}`)
}
}
})

View file

@ -0,0 +1,30 @@
'use strict';
const hasLookbehind = s => s.includes('(?<=') || s.includes('(?<!')
module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (hasLookbehind(node.regex.pattern)) {
context.report(node, `RegExp lookbehinds are not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [source] = node.arguments;
if (
source &&
(
(
source.type === 'Literal' &&
typeof source.value === 'string' &&
hasLookbehind(source.value)
) ||
(
source.type === 'TemplateLiteral' &&
source.quasis.some(({value: {raw}}) => hasLookbehind(raw))
)
)
) {
context.report(node, `RegExp lookbehinds are not supported in ${badBrowser}`)
}
}
})

View file

@ -0,0 +1,30 @@
'use strict';
const hasNamedGroup = s => /\(\?<[_$\w]/.test(s)
module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (hasNamedGroup(node.regex.pattern)) {
context.report(node, `RegExp named groups are not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [source] = node.arguments;
if (
source &&
(
(
source.type === 'Literal' &&
typeof source.value === 'string' &&
hasNamedGroup(source.value)
) ||
(
source.type === 'TemplateLiteral' &&
source.quasis.some(({value: {raw}}) => hasNamedGroup(raw))
)
)
) {
context.report(node, `RegExp named groups are not supported in ${badBrowser}`)
}
}
})

View file

@ -0,0 +1,28 @@
'use strict';
module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (node.regex.flags.includes('s')) {
context.report(node, `RegExp "s" flag is not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [, flags] = node.arguments;
if (
flags &&
(
(
flags.type === 'Literal' &&
typeof flags.value === 'string' &&
flags.value.includes('s')
) ||
(
flags.type === 'TemplateLiteral' &&
flags.quasis.some(({value: {raw}}) => raw.includes('s'))
)
)
) {
context.report(node, `RegExp "s" flag is not supported in ${badBrowser}`)
}
}
})

View file

@ -0,0 +1,28 @@
'use strict';
module.exports = (context, badBrowser) => ({
'Literal[regex]'(node) {
if (node.regex.flags.includes('v')) {
context.report(node, `RegExp "v" flag is not supported in ${badBrowser}`)
}
},
'CallExpression[callee.name="RegExp"], NewExpression[callee.name="RegExp"]'(node) {
const [, flags] = node.arguments;
if (
flags &&
(
(
flags.type === 'Literal' &&
typeof flags.value === 'string' &&
flags.value.includes('v')
) ||
(
flags.type === 'TemplateLiteral' &&
flags.quasis.some(({value: {raw}}) => raw.includes('v'))
)
)
) {
context.report(node, `RegExp "v" flag is not supported in ${badBrowser}`)
}
}
})

View file

@ -0,0 +1,20 @@
'use strict';
const functionTypes = new Set([
'FunctionDeclaration',
'FunctionExpression',
'ArrowFunctionExpression',
]);
module.exports = (context, badBrowser) => ({
AwaitExpression(node) {
let currentNode = node;
while (currentNode.parent) {
currentNode = currentNode.parent;
if (functionTypes.has(currentNode.type) && currentNode.async) {
return;
}
}
context.report(node, `Top-level await is not supported in ${badBrowser}`)
},
})

View file

@ -0,0 +1,39 @@
{
"name": "eslint-plugin-escompat",
"version": "3.11.4",
"description": "",
"keywords": [],
"repository": {
"type": "git",
"url": "https://github.com/keithamus/eslint-plugin-escompat"
},
"homepage": "https://github.com/keithamus/eslint-plugin-escompat",
"license": "MIT",
"author": "Keith Cirkel (https://keithcirkel.co.uk/)",
"files": [
"lib/*"
],
"main": "lib/index.js",
"scripts": {
"lint": "eslint .",
"test": "npm run lint && mocha"
},
"devDependencies": {
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-proposal-do-expressions": "^7.24.7",
"@babel/plugin-proposal-function-bind": "^7.24.7",
"@babel/plugin-proposal-pipeline-operator": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@eslint/js": "^9.6.0",
"eslint": "^9.6.0",
"globals": "^15.7.0",
"mocha": "^10.5.2"
},
"peerDependencies": {
"eslint": ">=5.14.1"
},
"dependencies": {
"browserslist": "^4.23.1"
}
}