@angular-eslint/eslint-plugin
Version:
ESLint plugin for Angular applications, following https://angular.dev/style-guide
116 lines (115 loc) • 5.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RULE_NAME = void 0;
const utils_1 = require("@angular-eslint/utils");
const utils_2 = require("@typescript-eslint/utils");
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
exports.RULE_NAME = 'no-input-prefix';
exports.default = (0, create_eslint_rule_1.createESLintRule)({
name: exports.RULE_NAME,
meta: {
type: 'suggestion',
docs: {
description: 'Ensures that input bindings, including aliases, are not named or prefixed by the configured disallowed prefixes',
},
schema: [
{
type: 'object',
properties: {
prefixes: {
type: 'array',
items: {
type: 'string',
},
},
},
additionalProperties: false,
},
],
messages: {
noInputPrefix: 'Input bindings, including aliases, should not be named, nor prefixed by {{prefixes}}',
},
},
defaultOptions: [{ prefixes: [] }],
create(context, [{ prefixes }]) {
return {
[utils_1.Selectors.INPUT_PROPERTY_OR_SETTER](node) {
const rawPropertyName = utils_1.ASTUtils.getRawText(node);
// The child that matched was just a literal initializer of a property definition
if (node.parent?.type === utils_2.TSESTree.AST_NODE_TYPES.PropertyDefinition) {
const initializingValue = node.parent.value;
if (initializingValue?.type === utils_2.TSESTree.AST_NODE_TYPES.Literal &&
rawPropertyName === utils_1.ASTUtils.getRawText(initializingValue) &&
node.range[0] === initializingValue.range[0] &&
node.range[1] === initializingValue.range[1]) {
return;
}
}
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, rawPropertyName));
// Direct violation on the property name
if (hasDisallowedPrefix) {
context.report({
node,
messageId: 'noInputPrefix',
data: {
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
},
});
}
// Check if decorator alias has a violation
let aliasProperty;
if (!node.parent) {
return;
}
const inputDecorator = utils_1.ASTUtils.getDecorator(node.parent, 'Input');
if (inputDecorator &&
utils_1.ASTUtils.isCallExpression(inputDecorator.expression)) {
// Angular 16+ alias property syntax
aliasProperty = utils_1.ASTUtils.getDecoratorPropertyValue(inputDecorator, 'alias');
let aliasValue = '';
let aliasArg;
if (aliasProperty) {
aliasValue = utils_1.ASTUtils.getRawText(aliasProperty);
}
else if (inputDecorator.expression.arguments.length > 0 &&
(utils_1.ASTUtils.isLiteral(inputDecorator.expression.arguments[0]) ||
utils_1.ASTUtils.isTemplateLiteral(inputDecorator.expression.arguments[0]))) {
aliasArg = inputDecorator.expression.arguments[0];
aliasValue = utils_1.ASTUtils.getRawText(aliasArg);
}
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, aliasValue));
if (!hasDisallowedPrefix) {
return;
}
return context.report({
node: aliasProperty || aliasArg || node,
messageId: 'noInputPrefix',
data: {
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
},
});
}
},
[utils_1.Selectors.INPUTS_METADATA_PROPERTY_LITERAL](node) {
const [propertyName, aliasName] = utils_1.ASTUtils.getRawText(node)
.replace(/\s/g, '')
.split(':');
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, propertyName, aliasName));
if (!hasDisallowedPrefix) {
return;
}
context.report({
node,
messageId: 'noInputPrefix',
data: {
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
},
});
},
};
},
});
function isDisallowedPrefix(prefix, propertyName, aliasName = '') {
const prefixPattern = new RegExp(`^${prefix}(([^a-z])|(?=$))`);
return prefixPattern.test(propertyName) || prefixPattern.test(aliasName);
}