110 строки
2.9 KiB
JavaScript
110 строки
2.9 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
module.exports = {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description: "Require error classes to extend 'Error'",
|
|
recommended: true,
|
|
},
|
|
messages: {
|
|
errorClass:
|
|
"'{{name}}' must extend an error class (like 'Error') because its name is in PascalCase and ends with 'Error'.",
|
|
errorSuperClass:
|
|
"'{{name}}' may not be the name of an error class. It should be in PascalCase and end with 'Error'.",
|
|
errorSuperClassMissingName:
|
|
"An error class should have a PascalCase name ending with 'Error'.",
|
|
errorFunction:
|
|
"'{{name}}' is a reserved name. PascalCase names ending with 'Error' are reserved for error classes and may not be used for regular functions. Either rename this function or convert it to a class that extends 'Error'.",
|
|
},
|
|
schema: [],
|
|
},
|
|
|
|
create(context) {
|
|
return {
|
|
ClassDeclaration(node) {
|
|
processClass(node);
|
|
},
|
|
ClassExpression(node) {
|
|
processClass(node);
|
|
},
|
|
FunctionExpression(node) {
|
|
processFunction(node);
|
|
},
|
|
FunctionDeclaration(node) {
|
|
processFunction(node);
|
|
},
|
|
};
|
|
|
|
function processClass(node) {
|
|
const {id, superClass} = node;
|
|
|
|
// First, handle all cases in which superclass is not error-like.
|
|
if (superClass == null || !isSuperClassErrorLike(superClass)) {
|
|
if (id == null || !isIdentifierErrorLike(id)) {
|
|
return;
|
|
}
|
|
context.report({
|
|
node: id,
|
|
messageId: 'errorClass',
|
|
data: {name: id.name},
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Then, handle all cases in which superclass is error-like.
|
|
if (id == null) {
|
|
context.report({
|
|
node,
|
|
messageId: 'errorSuperClassMissingName',
|
|
});
|
|
} else if (!isIdentifierErrorLike(id)) {
|
|
context.report({
|
|
node: id,
|
|
messageId: 'errorSuperClass',
|
|
data: {name: id.name},
|
|
});
|
|
}
|
|
}
|
|
|
|
function processFunction(node) {
|
|
const {id} = node;
|
|
if (id == null || !isIdentifierErrorLike(id)) {
|
|
return;
|
|
}
|
|
context.report({
|
|
node: id,
|
|
messageId: 'errorFunction',
|
|
data: {name: id.name},
|
|
});
|
|
}
|
|
},
|
|
};
|
|
|
|
function isSuperClassErrorLike(node) {
|
|
if (node.type === 'Identifier') {
|
|
return isNameErrorLike(node.name);
|
|
}
|
|
if (node.type === 'MemberExpression') {
|
|
return isSuperClassErrorLike(node.property);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function isIdentifierErrorLike(node) {
|
|
return node.type === 'Identifier' && isNameErrorLike(node.name);
|
|
}
|
|
|
|
function isNameErrorLike(name) {
|
|
return typeof name === 'string' && /^([A-Z].*)?Error$/.test(name);
|
|
}
|