Skip to content

Commit f13151f

Browse files
Marsupkanongil
andauthored
chore: next version (#1079)
* chore: change CI target for next * chore: add next branch to CI targets * feat: target ESLint v9 * Tighten type checking config (#1071) * Use more restrictive type signatures * Don't rely on broken expect.error() * chore: report node 18+ support (#1081) * chore: update documentation for eslint ignore --------- Co-authored-by: Gil Pedersen <[email protected]>
1 parent 4a2b357 commit f13151f

30 files changed

+233
-96
lines changed

.eslintignore

Lines changed: 0 additions & 9 deletions
This file was deleted.

.github/workflows/ci-module.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ on:
44
push:
55
branches:
66
- master
7+
- next
78
pull_request:
89
workflow_dispatch:
910

1011
jobs:
1112
test:
12-
uses: hapijs/.github/.github/workflows/ci-module.yml@master
13-
with:
14-
min-node-version: 14
13+
uses: hapijs/.github/.github/workflows/ci-module.yml@min-node-18-hapi-21

API.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -632,10 +632,17 @@ Your project's eslint configuration will now extend the default **lab** configur
632632

633633
### Ignoring files in linting
634634

635-
Since [eslint](http://eslint.org/) is used to lint, you can create an `.eslintignore` containing paths to be ignored:
636-
```
637-
node_modules/*
638-
**/vendor/*.js
635+
Since [eslint](http://eslint.org/) is used to lint, if you don't already have an `eslint.config.{js|cjs|mjs|ts|mts|cts}` you can create one,
636+
and add an `ignores` rule containing paths to be ignored. Here is an example preserving default hapi rules:
637+
```javascript
638+
import HapiPlugin from '@hapi/eslint-plugin';
639+
640+
export default [
641+
{
642+
ignores: ['node_modules/*', '**/vendor/*.js'],
643+
},
644+
...HapiPlugin.configs.module,
645+
];
639646
```
640647

641648
### Only run linting

eslint.config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const HapiPlugin = require('@hapi/eslint-plugin');
4+
5+
module.exports = [
6+
{
7+
ignores: [
8+
'node_modules/',
9+
'test_runner/',
10+
'test/coverage/',
11+
'test/cli/',
12+
'test/cli_*/',
13+
'test/lint/',
14+
'test/override/',
15+
'test/plan/',
16+
'test/transform/'
17+
]
18+
},
19+
...HapiPlugin.configs.module
20+
];

lib/linter/.eslintrc.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
22

3-
module.exports = {
4-
extends: 'plugin:@hapi/module'
5-
};
3+
const HapiPlugin = require('@hapi/eslint-plugin');
4+
5+
module.exports = [...HapiPlugin.configs.module];

lib/linter/index.js

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const Fs = require('fs');
4-
const Path = require('path');
54

65
const Eslint = require('eslint');
76
const Hoek = require('@hapi/hoek');
@@ -18,31 +17,50 @@ exports.lint = async function () {
1817

1918
const options = process.argv[2] ? JSON.parse(process.argv[2]) : undefined;
2019

21-
if (!Fs.existsSync('.eslintrc.js') &&
22-
!Fs.existsSync('.eslintrc.cjs') && // Needed for projects with "type": "module"
23-
!Fs.existsSync('.eslintrc.yaml') &&
24-
!Fs.existsSync('.eslintrc.yml') &&
25-
!Fs.existsSync('.eslintrc.json') &&
26-
!Fs.existsSync('.eslintrc')) {
27-
configuration.overrideConfigFile = Path.join(__dirname, '.eslintrc.js');
20+
let usingDefault = false;
21+
22+
if (!Fs.existsSync('eslint.config.js') &&
23+
!Fs.existsSync('eslint.config.cjs') &&
24+
!Fs.existsSync('eslint.config.mjs') &&
25+
!Fs.existsSync('eslint.config.ts') &&
26+
!Fs.existsSync('eslint.config.mts') &&
27+
!Fs.existsSync('eslint.config.cts')) {
28+
// No configuration file found, using the default one
29+
usingDefault = true;
30+
configuration.baseConfig = require('./.eslintrc.js');
31+
configuration.overrideConfigFile = true;
2832
}
2933

3034
if (options) {
3135
Hoek.merge(configuration, options, true, false);
3236
}
3337

34-
if (!configuration.extensions) {
35-
configuration.extensions = ['.js', '.cjs', '.mjs'];
38+
// Only the default configuration should be altered, otherwise the user's configuration should be used as is
39+
if (usingDefault) {
40+
if (!configuration.extensions) {
41+
const extensions = ['js', 'cjs', 'mjs'];
3642

37-
if (configuration.typescript) {
38-
configuration.extensions.push('.ts');
43+
if (configuration.typescript) {
44+
extensions.push('ts');
45+
}
46+
47+
configuration.baseConfig.unshift({
48+
files: extensions.map((ext) => `**/*.${ext}`)
49+
});
3950
}
40-
}
4151

42-
if (configuration.typescript) {
43-
delete configuration.typescript;
52+
if (configuration.ignores) {
53+
configuration.baseConfig.unshift({
54+
ignores: configuration.ignores
55+
});
56+
}
4457
}
4558

59+
delete configuration.extensions;
60+
delete configuration.typescript;
61+
delete configuration.ignores;
62+
63+
4664
let results;
4765
try {
4866
const eslint = new Eslint.ESLint(configuration);
@@ -66,6 +84,13 @@ exports.lint = async function () {
6684

6785
transformed.errors = result.messages.map((err) => {
6886

87+
if (err.messageTemplate === 'all-matched-files-ignored') {
88+
return {
89+
severity: 'ERROR',
90+
message: err.message
91+
};
92+
}
93+
6994
return {
7095
line: err.line,
7196
severity: err.severity === 1 ? 'WARNING' : 'ERROR',

lib/modules/coverage.js

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ const SourceMap = require('../source-map');
1616
const Transform = require('./transform');
1717

1818
const internals = {
19-
_state: Symbol.for('@hapi/lab/coverage/_state'),
20-
eslint: new ESLint.ESLint({ baseConfig: Eslintrc })
19+
_state: Symbol.for('@hapi/lab/coverage/_state')
2120
};
2221

2322

@@ -111,7 +110,7 @@ internals.prime = function (extension, ctx) {
111110
require.extensions[extension] = function (localModule, filename) {
112111

113112
// We never want to instrument eslint configs in order to avoid infinite recursion
114-
if (Path.basename(filename, extension) !== '.eslintrc') {
113+
if (!['.eslintrc', 'eslint.config'].includes(Path.basename(filename, extension))) {
115114
for (let i = 0; i < internals.state.patterns.length; ++i) {
116115
if (internals.state.patterns[i].test(filename.replace(/\\/g, '/'))) {
117116
return localModule._compile(internals.instrument(filename, ctx), filename);
@@ -761,11 +760,40 @@ internals.file = async function (filename, data, options) {
761760

762761
internals.context = async (options) => {
763762

763+
const filePath = Path.join(options.coveragePath || '', 'x.js');
764+
let calculated;
765+
764766
// The parserOptions are shared by all files for coverage purposes, based on
765767
// the effective eslint config for a hypothetical file {coveragePath}/x.js
766-
const { parserOptions } = await internals.eslint.calculateConfigForFile(
767-
Path.join(options.coveragePath || '', 'x.js')
768-
);
768+
try {
769+
// Let's try first with eslint's native configuration detection
770+
const eslint = new ESLint.ESLint({
771+
ignore: false
772+
});
773+
774+
calculated = await eslint.calculateConfigForFile(filePath);
775+
}
776+
catch (err) {
777+
/* $lab:coverage:off$ */
778+
if (err.messageTemplate !== 'config-file-missing') {
779+
throw err;
780+
}
781+
782+
// If the eslint config file is missing, we'll use the one provided by lab
783+
const eslint = new ESLint.ESLint({
784+
overrideConfig: Eslintrc,
785+
overrideConfigFile: true,
786+
ignore: false
787+
});
788+
789+
calculated = await eslint.calculateConfigForFile(filePath);
790+
/* $lab:coverage:on$ */
791+
}
792+
793+
const parserOptions = {
794+
...calculated.languageOptions,
795+
...calculated.languageOptions?.parserOptions
796+
};
769797

770798
return { parserOptions };
771799
};

lib/modules/lint.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ exports.lint = function (settings) {
2020
try {
2121
linterOptions = JSON.parse(settings['lint-options'] || '{}');
2222
}
23-
catch (err) {
23+
catch {
2424
return reject(new Error('lint-options could not be parsed'));
2525
}
2626

lib/modules/transform.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ exports.retrieveFile = function (path) {
7373
try {
7474
contents = Fs.readFileSync(path, 'utf8');
7575
}
76-
catch (e) {
76+
catch {
7777
contents = null;
7878
}
7979

lib/modules/types.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const Utils = require('../utils');
1515
const internals = {
1616
compiler: {
1717
strict: true,
18+
noUncheckedIndexedAccess: true,
19+
exactOptionalPropertyTypes: true,
1820
jsx: Ts.JsxEmit.React,
1921
lib: ['lib.es2020.d.ts'],
2022
module: Ts.ModuleKind.CommonJS,

0 commit comments

Comments
 (0)