mirror of
https://github.com/Sevichecc/Urara-Blog.git
synced 2025-05-06 08:59:14 +08:00
377 lines
No EOL
14 KiB
Text
377 lines
No EOL
14 KiB
Text
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.createValidator = void 0;
|
|
const utils_1 = require("@typescript-eslint/utils");
|
|
const enums_1 = require("./enums");
|
|
const format_1 = require("./format");
|
|
const shared_1 = require("./shared");
|
|
const util = __importStar(require("../../util"));
|
|
function createValidator(type, context, allConfigs) {
|
|
// make sure the "highest priority" configs are checked first
|
|
const selectorType = enums_1.Selectors[type];
|
|
const configs = allConfigs
|
|
// gather all of the applicable selectors
|
|
.filter(c => (c.selector & selectorType) !== 0 ||
|
|
c.selector === enums_1.MetaSelectors.default)
|
|
.sort((a, b) => {
|
|
if (a.selector === b.selector) {
|
|
// in the event of the same selector, order by modifier weight
|
|
// sort descending - the type modifiers are "more important"
|
|
return b.modifierWeight - a.modifierWeight;
|
|
}
|
|
const aIsMeta = (0, shared_1.isMetaSelector)(a.selector);
|
|
const bIsMeta = (0, shared_1.isMetaSelector)(b.selector);
|
|
// non-meta selectors should go ahead of meta selectors
|
|
if (aIsMeta && !bIsMeta) {
|
|
return 1;
|
|
}
|
|
if (!aIsMeta && bIsMeta) {
|
|
return -1;
|
|
}
|
|
const aIsMethodOrProperty = (0, shared_1.isMethodOrPropertySelector)(a.selector);
|
|
const bIsMethodOrProperty = (0, shared_1.isMethodOrPropertySelector)(b.selector);
|
|
// for backward compatibility, method and property have higher precedence than other meta selectors
|
|
if (aIsMethodOrProperty && !bIsMethodOrProperty) {
|
|
return -1;
|
|
}
|
|
if (!aIsMethodOrProperty && bIsMethodOrProperty) {
|
|
return 1;
|
|
}
|
|
// both aren't meta selectors
|
|
// sort descending - the meta selectors are "least important"
|
|
return b.selector - a.selector;
|
|
});
|
|
return (node, modifiers = new Set()) => {
|
|
var _a, _b, _c;
|
|
const originalName = node.type === utils_1.AST_NODE_TYPES.Identifier ||
|
|
node.type === utils_1.AST_NODE_TYPES.PrivateIdentifier
|
|
? node.name
|
|
: `${node.value}`;
|
|
// return will break the loop and stop checking configs
|
|
// it is only used when the name is known to have failed or succeeded a config.
|
|
for (const config of configs) {
|
|
if (((_a = config.filter) === null || _a === void 0 ? void 0 : _a.regex.test(originalName)) !== ((_b = config.filter) === null || _b === void 0 ? void 0 : _b.match)) {
|
|
// name does not match the filter
|
|
continue;
|
|
}
|
|
if ((_c = config.modifiers) === null || _c === void 0 ? void 0 : _c.some(modifier => !modifiers.has(modifier))) {
|
|
// does not have the required modifiers
|
|
continue;
|
|
}
|
|
if (!isCorrectType(node, config, context, selectorType)) {
|
|
// is not the correct type
|
|
continue;
|
|
}
|
|
let name = originalName;
|
|
name = validateUnderscore('leading', config, name, node, originalName);
|
|
if (name === null) {
|
|
// fail
|
|
return;
|
|
}
|
|
name = validateUnderscore('trailing', config, name, node, originalName);
|
|
if (name === null) {
|
|
// fail
|
|
return;
|
|
}
|
|
name = validateAffix('prefix', config, name, node, originalName);
|
|
if (name === null) {
|
|
// fail
|
|
return;
|
|
}
|
|
name = validateAffix('suffix', config, name, node, originalName);
|
|
if (name === null) {
|
|
// fail
|
|
return;
|
|
}
|
|
if (!validateCustom(config, name, node, originalName)) {
|
|
// fail
|
|
return;
|
|
}
|
|
if (!validatePredefinedFormat(config, name, node, originalName, modifiers)) {
|
|
// fail
|
|
return;
|
|
}
|
|
// it's valid for this config, so we don't need to check any more configs
|
|
return;
|
|
}
|
|
};
|
|
// centralizes the logic for formatting the report data
|
|
function formatReportData({ affixes, formats, originalName, processedName, position, custom, count, }) {
|
|
var _a;
|
|
return {
|
|
type: (0, shared_1.selectorTypeToMessageString)(type),
|
|
name: originalName,
|
|
processedName,
|
|
position,
|
|
count,
|
|
affixes: affixes === null || affixes === void 0 ? void 0 : affixes.join(', '),
|
|
formats: formats === null || formats === void 0 ? void 0 : formats.map(f => enums_1.PredefinedFormats[f]).join(', '),
|
|
regex: (_a = custom === null || custom === void 0 ? void 0 : custom.regex) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
regexMatch: (custom === null || custom === void 0 ? void 0 : custom.match) === true
|
|
? 'match'
|
|
: (custom === null || custom === void 0 ? void 0 : custom.match) === false
|
|
? 'not match'
|
|
: null,
|
|
};
|
|
}
|
|
/**
|
|
* @returns the name with the underscore removed, if it is valid according to the specified underscore option, null otherwise
|
|
*/
|
|
function validateUnderscore(position, config, name, node, originalName) {
|
|
const option = position === 'leading'
|
|
? config.leadingUnderscore
|
|
: config.trailingUnderscore;
|
|
if (!option) {
|
|
return name;
|
|
}
|
|
const hasSingleUnderscore = position === 'leading'
|
|
? () => name.startsWith('_')
|
|
: () => name.endsWith('_');
|
|
const trimSingleUnderscore = position === 'leading'
|
|
? () => name.slice(1)
|
|
: () => name.slice(0, -1);
|
|
const hasDoubleUnderscore = position === 'leading'
|
|
? () => name.startsWith('__')
|
|
: () => name.endsWith('__');
|
|
const trimDoubleUnderscore = position === 'leading'
|
|
? () => name.slice(2)
|
|
: () => name.slice(0, -2);
|
|
switch (option) {
|
|
// ALLOW - no conditions as the user doesn't care if it's there or not
|
|
case enums_1.UnderscoreOptions.allow: {
|
|
if (hasSingleUnderscore()) {
|
|
return trimSingleUnderscore();
|
|
}
|
|
return name;
|
|
}
|
|
case enums_1.UnderscoreOptions.allowDouble: {
|
|
if (hasDoubleUnderscore()) {
|
|
return trimDoubleUnderscore();
|
|
}
|
|
return name;
|
|
}
|
|
case enums_1.UnderscoreOptions.allowSingleOrDouble: {
|
|
if (hasDoubleUnderscore()) {
|
|
return trimDoubleUnderscore();
|
|
}
|
|
if (hasSingleUnderscore()) {
|
|
return trimSingleUnderscore();
|
|
}
|
|
return name;
|
|
}
|
|
// FORBID
|
|
case enums_1.UnderscoreOptions.forbid: {
|
|
if (hasSingleUnderscore()) {
|
|
context.report({
|
|
node,
|
|
messageId: 'unexpectedUnderscore',
|
|
data: formatReportData({
|
|
originalName,
|
|
position,
|
|
count: 'one',
|
|
}),
|
|
});
|
|
return null;
|
|
}
|
|
return name;
|
|
}
|
|
// REQUIRE
|
|
case enums_1.UnderscoreOptions.require: {
|
|
if (!hasSingleUnderscore()) {
|
|
context.report({
|
|
node,
|
|
messageId: 'missingUnderscore',
|
|
data: formatReportData({
|
|
originalName,
|
|
position,
|
|
count: 'one',
|
|
}),
|
|
});
|
|
return null;
|
|
}
|
|
return trimSingleUnderscore();
|
|
}
|
|
case enums_1.UnderscoreOptions.requireDouble: {
|
|
if (!hasDoubleUnderscore()) {
|
|
context.report({
|
|
node,
|
|
messageId: 'missingUnderscore',
|
|
data: formatReportData({
|
|
originalName,
|
|
position,
|
|
count: 'two',
|
|
}),
|
|
});
|
|
return null;
|
|
}
|
|
return trimDoubleUnderscore();
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @returns the name with the affix removed, if it is valid according to the specified affix option, null otherwise
|
|
*/
|
|
function validateAffix(position, config, name, node, originalName) {
|
|
const affixes = config[position];
|
|
if (!affixes || affixes.length === 0) {
|
|
return name;
|
|
}
|
|
for (const affix of affixes) {
|
|
const hasAffix = position === 'prefix' ? name.startsWith(affix) : name.endsWith(affix);
|
|
const trimAffix = position === 'prefix'
|
|
? () => name.slice(affix.length)
|
|
: () => name.slice(0, -affix.length);
|
|
if (hasAffix) {
|
|
// matches, so trim it and return
|
|
return trimAffix();
|
|
}
|
|
}
|
|
context.report({
|
|
node,
|
|
messageId: 'missingAffix',
|
|
data: formatReportData({
|
|
originalName,
|
|
position,
|
|
affixes,
|
|
}),
|
|
});
|
|
return null;
|
|
}
|
|
/**
|
|
* @returns true if the name is valid according to the `regex` option, false otherwise
|
|
*/
|
|
function validateCustom(config, name, node, originalName) {
|
|
const custom = config.custom;
|
|
if (!custom) {
|
|
return true;
|
|
}
|
|
const result = custom.regex.test(name);
|
|
if (custom.match && result) {
|
|
return true;
|
|
}
|
|
if (!custom.match && !result) {
|
|
return true;
|
|
}
|
|
context.report({
|
|
node,
|
|
messageId: 'satisfyCustom',
|
|
data: formatReportData({
|
|
originalName,
|
|
custom,
|
|
}),
|
|
});
|
|
return false;
|
|
}
|
|
/**
|
|
* @returns true if the name is valid according to the `format` option, false otherwise
|
|
*/
|
|
function validatePredefinedFormat(config, name, node, originalName, modifiers) {
|
|
const formats = config.format;
|
|
if (formats === null || formats.length === 0) {
|
|
return true;
|
|
}
|
|
if (!modifiers.has(enums_1.Modifiers.requiresQuotes)) {
|
|
for (const format of formats) {
|
|
const checker = format_1.PredefinedFormatToCheckFunction[format];
|
|
if (checker(name)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
context.report({
|
|
node,
|
|
messageId: originalName === name
|
|
? 'doesNotMatchFormat'
|
|
: 'doesNotMatchFormatTrimmed',
|
|
data: formatReportData({
|
|
originalName,
|
|
processedName: name,
|
|
formats,
|
|
}),
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
exports.createValidator = createValidator;
|
|
const SelectorsAllowedToHaveTypes = enums_1.Selectors.variable |
|
|
enums_1.Selectors.parameter |
|
|
enums_1.Selectors.classProperty |
|
|
enums_1.Selectors.objectLiteralProperty |
|
|
enums_1.Selectors.typeProperty |
|
|
enums_1.Selectors.parameterProperty |
|
|
enums_1.Selectors.accessor;
|
|
function isCorrectType(node, config, context, selector) {
|
|
if (config.types === null) {
|
|
return true;
|
|
}
|
|
if ((SelectorsAllowedToHaveTypes & selector) === 0) {
|
|
return true;
|
|
}
|
|
const { esTreeNodeToTSNodeMap, program } = util.getParserServices(context);
|
|
const checker = program.getTypeChecker();
|
|
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
const type = checker
|
|
.getTypeAtLocation(tsNode)
|
|
// remove null and undefined from the type, as we don't care about it here
|
|
.getNonNullableType();
|
|
for (const allowedType of config.types) {
|
|
switch (allowedType) {
|
|
case enums_1.TypeModifiers.array:
|
|
if (isAllTypesMatch(type, t => checker.isArrayType(t) || checker.isTupleType(t))) {
|
|
return true;
|
|
}
|
|
break;
|
|
case enums_1.TypeModifiers.function:
|
|
if (isAllTypesMatch(type, t => t.getCallSignatures().length > 0)) {
|
|
return true;
|
|
}
|
|
break;
|
|
case enums_1.TypeModifiers.boolean:
|
|
case enums_1.TypeModifiers.number:
|
|
case enums_1.TypeModifiers.string: {
|
|
const typeString = checker.typeToString(
|
|
// this will resolve things like true => boolean, 'a' => string and 1 => number
|
|
checker.getWidenedType(checker.getBaseTypeOfLiteralType(type)));
|
|
const allowedTypeString = enums_1.TypeModifiers[allowedType];
|
|
if (typeString === allowedTypeString) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* @returns `true` if the type (or all union types) in the given type return true for the callback
|
|
*/
|
|
function isAllTypesMatch(type, cb) {
|
|
if (type.isUnion()) {
|
|
return type.types.every(t => cb(t));
|
|
}
|
|
return cb(type);
|
|
}
|
|
//# sourceMappingURL=validator.js.map |