Skip to content

Commit

Permalink
QUA-460: support ESLint 8 (#569)
Browse files Browse the repository at this point in the history
* QUA-460: add support for ESLint 8

* QUA-460: remove prints and add runWithTimingAsync

* QUA-460: update typescript

* remove some excess testing code
* support typescript
* change eslint6-patch name
  • Loading branch information
dantevvp authored Feb 16, 2022
1 parent 895f37c commit 8be1e6b
Showing 11 changed files with 2,500 additions and 2,996 deletions.
2 changes: 1 addition & 1 deletion .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
engines:
eslint:
enabled: true
channel: eslint-6
channel: eslint-7
duplication:
enabled: true
config:
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
"block-spacing": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"comma-dangle": [2, "never"],
"comma-style": [2, "first", { exceptions: {ArrayExpression: true, ObjectExpression: true} }],
"comma-style": [2, "first", { "exceptions": {"ArrayExpression": true, "ObjectExpression": true } }],
"complexity": [2, 6],
"curly": 2,
"eqeqeq": [2, "allow-null"],
143 changes: 57 additions & 86 deletions integration/eslint_test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const sinon = require("sinon")
const expect = require("chai").expect
const chai = require("chai")
const expect = chai.expect
chai.use(require('chai-as-promised'))

const ESLint = require("../lib/eslint")
const LibESLint = require("../lib/eslint")
const fs = require("fs")
const path = require("path")
const temp = require("temp")
@@ -10,8 +12,8 @@ describe("eslint integration", function() {
let consoleMock = {}
const STDERR = console.error

function executeConfig(configPath) {
return ESLint.run(consoleMock, { dir: __dirname, configPath: `${__dirname}/${configPath}` })
async function executeConfig(configPath) {
return await LibESLint.run(consoleMock, { dir: __dirname, configPath: `${__dirname}/${configPath}` })
}

beforeEach(function() {
@@ -30,25 +32,22 @@ describe("eslint integration", function() {
})

describe("validating config", function() {
it("raise on file not found", function() {
function executeNoLintrc() {
executeConfig("no_lintrc/config.json")
}
it("raise on file not found", async function() {

expect(executeNoLintrc).to.throw()
await expect(executeConfig("no_lintrc/config.json")).to.be.rejectedWith(Error)
})

it("turns off blocked rules", function() {
executeConfig("with_unsupported_rules/config.json")
it("turns off blocked rules", async function() {
await executeConfig("with_unsupported_rules/config.json")

expect(consoleMock.outputErr).to.include(
"Ignoring the following rules that rely on module resolution:",
"\n\t * import/extensions"
)
})

it("remove blocked setting", function() {
executeConfig("with_unsupported_rules/config.json")
it("remove blocked setting", async function() {
await executeConfig("with_unsupported_rules/config.json")

expect(consoleMock.outputErr).to.include(
"Ignoring the following settings that rely on module resolution:",
@@ -57,113 +56,85 @@ describe("eslint integration", function() {
})
})

describe("sanitization", function() {
function withMinifiedSource(config, cb, done) {
temp.mkdir("code", function(err, directory) {
if (err) {
throw err
}

process.chdir(directory)

const eslintConfigPath = path.join(directory, ".eslintrc.json")
fs.writeFile(eslintConfigPath, "{}", function(err) {
if (err) {
throw err
}

const sourcePath = path.join(directory, "index.js")
fs.writeFile(
sourcePath,
[...Array(13).keys()]
.map(() => {
return "void(0);"
})
.join(""), // a long string of voids
function(err) {
if (err) {
throw err
}

const configPath = path.join(directory, "config.json")
fs.writeFile(
configPath,
JSON.stringify({
enabled: true,
config: config,
include_paths: [sourcePath],
}),
function(err) {
if (err) {
throw err
}

cb(directory)

done()
}
)
}
)
describe("sanitization", async function() {
async function withMinSource(config, cb) {
const directory = await temp.mkdir("code")
process.chdir(directory);
const eslintConfigPath = path.join(directory, ".eslintrc.json")
await fs.promises.writeFile(eslintConfigPath, "{}")
const sourcePath = path.join(directory, "index.js")
await fs.promises.writeFile(
sourcePath,
[...Array(13).keys()]
.map(() => {
return "void(0);"
})
.join(""), // a long string of voids
)
const configPath = path.join(directory, "config.json")
await fs.promises.writeFile(
configPath,
JSON.stringify({
enabled: true,
config: config,
include_paths: [sourcePath],
})
})
)
return await cb(directory)
}

const BatchSanitizer = require("../lib/batch_sanitizer")
const CLIEngine = require("../lib/eslint6-patch")().eslint.CLIEngine
const ESLint = require("../lib/eslint8-patch")().eslint.ESLint

beforeEach(() => {
sinon.spy(BatchSanitizer.prototype, "sanitizedFiles")
sinon.spy(CLIEngine.prototype, "executeOnFiles")
sinon.spy(ESLint.prototype, "lintFiles")
})

afterEach(() => {
BatchSanitizer.prototype.sanitizedFiles.restore()
CLIEngine.prototype.executeOnFiles.restore()
ESLint.prototype.lintFiles.restore()
})

it("is performed by default", function(done) {
it("is performed by default", async function() {
this.timeout(5000)

withMinifiedSource(
await withMinSource(
{},
function(dir) {
ESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })
async function(dir) {
await LibESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })

expect(BatchSanitizer.prototype.sanitizedFiles.callCount).to.eql(1)
expect(CLIEngine.prototype.executeOnFiles.firstCall.args).to.eql([[]])
},
done
expect(ESLint.prototype.lintFiles.firstCall.args).to.eql([[]])
}
)
})

it("is performed when explicitly specified", function(done) {
it("is performed when explicitly specified", async function() {
this.timeout(5000)

withMinifiedSource(
await withMinSource(
{ sanitize_batch: true },
function(dir) {
ESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })
async function(dir) {
await LibESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })

expect(BatchSanitizer.prototype.sanitizedFiles.callCount).to.eql(1)
expect(CLIEngine.prototype.executeOnFiles.firstCall.args).to.eql([[]])
},
done
expect(ESLint.prototype.lintFiles.firstCall.args).to.eql([[]])
}
)
})

it("can be disabled", function(done) {
it("can be disabled", async function() {
this.timeout(5000)

withMinifiedSource(
await withMinSource(
{ sanitize_batch: false },
function(dir) {
ESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })
async function(dir) {
await LibESLint.run(consoleMock, { dir: dir, configPath: `${dir}/config.json` })

expect(BatchSanitizer.prototype.sanitizedFiles.callCount).to.eql(0)
expect(CLIEngine.prototype.executeOnFiles.firstCall.args).to.eql([[`${dir}/index.js`]])
},
done
expect(ESLint.prototype.lintFiles.firstCall.args).to.eql([[`${dir}/index.js`]])
}
)
})
})
68 changes: 41 additions & 27 deletions lib/eslint.js
Original file line number Diff line number Diff line change
@@ -4,17 +4,17 @@ const fs = require("fs")
const glob = require("glob")
const stream = require('stream');

const patch = require("./eslint6-patch")()
const patch = require("./eslint8-patch")()
const docs = require("./docs")()
const BatchSanitizer = require("./batch_sanitizer")
const EngineConfig = require("./engine_config")
const checks = require("./checks")
const computeFingerprint = require("./compute_fingerprint")

const CLIEngine = patch.eslint.CLIEngine
const options = { extensions: [".js"], ignore: true, reset: false, useEslintrc: true, baseConfig: {} }
const ESLint = patch.eslint.ESLint
const options = { extensions: [".js"], ignore: true, useEslintrc: true, baseConfig: {} }

function run(console, runOptions) {
async function run(console, runOptions) {
const STDOUT = console.log
console.log = console.error

@@ -27,15 +27,26 @@ function run(console, runOptions) {
var sanitizeBatch = true
var ESLINT_WARNING_SEVERITY = 1

function printDebug(name, start) {
const duration = (new Date() - start) / 1000
console.error("eslint.timing." + name + ": " + duration + "s")
}

// a wrapper for emitting perf timing
function runWithTiming(name, fn) {
const start = new Date()
const result = fn()

if (debug) {
const duration = (new Date() - start) / 1000
console.error("eslint.timing." + name + ": " + duration + "s")
}
if (debug) printDebug(name, start)

return result
}

async function runWithTimingAsync(name, fn) {
const start = new Date()
const result = await fn()

if (debug) printDebug(name, start)

return result
}
@@ -77,7 +88,7 @@ function run(console, runOptions) {
},
},
},
remediation_points: checks.remediationPoints(checkName, message, cli.getConfigForFile(path)),
remediation_points: checks.remediationPoints(checkName, message, cli.calculateConfigForFile(path)),
}

var fingerprint = computeFingerprint(path, checkName, message.message)
@@ -99,8 +110,8 @@ function run(console, runOptions) {
return stats.isFile() && !stats.isSymbolicLink() && extensions.indexOf(extension) >= 0
}

function isFileIgnoredByLibrary(file) {
return cli.isPathIgnored(file)
async function isFileIgnoredByLibrary(file) {
return await cli.isPathIgnored(file)
}

function prunePathsWithinSymlinks(paths) {
@@ -123,35 +134,37 @@ function run(console, runOptions) {
function inclusionBasedFileListBuilder(includePaths) {
// Uses glob to expand the files and directories in includePaths, filtering
// down to match the list of desired extensions.
return function(extensions) {
return async function(extensions) {
var analysisFiles = []

includePaths.forEach(function(fileOrDirectory, i) {
await Promise.all(includePaths.map(async function(fileOrDirectory, i) {
if (/\/$/.test(fileOrDirectory)) {
// if it ends in a slash, expand and push
var filesInThisDirectory = glob.sync(fileOrDirectory + "/**/**")
prunePathsWithinSymlinks(filesInThisDirectory).forEach(function(file, j) {
if (!isFileIgnoredByLibrary(file) && isFileWithMatchingExtension(file, extensions)) {
prunePathsWithinSymlinks(filesInThisDirectory).forEach(async function(file, j) {
const isIgnored = await isFileIgnoredByLibrary(file)
if (!isIgnored && isFileWithMatchingExtension(file, extensions)) {
analysisFiles.push(file)
}
})
} else {
if (
!isFileIgnoredByLibrary(fileOrDirectory) &&
const isIgnored = await isFileIgnoredByLibrary(fileOrDirectory)
if(
!isIgnored &&
isFileWithMatchingExtension(fileOrDirectory, extensions)
) {
analysisFiles.push(fileOrDirectory)
}
}
})
}))

return analysisFiles
}
}

function overrideOptions(userConfig) {
if (userConfig.configPath) {
options.configFile = codeDir + "/" + userConfig.configPath
options.overrideConfigFile = codeDir + "/" + userConfig.configPath
options.useEslintrc = false
}

@@ -168,7 +181,7 @@ function run(console, runOptions) {
sanitizeBatch = userConfig.sanitizeBatch
}

function analyzeFiles(analysisFiles) {
async function analyzeFiles(analysisFiles) {
var batchNum = 0,
batchSize = 10,
batchFiles,
@@ -184,11 +197,12 @@ function run(console, runOptions) {
console.error("Analyzing: " + batchFiles)
}

runWithTiming("analyze-batch-" + batchNum, function() {
batchReport = cli.executeOnFiles(batchFiles)
await runWithTimingAsync("analyze-batch-" + batchNum, async function() {
batchReport = await cli.lintFiles(batchFiles)
})

runWithTiming("report-batch" + batchNum, function() {
batchReport.results.forEach(function(result) {
batchReport.forEach(function(result) {
var path = result.filePath.replace(/^\/code\//, "")

result.messages.forEach(function(message) {
@@ -251,13 +265,13 @@ function run(console, runOptions) {
}
})

cli = new CLIEngine(options)
cli = new ESLint(options)

var analysisFiles = runWithTiming("buildFileList", function() {
return buildFileList(options.extensions)
var analysisFiles = await runWithTimingAsync("buildFileList", async function() {
return await buildFileList(options.extensions)
})

analyzeFiles(analysisFiles)
await analyzeFiles(analysisFiles)

logInfo()
}
Loading
Oops, something went wrong.

0 comments on commit 8be1e6b

Please sign in to comment.