mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-09 19:13:08 +00:00
Custom ESLint rules to enforce new ThemedComponent selector convention
The following cases are covered: - ThemedComponent wrapper selectors must not start with ds-themed- - Base component selectors must start with ds-base- - Themed component selectors must start with ds-themed- - The ThemedComponent wrapper must always be used in HTML - The ThemedComponent wrapper must be used in TypeScript _where appropriate_: - Required - Explicit usages (e.g. modal instantiation, routing modules, ...) - By.css selector queries (in order to align with the HTML rule) - Unchecked - Non-routing modules (to ensure the components can be declared) - ViewChild hooks (since they need to attach to the underlying component) All rules work with --fix to automatically migrate to the new convention This covers most of the codebase, but minor manual adjustment are needed afterwards
This commit is contained in:
92
lint/src/rules/ts/themed-component-selectors.ts
Normal file
92
lint/src/rules/ts/themed-component-selectors.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
import { getComponentSelectorNode } from '../../util/angular';
|
||||
import { stringLiteral } from '../../util/misc';
|
||||
import {
|
||||
inThemedComponentOverrideFile,
|
||||
isThemeableComponent,
|
||||
isThemedComponentWrapper,
|
||||
} from '../../util/theme-support';
|
||||
|
||||
export default ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
schema: [],
|
||||
fixable: 'code',
|
||||
messages: {
|
||||
wrongSelectorUnthemedComponent: 'Unthemed version of themeable components should have a selector starting with \'ds-base-\'',
|
||||
wrongSelectorThemedComponentWrapper: 'Themed component wrapper of themeable components shouldn\'t have a selector starting with \'ds-themed-\'',
|
||||
wrongSelectorThemedComponentOverride: 'Theme override of themeable component should have a selector starting with \'ds-themed-\'',
|
||||
}
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context: any): any {
|
||||
if (context.getFilename()?.endsWith('.spec.ts')) {
|
||||
return {};
|
||||
}
|
||||
|
||||
function enforceWrapperSelector(selectorNode: any) {
|
||||
if (selectorNode?.value.startsWith('ds-themed-')) {
|
||||
context.report({
|
||||
messageId: 'wrongSelectorThemedComponentWrapper',
|
||||
node: selectorNode,
|
||||
fix(fixer: any) {
|
||||
return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-themed-', 'ds-')));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function enforceBaseSelector(selectorNode: any) {
|
||||
if (!selectorNode?.value.startsWith('ds-base-')) {
|
||||
context.report({
|
||||
messageId: 'wrongSelectorUnthemedComponent',
|
||||
node: selectorNode,
|
||||
fix(fixer: any) {
|
||||
return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-', 'ds-base-')));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function enforceThemedSelector(selectorNode: any) {
|
||||
if (!selectorNode?.value.startsWith('ds-themed-')) {
|
||||
context.report({
|
||||
messageId: 'wrongSelectorThemedComponentOverride',
|
||||
node: selectorNode,
|
||||
fix(fixer: any) {
|
||||
return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-', 'ds-themed-')));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
'ClassDeclaration > Decorator[expression.callee.name = "Component"]'(node: any) {
|
||||
// keep track of all @Component nodes by their selector
|
||||
const selectorNode = getComponentSelectorNode(node);
|
||||
const selector = selectorNode?.value;
|
||||
const classNode = node.parent;
|
||||
const className = classNode.id?.name;
|
||||
|
||||
if (selector === undefined || className === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isThemedComponentWrapper(node)) {
|
||||
enforceWrapperSelector(selectorNode);
|
||||
} else if (inThemedComponentOverrideFile(context)) {
|
||||
enforceThemedSelector(selectorNode);
|
||||
} else if (isThemeableComponent(className)) {
|
||||
enforceBaseSelector(selectorNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user