Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to eslint v8 #1035

Merged
merged 7 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ exports.run = async function () {
settings.lintingPath = process.cwd();

if (settings.coverage) {
Modules.coverage.instrument(settings);
await Modules.coverage.instrument(settings);
}
else if (settings.transform) {
Modules.transform.install(settings);
Expand Down
1 change: 0 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ for (const module of ['coverage', 'leaks', 'types']) {
Object.defineProperty(exports, module, Object.getOwnPropertyDescriptor(Modules, module));
}


/*
experiment('Utilities', () => {

Expand Down
23 changes: 13 additions & 10 deletions lib/linter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const Hoek = require('@hapi/hoek');
const internals = {};


exports.lint = function () {
exports.lint = async function () {

const configuration = {
ignore: true
Expand All @@ -24,7 +24,7 @@ exports.lint = function () {
!Fs.existsSync('.eslintrc.yml') &&
!Fs.existsSync('.eslintrc.json') &&
!Fs.existsSync('.eslintrc')) {
configuration.configFile = Path.join(__dirname, '.eslintrc.js');
configuration.overrideConfigFile = Path.join(__dirname, '.eslintrc.js');
}

if (options) {
Expand All @@ -33,17 +33,14 @@ exports.lint = function () {

let results;
try {
const engine = new Eslint.CLIEngine(configuration);
results = engine.executeOnFiles(['.']);
const eslint = new Eslint.ESLint(configuration);
results = await eslint.lintFiles(['.']);
}
catch (ex) {
results = {
results: [{ messages: [ex] }]
};
results = [{ messages: [ex] }];
}


return results.results.map((result) => {
return results.map((result) => {

const transformed = {
filename: result.filePath
Expand All @@ -68,4 +65,10 @@ exports.lint = function () {
});
};

process.send(exports.lint());
const main = async () => {

const results = await exports.lint();
process.send(results);
};

main();
31 changes: 22 additions & 9 deletions lib/modules/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Transform = require('./transform');
const internals = {
ext: Symbol.for('@hapi/lab/coverage/initialize'),
_state: Symbol.for('@hapi/lab/coverage/_state'),
EslintEngine: new ESLint.CLIEngine({ baseConfig: Eslintrc })
eslint: new ESLint.ESLint({ baseConfig: Eslintrc })
};


Expand Down Expand Up @@ -69,16 +69,18 @@ if (typeof global.__$$labCov === 'undefined') {
// $lab:coverage:on$


exports.instrument = function (options) {
exports.instrument = async function (options) {

if (options['coverage-module']) {
for (const name of options['coverage-module']) {
internals.state.modules.add(name);
}
}

const ctx = await internals.context(options);

internals.state.patterns.unshift(internals.pattern(options));
Transform.install(options, internals.prime);
Transform.install(options, (ext) => internals.prime(ext, ctx));
};


Expand Down Expand Up @@ -114,15 +116,15 @@ internals.escape = function (string) {
};


internals.prime = function (extension) {
internals.prime = function (extension, ctx) {

require.extensions[extension] = function (localModule, filename) {

// We never want to instrument eslint configs in order to avoid infinite recursion
if (Path.basename(filename, extension) !== '.eslintrc') {
for (let i = 0; i < internals.state.patterns.length; ++i) {
if (internals.state.patterns[i].test(filename.replace(/\\/g, '/'))) {
return localModule._compile(internals.instrument(filename), filename);
return localModule._compile(internals.instrument(filename, ctx), filename);
}
}
}
Expand All @@ -133,7 +135,7 @@ internals.prime = function (extension) {
};


internals.instrument = function (filename) {
internals.instrument = function (filename, ctx) {

filename = filename.replace(/\\/g, '/');

Expand Down Expand Up @@ -331,9 +333,8 @@ internals.instrument = function (filename) {

// Parse tree

const eslintConfig = internals.EslintEngine.getConfigForFile(filename);
const tree = ESLintParser.parse(content, {
...eslintConfig.parserOptions,
...ctx.parserOptions,
loc: true,
range: true,
comment: true
Expand Down Expand Up @@ -520,6 +521,7 @@ exports.analyze = async function (options) {

const report = internals.state.files;
const pattern = internals.pattern(options);
const ctx = await internals.context(options);

const cov = {
sloc: 0,
Expand All @@ -537,7 +539,7 @@ exports.analyze = async function (options) {
const filename = file.replace(/\\/g, '/');
if (pattern.test(filename)) {
if (!report[filename]) {
internals.instrument(filename);
internals.instrument(filename, ctx);
}

report[filename].source = internals.state.sources[filename] || [];
Expand Down Expand Up @@ -778,3 +780,14 @@ internals.external = function (filename) {

return reports.length ? reports : null;
};

internals.context = async (options) => {

// The parserOptions are shared by all files for coverage purposes, based on
// the effective eslint config for a hypothetical file {coveragePath}/x.js
const { parserOptions } = await internals.eslint.calculateConfigForFile(
Path.join(options.coveragePath || '', 'x.js')
);

return { parserOptions };
};
7 changes: 4 additions & 3 deletions lib/modules/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ internals.transform = function (content, fileName) {
if (!internals.configs.has(configFile)) {
try {
var { config, error } = Typescript.readConfigFile(configFile, Typescript.sys.readFile);
if (error) {
throw new Error(`TypeScript config error in ${configFile}: ${error.messageText}`);
}
}
catch (err) {
throw new Error(`Cannot find a tsconfig file for ${fileName}`);
}

if (error) {
throw new Error(`TypeScript config error in ${configFile}: ${error.messageText}`);
}

const { options } = Typescript.parseJsonConfigFileContent(config, Typescript.sys, Typescript.getDirectoryPath(configFile), {}, configFile);
options.sourceMap = false;
options.inlineSourceMap = true;
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
]
},
"dependencies": {
"@babel/core": "^7.14.3",
"@babel/eslint-parser": "^7.14.3",
"@babel/core": "^7.16.0",
"@babel/eslint-parser": "^7.16.0",
"@hapi/bossy": "5.x.x",
"@hapi/eslint-plugin": "^5.1.0",
"@hapi/hoek": "9.x.x",
"diff": "^5.0.0",
"eslint": "7.x.x",
"eslint": "8.x.x",
"find-rc": "4.x.x",
"globby": "10.x.x",
"handlebars": "4.x.x",
Expand Down
29 changes: 22 additions & 7 deletions test/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ const internals = {


const lab = exports.lab = _Lab.script();
const before = lab.before;
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;


describe('Coverage', () => {

Lab.coverage.instrument({ coveragePath: Path.join(__dirname, 'coverage'), coverageExclude: 'exclude' });
before({}, async () => {

await Lab.coverage.instrument({ coveragePath: Path.join(__dirname, 'coverage'), coverageExclude: 'exclude' });
});

it('computes sloc without comments', async () => {

Expand Down Expand Up @@ -132,7 +136,7 @@ describe('Coverage', () => {
expect(cov.percent).to.equal(100);
});

it('logs to stderr when coverageExclude file has fs.stat issue', async () => {
it('logs to stderr when coverageExclude file has fs.stat issue', async (flags) => {

const Test = require('./coverage/test-folder/test-name.js');

Expand All @@ -141,8 +145,15 @@ describe('Coverage', () => {
const origStatSync = Fs.statSync;
const origErrorLog = console.error;

let calls = 0;
Fs.statSync = () => {

calls++;
if (calls === 3) {
// Only mock for first 3 calls
Fs.statSync = origStatSync;
}

const err = new Error();
err.code = 'BOOM';
throw err;
Expand All @@ -153,9 +164,13 @@ describe('Coverage', () => {
expect(data.code).to.equal('BOOM');
};

flags.onCleanup = () => {

Fs.statSync = origStatSync;
console.error = origErrorLog;
};

const cov = await Lab.coverage.analyze({ coveragePath: Path.join(__dirname, 'coverage/test-folder'), coverageExclude: ['test', 'node_modules', 'test-name.js'] });
Fs.statSync = origStatSync;
console.error = origErrorLog;
expect(cov.percent).to.equal(100);
});

Expand Down Expand Up @@ -577,7 +592,7 @@ describe('Coverage', () => {
it('reports external coverage', async () => {

const coveragePath = Path.join(__dirname, 'coverage/module');
Lab.coverage.instrument({ coveragePath, 'coverage-module': ['@hapi/lab-external-module-test'] });
await Lab.coverage.instrument({ coveragePath, 'coverage-module': ['@hapi/lab-external-module-test'] });

require(coveragePath);

Expand Down Expand Up @@ -615,12 +630,12 @@ describe('Coverage', () => {

describe('Coverage via Transform API', () => {

lab.before(() => {
lab.before(async () => {

internals.js = require.extensions['.js'];
internals.inl = require.extensions['.inl'];

Lab.coverage.instrument({ coveragePath: Path.join(__dirname, 'coverage'), coverageExclude: 'exclude', transform: internals.transform });
await Lab.coverage.instrument({ coveragePath: Path.join(__dirname, 'coverage'), coverageExclude: 'exclude', transform: internals.transform });
});

lab.after(() => {
Expand Down
6 changes: 5 additions & 1 deletion test/reporters.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ const internals = {};


const lab = exports.lab = _Lab.script();
const before = lab.before;
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;


describe('Reporter', () => {

Lab.coverage.instrument({ coveragePath: Path.join(__dirname, './coverage/'), coverageExclude: 'exclude' });
before({}, async () => {

await Lab.coverage.instrument({ coveragePath: Path.join(__dirname, './coverage/'), coverageExclude: 'exclude' });
});

it('outputs to a stream', async () => {

Expand Down
6 changes: 5 additions & 1 deletion test/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ const internals = {
// Test shortcuts

const lab = exports.lab = _Lab.script();
const before = lab.before;
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;

describe('Transform', () => {

Lab.coverage.instrument({ coveragePath: Path.join(__dirname, './transform/'), coverageExclude: 'exclude', transform: internals.transform });
before({}, async () => {

await Lab.coverage.instrument({ coveragePath: Path.join(__dirname, './transform/'), coverageExclude: 'exclude', transform: internals.transform });
});

it('instruments and measures coverage', async () => {

Expand Down
33 changes: 33 additions & 0 deletions test/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Path = require('path');
const Code = require('@hapi/code');
const _Lab = require('../test_runner');
const RunCli = require('./run_cli');
const Ts = require('typescript');
const Typescript = require('../lib/modules/typescript');


Expand Down Expand Up @@ -53,6 +54,31 @@ describe('TypeScript', () => {

describe('transform', () => {

it('errors when failing to find a tsconfig file', () => {

const path = Path.join(__dirname, 'cli', 'simple.js');

expect(
() => Typescript.extensions[0].transform(Fs.readFileSync(path, { encoding: 'utf8' }), path)
).to.throw(/^Cannot find a tsconfig file for .+cli[\/\\]simple\.js/);
});

it('errors when unable to read a tsconfig file', (flags) => {

const path = Path.join(__dirname, 'cli_typescript', 'simple.ts');

const origReadFile = Ts.sys.readFile;
flags.onCleanup = () => Object.assign(Ts.sys, { readFile: origReadFile });
Ts.sys.readFile = () => {

throw new Error('Oops!');
};

expect(
() => Typescript.extensions[0].transform(Fs.readFileSync(path, { encoding: 'utf8' }), path)
).to.throw(/^TypeScript config error in .+?cli_typescript\/tsconfig\.json: Cannot read file \'.+?\/cli_typescript\/tsconfig\.json\': Oops!/);
});

it('generates embedded sourcemap with sourcesContent', () => {

const smre = /\/\/\#\s*sourceMappingURL=data:application\/json[^,]+base64,(.*)\r?\n?$/;
Expand All @@ -65,5 +91,12 @@ describe('TypeScript', () => {
expect(sourcemap.sourcesContent).to.exist();
expect(sourcemap.sourcesContent).to.have.length(1);
});

it('transforms identically when called multiple times', () => {
// This covers config file caching behavior, which is not directly observable by consumers.
const path = Path.join(__dirname, 'cli_typescript', 'simple.ts');
const transform = () => Typescript.extensions[0].transform(Fs.readFileSync(path, { encoding: 'utf8' }), path);
expect(transform()).to.equal(transform());
});
});
});