@open-xchange/linter-presets 0.0.3 → 0.0.5
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/CHANGELOG.md +10 -1
- package/lib/eslint/env/browser.md +40 -1
- package/lib/eslint/env/node.md +8 -1
- package/lib/eslint/env/project.md +3 -3
- package/lib/eslint/rules/no-invalid-modules.js +18 -16
- package/lib/eslint/shared/env-utils.d.ts +1 -3
- package/lib/eslint/shared/env-utils.js +13 -9
- package/lib/eslint/shared/rule-utils.js +19 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -18,4 +18,13 @@
|
|
|
18
18
|
- added: [ESLint] environment `env.project` (wraps all `env-project/*` rules)
|
|
19
19
|
- changed: [ESLint] environment `env.plugin` renamed to `env.eslint`
|
|
20
20
|
- fixed: [StyleLint] support for LESS files
|
|
21
|
-
- chore:
|
|
21
|
+
- chore: bump dependencies
|
|
22
|
+
|
|
23
|
+
## [0.0.4] - 2024-07-10
|
|
24
|
+
|
|
25
|
+
- fixed: [ESLint] file exists detection in rule `env-project/no-invalid-modules`
|
|
26
|
+
|
|
27
|
+
## [0.0.5] - 2024-07-10
|
|
28
|
+
|
|
29
|
+
- chore: [ESLint] documentation for option `restricted`
|
|
30
|
+
- chore: bump dependencies
|
|
@@ -14,9 +14,26 @@ function browser(options: EnvBrowserOptions): Linter.FlatConfig[]
|
|
|
14
14
|
| - | - | - | - |
|
|
15
15
|
| `files` | `string[]` | _required_ | Glob patterns for source files to be included. |
|
|
16
16
|
| `ignores` | `string[]` | `[]` | Glob patterns for source files matching `files` to be ignored. |
|
|
17
|
-
| `restricted` | `EnvRestrictedOptions` | `{}` | Settings for banned globals, imports, object properties, and syntax constructs. |
|
|
17
|
+
| `restricted` | `EnvRestrictedOptions` | `{}` | Settings for banned globals, imports, object properties, and syntax constructs (see below). |
|
|
18
18
|
| `rules` | `Linter.RulesRecord` | `{}` | Additional linter rules to be added to the configuration. |
|
|
19
19
|
|
|
20
|
+
### Option `restricted`
|
|
21
|
+
|
|
22
|
+
- Type: `EnvRestrictedOptions`
|
|
23
|
+
- Default: `{}`
|
|
24
|
+
|
|
25
|
+
This option allows to specify banned globals, imports, object properties, and syntax constructs. These restricted items will be set on top of the built-in restricted items of the environment preset, and will be passed to the ESLint core rules [`no-restricted-globals`](https://eslint.org/docs/latest/rules/no-restricted-globals), [`no-restricted-imports`](https://eslint.org/docs/latest/rules/no-restricted-imports), [`no-restricted-properties`](https://eslint.org/docs/latest/rules/no-restricted-properties), and [`no-restricted-syntax`](https://eslint.org/docs/latest/rules/no-restricted-syntax), respectively.
|
|
26
|
+
|
|
27
|
+
The option `restricted` is an object with the following properties:
|
|
28
|
+
|
|
29
|
+
| Name | Type | Default | Description |
|
|
30
|
+
| - | - | - | - |
|
|
31
|
+
| `globals` | `EnvRestrictedName[]` | `[]` | Banned global symbols. Each entry is an object with string properties `name` and `message`. |
|
|
32
|
+
| `imports` | `EnvRestrictedName[]` | `[]` | Banned modules that must not be imported. Each entry is an object with string properties `name` and `message`. |
|
|
33
|
+
| `properties` | `EnvRestrictedProperty[]` | `[]` | Banned object properties. Each entry is an object with string properties `object`, `property`, and `message`). |
|
|
34
|
+
| `syntax` | `EnvRestrictedSyntax[]` | `[]` | Banned syntax constructs by [AST selectors](https://eslint.org/docs/latest/extend/selectors). Each entry is an object with string properties `selector` and `message`. |
|
|
35
|
+
| `overrides` | `EnvRestrictedOverride[]` | `[]` | Overrides for specific subsets of files in the environment. Each entry is an object with the common properties `files` (required) and `ignores`, and the properties `globals`, `imports`, `properties`, and `syntax` to specify restricted items (see above). All restricted items of overrides will be merged with the common restricted items defined for the entire environment. |
|
|
36
|
+
|
|
20
37
|
## Example
|
|
21
38
|
|
|
22
39
|
```js
|
|
@@ -27,6 +44,28 @@ export default [
|
|
|
27
44
|
...eslint.configure({ /* ... */ }),
|
|
28
45
|
...eslint.env.browser({
|
|
29
46
|
files: ["src/**/*.{js,ts}"],
|
|
47
|
+
restricted: {
|
|
48
|
+
globals: [
|
|
49
|
+
{ name: "$", message: "Explicitly import the 'jquery' package." },
|
|
50
|
+
],
|
|
51
|
+
imports: [
|
|
52
|
+
{ name: "underscore", message: "Use the 'lodash' package." },
|
|
53
|
+
],
|
|
54
|
+
properties: [
|
|
55
|
+
{ object: "_", property: "flatten", message: "Use native 'Array::flat' instead." },
|
|
56
|
+
],
|
|
57
|
+
syntax: [
|
|
58
|
+
{ selector: "ClassBody > StaticBlock", message: "Static blocks not supported in all browsers." },
|
|
59
|
+
],
|
|
60
|
+
overrides: [
|
|
61
|
+
{
|
|
62
|
+
files: "src/**/*.ts",
|
|
63
|
+
properties: [
|
|
64
|
+
{ object: "$", property: "Deferred", message: "Use native promises in TypeScript code." },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
30
69
|
rules: { /* ... */ },
|
|
31
70
|
}),
|
|
32
71
|
]
|
package/lib/eslint/env/node.md
CHANGED
|
@@ -15,9 +15,16 @@ function node(options: EnvNodeOptions): Linter.FlatConfig[]
|
|
|
15
15
|
| `files` | `string[]` | _required_ | Glob patterns for source files to be included. |
|
|
16
16
|
| `ignores` | `string[]` | `[]` | Glob patterns for source files matching `files` to be ignored. |
|
|
17
17
|
| `sourceType` | `"module"\|"commonjs"` | `"module"` | Specifies how to treat `.js`, `.jsx`, `.ts`, and `.tsx`. |
|
|
18
|
-
| `restricted` | `EnvRestrictedOptions` | `{}` | Settings for banned globals, imports, object properties, and syntax constructs. |
|
|
18
|
+
| `restricted` | `EnvRestrictedOptions` | `{}` | Settings for banned globals, imports, object properties, and syntax constructs (see below). |
|
|
19
19
|
| `rules` | `Linter.RulesRecord` | `{}` | Additional linter rules to be added to the configuration. |
|
|
20
20
|
|
|
21
|
+
### Option `restricted`
|
|
22
|
+
|
|
23
|
+
- Type: `EnvRestrictedOptions`
|
|
24
|
+
- Default: `{}`
|
|
25
|
+
|
|
26
|
+
This option allows to specify banned globals, imports, object properties, and syntax constructs. See [documentation in `env.browser`](./browser.md#option-restricted) for a detailed description.
|
|
27
|
+
|
|
21
28
|
## Example
|
|
22
29
|
|
|
23
30
|
```js
|
|
@@ -90,7 +90,7 @@ Each key in the `packages` record is the arbitrary unique name of a package. The
|
|
|
90
90
|
| Name | Type | Default | Description |
|
|
91
91
|
| - | - | - | - |
|
|
92
92
|
| `src` | `string\|string[]` | _required_ | Glob patterns selecting all source files that are part of the package. |
|
|
93
|
-
| `
|
|
93
|
+
| `extends` | `string\|string[]` | `[]` | Specifies the names of all packages (dictionary keys of the option `packages`) this package depends on. |
|
|
94
94
|
| `optional` | `boolean` | `false` | Set to `true` to mark an optional package that may be missing in an installation. Such a package cannot be imported statically (with `import` statement) from a non-optional package, but can only be loaded dynamically at runtime (by calling `import()`). The rule will mark all static imports of optional code as an error. |
|
|
95
95
|
|
|
96
96
|
Modules that are part of such a package may import any modules from the same package, or from packages it depends on (also recursively from their dependent packages).
|
|
@@ -112,12 +112,12 @@ export default [
|
|
|
112
112
|
},
|
|
113
113
|
debug: {
|
|
114
114
|
src: "@/debug/**/*",
|
|
115
|
-
|
|
115
|
+
extends: "base",
|
|
116
116
|
optional: true,
|
|
117
117
|
},
|
|
118
118
|
special: {
|
|
119
119
|
src: "@/my/special/**/*",
|
|
120
|
-
|
|
120
|
+
extends: ["base", "debug"],
|
|
121
121
|
},
|
|
122
122
|
},
|
|
123
123
|
}),
|
|
@@ -21,11 +21,10 @@
|
|
|
21
21
|
|
|
22
22
|
import { createRequire } from "node:module";
|
|
23
23
|
import { posix, dirname, extname } from "node:path";
|
|
24
|
-
import { existsSync } from "node:fs";
|
|
25
24
|
|
|
26
25
|
import { packageUpSync } from "package-up";
|
|
27
26
|
|
|
28
|
-
import { Schema, makeArray, toPosixPath, matchModuleName, getModuleName } from "../shared/rule-utils.js";
|
|
27
|
+
import { Schema, makeArray, toPosixPath, isFile, matchModuleName, getModuleName } from "../shared/rule-utils.js";
|
|
29
28
|
|
|
30
29
|
// constants ==================================================================
|
|
31
30
|
|
|
@@ -45,7 +44,7 @@ export default {
|
|
|
45
44
|
external: Schema.maybeArray(Schema.stringNE()),
|
|
46
45
|
packages: Schema.dictionary(Schema.options({
|
|
47
46
|
src: Schema.maybeArray(Schema.stringNE()),
|
|
48
|
-
|
|
47
|
+
extends: Schema.maybeArray(Schema.stringNE()),
|
|
49
48
|
optional: Schema.boolean(),
|
|
50
49
|
}, ["src"])),
|
|
51
50
|
}),
|
|
@@ -70,16 +69,19 @@ export default {
|
|
|
70
69
|
// convert "alias" option to map
|
|
71
70
|
const aliasMap = new Map(Object.entries(alias));
|
|
72
71
|
|
|
73
|
-
// convert "packages"
|
|
72
|
+
// convert "packages" options (strings to arrays)
|
|
74
73
|
const packagesMap = new Map();
|
|
75
|
-
const packagesGlobs = [];
|
|
76
74
|
for (const [key, settings] of Object.entries(packages)) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
packagesMap.set(key, {
|
|
76
|
+
...settings,
|
|
77
|
+
src: makeArray(settings.src),
|
|
78
|
+
extends: makeArray(settings.extends),
|
|
79
|
+
});
|
|
81
80
|
}
|
|
82
81
|
|
|
82
|
+
// collect all globs for package members
|
|
83
|
+
const packagesGlobs = Array.from(packagesMap, settings => settings.src).flat();
|
|
84
|
+
|
|
83
85
|
// resolve file name
|
|
84
86
|
const packagePath = packageUpSync();
|
|
85
87
|
const rootDir = toPosixPath(dirname(packagePath));
|
|
@@ -106,10 +108,10 @@ export default {
|
|
|
106
108
|
|
|
107
109
|
// returns an existing alias key used by the passed module name
|
|
108
110
|
const resolveAlias = moduleName => {
|
|
109
|
-
const [key, rest] = moduleName.split("/"
|
|
110
|
-
const aliasPath = (key && rest) ? aliasMap.get(key) : undefined;
|
|
111
|
+
const [key, ...rest] = moduleName.split("/");
|
|
112
|
+
const aliasPath = (key && rest[0]) ? aliasMap.get(key) : undefined;
|
|
111
113
|
const aliasKey = aliasPath ? key : "";
|
|
112
|
-
const modulePath = aliasPath ? posix.join(aliasPath, rest) : moduleName;
|
|
114
|
+
const modulePath = aliasPath ? posix.join(aliasPath, ...rest) : moduleName;
|
|
113
115
|
return { aliasKey, modulePath };
|
|
114
116
|
};
|
|
115
117
|
|
|
@@ -117,9 +119,9 @@ export default {
|
|
|
117
119
|
const fileExists = resolvedName => {
|
|
118
120
|
// check modules with explicit extension
|
|
119
121
|
const resolvedPath = posix.join(rootDir, resolvedName);
|
|
120
|
-
if (extname(resolvedName)) { return
|
|
122
|
+
if (extname(resolvedName)) { return isFile(resolvedPath); }
|
|
121
123
|
// search for a file with a known extension
|
|
122
|
-
return FILE_EXTENSIONS.some(ext =>
|
|
124
|
+
return FILE_EXTENSIONS.some(ext => isFile(resolvedPath + "." + ext));
|
|
123
125
|
};
|
|
124
126
|
|
|
125
127
|
// returns whether the passed module name is an installed NPM package
|
|
@@ -177,12 +179,12 @@ export default {
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
// do not traverse into dependencies of optional modules
|
|
180
|
-
if (
|
|
182
|
+
if (!settings.extends.length || (!root && settings.optional)) {
|
|
181
183
|
return false;
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
// allow imports from any of the dependent packages
|
|
185
|
-
return settings.
|
|
187
|
+
return settings.extends.some(key => checkDependencies(packagesMap.get(key), false));
|
|
186
188
|
};
|
|
187
189
|
|
|
188
190
|
// check dependencies of all configured packages (not for anonymous modules)
|
|
@@ -80,9 +80,7 @@ export interface EnvRestrictedItems {
|
|
|
80
80
|
* Collection of banned globals, imports, properties, and syntax constructs,
|
|
81
81
|
* for a specific subset of the files included in an environment.
|
|
82
82
|
*/
|
|
83
|
-
export interface EnvRestrictedOverride extends EnvFilesOptions, EnvRestrictedItems {
|
|
84
|
-
merge?: boolean;
|
|
85
|
-
}
|
|
83
|
+
export interface EnvRestrictedOverride extends EnvFilesOptions, EnvRestrictedItems { }
|
|
86
84
|
|
|
87
85
|
/**
|
|
88
86
|
* Configuration options for restricted imports and globals.
|
|
@@ -33,17 +33,17 @@ export const NO_UNUSED_VARS_OPTIONS = {
|
|
|
33
33
|
// functions ==================================================================
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Concatenates the elements of multiple arrays. Skips all
|
|
36
|
+
* Concatenates the elements of multiple arrays. Skips all nullish parameters.
|
|
37
37
|
*
|
|
38
38
|
* @template T
|
|
39
39
|
*
|
|
40
|
-
* @param {Array<T[] | undefined | null
|
|
40
|
+
* @param {Array<T[] | undefined | null>} arrays
|
|
41
41
|
* The arrays to be concatenated.
|
|
42
42
|
*
|
|
43
43
|
* @returns {T[]}
|
|
44
44
|
* The concatenated arrays.
|
|
45
45
|
*/
|
|
46
|
-
function
|
|
46
|
+
function concatArrays(...arrays) {
|
|
47
47
|
return arrays.flatMap(array => array || []);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -63,6 +63,10 @@ function createRulesRecord(generator) {
|
|
|
63
63
|
const items = generator(key);
|
|
64
64
|
if (items?.length) { rules[`no-restricted-${key}`] = ["error", ...items]; }
|
|
65
65
|
}
|
|
66
|
+
// same restrictions for CommonJS `require` as for `import` statements
|
|
67
|
+
if ("no-restricted-imports" in rules) {
|
|
68
|
+
rules["no-restricted-modules"] = rules["no-restricted-imports"];
|
|
69
|
+
}
|
|
66
70
|
return rules;
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -82,22 +86,22 @@ export function generateRestrictedRules(fixed, options) {
|
|
|
82
86
|
|
|
83
87
|
// restricted items for all files in the environment
|
|
84
88
|
const items = {
|
|
85
|
-
globals:
|
|
86
|
-
imports:
|
|
87
|
-
properties:
|
|
88
|
-
syntax:
|
|
89
|
+
globals: concatArrays(RESTRICTED_GLOBALS, fixed.globals, options?.globals),
|
|
90
|
+
imports: concatArrays(fixed.imports, options?.imports),
|
|
91
|
+
properties: concatArrays(fixed.properties, options?.properties),
|
|
92
|
+
syntax: concatArrays(RESTRICTED_SYNTAX, fixed.syntax, options?.syntax),
|
|
89
93
|
};
|
|
90
94
|
|
|
91
95
|
// base rules for all files in the environment
|
|
92
96
|
const rules = createRulesRecord(key => items[key]);
|
|
93
97
|
|
|
94
|
-
// generate the override entries (join with base items
|
|
98
|
+
// generate the override entries (join with base items)
|
|
95
99
|
const overrides = [];
|
|
96
100
|
for (const override of options?.overrides ?? []) {
|
|
97
101
|
overrides.push({
|
|
98
102
|
files: override.files,
|
|
99
103
|
ignores: override.ignores ?? [],
|
|
100
|
-
rules: createRulesRecord(key =>
|
|
104
|
+
rules: createRulesRecord(key => concatArrays(items[key], override[key])),
|
|
101
105
|
});
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { posix, sep } from "node:path";
|
|
23
|
+
import { lstatSync } from "node:fs";
|
|
23
24
|
|
|
24
25
|
import pm from "picomatch";
|
|
25
26
|
|
|
@@ -101,6 +102,24 @@ export function toPosixPath(path) {
|
|
|
101
102
|
return path.replaceAll(sep, posix.sep);
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Returns whether the passed path refers to an existing file.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} path
|
|
109
|
+
* The path to be checked.
|
|
110
|
+
*
|
|
111
|
+
* @returns {boolean}
|
|
112
|
+
* Whether the passed path refers to an existing file (returns `false` for
|
|
113
|
+
* existing directories).
|
|
114
|
+
*/
|
|
115
|
+
export function isFile(path) {
|
|
116
|
+
try {
|
|
117
|
+
return lstatSync(path).isFile();
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
104
123
|
/**
|
|
105
124
|
* Returns whether a module name matches the specified glob patterns.
|
|
106
125
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-xchange/linter-presets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Configuration presets for ESLint and StyleLint",
|
|
5
5
|
"repository": "https://gitlab.open-xchange.com/fspd/npm-packages/linter-presets",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"eslint-plugin-import": "2.29.1",
|
|
33
33
|
"eslint-plugin-jest": "28.6.0",
|
|
34
34
|
"eslint-plugin-jest-dom": "5.4.0",
|
|
35
|
-
"eslint-plugin-jsdoc": "48.
|
|
35
|
+
"eslint-plugin-jsdoc": "48.6.0",
|
|
36
36
|
"eslint-plugin-jsonc": "2.16.0",
|
|
37
37
|
"eslint-plugin-jsx-a11y": "6.9.0",
|
|
38
38
|
"eslint-plugin-jsx-expressions": "1.3.2",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"eslint-plugin-react": "7.34.3",
|
|
43
43
|
"eslint-plugin-react-hooks": "4.6.2",
|
|
44
44
|
"eslint-plugin-react-hooks-static-deps": "1.0.7",
|
|
45
|
-
"eslint-plugin-react-refresh": "0.4.
|
|
45
|
+
"eslint-plugin-react-refresh": "0.4.8",
|
|
46
46
|
"eslint-plugin-testing-library": "6.2.2",
|
|
47
47
|
"eslint-plugin-vitest": "0.5.4",
|
|
48
48
|
"eslint-plugin-yml": "1.14.0",
|