301 lines
14 KiB
JavaScript
301 lines
14 KiB
JavaScript
|
"use strict";
|
|||
|
Object.defineProperty(exports, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
Object.defineProperty(exports, "runLintCheck", {
|
|||
|
enumerable: true,
|
|||
|
get: function() {
|
|||
|
return runLintCheck;
|
|||
|
}
|
|||
|
});
|
|||
|
const _fs = require("fs");
|
|||
|
const _picocolors = require("../picocolors");
|
|||
|
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|||
|
const _findup = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/find-up"));
|
|||
|
const _semver = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/semver"));
|
|||
|
const _commentjson = /*#__PURE__*/ _interop_require_wildcard(require("next/dist/compiled/comment-json"));
|
|||
|
const _customFormatter = require("./customFormatter");
|
|||
|
const _writeDefaultConfig = require("./writeDefaultConfig");
|
|||
|
const _hasEslintConfiguration = require("./hasEslintConfiguration");
|
|||
|
const _writeOutputFile = require("./writeOutputFile");
|
|||
|
const _constants = require("../constants");
|
|||
|
const _findpagesdir = require("../find-pages-dir");
|
|||
|
const _installdependencies = require("../install-dependencies");
|
|||
|
const _hasnecessarydependencies = require("../has-necessary-dependencies");
|
|||
|
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log"));
|
|||
|
const _iserror = /*#__PURE__*/ _interop_require_wildcard(require("../is-error"));
|
|||
|
const _getpkgmanager = require("../helpers/get-pkg-manager");
|
|||
|
function _interop_require_default(obj) {
|
|||
|
return obj && obj.__esModule ? obj : {
|
|||
|
default: obj
|
|||
|
};
|
|||
|
}
|
|||
|
function _getRequireWildcardCache(nodeInterop) {
|
|||
|
if (typeof WeakMap !== "function") return null;
|
|||
|
var cacheBabelInterop = new WeakMap();
|
|||
|
var cacheNodeInterop = new WeakMap();
|
|||
|
return (_getRequireWildcardCache = function(nodeInterop) {
|
|||
|
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|||
|
})(nodeInterop);
|
|||
|
}
|
|||
|
function _interop_require_wildcard(obj, nodeInterop) {
|
|||
|
if (!nodeInterop && obj && obj.__esModule) {
|
|||
|
return obj;
|
|||
|
}
|
|||
|
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|||
|
return {
|
|||
|
default: obj
|
|||
|
};
|
|||
|
}
|
|||
|
var cache = _getRequireWildcardCache(nodeInterop);
|
|||
|
if (cache && cache.has(obj)) {
|
|||
|
return cache.get(obj);
|
|||
|
}
|
|||
|
var newObj = {};
|
|||
|
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|||
|
for(var key in obj){
|
|||
|
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|||
|
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|||
|
if (desc && (desc.get || desc.set)) {
|
|||
|
Object.defineProperty(newObj, key, desc);
|
|||
|
} else {
|
|||
|
newObj[key] = obj[key];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
newObj.default = obj;
|
|||
|
if (cache) {
|
|||
|
cache.set(obj, newObj);
|
|||
|
}
|
|||
|
return newObj;
|
|||
|
}
|
|||
|
// 0 is off, 1 is warn, 2 is error. See https://eslint.org/docs/user-guide/configuring/rules#configuring-rules
|
|||
|
const VALID_SEVERITY = [
|
|||
|
"off",
|
|||
|
"warn",
|
|||
|
"error"
|
|||
|
];
|
|||
|
function isValidSeverity(severity) {
|
|||
|
return VALID_SEVERITY.includes(severity);
|
|||
|
}
|
|||
|
const requiredPackages = [
|
|||
|
{
|
|||
|
file: "eslint",
|
|||
|
pkg: "eslint",
|
|||
|
exportsRestrict: false
|
|||
|
},
|
|||
|
{
|
|||
|
file: "eslint-config-next",
|
|||
|
pkg: "eslint-config-next",
|
|||
|
exportsRestrict: false
|
|||
|
}
|
|||
|
];
|
|||
|
async function cliPrompt() {
|
|||
|
console.log((0, _picocolors.bold)(`${(0, _picocolors.cyan)("?")} How would you like to configure ESLint? https://nextjs.org/docs/basic-features/eslint`));
|
|||
|
try {
|
|||
|
const cliSelect = (await Promise.resolve(require("next/dist/compiled/cli-select"))).default;
|
|||
|
const { value } = await cliSelect({
|
|||
|
values: _constants.ESLINT_PROMPT_VALUES,
|
|||
|
valueRenderer: ({ title, recommended }, selected)=>{
|
|||
|
const name = selected ? (0, _picocolors.bold)((0, _picocolors.underline)((0, _picocolors.cyan)(title))) : title;
|
|||
|
return name + (recommended ? (0, _picocolors.bold)((0, _picocolors.yellow)(" (recommended)")) : "");
|
|||
|
},
|
|||
|
selected: (0, _picocolors.cyan)("❯ "),
|
|||
|
unselected: " "
|
|||
|
});
|
|||
|
return {
|
|||
|
config: (value == null ? void 0 : value.config) ?? null
|
|||
|
};
|
|||
|
} catch {
|
|||
|
return {
|
|||
|
config: null
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
async function lint(baseDir, lintDirs, eslintrcFile, pkgJsonPath, { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null }) {
|
|||
|
try {
|
|||
|
var _mod_CLIEngine, _ESLint_getErrorResults;
|
|||
|
// Load ESLint after we're sure it exists:
|
|||
|
const deps = await (0, _hasnecessarydependencies.hasNecessaryDependencies)(baseDir, requiredPackages);
|
|||
|
const packageManager = (0, _getpkgmanager.getPkgManager)(baseDir);
|
|||
|
if (deps.missing.some((dep)=>dep.pkg === "eslint")) {
|
|||
|
_log.error(`ESLint must be installed${lintDuringBuild ? " in order to run during builds:" : ":"} ${(0, _picocolors.bold)((0, _picocolors.cyan)((packageManager === "yarn" ? "yarn add --dev" : packageManager === "pnpm" ? "pnpm install --save-dev" : "npm install --save-dev") + " eslint"))}`);
|
|||
|
return null;
|
|||
|
}
|
|||
|
const mod = await Promise.resolve(require(deps.resolved.get("eslint")));
|
|||
|
const { ESLint } = mod;
|
|||
|
let eslintVersion = (ESLint == null ? void 0 : ESLint.version) ?? ((_mod_CLIEngine = mod.CLIEngine) == null ? void 0 : _mod_CLIEngine.version);
|
|||
|
if (!eslintVersion || _semver.default.lt(eslintVersion, "7.0.0")) {
|
|||
|
return `${(0, _picocolors.red)("error")} - Your project has an older version of ESLint installed${eslintVersion ? " (" + eslintVersion + ")" : ""}. Please upgrade to ESLint version 7 or above`;
|
|||
|
}
|
|||
|
let options = {
|
|||
|
useEslintrc: true,
|
|||
|
baseConfig: {},
|
|||
|
errorOnUnmatchedPattern: false,
|
|||
|
extensions: [
|
|||
|
".js",
|
|||
|
".jsx",
|
|||
|
".ts",
|
|||
|
".tsx"
|
|||
|
],
|
|||
|
cache: true,
|
|||
|
...eslintOptions
|
|||
|
};
|
|||
|
let eslint = new ESLint(options);
|
|||
|
let nextEslintPluginIsEnabled = false;
|
|||
|
const nextRulesEnabled = new Map();
|
|||
|
for (const configFile of [
|
|||
|
eslintrcFile,
|
|||
|
pkgJsonPath
|
|||
|
]){
|
|||
|
var _completeConfig_plugins;
|
|||
|
if (!configFile) continue;
|
|||
|
const completeConfig = await eslint.calculateConfigForFile(configFile);
|
|||
|
if ((_completeConfig_plugins = completeConfig.plugins) == null ? void 0 : _completeConfig_plugins.includes("@next/next")) {
|
|||
|
nextEslintPluginIsEnabled = true;
|
|||
|
for (const [name, [severity]] of Object.entries(completeConfig.rules)){
|
|||
|
if (!name.startsWith("@next/next/")) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (typeof severity === "number" && severity >= 0 && severity < VALID_SEVERITY.length) {
|
|||
|
nextRulesEnabled.set(name, VALID_SEVERITY[severity]);
|
|||
|
} else if (typeof severity === "string" && isValidSeverity(severity)) {
|
|||
|
nextRulesEnabled.set(name, severity);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
const pagesDir = (0, _findpagesdir.findPagesDir)(baseDir).pagesDir;
|
|||
|
const pagesDirRules = pagesDir ? [
|
|||
|
"@next/next/no-html-link-for-pages"
|
|||
|
] : [];
|
|||
|
if (nextEslintPluginIsEnabled) {
|
|||
|
let updatedPagesDir = false;
|
|||
|
for (const rule of pagesDirRules){
|
|||
|
var _options_baseConfig_rules, _options_baseConfig_rules1;
|
|||
|
if (!((_options_baseConfig_rules = options.baseConfig.rules) == null ? void 0 : _options_baseConfig_rules[rule]) && !((_options_baseConfig_rules1 = options.baseConfig.rules) == null ? void 0 : _options_baseConfig_rules1[rule.replace("@next/next", "@next/babel-plugin-next")])) {
|
|||
|
if (!options.baseConfig.rules) {
|
|||
|
options.baseConfig.rules = {};
|
|||
|
}
|
|||
|
options.baseConfig.rules[rule] = [
|
|||
|
1,
|
|||
|
pagesDir
|
|||
|
];
|
|||
|
updatedPagesDir = true;
|
|||
|
}
|
|||
|
}
|
|||
|
if (updatedPagesDir) {
|
|||
|
eslint = new ESLint(options);
|
|||
|
}
|
|||
|
} else {
|
|||
|
_log.warn("");
|
|||
|
_log.warn("The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config");
|
|||
|
}
|
|||
|
const lintStart = process.hrtime();
|
|||
|
let results = await eslint.lintFiles(lintDirs);
|
|||
|
let selectedFormatter = null;
|
|||
|
if (options.fix) await ESLint.outputFixes(results);
|
|||
|
if (reportErrorsOnly) results = await ESLint.getErrorResults(results) // Only return errors if --quiet flag is used
|
|||
|
;
|
|||
|
if (formatter) selectedFormatter = await eslint.loadFormatter(formatter);
|
|||
|
const formattedResult = (0, _customFormatter.formatResults)(baseDir, results, selectedFormatter == null ? void 0 : selectedFormatter.format);
|
|||
|
const lintEnd = process.hrtime(lintStart);
|
|||
|
const totalWarnings = results.reduce((sum, file)=>sum + file.warningCount, 0);
|
|||
|
if (outputFile) await (0, _writeOutputFile.writeOutputFile)(outputFile, formattedResult.output);
|
|||
|
return {
|
|||
|
output: formattedResult.outputWithMessages,
|
|||
|
isError: ((_ESLint_getErrorResults = ESLint.getErrorResults(results)) == null ? void 0 : _ESLint_getErrorResults.length) > 0 || maxWarnings >= 0 && totalWarnings > maxWarnings,
|
|||
|
eventInfo: {
|
|||
|
durationInSeconds: lintEnd[0],
|
|||
|
eslintVersion: eslintVersion,
|
|||
|
lintedFilesCount: results.length,
|
|||
|
lintFix: !!options.fix,
|
|||
|
nextEslintPluginVersion: nextEslintPluginIsEnabled && deps.resolved.has("eslint-config-next") ? require(_path.default.join(_path.default.dirname(deps.resolved.get("eslint-config-next")), "package.json")).version : null,
|
|||
|
nextEslintPluginErrorsCount: formattedResult.totalNextPluginErrorCount,
|
|||
|
nextEslintPluginWarningsCount: formattedResult.totalNextPluginWarningCount,
|
|||
|
nextRulesEnabled: Object.fromEntries(nextRulesEnabled)
|
|||
|
}
|
|||
|
};
|
|||
|
} catch (err) {
|
|||
|
if (lintDuringBuild) {
|
|||
|
_log.error(`ESLint: ${(0, _iserror.default)(err) && err.message ? err.message.replace(/\n/g, " ") : err}`);
|
|||
|
return null;
|
|||
|
} else {
|
|||
|
throw (0, _iserror.getProperError)(err);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
async function runLintCheck(baseDir, lintDirs, opts) {
|
|||
|
const { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null, strict = false } = opts;
|
|||
|
try {
|
|||
|
// Find user's .eslintrc file
|
|||
|
// See: https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats
|
|||
|
const eslintrcFile = await (0, _findup.default)([
|
|||
|
".eslintrc.js",
|
|||
|
".eslintrc.cjs",
|
|||
|
".eslintrc.yaml",
|
|||
|
".eslintrc.yml",
|
|||
|
".eslintrc.json",
|
|||
|
".eslintrc"
|
|||
|
], {
|
|||
|
cwd: baseDir
|
|||
|
}) ?? null;
|
|||
|
const pkgJsonPath = await (0, _findup.default)("package.json", {
|
|||
|
cwd: baseDir
|
|||
|
}) ?? null;
|
|||
|
let packageJsonConfig = null;
|
|||
|
if (pkgJsonPath) {
|
|||
|
const pkgJsonContent = await _fs.promises.readFile(pkgJsonPath, {
|
|||
|
encoding: "utf8"
|
|||
|
});
|
|||
|
packageJsonConfig = _commentjson.parse(pkgJsonContent);
|
|||
|
}
|
|||
|
const config = await (0, _hasEslintConfiguration.hasEslintConfiguration)(eslintrcFile, packageJsonConfig);
|
|||
|
let deps;
|
|||
|
if (config.exists) {
|
|||
|
// Run if ESLint config exists
|
|||
|
return await lint(baseDir, lintDirs, eslintrcFile, pkgJsonPath, {
|
|||
|
lintDuringBuild,
|
|||
|
eslintOptions,
|
|||
|
reportErrorsOnly,
|
|||
|
maxWarnings,
|
|||
|
formatter,
|
|||
|
outputFile
|
|||
|
});
|
|||
|
} else {
|
|||
|
// Display warning if no ESLint configuration is present inside
|
|||
|
// config file during "next build", no warning is shown when
|
|||
|
// no eslintrc file is present
|
|||
|
if (lintDuringBuild) {
|
|||
|
if (config.emptyPkgJsonConfig || config.emptyEslintrc) {
|
|||
|
_log.warn(`No ESLint configuration detected. Run ${(0, _picocolors.bold)((0, _picocolors.cyan)("next lint"))} to begin setup`);
|
|||
|
}
|
|||
|
return null;
|
|||
|
} else {
|
|||
|
// Ask user what config they would like to start with for first time "next lint" setup
|
|||
|
const { config: selectedConfig } = strict ? _constants.ESLINT_PROMPT_VALUES.find((opt)=>opt.title === "Strict") : await cliPrompt();
|
|||
|
if (selectedConfig == null) {
|
|||
|
// Show a warning if no option is selected in prompt
|
|||
|
_log.warn("If you set up ESLint yourself, we recommend adding the Next.js ESLint plugin. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config");
|
|||
|
return null;
|
|||
|
} else {
|
|||
|
// Check if necessary deps installed, and install any that are missing
|
|||
|
deps = await (0, _hasnecessarydependencies.hasNecessaryDependencies)(baseDir, requiredPackages);
|
|||
|
if (deps.missing.length > 0) await (0, _installdependencies.installDependencies)(baseDir, deps.missing, true);
|
|||
|
// Write default ESLint config.
|
|||
|
// Check for /pages and src/pages is to make sure this happens in Next.js folder
|
|||
|
if ((0, _fs.existsSync)(_path.default.join(baseDir, "pages")) || (0, _fs.existsSync)(_path.default.join(baseDir, "src/pages"))) {
|
|||
|
await (0, _writeDefaultConfig.writeDefaultConfig)(baseDir, config, selectedConfig, eslintrcFile, pkgJsonPath, packageJsonConfig);
|
|||
|
}
|
|||
|
}
|
|||
|
_log.ready(`ESLint has successfully been configured. Run ${(0, _picocolors.bold)((0, _picocolors.cyan)("next lint"))} again to view warnings and errors.`);
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
} catch (err) {
|
|||
|
throw err;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//# sourceMappingURL=runLintCheck.js.map
|