mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2025-09-15 12:27:30 +00:00
789 lines
26 KiB
JavaScript
789 lines
26 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
var debugOrig = require('debug');
|
|
var fs = require('fs');
|
|
var importFresh = require('import-fresh');
|
|
var Module = require('module');
|
|
var path = require('path');
|
|
var stripComments = require('strip-json-comments');
|
|
var assert = require('assert');
|
|
var ignore = require('ignore');
|
|
var util = require('util');
|
|
var minimatch = require('minimatch');
|
|
var Ajv = require('ajv');
|
|
var globals = require('globals');
|
|
var os = require('os');
|
|
|
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
|
|
var debugOrig__default = /*#__PURE__*/_interopDefaultLegacy(debugOrig);
|
|
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
var importFresh__default = /*#__PURE__*/_interopDefaultLegacy(importFresh);
|
|
var Module__default = /*#__PURE__*/_interopDefaultLegacy(Module);
|
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
var stripComments__default = /*#__PURE__*/_interopDefaultLegacy(stripComments);
|
|
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
|
|
var ignore__default = /*#__PURE__*/_interopDefaultLegacy(ignore);
|
|
var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
|
|
var minimatch__default = /*#__PURE__*/_interopDefaultLegacy(minimatch);
|
|
var Ajv__default = /*#__PURE__*/_interopDefaultLegacy(Ajv);
|
|
var globals__default = /*#__PURE__*/_interopDefaultLegacy(globals);
|
|
var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
|
|
|
/**
|
|
* @fileoverview `IgnorePattern` class.
|
|
*
|
|
* `IgnorePattern` class has the set of glob patterns and the base path.
|
|
*
|
|
* It provides two static methods.
|
|
*
|
|
* - `IgnorePattern.createDefaultIgnore(cwd)`
|
|
* Create the default predicate function.
|
|
* - `IgnorePattern.createIgnore(ignorePatterns)`
|
|
* Create the predicate function from multiple `IgnorePattern` objects.
|
|
*
|
|
* It provides two properties and a method.
|
|
*
|
|
* - `patterns`
|
|
* The glob patterns that ignore to lint.
|
|
* - `basePath`
|
|
* The base path of the glob patterns. If absolute paths existed in the
|
|
* glob patterns, those are handled as relative paths to the base path.
|
|
* - `getPatternsRelativeTo(basePath)`
|
|
* Get `patterns` as modified for a given base path. It modifies the
|
|
* absolute paths in the patterns as prepending the difference of two base
|
|
* paths.
|
|
*
|
|
* `ConfigArrayFactory` creates `IgnorePattern` objects when it processes
|
|
* `ignorePatterns` properties.
|
|
*
|
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
*/
|
|
|
|
const debug$3 = debugOrig__default["default"]("eslintrc:ignore-pattern");
|
|
|
|
/** @typedef {ReturnType<import("ignore").default>} Ignore */
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Get the path to the common ancestor directory of given paths.
|
|
* @param {string[]} sourcePaths The paths to calculate the common ancestor.
|
|
* @returns {string} The path to the common ancestor directory.
|
|
*/
|
|
function getCommonAncestorPath(sourcePaths) {
|
|
let result = sourcePaths[0];
|
|
|
|
for (let i = 1; i < sourcePaths.length; ++i) {
|
|
const a = result;
|
|
const b = sourcePaths[i];
|
|
|
|
// Set the shorter one (it's the common ancestor if one includes the other).
|
|
result = a.length < b.length ? a : b;
|
|
|
|
// Set the common ancestor.
|
|
for (let j = 0, lastSepPos = 0; j < a.length && j < b.length; ++j) {
|
|
if (a[j] !== b[j]) {
|
|
result = a.slice(0, lastSepPos);
|
|
break;
|
|
}
|
|
if (a[j] === path__default["default"].sep) {
|
|
lastSepPos = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
let resolvedResult = result || path__default["default"].sep;
|
|
|
|
// if Windows common ancestor is root of drive must have trailing slash to be absolute.
|
|
if (resolvedResult && resolvedResult.endsWith(":") && process.platform === "win32") {
|
|
resolvedResult += path__default["default"].sep;
|
|
}
|
|
return resolvedResult;
|
|
}
|
|
|
|
/**
|
|
* Make relative path.
|
|
* @param {string} from The source path to get relative path.
|
|
* @param {string} to The destination path to get relative path.
|
|
* @returns {string} The relative path.
|
|
*/
|
|
function relative(from, to) {
|
|
const relPath = path__default["default"].relative(from, to);
|
|
|
|
if (path__default["default"].sep === "/") {
|
|
return relPath;
|
|
}
|
|
return relPath.split(path__default["default"].sep).join("/");
|
|
}
|
|
|
|
/**
|
|
* Get the trailing slash if existed.
|
|
* @param {string} filePath The path to check.
|
|
* @returns {string} The trailing slash if existed.
|
|
*/
|
|
function dirSuffix(filePath) {
|
|
const isDir = (
|
|
filePath.endsWith(path__default["default"].sep) ||
|
|
(process.platform === "win32" && filePath.endsWith("/"))
|
|
);
|
|
|
|
return isDir ? "/" : "";
|
|
}
|
|
|
|
const DefaultPatterns = Object.freeze(["/**/node_modules/*"]);
|
|
const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public
|
|
//------------------------------------------------------------------------------
|
|
|
|
class IgnorePattern {
|
|
|
|
/**
|
|
* The default patterns.
|
|
* @type {string[]}
|
|
*/
|
|
static get DefaultPatterns() {
|
|
return DefaultPatterns;
|
|
}
|
|
|
|
/**
|
|
* Create the default predicate function.
|
|
* @param {string} cwd The current working directory.
|
|
* @returns {((filePath:string, dot:boolean) => boolean) & {basePath:string; patterns:string[]}}
|
|
* The preficate function.
|
|
* The first argument is an absolute path that is checked.
|
|
* The second argument is the flag to not ignore dotfiles.
|
|
* If the predicate function returned `true`, it means the path should be ignored.
|
|
*/
|
|
static createDefaultIgnore(cwd) {
|
|
return this.createIgnore([new IgnorePattern(DefaultPatterns, cwd)]);
|
|
}
|
|
|
|
/**
|
|
* Create the predicate function from multiple `IgnorePattern` objects.
|
|
* @param {IgnorePattern[]} ignorePatterns The list of ignore patterns.
|
|
* @returns {((filePath:string, dot?:boolean) => boolean) & {basePath:string; patterns:string[]}}
|
|
* The preficate function.
|
|
* The first argument is an absolute path that is checked.
|
|
* The second argument is the flag to not ignore dotfiles.
|
|
* If the predicate function returned `true`, it means the path should be ignored.
|
|
*/
|
|
static createIgnore(ignorePatterns) {
|
|
debug$3("Create with: %o", ignorePatterns);
|
|
|
|
const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
|
|
const patterns = [].concat(
|
|
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
|
|
);
|
|
const ig = ignore__default["default"]({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
|
|
const dotIg = ignore__default["default"]({ allowRelativePaths: true }).add(patterns);
|
|
|
|
debug$3(" processed: %o", { basePath, patterns });
|
|
|
|
return Object.assign(
|
|
(filePath, dot = false) => {
|
|
assert__default["default"](path__default["default"].isAbsolute(filePath), "'filePath' should be an absolute path.");
|
|
const relPathRaw = relative(basePath, filePath);
|
|
const relPath = relPathRaw && (relPathRaw + dirSuffix(filePath));
|
|
const adoptedIg = dot ? dotIg : ig;
|
|
const result = relPath !== "" && adoptedIg.ignores(relPath);
|
|
|
|
debug$3("Check", { filePath, dot, relativePath: relPath, result });
|
|
return result;
|
|
},
|
|
{ basePath, patterns }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Initialize a new `IgnorePattern` instance.
|
|
* @param {string[]} patterns The glob patterns that ignore to lint.
|
|
* @param {string} basePath The base path of `patterns`.
|
|
*/
|
|
constructor(patterns, basePath) {
|
|
assert__default["default"](path__default["default"].isAbsolute(basePath), "'basePath' should be an absolute path.");
|
|
|
|
/**
|
|
* The glob patterns that ignore to lint.
|
|
* @type {string[]}
|
|
*/
|
|
this.patterns = patterns;
|
|
|
|
/**
|
|
* The base path of `patterns`.
|
|
* @type {string}
|
|
*/
|
|
this.basePath = basePath;
|
|
|
|
/**
|
|
* If `true` then patterns which don't start with `/` will match the paths to the outside of `basePath`. Defaults to `false`.
|
|
*
|
|
* It's set `true` for `.eslintignore`, `package.json`, and `--ignore-path` for backward compatibility.
|
|
* It's `false` as-is for `ignorePatterns` property in config files.
|
|
* @type {boolean}
|
|
*/
|
|
this.loose = false;
|
|
}
|
|
|
|
/**
|
|
* Get `patterns` as modified for a given base path. It modifies the
|
|
* absolute paths in the patterns as prepending the difference of two base
|
|
* paths.
|
|
* @param {string} newBasePath The base path.
|
|
* @returns {string[]} Modifired patterns.
|
|
*/
|
|
getPatternsRelativeTo(newBasePath) {
|
|
assert__default["default"](path__default["default"].isAbsolute(newBasePath), "'newBasePath' should be an absolute path.");
|
|
const { basePath, loose, patterns } = this;
|
|
|
|
if (newBasePath === basePath) {
|
|
return patterns;
|
|
}
|
|
const prefix = `/${relative(newBasePath, basePath)}`;
|
|
|
|
return patterns.map(pattern => {
|
|
const negative = pattern.startsWith("!");
|
|
const head = negative ? "!" : "";
|
|
const body = negative ? pattern.slice(1) : pattern;
|
|
|
|
if (body.startsWith("/") || body.startsWith("../")) {
|
|
return `${head}${prefix}${body}`;
|
|
}
|
|
return loose ? pattern : `${head}${prefix}/**/${body}`;
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview `ExtractedConfig` class.
|
|
*
|
|
* `ExtractedConfig` class expresses a final configuration for a specific file.
|
|
*
|
|
* It provides one method.
|
|
*
|
|
* - `toCompatibleObjectAsConfigFileContent()`
|
|
* Convert this configuration to the compatible object as the content of
|
|
* config files. It converts the loaded parser and plugins to strings.
|
|
* `CLIEngine#getConfigForFile(filePath)` method uses this method.
|
|
*
|
|
* `ConfigArray#extractConfig(filePath)` creates a `ExtractedConfig` instance.
|
|
*
|
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
*/
|
|
|
|
// For VSCode intellisense
|
|
/** @typedef {import("../../shared/types").ConfigData} ConfigData */
|
|
/** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
|
|
/** @typedef {import("../../shared/types").SeverityConf} SeverityConf */
|
|
/** @typedef {import("./config-dependency").DependentParser} DependentParser */
|
|
/** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
|
|
|
|
/**
|
|
* Check if `xs` starts with `ys`.
|
|
* @template T
|
|
* @param {T[]} xs The array to check.
|
|
* @param {T[]} ys The array that may be the first part of `xs`.
|
|
* @returns {boolean} `true` if `xs` starts with `ys`.
|
|
*/
|
|
function startsWith(xs, ys) {
|
|
return xs.length >= ys.length && ys.every((y, i) => y === xs[i]);
|
|
}
|
|
|
|
/**
|
|
* The class for extracted config data.
|
|
*/
|
|
class ExtractedConfig {
|
|
constructor() {
|
|
|
|
/**
|
|
* The config name what `noInlineConfig` setting came from.
|
|
* @type {string}
|
|
*/
|
|
this.configNameOfNoInlineConfig = "";
|
|
|
|
/**
|
|
* Environments.
|
|
* @type {Record<string, boolean>}
|
|
*/
|
|
this.env = {};
|
|
|
|
/**
|
|
* Global variables.
|
|
* @type {Record<string, GlobalConf>}
|
|
*/
|
|
this.globals = {};
|
|
|
|
/**
|
|
* The glob patterns that ignore to lint.
|
|
* @type {(((filePath:string, dot?:boolean) => boolean) & { basePath:string; patterns:string[] }) | undefined}
|
|
*/
|
|
this.ignores = void 0;
|
|
|
|
/**
|
|
* The flag that disables directive comments.
|
|
* @type {boolean|undefined}
|
|
*/
|
|
this.noInlineConfig = void 0;
|
|
|
|
/**
|
|
* Parser definition.
|
|
* @type {DependentParser|null}
|
|
*/
|
|
this.parser = null;
|
|
|
|
/**
|
|
* Options for the parser.
|
|
* @type {Object}
|
|
*/
|
|
this.parserOptions = {};
|
|
|
|
/**
|
|
* Plugin definitions.
|
|
* @type {Record<string, DependentPlugin>}
|
|
*/
|
|
this.plugins = {};
|
|
|
|
/**
|
|
* Processor ID.
|
|
* @type {string|null}
|
|
*/
|
|
this.processor = null;
|
|
|
|
/**
|
|
* The flag that reports unused `eslint-disable` directive comments.
|
|
* @type {boolean|undefined}
|
|
*/
|
|
this.reportUnusedDisableDirectives = void 0;
|
|
|
|
/**
|
|
* Rule settings.
|
|
* @type {Record<string, [SeverityConf, ...any[]]>}
|
|
*/
|
|
this.rules = {};
|
|
|
|
/**
|
|
* Shared settings.
|
|
* @type {Object}
|
|
*/
|
|
this.settings = {};
|
|
}
|
|
|
|
/**
|
|
* Convert this config to the compatible object as a config file content.
|
|
* @returns {ConfigData} The converted object.
|
|
*/
|
|
toCompatibleObjectAsConfigFileContent() {
|
|
const {
|
|
/* eslint-disable no-unused-vars */
|
|
configNameOfNoInlineConfig: _ignore1,
|
|
processor: _ignore2,
|
|
/* eslint-enable no-unused-vars */
|
|
ignores,
|
|
...config
|
|
} = this;
|
|
|
|
config.parser = config.parser && config.parser.filePath;
|
|
config.plugins = Object.keys(config.plugins).filter(Boolean).reverse();
|
|
config.ignorePatterns = ignores ? ignores.patterns : [];
|
|
|
|
// Strip the default patterns from `ignorePatterns`.
|
|
if (startsWith(config.ignorePatterns, IgnorePattern.DefaultPatterns)) {
|
|
config.ignorePatterns =
|
|
config.ignorePatterns.slice(IgnorePattern.DefaultPatterns.length);
|
|
}
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview `ConfigArray` class.
|
|
*
|
|
* `ConfigArray` class expresses the full of a configuration. It has the entry
|
|
* config file, base config files that were extended, loaded parsers, and loaded
|
|
* plugins.
|
|
*
|
|
* `ConfigArray` class provides three properties and two methods.
|
|
*
|
|
* - `pluginEnvironments`
|
|
* - `pluginProcessors`
|
|
* - `pluginRules`
|
|
* The `Map` objects that contain the members of all plugins that this
|
|
* config array contains. Those map objects don't have mutation methods.
|
|
* Those keys are the member ID such as `pluginId/memberName`.
|
|
* - `isRoot()`
|
|
* If `true` then this configuration has `root:true` property.
|
|
* - `extractConfig(filePath)`
|
|
* Extract the final configuration for a given file. This means merging
|
|
* every config array element which that `criteria` property matched. The
|
|
* `filePath` argument must be an absolute path.
|
|
*
|
|
* `ConfigArrayFactory` provides the loading logic of config files.
|
|
*
|
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Define types for VSCode IntelliSense.
|
|
/** @typedef {import("../../shared/types").Environment} Environment */
|
|
/** @typedef {import("../../shared/types").GlobalConf} GlobalConf */
|
|
/** @typedef {import("../../shared/types").RuleConf} RuleConf */
|
|
/** @typedef {import("../../shared/types").Rule} Rule */
|
|
/** @typedef {import("../../shared/types").Plugin} Plugin */
|
|
/** @typedef {import("../../shared/types").Processor} Processor */
|
|
/** @typedef {import("./config-dependency").DependentParser} DependentParser */
|
|
/** @typedef {import("./config-dependency").DependentPlugin} DependentPlugin */
|
|
/** @typedef {import("./override-tester")["OverrideTester"]} OverrideTester */
|
|
|
|
/**
|
|
* @typedef {Object} ConfigArrayElement
|
|
* @property {string} name The name of this config element.
|
|
* @property {string} filePath The path to the source file of this config element.
|
|
* @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element.
|
|
* @property {Record<string, boolean>|undefined} env The environment settings.
|
|
* @property {Record<string, GlobalConf>|undefined} globals The global variable settings.
|
|
* @property {IgnorePattern|undefined} ignorePattern The ignore patterns.
|
|
* @property {boolean|undefined} noInlineConfig The flag that disables directive comments.
|
|
* @property {DependentParser|undefined} parser The parser loader.
|
|
* @property {Object|undefined} parserOptions The parser options.
|
|
* @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
|
|
* @property {string|undefined} processor The processor name to refer plugin's processor.
|
|
* @property {boolean|undefined} reportUnusedDisableDirectives The flag to report unused `eslint-disable` comments.
|
|
* @property {boolean|undefined} root The flag to express root.
|
|
* @property {Record<string, RuleConf>|undefined} rules The rule settings
|
|
* @property {Object|undefined} settings The shared settings.
|
|
* @property {"config" | "ignore" | "implicit-processor"} type The element type.
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} ConfigArrayInternalSlots
|
|
* @property {Map<string, ExtractedConfig>} cache The cache to extract configs.
|
|
* @property {ReadonlyMap<string, Environment>|null} envMap The map from environment ID to environment definition.
|
|
* @property {ReadonlyMap<string, Processor>|null} processorMap The map from processor ID to environment definition.
|
|
* @property {ReadonlyMap<string, Rule>|null} ruleMap The map from rule ID to rule definition.
|
|
*/
|
|
|
|
/** @type {WeakMap<ConfigArray, ConfigArrayInternalSlots>} */
|
|
const internalSlotsMap$2 = new class extends WeakMap {
|
|
get(key) {
|
|
let value = super.get(key);
|
|
|
|
if (!value) {
|
|
value = {
|
|
cache: new Map(),
|
|
envMap: null,
|
|
processorMap: null,
|
|
ruleMap: null
|
|
};
|
|
super.set(key, value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}();
|
|
|
|
/**
|
|
* Get the indices which are matched to a given file.
|
|
* @param {ConfigArrayElement[]} elements The elements.
|
|
* @param {string} filePath The path to a target file.
|
|
* @returns {number[]} The indices.
|
|
*/
|
|
function getMatchedIndices(elements, filePath) {
|
|
const indices = [];
|
|
|
|
for (let i = elements.length - 1; i >= 0; --i) {
|
|
const element = elements[i];
|
|
|
|
if (!element.criteria || (filePath && element.criteria.test(filePath))) {
|
|
indices.push(i);
|
|
}
|
|
}
|
|
|
|
return indices;
|
|
}
|
|
|
|
/**
|
|
* Check if a value is a non-null object.
|
|
* @param {any} x The value to check.
|
|
* @returns {boolean} `true` if the value is a non-null object.
|
|
*/
|
|
function isNonNullObject(x) {
|
|
return typeof x === "object" && x !== null;
|
|
}
|
|
|
|
/**
|
|
* Merge two objects.
|
|
*
|
|
* Assign every property values of `y` to `x` if `x` doesn't have the property.
|
|
* If `x`'s property value is an object, it does recursive.
|
|
* @param {Object} target The destination to merge
|
|
* @param {Object|undefined} source The source to merge.
|
|
* @returns {void}
|
|
*/
|
|
function mergeWithoutOverwrite(target, source) {
|
|
if (!isNonNullObject(source)) {
|
|
return;
|
|
}
|
|
|
|
for (const key of Object.keys(source)) {
|
|
if (key === "__proto__") {
|
|
continue;
|
|
}
|
|
|
|
if (isNonNullObject(target[key])) {
|
|
mergeWithoutOverwrite(target[key], source[key]);
|
|
} else if (target[key] === void 0) {
|
|
if (isNonNullObject(source[key])) {
|
|
target[key] = Array.isArray(source[key]) ? [] : {};
|
|
mergeWithoutOverwrite(target[key], source[key]);
|
|
} else if (source[key] !== void 0) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The error for plugin conflicts.
|
|
*/
|
|
class PluginConflictError extends Error {
|
|
|
|
/**
|
|
* Initialize this error object.
|
|
* @param {string} pluginId The plugin ID.
|
|
* @param {{filePath:string, importerName:string}[]} plugins The resolved plugins.
|
|
*/
|
|
constructor(pluginId, plugins) {
|
|
super(`Plugin "${pluginId}" was conflicted between ${plugins.map(p => `"${p.importerName}"`).join(" and ")}.`);
|
|
this.messageTemplate = "plugin-conflict";
|
|
this.messageData = { pluginId, plugins };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge plugins.
|
|
* `target`'s definition is prior to `source`'s.
|
|
* @param {Record<string, DependentPlugin>} target The destination to merge
|
|
* @param {Record<string, DependentPlugin>|undefined} source The source to merge.
|
|
* @returns {void}
|
|
*/
|
|
function mergePlugins(target, source) {
|
|
if (!isNonNullObject(source)) {
|
|
return;
|
|
}
|
|
|
|
for (const key of Object.keys(source)) {
|
|
if (key === "__proto__") {
|
|
continue;
|
|
}
|
|
const targetValue = target[key];
|
|
const sourceValue = source[key];
|
|
|
|
// Adopt the plugin which was found at first.
|
|
if (targetValue === void 0) {
|
|
if (sourceValue.error) {
|
|
throw sourceValue.error;
|
|
}
|
|
target[key] = sourceValue;
|
|
} else if (sourceValue.filePath !== targetValue.filePath) {
|
|
throw new PluginConflictError(key, [
|
|
{
|
|
filePath: targetValue.filePath,
|
|
importerName: targetValue.importerName
|
|
},
|
|
{
|
|
filePath: sourceValue.filePath,
|
|
importerName: sourceValue.importerName
|
|
}
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge rule configs.
|
|
* `target`'s definition is prior to `source`'s.
|
|
* @param {Record<string, Array>} target The destination to merge
|
|
* @param {Record<string, RuleConf>|undefined} source The source to merge.
|
|
* @returns {void}
|
|
*/
|
|
function mergeRuleConfigs(target, source) {
|
|
if (!isNonNullObject(source)) {
|
|
return;
|
|
}
|
|
|
|
for (const key of Object.keys(source)) {
|
|
if (key === "__proto__") {
|
|
continue;
|
|
}
|
|
const targetDef = target[key];
|
|
const sourceDef = source[key];
|
|
|
|
// Adopt the rule config which was found at first.
|
|
if (targetDef === void 0) {
|
|
if (Array.isArray(sourceDef)) {
|
|
target[key] = [...sourceDef];
|
|
} else {
|
|
target[key] = [sourceDef];
|
|
}
|
|
|
|
/*
|
|
* If the first found rule config is severity only and the current rule
|
|
* config has options, merge the severity and the options.
|
|
*/
|
|
} else if (
|
|
targetDef.length === 1 &&
|
|
Array.isArray(sourceDef) &&
|
|
sourceDef.length >= 2
|
|
) {
|
|
targetDef.push(...sourceDef.slice(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the extracted config.
|
|
* @param {ConfigArray} instance The config elements.
|
|
* @param {number[]} indices The indices to use.
|
|
* @returns {ExtractedConfig} The extracted config.
|
|
*/
|
|
function createConfig(instance, indices) {
|
|
const config = new ExtractedConfig();
|
|
const ignorePatterns = [];
|
|
|
|
// Merge elements.
|
|
for (const index of indices) {
|
|
const element = instance[index];
|
|
|
|
// Adopt the parser which was found at first.
|
|
if (!config.parser && element.parser) {
|
|
if (element.parser.error) {
|
|
throw element.parser.error;
|
|
}
|
|
config.parser = element.parser;
|
|
}
|
|
|
|
// Adopt the processor which was found at first.
|
|
if (!config.processor && element.processor) {
|
|
config.processor = element.processor;
|
|
}
|
|
|
|
// Adopt the noInlineConfig which was found at first.
|
|
if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) {
|
|
config.noInlineConfig = element.noInlineConfig;
|
|
config.configNameOfNoInlineConfig = element.name;
|
|
}
|
|
|
|
// Adopt the reportUnusedDisableDirectives which was found at first.
|
|
if (config.reportUnusedDisableDirectives === void 0 && element.reportUnusedDisableDirectives !== void 0) {
|
|
config.reportUnusedDisableDirectives = element.reportUnusedDisableDirectives;
|
|
}
|
|
|
|
// Collect ignorePatterns
|
|
if (element.ignorePattern) {
|
|
ignorePatterns.push(element.ignorePattern);
|
|
}
|
|
|
|
// Merge others.
|
|
mergeWithoutOverwrite(config.env, element.env);
|
|
mergeWithoutOverwrite(config.globals, element.globals);
|
|
mergeWithoutOverwrite(config.parserOptions, element.parserOptions);
|
|
mergeWithoutOverwrite(config.settings, element.settings);
|
|
mergePlugins(config.plugins, element.plugins);
|
|
mergeRuleConfigs(config.rules, element.rules);
|
|
}
|
|
|
|
// Create the predicate function for ignore patterns.
|
|
if (ignorePatterns.length > 0) {
|
|
config.ignores = IgnorePattern.createIgnore(ignorePatterns.reverse());
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Collect definitions.
|
|
* @template T, U
|
|
* @param {string} pluginId The plugin ID for prefix.
|
|
* @param {Record<string,T>} defs The definitions to collect.
|
|
* @param {Map<string, U>} map The map to output.
|
|
* @param {function(T): U} [normalize] The normalize function for each value.
|
|
* @returns {void}
|
|
*/
|
|
function collect(pluginId, defs, map, normalize) {
|
|
if (defs) {
|
|
const prefix = pluginId && `${pluginId}/`;
|
|
|
|
for (const [key, value] of Object.entries(defs)) {
|
|
map.set(
|
|
`${prefix}${key}`,
|
|
normalize ? normalize(value) : value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Normalize a rule definition.
|
|
* @param {Function|Rule} rule The rule definition to normalize.
|
|
* @returns {Rule} The normalized rule definition.
|
|
*/
|
|
function normalizePluginRule(rule) {
|
|
return typeof rule === "function" ? { create: rule } : rule;
|
|
}
|
|
|
|
/**
|
|
* Delete the mutation methods from a given map.
|
|
* @param {Map<any, any>} map The map object to delete.
|
|
* @returns {void}
|
|
*/
|
|
function deleteMutationMethods(map) {
|
|
Object.defineProperties(map, {
|
|
clear: { configurable: true, value: void 0 },
|
|
delete: { configurable: true, value: void 0 },
|
|
set: { configurable: true, value: void 0 }
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create `envMap`, `processorMap`, `ruleMap` with the plugins in the config array.
|
|
* @param {ConfigArrayElement[]} elements The config elements.
|
|
* @param {ConfigArrayInternalSlots} slots The internal slots.
|
|
* @returns {void}
|
|
*/
|
|
function initPluginMemberMaps(elements, slots) {
|
|
const processed = new Set();
|
|
|
|
slots.envMap = new Map();
|
|
slots.processorMap = new Map();
|
|
slots.ruleMap = new Map();
|
|
|
|
for (const element of elements) {
|
|
if (!element.plugins) {
|
|
continue;
|
|
}
|
|
|
|
for (const [pluginId, value] of Object.entries(element.plugins)) {
|
|
const plugin = value.definition;
|
|
|
|
if (!plugin || processed.has(pluginId)) {
|
|
continue;
|
|
}
|
|
processed.add(pluginId);
|
|
|
|
collect(pluginId, plugin.environments, slots.envMap);
|
|
collect(pluginId, plugin.processors, slots.processorMap);
|
|
collect(pluginId, plugin.rules, slots.ruleMap, normalizePluginRule);
|
|
}
|
|
}
|
|
|
|
dele |