@valkyrjaio/ci-eslint 26.0.0 → 26.1.0
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 +38 -13
- package/dist/Eslint/Constant/EslintInfo.d.ts +2 -2
- package/dist/Eslint/Constant/EslintInfo.js +2 -2
- package/dist/Eslint/Rules.d.ts +59 -0
- package/dist/Eslint/Rules.d.ts.map +1 -0
- package/dist/Eslint/Rules.js +103 -0
- package/dist/Eslint/Rules.js.map +1 -0
- package/dist/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.d.ts +8 -0
- package/dist/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.d.ts.map +1 -0
- package/dist/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.js +18 -0
- package/dist/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +14 -2
- package/src/Eslint/Constant/EslintInfo.ts +2 -2
- package/src/Eslint/Rules.ts +132 -0
- package/src/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.ts +20 -0
- package/src/index.ts +3 -0
package/README.md
CHANGED
|
@@ -28,19 +28,40 @@ itself.
|
|
|
28
28
|
|
|
29
29
|
## Usage
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
that it returns:
|
|
31
|
+
A repository states only what is true of itself, and `Rules` supplies the rest:
|
|
33
32
|
|
|
34
33
|
```js
|
|
35
|
-
import
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
import path from 'path';
|
|
35
|
+
import { Rules } from '@valkyrjaio/ci-eslint';
|
|
36
|
+
|
|
37
|
+
export default Rules.getConfig({
|
|
38
|
+
packageName: 'Valkyrja Framework',
|
|
39
|
+
tsconfigRootDir: path.resolve(import.meta.dirname, '../../..'),
|
|
40
|
+
project: ['./tsconfig.tests.json'],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`getConfig` returns the whole flat configuration: the ESLint and typescript-eslint
|
|
45
|
+
presets, the shared rules, the copyright header rule, and the test-file rules.
|
|
46
|
+
|
|
47
|
+
A repository picks one of two ways to find its TypeScript project. Give `project`
|
|
48
|
+
when one tsconfig spans both `src` and `tests`. Give `projectService` to let
|
|
49
|
+
typescript-eslint find the project, which reads `tsconfig.json` only. Give exactly
|
|
50
|
+
one; `getConfig` rejects neither and both.
|
|
51
|
+
|
|
52
|
+
Warning: with neither option typescript-eslint reads no type information, every
|
|
53
|
+
type-aware rule goes quiet, and the run still reports success. That is why the
|
|
54
|
+
guard stops rather than picking a default.
|
|
55
|
+
|
|
56
|
+
Add what only this repository needs through `overrides`, which append after the
|
|
57
|
+
shared entries:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
Rules.getConfig({
|
|
61
|
+
packageName: 'Valkyrja Application',
|
|
62
|
+
tsconfigRootDir: path.resolve(import.meta.dirname, '../../..'),
|
|
63
|
+
projectService: true,
|
|
64
|
+
overrides: [{ files: ['bin/**/*.ts'], rules: { 'no-console': 'off' } }],
|
|
44
65
|
});
|
|
45
66
|
```
|
|
46
67
|
|
|
@@ -53,12 +74,16 @@ every repository to its identifier. `valkyrja-ts` takes `Valkyrja Framework`,
|
|
|
53
74
|
|
|
54
75
|
| Member | Returns |
|
|
55
76
|
| :---------------------------------------- | :-------------------------------------------------- |
|
|
77
|
+
| `Rules.getConfig(options)` | the whole flat configuration |
|
|
78
|
+
| `Rules.getRules()` | the rules that apply to every linted file |
|
|
79
|
+
| `Rules.getTestRules()` | the rules that apply to a test file only |
|
|
80
|
+
| `Rules.getParserOptions(options)` | the parser options that find the project |
|
|
56
81
|
| `CopyrightHeaderFactory.getRule(name)` | the ESLint rule that requires the header |
|
|
57
82
|
| `CopyrightHeaderFactory.getHeader(name)` | the full block comment, and the blank line below it |
|
|
58
83
|
| `CopyrightHeaderFactory.getComment(name)` | the text between the two comment delimiters |
|
|
59
84
|
|
|
60
|
-
Each member takes the package identifier, and each one
|
|
61
|
-
names no package.
|
|
85
|
+
Each `CopyrightHeaderFactory` member takes the package identifier, and each one
|
|
86
|
+
rejects a value that names no package.
|
|
62
87
|
|
|
63
88
|
## Why the package name is guarded
|
|
64
89
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare class EslintInfo {
|
|
2
|
-
static readonly VERSION: "26.
|
|
3
|
-
static readonly VERSION_BUILD_DATE_TIME: "August
|
|
2
|
+
static readonly VERSION: "26.1.0";
|
|
3
|
+
static readonly VERSION_BUILD_DATE_TIME: "August 3 2026 00:42:35 MST";
|
|
4
4
|
}
|
|
5
5
|
//# sourceMappingURL=EslintInfo.d.ts.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Released under the MIT License. See LICENSE.md for details.
|
|
7
7
|
*/
|
|
8
8
|
export class EslintInfo {
|
|
9
|
-
static VERSION = '26.
|
|
10
|
-
static VERSION_BUILD_DATE_TIME = 'August
|
|
9
|
+
static VERSION = '26.1.0';
|
|
10
|
+
static VERSION_BUILD_DATE_TIME = 'August 3 2026 00:42:35 MST';
|
|
11
11
|
}
|
|
12
12
|
//# sourceMappingURL=EslintInfo.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* What a repository states about itself.
|
|
4
|
+
*
|
|
5
|
+
* Every other part of the configuration is the same in each repository, so this package holds it.
|
|
6
|
+
*/
|
|
7
|
+
export interface RulesOptions {
|
|
8
|
+
/** The package identifier the header states, such as `Valkyrja Framework`. */
|
|
9
|
+
packageName: string;
|
|
10
|
+
/** The absolute directory that a `project` path resolves from. */
|
|
11
|
+
tsconfigRootDir: string;
|
|
12
|
+
/** The TypeScript projects to read. Give this, or `projectService`, and never both. */
|
|
13
|
+
project?: string[];
|
|
14
|
+
/** Let typescript-eslint find the project. Give this, or `project`, and never both. */
|
|
15
|
+
projectService?: boolean;
|
|
16
|
+
/** Flat configuration entries this repository adds after the shared ones. */
|
|
17
|
+
overrides?: Linter.Config[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds the ESLint configuration that every Valkyrja TypeScript repository runs.
|
|
21
|
+
*
|
|
22
|
+
* A repository that keeps its own copy of these rules drifts from the others, and no tool reports
|
|
23
|
+
* the drift. This class therefore holds the rules, and a repository states only what is true of
|
|
24
|
+
* itself: its package identifier, and how to find its TypeScript project.
|
|
25
|
+
*/
|
|
26
|
+
export declare class Rules {
|
|
27
|
+
/**
|
|
28
|
+
* Builds the whole configuration.
|
|
29
|
+
*
|
|
30
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither `project` nor
|
|
31
|
+
* `projectService`, or names both
|
|
32
|
+
*/
|
|
33
|
+
static getConfig(options: RulesOptions): Linter.Config[];
|
|
34
|
+
/**
|
|
35
|
+
* The rules that apply to every linted file.
|
|
36
|
+
*/
|
|
37
|
+
static getRules(): Linter.RulesRecord;
|
|
38
|
+
/**
|
|
39
|
+
* The rules that apply to a test file only.
|
|
40
|
+
*
|
|
41
|
+
* A test builds a stub as `{ method: vi.fn() } as unknown as SomeContract`, so
|
|
42
|
+
* `expect(stub.method)` reads the method off the contract type purely to assert on the spy. The
|
|
43
|
+
* test never invokes the method unbound. `unbound-method` sees the declared contract type only,
|
|
44
|
+
* and it cannot tell the two apart, so it reports every such assertion. The rule still applies
|
|
45
|
+
* in full to `src`.
|
|
46
|
+
*/
|
|
47
|
+
static getTestRules(): Linter.RulesRecord;
|
|
48
|
+
/**
|
|
49
|
+
* The parser options that find the repository's TypeScript project.
|
|
50
|
+
*
|
|
51
|
+
* A repository picks one of the two ways. `project` names the tsconfig files to read, which a
|
|
52
|
+
* repository needs when one tsconfig spans both `src` and `tests`. `projectService` lets
|
|
53
|
+
* typescript-eslint find the project, which reads `tsconfig.json` only.
|
|
54
|
+
*
|
|
55
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither, or both
|
|
56
|
+
*/
|
|
57
|
+
static getParserOptions(options: RulesOptions): Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=Rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Rules.d.ts","sourceRoot":"","sources":["../../src/Eslint/Rules.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAQrC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IACzB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,uFAAuF;IACvF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,KAAK;IACd;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE;IAqBxD;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,WAAW;IAWrC;;;;;;;;OAQG;IACH,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,WAAW;IAMzC;;;;;;;;OAQG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAuB1E"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Valkyrja ESLint package.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
|
+
*
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
7
|
+
*/
|
|
8
|
+
import eslint from '@eslint/js';
|
|
9
|
+
// `defineConfig` comes from ESLint core. `tseslint.config` did the same job and is deprecated.
|
|
10
|
+
import { defineConfig } from 'eslint/config';
|
|
11
|
+
import tseslint from 'typescript-eslint';
|
|
12
|
+
import { CopyrightHeaderFactory } from "./Factory/CopyrightHeaderFactory.js";
|
|
13
|
+
import { EslintInvalidParserOptionsException } from "./Throwable/Exception/EslintInvalidParserOptionsException.js";
|
|
14
|
+
/**
|
|
15
|
+
* Builds the ESLint configuration that every Valkyrja TypeScript repository runs.
|
|
16
|
+
*
|
|
17
|
+
* A repository that keeps its own copy of these rules drifts from the others, and no tool reports
|
|
18
|
+
* the drift. This class therefore holds the rules, and a repository states only what is true of
|
|
19
|
+
* itself: its package identifier, and how to find its TypeScript project.
|
|
20
|
+
*/
|
|
21
|
+
export class Rules {
|
|
22
|
+
/**
|
|
23
|
+
* Builds the whole configuration.
|
|
24
|
+
*
|
|
25
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither `project` nor
|
|
26
|
+
* `projectService`, or names both
|
|
27
|
+
*/
|
|
28
|
+
static getConfig(options) {
|
|
29
|
+
return defineConfig([
|
|
30
|
+
eslint.configs.recommended,
|
|
31
|
+
tseslint.configs.strictTypeChecked,
|
|
32
|
+
{
|
|
33
|
+
languageOptions: {
|
|
34
|
+
parserOptions: Rules.getParserOptions(options),
|
|
35
|
+
},
|
|
36
|
+
plugins: {
|
|
37
|
+
local: { rules: { 'copyright-header': CopyrightHeaderFactory.getRule(options.packageName) } },
|
|
38
|
+
},
|
|
39
|
+
rules: Rules.getRules(),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
files: ['tests/**/*.ts'],
|
|
43
|
+
rules: Rules.getTestRules(),
|
|
44
|
+
},
|
|
45
|
+
...(options.overrides ?? []),
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The rules that apply to every linted file.
|
|
50
|
+
*/
|
|
51
|
+
static getRules() {
|
|
52
|
+
return {
|
|
53
|
+
'local/copyright-header': 'error',
|
|
54
|
+
'@typescript-eslint/no-namespace': 'off',
|
|
55
|
+
'@typescript-eslint/no-extraneous-class': 'off',
|
|
56
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
57
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
58
|
+
'@typescript-eslint/no-invalid-void-type': ['error', { allowAsThisParameter: true }],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The rules that apply to a test file only.
|
|
63
|
+
*
|
|
64
|
+
* A test builds a stub as `{ method: vi.fn() } as unknown as SomeContract`, so
|
|
65
|
+
* `expect(stub.method)` reads the method off the contract type purely to assert on the spy. The
|
|
66
|
+
* test never invokes the method unbound. `unbound-method` sees the declared contract type only,
|
|
67
|
+
* and it cannot tell the two apart, so it reports every such assertion. The rule still applies
|
|
68
|
+
* in full to `src`.
|
|
69
|
+
*/
|
|
70
|
+
static getTestRules() {
|
|
71
|
+
return {
|
|
72
|
+
'@typescript-eslint/unbound-method': 'off',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The parser options that find the repository's TypeScript project.
|
|
77
|
+
*
|
|
78
|
+
* A repository picks one of the two ways. `project` names the tsconfig files to read, which a
|
|
79
|
+
* repository needs when one tsconfig spans both `src` and `tests`. `projectService` lets
|
|
80
|
+
* typescript-eslint find the project, which reads `tsconfig.json` only.
|
|
81
|
+
*
|
|
82
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither, or both
|
|
83
|
+
*/
|
|
84
|
+
static getParserOptions(options) {
|
|
85
|
+
const hasProject = options.project !== undefined;
|
|
86
|
+
const hasProjectService = options.projectService !== undefined;
|
|
87
|
+
// Warning: neither option set means typescript-eslint parses no type information, and every
|
|
88
|
+
// type-aware rule goes quiet while the run still reports success. Both set is ambiguous.
|
|
89
|
+
// Stop on each, rather than pick one and lint less than the repository expects.
|
|
90
|
+
if (hasProject === hasProjectService) {
|
|
91
|
+
// The message names the options rather than a method. Both `getConfig` and
|
|
92
|
+
// `getParserOptions` are public and reach this guard, so a method name in the text is
|
|
93
|
+
// wrong for one of the two callers.
|
|
94
|
+
throw new EslintInvalidParserOptionsException('The options take either `project` or `projectService`, and they name ' +
|
|
95
|
+
(hasProject ? 'both.' : 'neither.'));
|
|
96
|
+
}
|
|
97
|
+
if (options.project !== undefined) {
|
|
98
|
+
return { project: options.project, tsconfigRootDir: options.tsconfigRootDir };
|
|
99
|
+
}
|
|
100
|
+
return { projectService: options.projectService, tsconfigRootDir: options.tsconfigRootDir };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=Rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Rules.js","sourceRoot":"","sources":["../../src/Eslint/Rules.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,MAAM,MAAM,YAAY,CAAC;AAEhC,+FAA+F;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,mCAAmC,EAAE,MAAM,8DAA8D,CAAC;AAoBnH;;;;;;GAMG;AACH,MAAM,OAAO,KAAK;IACd;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,OAAqB;QAClC,OAAO,YAAY,CAAC;YAChB,MAAM,CAAC,OAAO,CAAC,WAAW;YAC1B,QAAQ,CAAC,OAAO,CAAC,iBAAiB;YAClC;gBACI,eAAe,EAAE;oBACb,aAAa,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC;iBACjD;gBACD,OAAO,EAAE;oBACL,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,kBAAkB,EAAE,sBAAsB,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE;iBAChG;gBACD,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;aAC1B;YACD;gBACI,KAAK,EAAE,CAAC,eAAe,CAAC;gBACxB,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE;aAC9B;YACD,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;SAC/B,CAAC,CAAC;IACP,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAQ;QACX,OAAO;YACH,wBAAwB,EAAE,OAAO;YACjC,iCAAiC,EAAE,KAAK;YACxC,wCAAwC,EAAE,KAAK;YAC/C,mDAAmD,EAAE,KAAK;YAC1D,mCAAmC,EAAE,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;YACpG,yCAAyC,EAAE,CAAC,OAAO,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC;SACvF,CAAC;IACN,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,YAAY;QACf,OAAO;YACH,mCAAmC,EAAE,KAAK;SAC7C,CAAC;IACN,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAqB;QACzC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC;QACjD,MAAM,iBAAiB,GAAG,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC;QAE/D,4FAA4F;QAC5F,yFAAyF;QACzF,gFAAgF;QAChF,IAAI,UAAU,KAAK,iBAAiB,EAAE,CAAC;YACnC,2EAA2E;YAC3E,sFAAsF;YACtF,oCAAoC;YACpC,MAAM,IAAI,mCAAmC,CACzC,uEAAuE;gBACnE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAC1C,CAAC;QACN,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;QAClF,CAAC;QAED,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC;IAChG,CAAC;CACJ"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EslintInvalidArgumentException } from './Abstract/EslintInvalidArgumentException.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The caller named neither, or both, of the two ways to find the TypeScript project.
|
|
4
|
+
*/
|
|
5
|
+
export declare class EslintInvalidParserOptionsException extends EslintInvalidArgumentException {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=EslintInvalidParserOptionsException.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EslintInvalidParserOptionsException.d.ts","sourceRoot":"","sources":["../../../../src/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AAE9F;;GAEG;AACH,qBAAa,mCAAoC,SAAQ,8BAA8B;gBACvE,OAAO,EAAE,MAAM;CAK9B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Valkyrja ESLint package.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
|
+
*
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
7
|
+
*/
|
|
8
|
+
import { EslintInvalidArgumentException } from "./Abstract/EslintInvalidArgumentException.js";
|
|
9
|
+
/**
|
|
10
|
+
* The caller named neither, or both, of the two ways to find the TypeScript project.
|
|
11
|
+
*/
|
|
12
|
+
export class EslintInvalidParserOptionsException extends EslintInvalidArgumentException {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'EslintInvalidParserOptionsException';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=EslintInvalidParserOptionsException.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EslintInvalidParserOptionsException.js","sourceRoot":"","sources":["../../../../src/Eslint/Throwable/Exception/EslintInvalidParserOptionsException.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,8BAA8B,EAAE,MAAM,8CAA8C,CAAC;AAE9F;;GAEG;AACH,MAAM,OAAO,mCAAoC,SAAQ,8BAA8B;IACnF,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,IAAI,GAAG,qCAAqC,CAAC;IACtD,CAAC;CACJ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { EslintInfo } from './Eslint/Constant/EslintInfo.ts';
|
|
2
2
|
export { CopyrightHeaderFactory } from './Eslint/Factory/CopyrightHeaderFactory.ts';
|
|
3
|
+
export { Rules } from './Eslint/Rules.ts';
|
|
4
|
+
export type { RulesOptions } from './Eslint/Rules.ts';
|
|
3
5
|
export { EslintInvalidArgumentException } from './Eslint/Throwable/Exception/Abstract/EslintInvalidArgumentException.ts';
|
|
4
6
|
export { EslintInvalidPackageNameException } from './Eslint/Throwable/Exception/EslintInvalidPackageNameException.ts';
|
|
7
|
+
export { EslintInvalidParserOptionsException } from './Eslint/Throwable/Exception/EslintInvalidParserOptionsException.ts';
|
|
5
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAE,8BAA8B,EAAE,MAAM,yEAAyE,CAAC;AACzH,OAAO,EAAE,iCAAiC,EAAE,MAAM,mEAAmE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,8BAA8B,EAAE,MAAM,yEAAyE,CAAC;AACzH,OAAO,EAAE,iCAAiC,EAAE,MAAM,mEAAmE,CAAC;AACtH,OAAO,EAAE,mCAAmC,EAAE,MAAM,qEAAqE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { EslintInfo } from "./Eslint/Constant/EslintInfo.js";
|
|
9
9
|
export { CopyrightHeaderFactory } from "./Eslint/Factory/CopyrightHeaderFactory.js";
|
|
10
|
+
export { Rules } from "./Eslint/Rules.js";
|
|
10
11
|
export { EslintInvalidArgumentException } from "./Eslint/Throwable/Exception/Abstract/EslintInvalidArgumentException.js";
|
|
11
12
|
export { EslintInvalidPackageNameException } from "./Eslint/Throwable/Exception/EslintInvalidPackageNameException.js";
|
|
13
|
+
export { EslintInvalidParserOptionsException } from "./Eslint/Throwable/Exception/EslintInvalidParserOptionsException.js";
|
|
12
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAE,8BAA8B,EAAE,MAAM,yEAAyE,CAAC;AACzH,OAAO,EAAE,iCAAiC,EAAE,MAAM,mEAAmE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,8BAA8B,EAAE,MAAM,yEAAyE,CAAC;AACzH,OAAO,EAAE,iCAAiC,EAAE,MAAM,mEAAmE,CAAC;AACtH,OAAO,EAAE,mCAAmC,EAAE,MAAM,qEAAqE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valkyrjaio/ci-eslint",
|
|
3
|
-
"version": "26.
|
|
3
|
+
"version": "26.1.0",
|
|
4
4
|
"description": "Shared ESLint configuration for Valkyrja TypeScript repositories",
|
|
5
5
|
"homepage": "https://www.valkyrja.io",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/valkyrjaio/ci-eslint-ts/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/valkyrjaio/ci-eslint-ts.git"
|
|
12
|
+
},
|
|
6
13
|
"keywords": [
|
|
7
14
|
"ci",
|
|
8
15
|
"eslint",
|
|
@@ -34,7 +41,8 @@
|
|
|
34
41
|
"typescript-outdated-check": "cd .github/ci/typescript && npm install && npm outdated",
|
|
35
42
|
"typescript-outdated-check-major-release": "cd .github/ci/typescript && npm install && npm outdated",
|
|
36
43
|
"typescript-npm-update": "cd .github/ci/typescript && npm update",
|
|
37
|
-
"eslint": "cd .github/ci/eslint && npm run
|
|
44
|
+
"eslint": "cd .github/ci/eslint && npm run fix",
|
|
45
|
+
"eslint-check": "cd .github/ci/eslint && npm run check",
|
|
38
46
|
"eslint-outdated-check": "cd .github/ci/eslint && npm install && npm outdated",
|
|
39
47
|
"eslint-outdated-check-major-release": "cd .github/ci/eslint && npm install && npm outdated",
|
|
40
48
|
"eslint-npm-update": "cd .github/ci/eslint && npm update",
|
|
@@ -56,5 +64,9 @@
|
|
|
56
64
|
},
|
|
57
65
|
"peerDependencies": {
|
|
58
66
|
"eslint": ">=9"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@eslint/js": "^10.0.1",
|
|
70
|
+
"typescript-eslint": "^8.65.0"
|
|
59
71
|
}
|
|
60
72
|
}
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
export class EslintInfo {
|
|
10
|
-
static readonly VERSION = '26.
|
|
11
|
-
static readonly VERSION_BUILD_DATE_TIME = 'August
|
|
10
|
+
static readonly VERSION = '26.1.0' as const;
|
|
11
|
+
static readonly VERSION_BUILD_DATE_TIME = 'August 3 2026 00:42:35 MST' as const;
|
|
12
12
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Valkyrja ESLint package.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
|
+
*
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import eslint from '@eslint/js';
|
|
10
|
+
import type { Linter } from 'eslint';
|
|
11
|
+
// `defineConfig` comes from ESLint core. `tseslint.config` did the same job and is deprecated.
|
|
12
|
+
import { defineConfig } from 'eslint/config';
|
|
13
|
+
import tseslint from 'typescript-eslint';
|
|
14
|
+
|
|
15
|
+
import { CopyrightHeaderFactory } from './Factory/CopyrightHeaderFactory.ts';
|
|
16
|
+
import { EslintInvalidParserOptionsException } from './Throwable/Exception/EslintInvalidParserOptionsException.ts';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* What a repository states about itself.
|
|
20
|
+
*
|
|
21
|
+
* Every other part of the configuration is the same in each repository, so this package holds it.
|
|
22
|
+
*/
|
|
23
|
+
export interface RulesOptions {
|
|
24
|
+
/** The package identifier the header states, such as `Valkyrja Framework`. */
|
|
25
|
+
packageName: string;
|
|
26
|
+
/** The absolute directory that a `project` path resolves from. */
|
|
27
|
+
tsconfigRootDir: string;
|
|
28
|
+
/** The TypeScript projects to read. Give this, or `projectService`, and never both. */
|
|
29
|
+
project?: string[];
|
|
30
|
+
/** Let typescript-eslint find the project. Give this, or `project`, and never both. */
|
|
31
|
+
projectService?: boolean;
|
|
32
|
+
/** Flat configuration entries this repository adds after the shared ones. */
|
|
33
|
+
overrides?: Linter.Config[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Builds the ESLint configuration that every Valkyrja TypeScript repository runs.
|
|
38
|
+
*
|
|
39
|
+
* A repository that keeps its own copy of these rules drifts from the others, and no tool reports
|
|
40
|
+
* the drift. This class therefore holds the rules, and a repository states only what is true of
|
|
41
|
+
* itself: its package identifier, and how to find its TypeScript project.
|
|
42
|
+
*/
|
|
43
|
+
export class Rules {
|
|
44
|
+
/**
|
|
45
|
+
* Builds the whole configuration.
|
|
46
|
+
*
|
|
47
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither `project` nor
|
|
48
|
+
* `projectService`, or names both
|
|
49
|
+
*/
|
|
50
|
+
static getConfig(options: RulesOptions): Linter.Config[] {
|
|
51
|
+
return defineConfig([
|
|
52
|
+
eslint.configs.recommended,
|
|
53
|
+
tseslint.configs.strictTypeChecked,
|
|
54
|
+
{
|
|
55
|
+
languageOptions: {
|
|
56
|
+
parserOptions: Rules.getParserOptions(options),
|
|
57
|
+
},
|
|
58
|
+
plugins: {
|
|
59
|
+
local: { rules: { 'copyright-header': CopyrightHeaderFactory.getRule(options.packageName) } },
|
|
60
|
+
},
|
|
61
|
+
rules: Rules.getRules(),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
files: ['tests/**/*.ts'],
|
|
65
|
+
rules: Rules.getTestRules(),
|
|
66
|
+
},
|
|
67
|
+
...(options.overrides ?? []),
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The rules that apply to every linted file.
|
|
73
|
+
*/
|
|
74
|
+
static getRules(): Linter.RulesRecord {
|
|
75
|
+
return {
|
|
76
|
+
'local/copyright-header': 'error',
|
|
77
|
+
'@typescript-eslint/no-namespace': 'off',
|
|
78
|
+
'@typescript-eslint/no-extraneous-class': 'off',
|
|
79
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
80
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
81
|
+
'@typescript-eslint/no-invalid-void-type': ['error', { allowAsThisParameter: true }],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The rules that apply to a test file only.
|
|
87
|
+
*
|
|
88
|
+
* A test builds a stub as `{ method: vi.fn() } as unknown as SomeContract`, so
|
|
89
|
+
* `expect(stub.method)` reads the method off the contract type purely to assert on the spy. The
|
|
90
|
+
* test never invokes the method unbound. `unbound-method` sees the declared contract type only,
|
|
91
|
+
* and it cannot tell the two apart, so it reports every such assertion. The rule still applies
|
|
92
|
+
* in full to `src`.
|
|
93
|
+
*/
|
|
94
|
+
static getTestRules(): Linter.RulesRecord {
|
|
95
|
+
return {
|
|
96
|
+
'@typescript-eslint/unbound-method': 'off',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The parser options that find the repository's TypeScript project.
|
|
102
|
+
*
|
|
103
|
+
* A repository picks one of the two ways. `project` names the tsconfig files to read, which a
|
|
104
|
+
* repository needs when one tsconfig spans both `src` and `tests`. `projectService` lets
|
|
105
|
+
* typescript-eslint find the project, which reads `tsconfig.json` only.
|
|
106
|
+
*
|
|
107
|
+
* @throws EslintInvalidParserOptionsException When the caller names neither, or both
|
|
108
|
+
*/
|
|
109
|
+
static getParserOptions(options: RulesOptions): Record<string, unknown> {
|
|
110
|
+
const hasProject = options.project !== undefined;
|
|
111
|
+
const hasProjectService = options.projectService !== undefined;
|
|
112
|
+
|
|
113
|
+
// Warning: neither option set means typescript-eslint parses no type information, and every
|
|
114
|
+
// type-aware rule goes quiet while the run still reports success. Both set is ambiguous.
|
|
115
|
+
// Stop on each, rather than pick one and lint less than the repository expects.
|
|
116
|
+
if (hasProject === hasProjectService) {
|
|
117
|
+
// The message names the options rather than a method. Both `getConfig` and
|
|
118
|
+
// `getParserOptions` are public and reach this guard, so a method name in the text is
|
|
119
|
+
// wrong for one of the two callers.
|
|
120
|
+
throw new EslintInvalidParserOptionsException(
|
|
121
|
+
'The options take either `project` or `projectService`, and they name ' +
|
|
122
|
+
(hasProject ? 'both.' : 'neither.'),
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (options.project !== undefined) {
|
|
127
|
+
return { project: options.project, tsconfigRootDir: options.tsconfigRootDir };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { projectService: options.projectService, tsconfigRootDir: options.tsconfigRootDir };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Valkyrja ESLint package.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
|
+
*
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EslintInvalidArgumentException } from './Abstract/EslintInvalidArgumentException.ts';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The caller named neither, or both, of the two ways to find the TypeScript project.
|
|
13
|
+
*/
|
|
14
|
+
export class EslintInvalidParserOptionsException extends EslintInvalidArgumentException {
|
|
15
|
+
constructor(message: string) {
|
|
16
|
+
super(message);
|
|
17
|
+
|
|
18
|
+
this.name = 'EslintInvalidParserOptionsException';
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,5 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
export { EslintInfo } from './Eslint/Constant/EslintInfo.ts';
|
|
10
10
|
export { CopyrightHeaderFactory } from './Eslint/Factory/CopyrightHeaderFactory.ts';
|
|
11
|
+
export { Rules } from './Eslint/Rules.ts';
|
|
12
|
+
export type { RulesOptions } from './Eslint/Rules.ts';
|
|
11
13
|
export { EslintInvalidArgumentException } from './Eslint/Throwable/Exception/Abstract/EslintInvalidArgumentException.ts';
|
|
12
14
|
export { EslintInvalidPackageNameException } from './Eslint/Throwable/Exception/EslintInvalidPackageNameException.ts';
|
|
15
|
+
export { EslintInvalidParserOptionsException } from './Eslint/Throwable/Exception/EslintInvalidParserOptionsException.ts';
|