forked from hazza/dspace-angular

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
93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
/**
|
|
* 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);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|