ember-template-lint-plugin-denylist
Version:
`ember-template-lint` plugin for setting attribute denylists
119 lines • 4.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_CONFIG = void 0;
const ember_template_lint_1 = require("ember-template-lint");
const create_error_message_1 = require("ember-template-lint/lib/helpers/create-error-message");
const lodash_1 = require("lodash");
exports.DEFAULT_CONFIG = { attributes: [] };
/**
* Predicate for correctly configured attributes.
*
* @param attributes Configured attributes
* @returns Evaluation of valid attributes
* @private
*/
const isValidAttributes = (attributes) => Array.isArray(attributes) &&
attributes.every((attribute) => {
const attributeKeys = Object.keys(attribute).sort();
return (0, lodash_1.difference)(attributeKeys, ['name', 'values']).length === 0;
});
/**
* Extract stringified values from attribute.
*
* @param attribute AST attribute node
* @returns String of attribute values
*/
const getAttributeValues = (attribute) => {
var _a, _b;
switch (attribute.value.type) {
case 'MustacheStatement':
return '';
case 'ConcatStatement':
const parts = (_b = (_a = attribute === null || attribute === void 0 ? void 0 : attribute.value) === null || _a === void 0 ? void 0 : _a.parts) !== null && _b !== void 0 ? _b : [];
return parts
.filter((part) => part.type === 'TextNode')
.map((part) => part.chars)
.join(' ');
case 'TextNode':
return attribute.value.chars;
}
};
/**
* Predicate for whether a provided raw value is forbidden.
*
* @param attributeValues Attribute values
* @param rawValue Raw forbidden value
* @returns Evaluation of value acceptability
* @private
*/
const hasForbiddenAttribute = (attributeValues, rawValue) => {
if (rawValue.startsWith('^') && rawValue.endsWith('$')) {
const value = rawValue.slice(1, -1);
return attributeValues.split(' ').includes(value);
}
else if (rawValue.startsWith('^')) {
const value = rawValue.slice(1);
return attributeValues
.split(' ')
.some((attributeValue) => attributeValue.startsWith(value));
}
else if (rawValue.endsWith('$')) {
const value = rawValue.slice(0, -1);
return attributeValues
.split(' ')
.some((attributeValue) => attributeValue.endsWith(value));
}
else {
return attributeValues.includes(rawValue);
}
};
class DenylistRule extends ember_template_lint_1.Rule {
parseConfig(config) {
if (config === true) {
return exports.DEFAULT_CONFIG;
}
if (config && typeof config === 'object') {
return {
attributes: isValidAttributes(config.attributes)
? config.attributes
: [],
};
}
const errorMessage = (0, create_error_message_1.default)('denylist', [
'Please refer to https://github.com/shamrt/ember-template-lint-plugin-denylist/ for details',
], config);
throw new Error(errorMessage);
}
visitor() {
return {
ElementNode: (node) => {
for (const configAttribute of this.config.attributes) {
const { name: attributeName, values: forbiddenValue } = configAttribute;
const attribute = ember_template_lint_1.ASTHelpers.findAttribute(node, attributeName);
if (!attribute) {
continue;
}
const attributeValues = getAttributeValues(attribute);
const forbiddenValues = Array.isArray(forbiddenValue)
? forbiddenValue
: [forbiddenValue];
for (const value of forbiddenValues) {
if (hasForbiddenAttribute(attributeValues, value)) {
this.log({
message: `The value '${value}' is present in attribute '${attributeName}', but is forbidden`,
line: attribute.loc && attribute.loc.start.line,
column: attribute.loc && attribute.loc.start.column,
endLine: attribute.loc && attribute.loc.end.line,
endColumn: attribute.loc && attribute.loc.end.column,
source: this.sourceForNode(node),
isFixable: false,
});
}
}
}
},
};
}
}
exports.default = DenylistRule;
//# sourceMappingURL=denylist.js.map