diff --git a/lib/init/autoconfig.js b/lib/init/autoconfig.js index 054c538496f..3233f686539 100644 --- a/lib/init/autoconfig.js +++ b/lib/init/autoconfig.js @@ -11,7 +11,11 @@ const equal = require("fast-deep-equal"), recConfig = require("../../conf/eslint-recommended"), - ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"), + { + Legacy: { + ConfigOps + } + } = require("@eslint/eslintrc"), { Linter } = require("../linter"), configRule = require("./config-rule"); diff --git a/lib/init/config-initializer.js b/lib/init/config-initializer.js index 3c7f2ba0944..7ed69dfed5f 100644 --- a/lib/init/config-initializer.js +++ b/lib/init/config-initializer.js @@ -18,9 +18,13 @@ const util = require("util"), semver = require("semver"), espree = require("espree"), recConfig = require("../../conf/eslint-recommended"), - ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"), + { + Legacy: { + ConfigOps, + naming + } + } = require("@eslint/eslintrc"), log = require("../shared/logging"), - naming = require("@eslint/eslintrc/lib/shared/naming"), ModuleResolver = require("../shared/relative-module-resolver"), autoconfig = require("./autoconfig.js"), ConfigFile = require("./config-file"), diff --git a/lib/linter/config-comment-parser.js b/lib/linter/config-comment-parser.js index 07bbead281c..64482489535 100644 --- a/lib/linter/config-comment-parser.js +++ b/lib/linter/config-comment-parser.js @@ -11,7 +11,11 @@ //------------------------------------------------------------------------------ const levn = require("levn"), - ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"); + { + Legacy: { + ConfigOps + } + } = require("@eslint/eslintrc/universal"); // eslint-disable-line node/no-missing-require -- false positive const debug = require("debug")("eslint:config-comment-parser"); diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 76a3a2062fe..ae564b6610b 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -16,11 +16,15 @@ const evk = require("eslint-visitor-keys"), espree = require("espree"), merge = require("lodash.merge"), - BuiltInEnvironments = require("@eslint/eslintrc/conf/environments"), pkg = require("../../package.json"), astUtils = require("../shared/ast-utils"), - ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"), - ConfigValidator = require("@eslint/eslintrc/lib/shared/config-validator"), + { + Legacy: { + ConfigOps, + ConfigValidator, + environments: BuiltInEnvironments + } + } = require("@eslint/eslintrc/universal"), // eslint-disable-line node/no-missing-require -- false positive Traverser = require("../shared/traverser"), { SourceCode } = require("../source-code"), CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"), diff --git a/lib/shared/config-validator.js b/lib/shared/config-validator.js index 03b32f1c918..928d3ce5650 100644 --- a/lib/shared/config-validator.js +++ b/lib/shared/config-validator.js @@ -24,9 +24,13 @@ const util = require("util"), configSchema = require("../../conf/config-schema"), - BuiltInEnvironments = require("@eslint/eslintrc/conf/environments"), BuiltInRules = require("../rules"), - ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"), + { + Legacy: { + ConfigOps, + environments: BuiltInEnvironments + } + } = require("@eslint/eslintrc"), { emitDeprecationWarning } = require("./deprecation-warnings"); const ajv = require("./ajv")(); diff --git a/package.json b/package.json index 275554884bd..53c28de3bbc 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "homepage": "https://eslint.org", "bugs": "https://github.com/eslint/eslint/issues/", "dependencies": { - "@eslint/eslintrc": "^0.4.3", + "@eslint/eslintrc": "^1.0.0", "@humanwhocodes/config-array": "^0.6.0", "ajv": "^6.10.0", "chalk": "^4.0.0", diff --git a/tests/_utils/in-memory-fs.js b/tests/_utils/in-memory-fs.js index ddacfc7bec6..2cf536794c0 100644 --- a/tests/_utils/in-memory-fs.js +++ b/tests/_utils/in-memory-fs.js @@ -1,244 +1,11 @@ /** - * @fileoverview Define classes what use the in-memory file system. - * - * This provides utilities to test `ConfigArrayFactory`, - * `CascadingConfigArrayFactory`, `FileEnumerator`, `CLIEngine`, and `ESLint`. - * - * - `defineConfigArrayFactoryWithInMemoryFileSystem({ cwd, files })` - * - `defineCascadingConfigArrayFactoryWithInMemoryFileSystem({ cwd, files })` - * - `defineFileEnumeratorWithInMemoryFileSystem({ cwd, files })` - * - `defineCLIEngineWithInMemoryFileSystem({ cwd, files })` - * - `defineESLintWithInMemoryFileSystem({ cwd, files })` - * - * Those functions define correspond classes with the in-memory file system. - * Those search config files, parsers, and plugins in the `files` option via the - * in-memory file system. - * - * For each test case, it makes more readable if we define minimal files the - * test case requires. - * - * For example: - * - * ```js - * const { ConfigArrayFactory } = defineConfigArrayFactoryWithInMemoryFileSystem({ - * files: { - * "node_modules/eslint-config-foo/index.js": ` - * module.exports = { - * parser: "./parser", - * rules: { - * "no-undef": "error" - * } - * } - * `, - * "node_modules/eslint-config-foo/parser.js": ` - * module.exports = { - * parse() {} - * } - * `, - * ".eslintrc.json": JSON.stringify({ root: true, extends: "foo" }) - * } - * }); - * const factory = new ConfigArrayFactory(); - * const config = factory.loadFile(".eslintrc.json"); - * - * assert(config[0].name === ".eslintrc.json ยป eslint-config-foo"); - * assert(config[0].filePath === path.resolve("node_modules/eslint-config-foo/index.js")); - * assert(config[0].parser.filePath === path.resolve("node_modules/eslint-config-foo/parser.js")); - * - * assert(config[1].name === ".eslintrc.json"); - * assert(config[1].filePath === path.resolve(".eslintrc.json")); - * assert(config[1].root === true); - * ``` - * + * @fileoverview in-memory file system. * @author Toru Nagashima */ "use strict"; const path = require("path"); -const vm = require("vm"); const { Volume, createFsFromVolume } = require("memfs"); -const Proxyquire = require("proxyquire/lib/proxyquire"); - -const CascadingConfigArrayFactoryPath = - require.resolve("@eslint/eslintrc/lib/cascading-config-array-factory"); -const CLIEnginePath = - require.resolve("../../lib/cli-engine/cli-engine"); -const ConfigArrayFactoryPath = - require.resolve("@eslint/eslintrc/lib/config-array-factory"); -const FileEnumeratorPath = - require.resolve("../../lib/cli-engine/file-enumerator"); -const LoadRulesPath = - require.resolve("../../lib/cli-engine/load-rules"); -const ESLintPath = - require.resolve("../../lib/eslint/eslint"); -const ESLintAllPath = - require.resolve("../../conf/eslint-all"); -const ESLintRecommendedPath = - require.resolve("../../conf/eslint-recommended"); - -// Ensure the needed files has been loaded and cached. -require(CascadingConfigArrayFactoryPath); -require(CLIEnginePath); -require(ConfigArrayFactoryPath); -require(FileEnumeratorPath); -require(LoadRulesPath); -require(ESLintPath); -require("js-yaml"); -require("espree"); - -// Override `_require` in order to throw runtime errors in stubs. -const ERRORED = Symbol("errored"); -const proxyquire = new class extends Proxyquire { - _require(...args) { - const retv = super._require(...args); // eslint-disable-line no-underscore-dangle - - if (retv[ERRORED]) { - throw retv[ERRORED]; - } - return retv; - } -}(module).noCallThru().noPreserveCache(); - -// Separated (sandbox) context to compile fixture files. -const context = vm.createContext(); - -/** - * Check if a given path is an existing file. - * @param {import("fs")} fs The file system. - * @param {string} filePath Tha path to a file to check. - * @returns {boolean} `true` if the file existed. - */ -function isExistingFile(fs, filePath) { - try { - return fs.statSync(filePath).isFile(); - } catch { - return false; - } -} - -/** - * Get some paths to test. - * @param {string} prefix The prefix to try. - * @returns {string[]} The paths to test. - */ -function getTestPaths(prefix) { - return [ - path.join(prefix), - path.join(`${prefix}.js`), - path.join(prefix, "index.js") - ]; -} - -/** - * Iterate the candidate paths of a given request to resolve. - * @param {string} request Tha package name or file path to resolve. - * @param {string} relativeTo Tha path to the file what called this resolving. - * @returns {IterableIterator} The candidate paths. - */ -function *iterateCandidatePaths(request, relativeTo) { - if (path.isAbsolute(request)) { - yield* getTestPaths(request); - return; - } - if (/^\.{1,2}[/\\]/u.test(request)) { - yield* getTestPaths(path.resolve(path.dirname(relativeTo), request)); - return; - } - - let prevPath = path.resolve(relativeTo); - let dirPath = path.dirname(prevPath); - - while (dirPath && dirPath !== prevPath) { - yield* getTestPaths(path.join(dirPath, "node_modules", request)); - prevPath = dirPath; - dirPath = path.dirname(dirPath); - } -} - -/** - * Resolve a given module name or file path relatively in the given file system. - * @param {import("fs")} fs The file system. - * @param {string} request Tha package name or file path to resolve. - * @param {string} relativeTo Tha path to the file what called this resolving. - * @returns {void} - */ -function fsResolve(fs, request, relativeTo) { - for (const filePath of iterateCandidatePaths(request, relativeTo)) { - if (isExistingFile(fs, filePath)) { - return filePath; - } - } - - throw Object.assign( - new Error(`Cannot find module '${request}'`), - { code: "MODULE_NOT_FOUND" } - ); -} - -/** - * Compile a JavaScript file. - * This is used to compile only fixture files, so this is minimam. - * @param {import("fs")} fs The file system. - * @param {Object} stubs The stubs. - * @param {string} filePath The path to a JavaScript file to compile. - * @param {string} content The source code to compile. - * @returns {any} The exported value. - */ -function compile(fs, stubs, filePath, content) { - const code = `(function(exports, require, module, __filename, __dirname) { ${content} })`; - const f = vm.runInContext(code, context); - const exports = {}; - const module = { exports }; - - f.call( - exports, - exports, - request => { - const modulePath = fsResolve(fs, request, filePath); - const stub = stubs[modulePath]; - - if (stub[ERRORED]) { - throw stub[ERRORED]; - } - return stub; - }, - module, - filePath, - path.dirname(filePath) - ); - - return module.exports; -} - -/** - * Import a given file path in the given file system. - * @param {import("fs")} fs The file system. - * @param {Object} stubs The stubs. - * @param {string} absolutePath Tha file path to import. - * @returns {void} - */ -function fsImportFresh(fs, stubs, absolutePath) { - if (absolutePath === ESLintAllPath) { - return require(ESLintAllPath); - } - if (absolutePath === ESLintRecommendedPath) { - return require(ESLintRecommendedPath); - } - - if (fs.existsSync(absolutePath)) { - return compile( - fs, - stubs, - absolutePath, - fs.readFileSync(absolutePath, "utf8") - ); - } - - throw Object.assign( - new Error(`Cannot find module '${absolutePath}'`), - { code: "MODULE_NOT_FOUND" } - ); -} /** * Define in-memory file system. @@ -285,257 +52,6 @@ function defineInMemoryFs({ return fs; } -/** - * Define stubbed `ConfigArrayFactory` class what uses the in-memory file system. - * @param {Object} options The options. - * @param {() => string} [options.cwd] The current working directory. - * @param {Object} [options.files] The initial files definition in the in-memory file system. - * @returns {{ fs: import("fs"), RelativeModuleResolver: import("../../lib/shared/relative-module-resolver"), ConfigArrayFactory: import("../../lib/cli-engine/config-array-factory")["ConfigArrayFactory"] }} The stubbed `ConfigArrayFactory` class. - */ -function defineConfigArrayFactoryWithInMemoryFileSystem({ - cwd = process.cwd, - files = {} -} = {}) { - const fs = defineInMemoryFs({ cwd, files }); - const RelativeModuleResolver = { resolve: fsResolve.bind(null, fs) }; - - /* - * Stubs for proxyquire. - * This contains the JavaScript files in `options.files`. - */ - const stubs = {}; - - stubs.fs = fs; - stubs["import-fresh"] = fsImportFresh.bind(null, fs, stubs); - stubs["../shared/relative-module-resolver"] = RelativeModuleResolver; - - /* - * Write all files to the in-memory file system and compile all JavaScript - * files then set to `stubs`. - */ - (function initFiles(directoryPath, definition) { - for (const [filename, content] of Object.entries(definition)) { - const filePath = path.resolve(directoryPath, filename); - - if (typeof content === "object") { - initFiles(filePath, content); - continue; - } - - /* - * Compile then stub if this file is a JavaScript file. - * For parsers and plugins that `require()` will import. - */ - if (path.extname(filePath) === ".js") { - Object.defineProperty(stubs, filePath, { - configurable: true, - enumerable: true, - get() { - let stub; - - try { - stub = compile(fs, stubs, filePath, content); - } catch (error) { - stub = { [ERRORED]: error }; - } - Object.defineProperty(stubs, filePath, { - configurable: true, - enumerable: true, - value: stub - }); - - return stub; - } - }); - } - } - }(cwd(), files)); - - // Load the stubbed one. - const { ConfigArrayFactory } = proxyquire(ConfigArrayFactoryPath, stubs); - - // Override the default cwd. - return { - fs, - stubs, - RelativeModuleResolver, - ConfigArrayFactory: cwd === process.cwd - ? ConfigArrayFactory - : class extends ConfigArrayFactory { - constructor(options) { - super({ cwd: cwd(), ...options }); - } - } - }; -} - -/** - * Define stubbed `CascadingConfigArrayFactory` class what uses the in-memory file system. - * @param {Object} options The options. - * @param {() => string} [options.cwd] The current working directory. - * @param {Object} [options.files] The initial files definition in the in-memory file system. - * @returns {{ fs: import("fs"), RelativeModuleResolver: import("../../../lib/shared/relative-module-resolver"), ConfigArrayFactory: import("../../../lib/cli-engine/config-array-factory")["ConfigArrayFactory"], CascadingConfigArrayFactory: import("../../../lib/cli-engine/cascading-config-array-factory")["CascadingConfigArrayFactory"] }} The stubbed `CascadingConfigArrayFactory` class. - */ -function defineCascadingConfigArrayFactoryWithInMemoryFileSystem({ - cwd = process.cwd, - files = {} -} = {}) { - const { fs, stubs, RelativeModuleResolver, ConfigArrayFactory } = - defineConfigArrayFactoryWithInMemoryFileSystem({ cwd, files }); - const loadRules = proxyquire(LoadRulesPath, stubs); - const { CascadingConfigArrayFactory } = - proxyquire(CascadingConfigArrayFactoryPath, { - "./config-array-factory": { ConfigArrayFactory }, - "./load-rules": loadRules - }); - - // Override the default cwd. - return { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory: cwd === process.cwd - ? CascadingConfigArrayFactory - : class extends CascadingConfigArrayFactory { - constructor(options) { - super({ cwd: cwd(), ...options }); - } - } - }; -} - -/** - * Define stubbed `FileEnumerator` class what uses the in-memory file system. - * @param {Object} options The options. - * @param {() => string} [options.cwd] The current working directory. - * @param {Object} [options.files] The initial files definition in the in-memory file system. - * @returns {{ fs: import("fs"), RelativeModuleResolver: import("../../../lib/shared/relative-module-resolver"), ConfigArrayFactory: import("../../../lib/cli-engine/config-array-factory")["ConfigArrayFactory"], CascadingConfigArrayFactory: import("../../../lib/cli-engine/cascading-config-array-factory")["CascadingConfigArrayFactory"], FileEnumerator: import("../../../lib/cli-engine/file-enumerator")["FileEnumerator"] }} The stubbed `FileEnumerator` class. - */ -function defineFileEnumeratorWithInMemoryFileSystem({ - cwd = process.cwd, - files = {} -} = {}) { - const { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory - } = - defineCascadingConfigArrayFactoryWithInMemoryFileSystem({ cwd, files }); - const { FileEnumerator } = proxyquire(FileEnumeratorPath, { - fs, - "./cascading-config-array-factory": { CascadingConfigArrayFactory } - }); - - // Override the default cwd. - return { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory, - FileEnumerator: cwd === process.cwd - ? FileEnumerator - : class extends FileEnumerator { - constructor(options) { - super({ cwd: cwd(), ...options }); - } - } - }; -} - -/** - * Define stubbed `CLIEngine` class what uses the in-memory file system. - * @param {Object} options The options. - * @param {() => string} [options.cwd] The current working directory. - * @param {Object} [options.files] The initial files definition in the in-memory file system. - * @returns {{ fs: import("fs"), RelativeModuleResolver: import("../../../lib/shared/relative-module-resolver"), ConfigArrayFactory: import("../../../lib/cli-engine/config-array-factory")["ConfigArrayFactory"], CascadingConfigArrayFactory: import("../../../lib/cli-engine/cascading-config-array-factory")["CascadingConfigArrayFactory"], FileEnumerator: import("../../../lib/cli-engine/file-enumerator")["FileEnumerator"], CLIEngine: import("../../../lib/cli-engine/cli-engine")["CLIEngine"], getCLIEngineInternalSlots: import("../../../lib/cli-engine/cli-engine")["getCLIEngineInternalSlots"] }} The stubbed `CLIEngine` class. - */ -function defineCLIEngineWithInMemoryFileSystem({ - cwd = process.cwd, - files = {} -} = {}) { - const { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory, - FileEnumerator - } = - defineFileEnumeratorWithInMemoryFileSystem({ cwd, files }); - const { CLIEngine, getCLIEngineInternalSlots } = proxyquire(CLIEnginePath, { - fs, - "./cascading-config-array-factory": { CascadingConfigArrayFactory }, - "./file-enumerator": { FileEnumerator }, - "../shared/relative-module-resolver": RelativeModuleResolver - }); - - // Override the default cwd. - return { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory, - FileEnumerator, - CLIEngine: cwd === process.cwd - ? CLIEngine - : class extends CLIEngine { - constructor(options) { - super({ cwd: cwd(), ...options }); - } - }, - getCLIEngineInternalSlots - }; -} - -/** - * Define stubbed `ESLint` class that uses the in-memory file system. - * @param {Object} options The options. - * @param {() => string} [options.cwd] The current working directory. - * @param {Object} [options.files] The initial files definition in the in-memory file system. - * @returns {{ fs: import("fs"), RelativeModuleResolver: import("../../lib/shared/relative-module-resolver"), ConfigArrayFactory: import("../../lib/cli-engine/config-array-factory")["ConfigArrayFactory"], CascadingConfigArrayFactory: import("../../lib/cli-engine/cascading-config-array-factory")["CascadingConfigArrayFactory"], FileEnumerator: import("../../lib/cli-engine/file-enumerator")["FileEnumerator"], ESLint: import("../../lib/eslint/eslint")["ESLint"], getCLIEngineInternalSlots: import("../../lib//eslint/eslint")["getESLintInternalSlots"] }} The stubbed `ESLint` class. - */ -function defineESLintWithInMemoryFileSystem({ - cwd = process.cwd, - files = {} -} = {}) { - const { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory, - FileEnumerator, - CLIEngine, - getCLIEngineInternalSlots - } = defineCLIEngineWithInMemoryFileSystem({ cwd, files }); - const { ESLint, getESLintPrivateMembers } = proxyquire(ESLintPath, { - "../cli-engine/cli-engine": { CLIEngine, getCLIEngineInternalSlots } - }); - - // Override the default cwd. - return { - fs, - RelativeModuleResolver, - ConfigArrayFactory, - CascadingConfigArrayFactory, - FileEnumerator, - CLIEngine, - getCLIEngineInternalSlots, - ESLint: cwd === process.cwd - ? ESLint - : class extends ESLint { - constructor(options) { - super({ cwd: cwd(), ...options }); - } - }, - getESLintPrivateMembers - }; -} - module.exports = { - defineInMemoryFs, - defineConfigArrayFactoryWithInMemoryFileSystem, - defineCascadingConfigArrayFactoryWithInMemoryFileSystem, - defineFileEnumeratorWithInMemoryFileSystem, - defineCLIEngineWithInMemoryFileSystem, - defineESLintWithInMemoryFileSystem + defineInMemoryFs }; diff --git a/tests/_utils/index.js b/tests/_utils/index.js index 7615613d25c..08ef08ae690 100644 --- a/tests/_utils/index.js +++ b/tests/_utils/index.js @@ -9,12 +9,7 @@ //----------------------------------------------------------------------------- const { - defineInMemoryFs, - defineConfigArrayFactoryWithInMemoryFileSystem, - defineCascadingConfigArrayFactoryWithInMemoryFileSystem, - defineFileEnumeratorWithInMemoryFileSystem, - defineCLIEngineWithInMemoryFileSystem, - defineESLintWithInMemoryFileSystem + defineInMemoryFs } = require("./in-memory-fs"); const { createTeardown, addFile } = require("fs-teardown"); @@ -64,10 +59,5 @@ function createCustomTeardown({ cwd, files }) { module.exports = { unIndent, defineInMemoryFs, - defineConfigArrayFactoryWithInMemoryFileSystem, - defineCascadingConfigArrayFactoryWithInMemoryFileSystem, - defineFileEnumeratorWithInMemoryFileSystem, - defineCLIEngineWithInMemoryFileSystem, - defineESLintWithInMemoryFileSystem, createCustomTeardown }; diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js index b7a82ff2209..431437e4fd1 100644 --- a/tests/lib/cli-engine/cli-engine.js +++ b/tests/lib/cli-engine/cli-engine.js @@ -16,7 +16,11 @@ const assert = require("chai").assert, fs = require("fs"), os = require("os"), hash = require("../../../lib/cli-engine/hash"), - { CascadingConfigArrayFactory } = require("@eslint/eslintrc/lib/cascading-config-array-factory"), + { + Legacy: { + CascadingConfigArrayFactory + } + } = require("@eslint/eslintrc"), { unIndent, createCustomTeardown } = require("../../_utils"); const proxyquire = require("proxyquire").noCallThru().noPreserveCache(); diff --git a/tests/lib/cli-engine/file-enumerator.js b/tests/lib/cli-engine/file-enumerator.js index 1ea7a3bd2c4..a2ad62e4e27 100644 --- a/tests/lib/cli-engine/file-enumerator.js +++ b/tests/lib/cli-engine/file-enumerator.js @@ -9,8 +9,11 @@ const path = require("path"); const os = require("os"); const { assert } = require("chai"); const sh = require("shelljs"); -const { CascadingConfigArrayFactory } = - require("@eslint/eslintrc/lib/cascading-config-array-factory"); +const { + Legacy: { + CascadingConfigArrayFactory + } +} = require("@eslint/eslintrc"); const { createCustomTeardown } = require("../../_utils"); const { FileEnumerator } = require("../../../lib/cli-engine/file-enumerator"); diff --git a/tests/lib/eslint/eslint.js b/tests/lib/eslint/eslint.js index 0a5b5e1a9a4..a5e342f0dca 100644 --- a/tests/lib/eslint/eslint.js +++ b/tests/lib/eslint/eslint.js @@ -19,7 +19,11 @@ const fCache = require("file-entry-cache"); const sinon = require("sinon"); const proxyquire = require("proxyquire").noCallThru().noPreserveCache(); const shell = require("shelljs"); -const { CascadingConfigArrayFactory } = require("@eslint/eslintrc/lib/cascading-config-array-factory"); +const { + Legacy: { + CascadingConfigArrayFactory + } +} = require("@eslint/eslintrc"); const hash = require("../../../lib/cli-engine/hash"); const { unIndent, createCustomTeardown } = require("../../_utils"); const coreRules = require("../../../lib/rules");