first commit
This commit is contained in:
348
app_vue/node_modules/eslint/lib/init/autoconfig.js
generated
vendored
Normal file
348
app_vue/node_modules/eslint/lib/init/autoconfig.js
generated
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
/**
|
||||
* @fileoverview Used for creating a suggested configuration based on project code.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const equal = require("fast-deep-equal"),
|
||||
recConfig = require("../../conf/eslint-recommended"),
|
||||
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"),
|
||||
{ Linter } = require("../linter"),
|
||||
configRule = require("./config-rule");
|
||||
|
||||
const debug = require("debug")("eslint:autoconfig");
|
||||
const linter = new Linter();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Data
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only
|
||||
RECOMMENDED_CONFIG_NAME = "eslint:recommended";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Information about a rule configuration, in the context of a Registry.
|
||||
* @typedef {Object} registryItem
|
||||
* @param {ruleConfig} config A valid configuration for the rule
|
||||
* @param {number} specificity The number of elements in the ruleConfig array
|
||||
* @param {number} errorCount The number of errors encountered when linting with the config
|
||||
*/
|
||||
|
||||
/**
|
||||
* This callback is used to measure execution status in a progress bar
|
||||
* @callback progressCallback
|
||||
* @param {number} The total number of times the callback will be called.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create registryItems for rules
|
||||
* @param {rulesConfig} rulesConfig Hash of rule names and arrays of ruleConfig items
|
||||
* @returns {Object} registryItems for each rule in provided rulesConfig
|
||||
*/
|
||||
function makeRegistryItems(rulesConfig) {
|
||||
return Object.keys(rulesConfig).reduce((accumulator, ruleId) => {
|
||||
accumulator[ruleId] = rulesConfig[ruleId].map(config => ({
|
||||
config,
|
||||
specificity: config.length || 1,
|
||||
errorCount: void 0
|
||||
}));
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object in which to store rule configs and error counts
|
||||
*
|
||||
* Unless a rulesConfig is provided at construction, the registry will not contain
|
||||
* any rules, only methods. This will be useful for building up registries manually.
|
||||
*
|
||||
* Registry class
|
||||
*/
|
||||
class Registry {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
|
||||
*/
|
||||
constructor(rulesConfig) {
|
||||
this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the registry with core rule configs.
|
||||
*
|
||||
* It will set the registry's `rule` property to an object having rule names
|
||||
* as keys and an array of registryItems as values.
|
||||
* @returns {void}
|
||||
*/
|
||||
populateFromCoreRules() {
|
||||
const rulesConfig = configRule.createCoreRuleConfigs(/* noDeprecated = */ true);
|
||||
|
||||
this.rules = makeRegistryItems(rulesConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates sets of rule configurations which can be used for linting
|
||||
* and initializes registry errors to zero for those configurations (side effect).
|
||||
*
|
||||
* This combines as many rules together as possible, such that the first sets
|
||||
* in the array will have the highest number of rules configured, and later sets
|
||||
* will have fewer and fewer, as not all rules have the same number of possible
|
||||
* configurations.
|
||||
*
|
||||
* The length of the returned array will be <= MAX_CONFIG_COMBINATIONS.
|
||||
* @returns {Object[]} "rules" configurations to use for linting
|
||||
*/
|
||||
buildRuleSets() {
|
||||
let idx = 0;
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
ruleSets = [];
|
||||
|
||||
/**
|
||||
* Add a rule configuration from the registry to the ruleSets
|
||||
*
|
||||
* This is broken out into its own function so that it doesn't need to be
|
||||
* created inside of the while loop.
|
||||
* @param {string} rule The ruleId to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
const addRuleToRuleSet = function(rule) {
|
||||
|
||||
/*
|
||||
* This check ensures that there is a rule configuration and that
|
||||
* it has fewer than the max combinations allowed.
|
||||
* If it has too many configs, we will only use the most basic of
|
||||
* the possible configurations.
|
||||
*/
|
||||
const hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS);
|
||||
|
||||
if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) {
|
||||
|
||||
/*
|
||||
* If the rule has too many possible combinations, only take
|
||||
* simple ones, avoiding objects.
|
||||
*/
|
||||
if (!hasFewCombos && typeof this.rules[rule][idx].config[1] === "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
ruleSets[idx] = ruleSets[idx] || {};
|
||||
ruleSets[idx][rule] = this.rules[rule][idx].config;
|
||||
|
||||
/*
|
||||
* Initialize errorCount to zero, since this is a config which
|
||||
* will be linted.
|
||||
*/
|
||||
this.rules[rule][idx].errorCount = 0;
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
while (ruleSets.length === idx) {
|
||||
ruleIds.forEach(addRuleToRuleSet);
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return ruleSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the registry with a non-zero number of errors
|
||||
*
|
||||
* Note: this also removes rule configurations which were not linted
|
||||
* (meaning, they have an undefined errorCount).
|
||||
* @returns {void}
|
||||
*/
|
||||
stripFailingConfigs() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
const errorFreeItems = newRegistry.rules[ruleId].filter(registryItem => (registryItem.errorCount === 0));
|
||||
|
||||
if (errorFreeItems.length > 0) {
|
||||
newRegistry.rules[ruleId] = errorFreeItems;
|
||||
} else {
|
||||
delete newRegistry.rules[ruleId];
|
||||
}
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes rule configurations which were not included in a ruleSet
|
||||
* @returns {void}
|
||||
*/
|
||||
stripExtraConfigs() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(registryItem => (typeof registryItem.errorCount !== "undefined"));
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a registry of rules which had no error-free configs.
|
||||
* The new registry is intended to be analyzed to determine whether its rules
|
||||
* should be disabled or set to warning.
|
||||
* @returns {Registry} A registry of failing rules.
|
||||
*/
|
||||
getFailingRulesRegistry() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
failingRegistry = new Registry();
|
||||
|
||||
ruleIds.forEach(ruleId => {
|
||||
const failingConfigs = this.rules[ruleId].filter(registryItem => (registryItem.errorCount > 0));
|
||||
|
||||
if (failingConfigs && failingConfigs.length === this.rules[ruleId].length) {
|
||||
failingRegistry.rules[ruleId] = failingConfigs;
|
||||
}
|
||||
});
|
||||
|
||||
return failingRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an eslint config for any rules which only have one configuration
|
||||
* in the registry.
|
||||
* @returns {Object} An eslint config with rules section populated
|
||||
*/
|
||||
createConfig() {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
config = { rules: {} };
|
||||
|
||||
ruleIds.forEach(ruleId => {
|
||||
if (this.rules[ruleId].length === 1) {
|
||||
config.rules[ruleId] = this.rules[ruleId][0].config;
|
||||
}
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a cloned registry containing only configs with a desired specificity
|
||||
* @param {number} specificity Only keep configs with this specificity
|
||||
* @returns {Registry} A registry of rules
|
||||
*/
|
||||
filterBySpecificity(specificity) {
|
||||
const ruleIds = Object.keys(this.rules),
|
||||
newRegistry = new Registry();
|
||||
|
||||
newRegistry.rules = Object.assign({}, this.rules);
|
||||
ruleIds.forEach(ruleId => {
|
||||
newRegistry.rules[ruleId] = this.rules[ruleId].filter(registryItem => (registryItem.specificity === specificity));
|
||||
});
|
||||
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lint SourceCodes against all configurations in the registry, and record results
|
||||
* @param {Object[]} sourceCodes SourceCode objects for each filename
|
||||
* @param {Object} config ESLint config object
|
||||
* @param {progressCallback} [cb] Optional callback for reporting execution status
|
||||
* @returns {Registry} New registry with errorCount populated
|
||||
*/
|
||||
lintSourceCode(sourceCodes, config, cb) {
|
||||
let lintedRegistry = new Registry();
|
||||
|
||||
lintedRegistry.rules = Object.assign({}, this.rules);
|
||||
|
||||
const ruleSets = lintedRegistry.buildRuleSets();
|
||||
|
||||
lintedRegistry = lintedRegistry.stripExtraConfigs();
|
||||
|
||||
debug("Linting with all possible rule combinations");
|
||||
|
||||
const filenames = Object.keys(sourceCodes);
|
||||
const totalFilesLinting = filenames.length * ruleSets.length;
|
||||
|
||||
filenames.forEach(filename => {
|
||||
debug(`Linting file: ${filename}`);
|
||||
|
||||
let ruleSetIdx = 0;
|
||||
|
||||
ruleSets.forEach(ruleSet => {
|
||||
const lintConfig = Object.assign({}, config, { rules: ruleSet });
|
||||
const lintResults = linter.verify(sourceCodes[filename], lintConfig);
|
||||
|
||||
lintResults.forEach(result => {
|
||||
|
||||
/*
|
||||
* It is possible that the error is from a configuration comment
|
||||
* in a linted file, in which case there may not be a config
|
||||
* set in this ruleSetIdx.
|
||||
* (https://github.com/eslint/eslint/issues/5992)
|
||||
* (https://github.com/eslint/eslint/issues/7860)
|
||||
*/
|
||||
if (
|
||||
lintedRegistry.rules[result.ruleId] &&
|
||||
lintedRegistry.rules[result.ruleId][ruleSetIdx]
|
||||
) {
|
||||
lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
|
||||
}
|
||||
});
|
||||
|
||||
ruleSetIdx += 1;
|
||||
|
||||
if (cb) {
|
||||
cb(totalFilesLinting); // eslint-disable-line node/callback-return
|
||||
}
|
||||
});
|
||||
|
||||
// Deallocate for GC
|
||||
sourceCodes[filename] = null;
|
||||
});
|
||||
|
||||
return lintedRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract rule configuration into eslint:recommended where possible.
|
||||
*
|
||||
* This will return a new config with `["extends": [ ..., "eslint:recommended"]` and
|
||||
* only the rules which have configurations different from the recommended config.
|
||||
* @param {Object} config config object
|
||||
* @returns {Object} config object using `"extends": ["eslint:recommended"]`
|
||||
*/
|
||||
function extendFromRecommended(config) {
|
||||
const newConfig = Object.assign({}, config);
|
||||
|
||||
ConfigOps.normalizeToStrings(newConfig);
|
||||
|
||||
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
||||
|
||||
recRules.forEach(ruleId => {
|
||||
if (equal(recConfig.rules[ruleId], newConfig.rules[ruleId])) {
|
||||
delete newConfig.rules[ruleId];
|
||||
}
|
||||
});
|
||||
newConfig.extends.unshift(RECOMMENDED_CONFIG_NAME);
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
Registry,
|
||||
extendFromRecommended
|
||||
};
|
144
app_vue/node_modules/eslint/lib/init/config-file.js
generated
vendored
Normal file
144
app_vue/node_modules/eslint/lib/init/config-file.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @fileoverview Helper to locate and load configuration files.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
path = require("path"),
|
||||
stringify = require("json-stable-stringify-without-jsonify");
|
||||
|
||||
const debug = require("debug")("eslint:config-file");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines sort order for object keys for json-stable-stringify
|
||||
*
|
||||
* see: https://github.com/samn/json-stable-stringify#cmp
|
||||
* @param {Object} a The first comparison object ({key: akey, value: avalue})
|
||||
* @param {Object} b The second comparison object ({key: bkey, value: bvalue})
|
||||
* @returns {number} 1 or -1, used in stringify cmp method
|
||||
*/
|
||||
function sortByKey(a, b) {
|
||||
return a.key > b.key ? 1 : -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Writes a configuration file in JSON format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeJSONConfigFile(config, filePath) {
|
||||
debug(`Writing JSON config file: ${filePath}`);
|
||||
|
||||
const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
|
||||
|
||||
fs.writeFileSync(filePath, content, "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file in YAML format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeYAMLConfigFile(config, filePath) {
|
||||
debug(`Writing YAML config file: ${filePath}`);
|
||||
|
||||
// lazy load YAML to improve performance when not used
|
||||
const yaml = require("js-yaml");
|
||||
|
||||
const content = yaml.safeDump(config, { sortKeys: true });
|
||||
|
||||
fs.writeFileSync(filePath, content, "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file in JavaScript format.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @throws {Error} If an error occurs linting the config file contents.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function writeJSConfigFile(config, filePath) {
|
||||
debug(`Writing JS config file: ${filePath}`);
|
||||
|
||||
let contentToWrite;
|
||||
const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
|
||||
|
||||
try {
|
||||
const { CLIEngine } = require("../cli-engine");
|
||||
const linter = new CLIEngine({
|
||||
baseConfig: config,
|
||||
fix: true,
|
||||
useEslintrc: false
|
||||
});
|
||||
const report = linter.executeOnText(stringifiedContent);
|
||||
|
||||
contentToWrite = report.results[0].output || stringifiedContent;
|
||||
} catch (e) {
|
||||
debug("Error linting JavaScript config file, writing unlinted version");
|
||||
const errorMessage = e.message;
|
||||
|
||||
contentToWrite = stringifiedContent;
|
||||
e.message = "An error occurred while generating your JavaScript config file. ";
|
||||
e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
|
||||
e.message += `\nError: ${errorMessage}`;
|
||||
throw e;
|
||||
} finally {
|
||||
fs.writeFileSync(filePath, contentToWrite, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a configuration file.
|
||||
* @param {Object} config The configuration object to write.
|
||||
* @param {string} filePath The filename to write to.
|
||||
* @returns {void}
|
||||
* @throws {Error} When an unknown file type is specified.
|
||||
* @private
|
||||
*/
|
||||
function write(config, filePath) {
|
||||
switch (path.extname(filePath)) {
|
||||
case ".js":
|
||||
case ".cjs":
|
||||
writeJSConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
case ".json":
|
||||
writeJSONConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
case ".yaml":
|
||||
case ".yml":
|
||||
writeYAMLConfigFile(config, filePath);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Can't write to unknown file type.");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
write
|
||||
};
|
704
app_vue/node_modules/eslint/lib/init/config-initializer.js
generated
vendored
Normal file
704
app_vue/node_modules/eslint/lib/init/config-initializer.js
generated
vendored
Normal file
@ -0,0 +1,704 @@
|
||||
/**
|
||||
* @fileoverview Config initialization wizard.
|
||||
* @author Ilya Volodin
|
||||
*/
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const util = require("util"),
|
||||
path = require("path"),
|
||||
fs = require("fs"),
|
||||
enquirer = require("enquirer"),
|
||||
ProgressBar = require("progress"),
|
||||
semver = require("semver"),
|
||||
espree = require("espree"),
|
||||
recConfig = require("../../conf/eslint-recommended"),
|
||||
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"),
|
||||
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"),
|
||||
npmUtils = require("./npm-utils"),
|
||||
{ getSourceCodeOfFiles } = require("./source-code-utils");
|
||||
|
||||
const debug = require("debug")("eslint:config-initializer");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* istanbul ignore next: hard to test fs function */
|
||||
/**
|
||||
* Create .eslintrc file in the current working directory
|
||||
* @param {Object} config object that contains user's answers
|
||||
* @param {string} format The file format to write to.
|
||||
* @returns {void}
|
||||
*/
|
||||
function writeFile(config, format) {
|
||||
|
||||
// default is .js
|
||||
let extname = ".js";
|
||||
|
||||
if (format === "YAML") {
|
||||
extname = ".yml";
|
||||
} else if (format === "JSON") {
|
||||
extname = ".json";
|
||||
} else if (format === "JavaScript") {
|
||||
const pkgJSONPath = npmUtils.findPackageJson();
|
||||
|
||||
if (pkgJSONPath) {
|
||||
const pkgJSONContents = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8"));
|
||||
|
||||
if (pkgJSONContents.type === "module") {
|
||||
extname = ".cjs";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const installedESLint = config.installedESLint;
|
||||
|
||||
delete config.installedESLint;
|
||||
|
||||
ConfigFile.write(config, `./.eslintrc${extname}`);
|
||||
log.info(`Successfully created .eslintrc${extname} file in ${process.cwd()}`);
|
||||
|
||||
if (installedESLint) {
|
||||
log.info("ESLint was installed locally. We recommend using this local copy instead of your globally-installed copy.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the peer dependencies of the given module.
|
||||
* This adds the gotten value to cache at the first time, then reuses it.
|
||||
* In a process, this function is called twice, but `npmUtils.fetchPeerDependencies` needs to access network which is relatively slow.
|
||||
* @param {string} moduleName The module name to get.
|
||||
* @returns {Object} The peer dependencies of the given module.
|
||||
* This object is the object of `peerDependencies` field of `package.json`.
|
||||
* Returns null if npm was not found.
|
||||
*/
|
||||
function getPeerDependencies(moduleName) {
|
||||
let result = getPeerDependencies.cache.get(moduleName);
|
||||
|
||||
if (!result) {
|
||||
log.info(`Checking peerDependencies of ${moduleName}`);
|
||||
|
||||
result = npmUtils.fetchPeerDependencies(moduleName);
|
||||
getPeerDependencies.cache.set(moduleName, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
getPeerDependencies.cache = new Map();
|
||||
|
||||
/**
|
||||
* Return necessary plugins, configs, parsers, etc. based on the config
|
||||
* @param {Object} config config object
|
||||
* @param {boolean} [installESLint=true] If `false` is given, it does not install eslint.
|
||||
* @returns {string[]} An array of modules to be installed.
|
||||
*/
|
||||
function getModulesList(config, installESLint) {
|
||||
const modules = {};
|
||||
|
||||
// Create a list of modules which should be installed based on config
|
||||
if (config.plugins) {
|
||||
for (const plugin of config.plugins) {
|
||||
const moduleName = naming.normalizePackageName(plugin, "eslint-plugin");
|
||||
|
||||
modules[moduleName] = "latest";
|
||||
}
|
||||
}
|
||||
if (config.extends) {
|
||||
const extendList = Array.isArray(config.extends) ? config.extends : [config.extends];
|
||||
|
||||
for (const extend of extendList) {
|
||||
if (extend.startsWith("eslint:") || extend.startsWith("plugin:")) {
|
||||
continue;
|
||||
}
|
||||
const moduleName = naming.normalizePackageName(extend, "eslint-config");
|
||||
|
||||
modules[moduleName] = "latest";
|
||||
Object.assign(
|
||||
modules,
|
||||
getPeerDependencies(`${moduleName}@latest`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const parser = config.parser || (config.parserOptions && config.parserOptions.parser);
|
||||
|
||||
if (parser) {
|
||||
modules[parser] = "latest";
|
||||
}
|
||||
|
||||
if (installESLint === false) {
|
||||
delete modules.eslint;
|
||||
} else {
|
||||
const installStatus = npmUtils.checkDevDeps(["eslint"]);
|
||||
|
||||
// Mark to show messages if it's new installation of eslint.
|
||||
if (installStatus.eslint === false) {
|
||||
log.info("Local ESLint installation not found.");
|
||||
modules.eslint = modules.eslint || "latest";
|
||||
config.installedESLint = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(modules).map(name => `${name}@${modules[name]}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the `rules` of a config by examining a user's source code
|
||||
*
|
||||
* Note: This clones the config object and returns a new config to avoid mutating
|
||||
* the original config parameter.
|
||||
* @param {Object} answers answers received from enquirer
|
||||
* @param {Object} config config object
|
||||
* @returns {Object} config object with configured rules
|
||||
*/
|
||||
function configureRules(answers, config) {
|
||||
const BAR_TOTAL = 20,
|
||||
BAR_SOURCE_CODE_TOTAL = 4,
|
||||
newConfig = Object.assign({}, config),
|
||||
disabledConfigs = {};
|
||||
let sourceCodes,
|
||||
registry;
|
||||
|
||||
// Set up a progress bar, as this process can take a long time
|
||||
const bar = new ProgressBar("Determining Config: :percent [:bar] :elapseds elapsed, eta :etas ", {
|
||||
width: 30,
|
||||
total: BAR_TOTAL
|
||||
});
|
||||
|
||||
bar.tick(0); // Shows the progress bar
|
||||
|
||||
// Get the SourceCode of all chosen files
|
||||
const patterns = answers.patterns.split(/[\s]+/u);
|
||||
|
||||
try {
|
||||
sourceCodes = getSourceCodeOfFiles(patterns, { baseConfig: newConfig, useEslintrc: false }, total => {
|
||||
bar.tick((BAR_SOURCE_CODE_TOTAL / total));
|
||||
});
|
||||
} catch (e) {
|
||||
log.info("\n");
|
||||
throw e;
|
||||
}
|
||||
const fileQty = Object.keys(sourceCodes).length;
|
||||
|
||||
if (fileQty === 0) {
|
||||
log.info("\n");
|
||||
throw new Error("Automatic Configuration failed. No files were able to be parsed.");
|
||||
}
|
||||
|
||||
// Create a registry of rule configs
|
||||
registry = new autoconfig.Registry();
|
||||
registry.populateFromCoreRules();
|
||||
|
||||
// Lint all files with each rule config in the registry
|
||||
registry = registry.lintSourceCode(sourceCodes, newConfig, total => {
|
||||
bar.tick((BAR_TOTAL - BAR_SOURCE_CODE_TOTAL) / total); // Subtract out ticks used at beginning
|
||||
});
|
||||
debug(`\nRegistry: ${util.inspect(registry.rules, { depth: null })}`);
|
||||
|
||||
// Create a list of recommended rules, because we don't want to disable them
|
||||
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
||||
|
||||
// Find and disable rules which had no error-free configuration
|
||||
const failingRegistry = registry.getFailingRulesRegistry();
|
||||
|
||||
Object.keys(failingRegistry.rules).forEach(ruleId => {
|
||||
|
||||
// If the rule is recommended, set it to error, otherwise disable it
|
||||
disabledConfigs[ruleId] = (recRules.indexOf(ruleId) !== -1) ? 2 : 0;
|
||||
});
|
||||
|
||||
// Now that we know which rules to disable, strip out configs with errors
|
||||
registry = registry.stripFailingConfigs();
|
||||
|
||||
/*
|
||||
* If there is only one config that results in no errors for a rule, we should use it.
|
||||
* createConfig will only add rules that have one configuration in the registry.
|
||||
*/
|
||||
const singleConfigs = registry.createConfig().rules;
|
||||
|
||||
/*
|
||||
* The "sweet spot" for number of options in a config seems to be two (severity plus one option).
|
||||
* Very often, a third option (usually an object) is available to address
|
||||
* edge cases, exceptions, or unique situations. We will prefer to use a config with
|
||||
* specificity of two.
|
||||
*/
|
||||
const specTwoConfigs = registry.filterBySpecificity(2).createConfig().rules;
|
||||
|
||||
// Maybe a specific combination using all three options works
|
||||
const specThreeConfigs = registry.filterBySpecificity(3).createConfig().rules;
|
||||
|
||||
// If all else fails, try to use the default (severity only)
|
||||
const defaultConfigs = registry.filterBySpecificity(1).createConfig().rules;
|
||||
|
||||
// Combine configs in reverse priority order (later take precedence)
|
||||
newConfig.rules = Object.assign({}, disabledConfigs, defaultConfigs, specThreeConfigs, specTwoConfigs, singleConfigs);
|
||||
|
||||
// Make sure progress bar has finished (floating point rounding)
|
||||
bar.update(BAR_TOTAL);
|
||||
|
||||
// Log out some stats to let the user know what happened
|
||||
const finalRuleIds = Object.keys(newConfig.rules);
|
||||
const totalRules = finalRuleIds.length;
|
||||
const enabledRules = finalRuleIds.filter(ruleId => (newConfig.rules[ruleId] !== 0)).length;
|
||||
const resultMessage = [
|
||||
`\nEnabled ${enabledRules} out of ${totalRules}`,
|
||||
`rules based on ${fileQty}`,
|
||||
`file${(fileQty === 1) ? "." : "s."}`
|
||||
].join(" ");
|
||||
|
||||
log.info(resultMessage);
|
||||
|
||||
ConfigOps.normalizeToStrings(newConfig);
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* process user's answers and create config object
|
||||
* @param {Object} answers answers received from enquirer
|
||||
* @returns {Object} config object
|
||||
*/
|
||||
function processAnswers(answers) {
|
||||
let config = {
|
||||
rules: {},
|
||||
env: {},
|
||||
parserOptions: {},
|
||||
extends: []
|
||||
};
|
||||
|
||||
config.parserOptions.ecmaVersion = espree.latestEcmaVersion;
|
||||
config.env.es2021 = true;
|
||||
|
||||
// set the module type
|
||||
if (answers.moduleType === "esm") {
|
||||
config.parserOptions.sourceType = "module";
|
||||
} else if (answers.moduleType === "commonjs") {
|
||||
config.env.commonjs = true;
|
||||
}
|
||||
|
||||
// add in browser and node environments if necessary
|
||||
answers.env.forEach(env => {
|
||||
config.env[env] = true;
|
||||
});
|
||||
|
||||
// add in library information
|
||||
if (answers.framework === "react") {
|
||||
config.parserOptions.ecmaFeatures = {
|
||||
jsx: true
|
||||
};
|
||||
config.plugins = ["react"];
|
||||
config.extends.push("plugin:react/recommended");
|
||||
} else if (answers.framework === "vue") {
|
||||
config.plugins = ["vue"];
|
||||
config.extends.push("plugin:vue/essential");
|
||||
}
|
||||
|
||||
if (answers.typescript) {
|
||||
if (answers.framework === "vue") {
|
||||
config.parserOptions.parser = "@typescript-eslint/parser";
|
||||
} else {
|
||||
config.parser = "@typescript-eslint/parser";
|
||||
}
|
||||
|
||||
if (Array.isArray(config.plugins)) {
|
||||
config.plugins.push("@typescript-eslint");
|
||||
} else {
|
||||
config.plugins = ["@typescript-eslint"];
|
||||
}
|
||||
}
|
||||
|
||||
// setup rules based on problems/style enforcement preferences
|
||||
if (answers.purpose === "problems") {
|
||||
config.extends.unshift("eslint:recommended");
|
||||
} else if (answers.purpose === "style") {
|
||||
if (answers.source === "prompt") {
|
||||
config.extends.unshift("eslint:recommended");
|
||||
config.rules.indent = ["error", answers.indent];
|
||||
config.rules.quotes = ["error", answers.quotes];
|
||||
config.rules["linebreak-style"] = ["error", answers.linebreak];
|
||||
config.rules.semi = ["error", answers.semi ? "always" : "never"];
|
||||
} else if (answers.source === "auto") {
|
||||
config = configureRules(answers, config);
|
||||
config = autoconfig.extendFromRecommended(config);
|
||||
}
|
||||
}
|
||||
if (answers.typescript && config.extends.includes("eslint:recommended")) {
|
||||
config.extends.push("plugin:@typescript-eslint/recommended");
|
||||
}
|
||||
|
||||
// normalize extends
|
||||
if (config.extends.length === 0) {
|
||||
delete config.extends;
|
||||
} else if (config.extends.length === 1) {
|
||||
config.extends = config.extends[0];
|
||||
}
|
||||
|
||||
ConfigOps.normalizeToStrings(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of the local ESLint.
|
||||
* @returns {string|null} The version. If the local ESLint was not found, returns null.
|
||||
*/
|
||||
function getLocalESLintVersion() {
|
||||
try {
|
||||
const eslintPath = ModuleResolver.resolve("eslint", path.join(process.cwd(), "__placeholder__.js"));
|
||||
const eslint = require(eslintPath);
|
||||
|
||||
return eslint.linter.version || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shareable config name of the chosen style guide.
|
||||
* @param {Object} answers The answers object.
|
||||
* @returns {string} The shareable config name.
|
||||
*/
|
||||
function getStyleGuideName(answers) {
|
||||
if (answers.styleguide === "airbnb" && answers.framework !== "react") {
|
||||
return "airbnb-base";
|
||||
}
|
||||
return answers.styleguide;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the local ESLint version conflicts with the required version of the chosen shareable config.
|
||||
* @param {Object} answers The answers object.
|
||||
* @returns {boolean} `true` if the local ESLint is found then it conflicts with the required version of the chosen shareable config.
|
||||
*/
|
||||
function hasESLintVersionConflict(answers) {
|
||||
|
||||
// Get the local ESLint version.
|
||||
const localESLintVersion = getLocalESLintVersion();
|
||||
|
||||
if (!localESLintVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the required range of ESLint version.
|
||||
const configName = getStyleGuideName(answers);
|
||||
const moduleName = `eslint-config-${configName}@latest`;
|
||||
const peerDependencies = getPeerDependencies(moduleName) || {};
|
||||
const requiredESLintVersionRange = peerDependencies.eslint;
|
||||
|
||||
if (!requiredESLintVersionRange) {
|
||||
return false;
|
||||
}
|
||||
|
||||
answers.localESLintVersion = localESLintVersion;
|
||||
answers.requiredESLintVersionRange = requiredESLintVersionRange;
|
||||
|
||||
// Check the version.
|
||||
if (semver.satisfies(localESLintVersion, requiredESLintVersionRange)) {
|
||||
answers.installESLint = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install modules.
|
||||
* @param {string[]} modules Modules to be installed.
|
||||
* @returns {void}
|
||||
*/
|
||||
function installModules(modules) {
|
||||
log.info(`Installing ${modules.join(", ")}`);
|
||||
npmUtils.installSyncSaveDev(modules);
|
||||
}
|
||||
|
||||
/* istanbul ignore next: no need to test enquirer */
|
||||
/**
|
||||
* Ask user to install modules.
|
||||
* @param {string[]} modules Array of modules to be installed.
|
||||
* @param {boolean} packageJsonExists Indicates if package.json is existed.
|
||||
* @returns {Promise} Answer that indicates if user wants to install.
|
||||
*/
|
||||
function askInstallModules(modules, packageJsonExists) {
|
||||
|
||||
// If no modules, do nothing.
|
||||
if (modules.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
log.info("The config that you've selected requires the following dependencies:\n");
|
||||
log.info(modules.join(" "));
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "toggle",
|
||||
name: "executeInstallation",
|
||||
message: "Would you like to install them now with npm?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1,
|
||||
skip() {
|
||||
return !(modules.length && packageJsonExists);
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
}
|
||||
]).then(({ executeInstallation }) => {
|
||||
if (executeInstallation) {
|
||||
installModules(modules);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* istanbul ignore next: no need to test enquirer */
|
||||
/**
|
||||
* Ask use a few questions on command prompt
|
||||
* @returns {Promise} The promise with the result of the prompt
|
||||
*/
|
||||
function promptUser() {
|
||||
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "select",
|
||||
name: "purpose",
|
||||
message: "How would you like to use ESLint?",
|
||||
|
||||
// The returned number matches the name value of nth in the choices array.
|
||||
initial: 1,
|
||||
choices: [
|
||||
{ message: "To check syntax only", name: "syntax" },
|
||||
{ message: "To check syntax and find problems", name: "problems" },
|
||||
{ message: "To check syntax, find problems, and enforce code style", name: "style" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "moduleType",
|
||||
message: "What type of modules does your project use?",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "JavaScript modules (import/export)", name: "esm" },
|
||||
{ message: "CommonJS (require/exports)", name: "commonjs" },
|
||||
{ message: "None of these", name: "none" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: "Which framework does your project use?",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "React", name: "react" },
|
||||
{ message: "Vue.js", name: "vue" },
|
||||
{ message: "None of these", name: "none" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "typescript",
|
||||
message: "Does your project use TypeScript?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 0
|
||||
},
|
||||
{
|
||||
type: "multiselect",
|
||||
name: "env",
|
||||
message: "Where does your code run?",
|
||||
hint: "(Press <space> to select, <a> to toggle all, <i> to invert selection)",
|
||||
initial: 0,
|
||||
choices: [
|
||||
{ message: "Browser", name: "browser" },
|
||||
{ message: "Node", name: "node" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "source",
|
||||
message: "How would you like to define a style for your project?",
|
||||
choices: [
|
||||
{ message: "Use a popular style guide", name: "guide" },
|
||||
{ message: "Answer questions about your style", name: "prompt" },
|
||||
{ message: "Inspect your JavaScript file(s)", name: "auto" }
|
||||
],
|
||||
skip() {
|
||||
return this.state.answers.purpose !== "style";
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "styleguide",
|
||||
message: "Which style guide do you want to follow?",
|
||||
choices: [
|
||||
{ message: "Airbnb: https://github.com/airbnb/javascript", name: "airbnb" },
|
||||
{ message: "Standard: https://github.com/standard/standard", name: "standard" },
|
||||
{ message: "Google: https://github.com/google/eslint-config-google", name: "google" },
|
||||
{ message: "XO: https://github.com/xojs/eslint-config-xo", name: "xo" }
|
||||
],
|
||||
skip() {
|
||||
this.state.answers.packageJsonExists = npmUtils.checkPackageJson();
|
||||
return !(this.state.answers.source === "guide" && this.state.answers.packageJsonExists);
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "patterns",
|
||||
message: "Which file(s), path(s), or glob(s) should be examined?",
|
||||
skip() {
|
||||
return this.state.answers.source !== "auto";
|
||||
},
|
||||
validate(input) {
|
||||
if (!this.skipped && input.trim().length === 0 && input.trim() !== ",") {
|
||||
return "You must tell us what code to examine. Try again.";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "format",
|
||||
message: "What format do you want your config file to be in?",
|
||||
initial: 0,
|
||||
choices: ["JavaScript", "YAML", "JSON"]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "installESLint",
|
||||
message() {
|
||||
const { answers } = this.state;
|
||||
const verb = semver.ltr(answers.localESLintVersion, answers.requiredESLintVersionRange)
|
||||
? "upgrade"
|
||||
: "downgrade";
|
||||
|
||||
return `The style guide "${answers.styleguide}" requires eslint@${answers.requiredESLintVersionRange}. You are currently using eslint@${answers.localESLintVersion}.\n Do you want to ${verb}?`;
|
||||
},
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1,
|
||||
skip() {
|
||||
return !(this.state.answers.source === "guide" && this.state.answers.packageJsonExists && hasESLintVersionConflict(this.state.answers));
|
||||
},
|
||||
result(input) {
|
||||
return this.skipped ? null : input;
|
||||
}
|
||||
}
|
||||
]).then(earlyAnswers => {
|
||||
|
||||
// early exit if no style guide is necessary
|
||||
if (earlyAnswers.purpose !== "style") {
|
||||
const config = processAnswers(earlyAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules, earlyAnswers.packageJsonExists)
|
||||
.then(() => writeFile(config, earlyAnswers.format));
|
||||
}
|
||||
|
||||
// early exit if you are using a style guide
|
||||
if (earlyAnswers.source === "guide") {
|
||||
if (!earlyAnswers.packageJsonExists) {
|
||||
log.info("A package.json is necessary to install plugins such as style guides. Run `npm init` to create a package.json file and try again.");
|
||||
return void 0;
|
||||
}
|
||||
if (earlyAnswers.installESLint === false && !semver.satisfies(earlyAnswers.localESLintVersion, earlyAnswers.requiredESLintVersionRange)) {
|
||||
log.info(`Note: it might not work since ESLint's version is mismatched with the ${earlyAnswers.styleguide} config.`);
|
||||
}
|
||||
if (earlyAnswers.styleguide === "airbnb" && earlyAnswers.framework !== "react") {
|
||||
earlyAnswers.styleguide = "airbnb-base";
|
||||
}
|
||||
|
||||
const config = processAnswers(earlyAnswers);
|
||||
|
||||
if (Array.isArray(config.extends)) {
|
||||
config.extends.push(earlyAnswers.styleguide);
|
||||
} else if (config.extends) {
|
||||
config.extends = [config.extends, earlyAnswers.styleguide];
|
||||
} else {
|
||||
config.extends = [earlyAnswers.styleguide];
|
||||
}
|
||||
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules, earlyAnswers.packageJsonExists)
|
||||
.then(() => writeFile(config, earlyAnswers.format));
|
||||
|
||||
}
|
||||
|
||||
if (earlyAnswers.source === "auto") {
|
||||
const combinedAnswers = Object.assign({}, earlyAnswers);
|
||||
const config = processAnswers(combinedAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
|
||||
}
|
||||
|
||||
// continue with the style questions otherwise...
|
||||
return enquirer.prompt([
|
||||
{
|
||||
type: "select",
|
||||
name: "indent",
|
||||
message: "What style of indentation do you use?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Tabs", name: "tab" }, { message: "Spaces", name: 4 }]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "quotes",
|
||||
message: "What quotes do you use for strings?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Double", name: "double" }, { message: "Single", name: "single" }]
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "linebreak",
|
||||
message: "What line endings do you use?",
|
||||
initial: 0,
|
||||
choices: [{ message: "Unix", name: "unix" }, { message: "Windows", name: "windows" }]
|
||||
},
|
||||
{
|
||||
type: "toggle",
|
||||
name: "semi",
|
||||
message: "Do you require semicolons?",
|
||||
enabled: "Yes",
|
||||
disabled: "No",
|
||||
initial: 1
|
||||
}
|
||||
]).then(answers => {
|
||||
const totalAnswers = Object.assign({}, earlyAnswers, answers);
|
||||
|
||||
const config = processAnswers(totalAnswers);
|
||||
const modules = getModulesList(config);
|
||||
|
||||
return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const init = {
|
||||
getModulesList,
|
||||
hasESLintVersionConflict,
|
||||
installModules,
|
||||
processAnswers,
|
||||
writeFile,
|
||||
/* istanbul ignore next */initializeConfig() {
|
||||
return promptUser();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = init;
|
317
app_vue/node_modules/eslint/lib/init/config-rule.js
generated
vendored
Normal file
317
app_vue/node_modules/eslint/lib/init/config-rule.js
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* @fileoverview Create configurations for a rule
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const builtInRules = require("../rules");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Wrap all of the elements of an array into arrays.
|
||||
* @param {*[]} xs Any array.
|
||||
* @returns {Array[]} An array of arrays.
|
||||
*/
|
||||
function explodeArray(xs) {
|
||||
return xs.reduce((accumulator, x) => {
|
||||
accumulator.push([x]);
|
||||
return accumulator;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix two arrays such that each element of the second array is concatenated
|
||||
* onto each element of the first array.
|
||||
*
|
||||
* For example:
|
||||
* combineArrays([a, [b, c]], [x, y]); // -> [[a, x], [a, y], [b, c, x], [b, c, y]]
|
||||
* @param {Array} arr1 The first array to combine.
|
||||
* @param {Array} arr2 The second array to combine.
|
||||
* @returns {Array} A mixture of the elements of the first and second arrays.
|
||||
*/
|
||||
function combineArrays(arr1, arr2) {
|
||||
const res = [];
|
||||
|
||||
if (arr1.length === 0) {
|
||||
return explodeArray(arr2);
|
||||
}
|
||||
if (arr2.length === 0) {
|
||||
return explodeArray(arr1);
|
||||
}
|
||||
arr1.forEach(x1 => {
|
||||
arr2.forEach(x2 => {
|
||||
res.push([].concat(x1, x2));
|
||||
});
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group together valid rule configurations based on object properties
|
||||
*
|
||||
* e.g.:
|
||||
* groupByProperty([
|
||||
* {before: true},
|
||||
* {before: false},
|
||||
* {after: true},
|
||||
* {after: false}
|
||||
* ]);
|
||||
*
|
||||
* will return:
|
||||
* [
|
||||
* [{before: true}, {before: false}],
|
||||
* [{after: true}, {after: false}]
|
||||
* ]
|
||||
* @param {Object[]} objects Array of objects, each with one property/value pair
|
||||
* @returns {Array[]} Array of arrays of objects grouped by property
|
||||
*/
|
||||
function groupByProperty(objects) {
|
||||
const groupedObj = objects.reduce((accumulator, obj) => {
|
||||
const prop = Object.keys(obj)[0];
|
||||
|
||||
accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj];
|
||||
return accumulator;
|
||||
}, {});
|
||||
|
||||
return Object.keys(groupedObj).map(prop => groupedObj[prop]);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configuration settings for a rule.
|
||||
*
|
||||
* A configuration can be a single number (severity), or an array where the first
|
||||
* element in the array is the severity, and is the only required element.
|
||||
* Configs may also have one or more additional elements to specify rule
|
||||
* configuration or options.
|
||||
* @typedef {Array|number} ruleConfig
|
||||
* @param {number} 0 The rule's severity (0, 1, 2).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object whose keys are rule names and values are arrays of valid ruleConfig items
|
||||
* which should be linted against the target source code to determine error counts.
|
||||
* (a ruleConfigSet.ruleConfigs).
|
||||
*
|
||||
* e.g. rulesConfig = {
|
||||
* "comma-dangle": [2, [2, "always"], [2, "always-multiline"], [2, "never"]],
|
||||
* "no-console": [2]
|
||||
* }
|
||||
* @typedef rulesConfig
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create valid rule configurations by combining two arrays,
|
||||
* with each array containing multiple objects each with a
|
||||
* single property/value pair and matching properties.
|
||||
*
|
||||
* e.g.:
|
||||
* combinePropertyObjects(
|
||||
* [{before: true}, {before: false}],
|
||||
* [{after: true}, {after: false}]
|
||||
* );
|
||||
*
|
||||
* will return:
|
||||
* [
|
||||
* {before: true, after: true},
|
||||
* {before: true, after: false},
|
||||
* {before: false, after: true},
|
||||
* {before: false, after: false}
|
||||
* ]
|
||||
* @param {Object[]} objArr1 Single key/value objects, all with the same key
|
||||
* @param {Object[]} objArr2 Single key/value objects, all with another key
|
||||
* @returns {Object[]} Combined objects for each combination of input properties and values
|
||||
*/
|
||||
function combinePropertyObjects(objArr1, objArr2) {
|
||||
const res = [];
|
||||
|
||||
if (objArr1.length === 0) {
|
||||
return objArr2;
|
||||
}
|
||||
if (objArr2.length === 0) {
|
||||
return objArr1;
|
||||
}
|
||||
objArr1.forEach(obj1 => {
|
||||
objArr2.forEach(obj2 => {
|
||||
const combinedObj = {};
|
||||
const obj1Props = Object.keys(obj1);
|
||||
const obj2Props = Object.keys(obj2);
|
||||
|
||||
obj1Props.forEach(prop1 => {
|
||||
combinedObj[prop1] = obj1[prop1];
|
||||
});
|
||||
obj2Props.forEach(prop2 => {
|
||||
combinedObj[prop2] = obj2[prop2];
|
||||
});
|
||||
res.push(combinedObj);
|
||||
});
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a rule configuration set
|
||||
*
|
||||
* A rule configuration set is an array of configurations that are valid for a
|
||||
* given rule. For example, the configuration set for the "semi" rule could be:
|
||||
*
|
||||
* ruleConfigSet.ruleConfigs // -> [[2], [2, "always"], [2, "never"]]
|
||||
*
|
||||
* Rule configuration set class
|
||||
*/
|
||||
class RuleConfigSet {
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description
|
||||
/**
|
||||
* @param {ruleConfig[]} configs Valid rule configurations
|
||||
*/
|
||||
constructor(configs) {
|
||||
|
||||
/**
|
||||
* Stored valid rule configurations for this instance
|
||||
* @type {Array}
|
||||
*/
|
||||
this.ruleConfigs = configs || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a severity level to the front of all configs in the instance.
|
||||
* This should only be called after all configs have been added to the instance.
|
||||
* @returns {void}
|
||||
*/
|
||||
addErrorSeverity() {
|
||||
const severity = 2;
|
||||
|
||||
this.ruleConfigs = this.ruleConfigs.map(config => {
|
||||
config.unshift(severity);
|
||||
return config;
|
||||
});
|
||||
|
||||
// Add a single config at the beginning consisting of only the severity
|
||||
this.ruleConfigs.unshift(severity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rule configs from an array of strings (schema enums)
|
||||
* @param {string[]} enums Array of valid rule options (e.g. ["always", "never"])
|
||||
* @returns {void}
|
||||
*/
|
||||
addEnums(enums) {
|
||||
this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, enums));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rule configurations from a schema object
|
||||
* @param {Object} obj Schema item with type === "object"
|
||||
* @returns {boolean} true if at least one schema for the object could be generated, false otherwise
|
||||
*/
|
||||
addObject(obj) {
|
||||
const objectConfigSet = {
|
||||
objectConfigs: [],
|
||||
add(property, values) {
|
||||
for (let idx = 0; idx < values.length; idx++) {
|
||||
const optionObj = {};
|
||||
|
||||
optionObj[property] = values[idx];
|
||||
this.objectConfigs.push(optionObj);
|
||||
}
|
||||
},
|
||||
|
||||
combine() {
|
||||
this.objectConfigs = groupByProperty(this.objectConfigs).reduce((accumulator, objArr) => combinePropertyObjects(accumulator, objArr), []);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The object schema could have multiple independent properties.
|
||||
* If any contain enums or booleans, they can be added and then combined
|
||||
*/
|
||||
Object.keys(obj.properties).forEach(prop => {
|
||||
if (obj.properties[prop].enum) {
|
||||
objectConfigSet.add(prop, obj.properties[prop].enum);
|
||||
}
|
||||
if (obj.properties[prop].type && obj.properties[prop].type === "boolean") {
|
||||
objectConfigSet.add(prop, [true, false]);
|
||||
}
|
||||
});
|
||||
objectConfigSet.combine();
|
||||
|
||||
if (objectConfigSet.objectConfigs.length > 0) {
|
||||
this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, objectConfigSet.objectConfigs));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate valid rule configurations based on a schema object
|
||||
* @param {Object} schema A rule's schema object
|
||||
* @returns {Array[]} Valid rule configurations
|
||||
*/
|
||||
function generateConfigsFromSchema(schema) {
|
||||
const configSet = new RuleConfigSet();
|
||||
|
||||
if (Array.isArray(schema)) {
|
||||
for (const opt of schema) {
|
||||
if (opt.enum) {
|
||||
configSet.addEnums(opt.enum);
|
||||
} else if (opt.type && opt.type === "object") {
|
||||
if (!configSet.addObject(opt)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO (IanVS): support oneOf
|
||||
} else {
|
||||
|
||||
// If we don't know how to fill in this option, don't fill in any of the following options.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
configSet.addErrorSeverity();
|
||||
return configSet.ruleConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate possible rule configurations for all of the core rules
|
||||
* @param {boolean} noDeprecated Indicates whether ignores deprecated rules or not.
|
||||
* @returns {rulesConfig} Hash of rule names and arrays of possible configurations
|
||||
*/
|
||||
function createCoreRuleConfigs(noDeprecated = false) {
|
||||
return Array.from(builtInRules).reduce((accumulator, [id, rule]) => {
|
||||
const schema = (typeof rule === "function") ? rule.schema : rule.meta.schema;
|
||||
const isDeprecated = (typeof rule === "function") ? rule.deprecated : rule.meta.deprecated;
|
||||
|
||||
if (noDeprecated && isDeprecated) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
accumulator[id] = generateConfigsFromSchema(schema);
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
generateConfigsFromSchema,
|
||||
createCoreRuleConfigs
|
||||
};
|
178
app_vue/node_modules/eslint/lib/init/npm-utils.js
generated
vendored
Normal file
178
app_vue/node_modules/eslint/lib/init/npm-utils.js
generated
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @fileoverview Utility for executing npm commands.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const fs = require("fs"),
|
||||
spawn = require("cross-spawn"),
|
||||
path = require("path"),
|
||||
log = require("../shared/logging");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find the closest package.json file, starting at process.cwd (by default),
|
||||
* and working up to root.
|
||||
* @param {string} [startDir=process.cwd()] Starting directory
|
||||
* @returns {string} Absolute path to closest package.json file
|
||||
*/
|
||||
function findPackageJson(startDir) {
|
||||
let dir = path.resolve(startDir || process.cwd());
|
||||
|
||||
do {
|
||||
const pkgFile = path.join(dir, "package.json");
|
||||
|
||||
if (!fs.existsSync(pkgFile) || !fs.statSync(pkgFile).isFile()) {
|
||||
dir = path.join(dir, "..");
|
||||
continue;
|
||||
}
|
||||
return pkgFile;
|
||||
} while (dir !== path.resolve(dir, ".."));
|
||||
return null;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Install node modules synchronously and save to devDependencies in package.json
|
||||
* @param {string|string[]} packages Node module or modules to install
|
||||
* @returns {void}
|
||||
*/
|
||||
function installSyncSaveDev(packages) {
|
||||
const packageList = Array.isArray(packages) ? packages : [packages];
|
||||
const npmProcess = spawn.sync("npm", ["i", "--save-dev"].concat(packageList), { stdio: "inherit" });
|
||||
const error = npmProcess.error;
|
||||
|
||||
if (error && error.code === "ENOENT") {
|
||||
const pluralS = packageList.length > 1 ? "s" : "";
|
||||
|
||||
log.error(`Could not execute npm. Please install the following package${pluralS} with a package manager of your choice: ${packageList.join(", ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch `peerDependencies` of the given package by `npm show` command.
|
||||
* @param {string} packageName The package name to fetch peerDependencies.
|
||||
* @returns {Object} Gotten peerDependencies. Returns null if npm was not found.
|
||||
*/
|
||||
function fetchPeerDependencies(packageName) {
|
||||
const npmProcess = spawn.sync(
|
||||
"npm",
|
||||
["show", "--json", packageName, "peerDependencies"],
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
|
||||
const error = npmProcess.error;
|
||||
|
||||
if (error && error.code === "ENOENT") {
|
||||
return null;
|
||||
}
|
||||
const fetchedText = npmProcess.stdout.trim();
|
||||
|
||||
return JSON.parse(fetchedText || "{}");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are include in a project's package.json.
|
||||
* @param {string[]} packages Array of node module names
|
||||
* @param {Object} opt Options Object
|
||||
* @param {boolean} opt.dependencies Set to true to check for direct dependencies
|
||||
* @param {boolean} opt.devDependencies Set to true to check for development dependencies
|
||||
* @param {boolean} opt.startdir Directory to begin searching from
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function check(packages, opt) {
|
||||
const deps = new Set();
|
||||
const pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson();
|
||||
let fileJson;
|
||||
|
||||
if (!pkgJson) {
|
||||
throw new Error("Could not find a package.json file. Run 'npm init' to create one.");
|
||||
}
|
||||
|
||||
try {
|
||||
fileJson = JSON.parse(fs.readFileSync(pkgJson, "utf8"));
|
||||
} catch (e) {
|
||||
const error = new Error(e);
|
||||
|
||||
error.messageTemplate = "failed-to-read-json";
|
||||
error.messageData = {
|
||||
path: pkgJson,
|
||||
message: e.message
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
|
||||
["dependencies", "devDependencies"].forEach(key => {
|
||||
if (opt[key] && typeof fileJson[key] === "object") {
|
||||
Object.keys(fileJson[key]).forEach(dep => deps.add(dep));
|
||||
}
|
||||
});
|
||||
|
||||
return packages.reduce((status, pkg) => {
|
||||
status[pkg] = deps.has(pkg);
|
||||
return status;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are included in the dependencies of a project's
|
||||
* package.json.
|
||||
*
|
||||
* Convenience wrapper around check().
|
||||
* @param {string[]} packages Array of node modules to check.
|
||||
* @param {string} rootDir The directory containing a package.json
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function checkDeps(packages, rootDir) {
|
||||
return check(packages, { dependencies: true, startDir: rootDir });
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether node modules are included in the devDependencies of a project's
|
||||
* package.json.
|
||||
*
|
||||
* Convenience wrapper around check().
|
||||
* @param {string[]} packages Array of node modules to check.
|
||||
* @returns {Object} An object whose keys are the module names
|
||||
* and values are booleans indicating installation.
|
||||
*/
|
||||
function checkDevDeps(packages) {
|
||||
return check(packages, { devDependencies: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether package.json is found in current path.
|
||||
* @param {string} [startDir] Starting directory
|
||||
* @returns {boolean} Whether a package.json is found in current path.
|
||||
*/
|
||||
function checkPackageJson(startDir) {
|
||||
return !!findPackageJson(startDir);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
module.exports = {
|
||||
installSyncSaveDev,
|
||||
fetchPeerDependencies,
|
||||
findPackageJson,
|
||||
checkDeps,
|
||||
checkDevDeps,
|
||||
checkPackageJson
|
||||
};
|
109
app_vue/node_modules/eslint/lib/init/source-code-utils.js
generated
vendored
Normal file
109
app_vue/node_modules/eslint/lib/init/source-code-utils.js
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @fileoverview Tools for obtaining SourceCode objects.
|
||||
* @author Ian VanSchooten
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { CLIEngine } = require("../cli-engine");
|
||||
|
||||
/*
|
||||
* This is used for:
|
||||
*
|
||||
* 1. Enumerate target file because we have not expose such a API on `CLIEngine`
|
||||
* (https://github.com/eslint/eslint/issues/11222).
|
||||
* 2. Create `SourceCode` instances. Because we don't have any function which
|
||||
* instantiate `SourceCode` so it needs to take the created `SourceCode`
|
||||
* instance out after linting.
|
||||
*
|
||||
* TODO1: Expose the API that enumerates target files.
|
||||
* TODO2: Extract the creation logic of `SourceCode` from `Linter` class.
|
||||
*/
|
||||
const { getCLIEngineInternalSlots } = require("../cli-engine/cli-engine"); // eslint-disable-line node/no-restricted-require
|
||||
|
||||
const debug = require("debug")("eslint:source-code-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the SourceCode object for a single file
|
||||
* @param {string} filename The fully resolved filename to get SourceCode from.
|
||||
* @param {Object} engine A CLIEngine.
|
||||
* @returns {Array} Array of the SourceCode object representing the file
|
||||
* and fatal error message.
|
||||
*/
|
||||
function getSourceCodeOfFile(filename, engine) {
|
||||
debug("getting sourceCode of", filename);
|
||||
const results = engine.executeOnFiles([filename]);
|
||||
|
||||
if (results && results.results[0] && results.results[0].messages[0] && results.results[0].messages[0].fatal) {
|
||||
const msg = results.results[0].messages[0];
|
||||
|
||||
throw new Error(`(${filename}:${msg.line}:${msg.column}) ${msg.message}`);
|
||||
}
|
||||
|
||||
// TODO: extract the logic that creates source code objects to `SourceCode#parse(text, options)` or something like.
|
||||
const { linter } = getCLIEngineInternalSlots(engine);
|
||||
const sourceCode = linter.getSourceCode();
|
||||
|
||||
return sourceCode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This callback is used to measure execution status in a progress bar
|
||||
* @callback progressCallback
|
||||
* @param {number} The total number of times the callback will be called.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the SourceCode of a single file, or set of files.
|
||||
* @param {string[]|string} patterns A filename, directory name, or glob, or an array of them
|
||||
* @param {Object} options A CLIEngine options object. If not provided, the default cli options will be used.
|
||||
* @param {progressCallback} callback Callback for reporting execution status
|
||||
* @returns {Object} The SourceCode of all processed files.
|
||||
*/
|
||||
function getSourceCodeOfFiles(patterns, options, callback) {
|
||||
const sourceCodes = {};
|
||||
const globPatternsList = typeof patterns === "string" ? [patterns] : patterns;
|
||||
const engine = new CLIEngine({ ...options, rules: {} });
|
||||
|
||||
// TODO: make file iteration as a public API and use it.
|
||||
const { fileEnumerator } = getCLIEngineInternalSlots(engine);
|
||||
const filenames =
|
||||
Array.from(fileEnumerator.iterateFiles(globPatternsList))
|
||||
.filter(entry => !entry.ignored)
|
||||
.map(entry => entry.filePath);
|
||||
|
||||
if (filenames.length === 0) {
|
||||
debug(`Did not find any files matching pattern(s): ${globPatternsList}`);
|
||||
}
|
||||
|
||||
filenames.forEach(filename => {
|
||||
const sourceCode = getSourceCodeOfFile(filename, engine);
|
||||
|
||||
if (sourceCode) {
|
||||
debug("got sourceCode of", filename);
|
||||
sourceCodes[filename] = sourceCode;
|
||||
}
|
||||
if (callback) {
|
||||
callback(filenames.length); // eslint-disable-line node/callback-return
|
||||
}
|
||||
});
|
||||
|
||||
return sourceCodes;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSourceCodeOfFiles
|
||||
};
|
Reference in New Issue
Block a user