From 0ee530c63df77fd9cf458d67571b18dd621d66a9 Mon Sep 17 00:00:00 2001 From: Jeremias Peier Date: Tue, 12 Dec 2023 16:12:18 +0100 Subject: [PATCH] build: add eslint rule for custom element class name --- .../eslint/custom-element-class-name-rule.ts | 61 +++++++++++++++++++ tools/eslint/index.ts | 3 + 2 files changed, 64 insertions(+) create mode 100644 tools/eslint/custom-element-class-name-rule.ts diff --git a/tools/eslint/custom-element-class-name-rule.ts b/tools/eslint/custom-element-class-name-rule.ts new file mode 100644 index 0000000000..a5ace4a6c4 --- /dev/null +++ b/tools/eslint/custom-element-class-name-rule.ts @@ -0,0 +1,61 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { ESLintUtils, TSESLint, TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils'; + +const createRule = ESLintUtils.RuleCreator( + (name) => + `https://github.com/lyne-design-system/lyne-components/blob/main/tools/eslint/${name}.ts`, +); + +type MessageIds = 'customElementClassName'; + +export const name = 'custom-element-class-name-rule'; +export const rule: TSESLint.RuleModule<'customElementClassName', never[]> = createRule< + never[], + MessageIds +>({ + create(context) { + return { + ['ClassDeclaration > Decorator[expression.callee.name="customElement"]']( + node: TSESTree.Decorator, + ) { + const isClassDeclaration = (node: TSESTree.Node): node is TSESTree.ClassDeclaration => { + return node.type === AST_NODE_TYPES.ClassDeclaration; + }; + + const getClassName = (node: TSESTree.Node): string | undefined => { + if (isClassDeclaration(node)) { + return node.id?.name; + } + if (node.parent) { + return getClassName(node.parent); + } + return undefined; + }; + + const classParent = node.parent as TSESTree.ClassDeclaration; + const className = getClassName(classParent); + + if (!className || !className.startsWith('Sbb') || !className.endsWith('Element')) { + context.report({ + node: classParent.id ? classParent.id : classParent, + messageId: 'customElementClassName', + }); + } + }, + }; + }, + name, + meta: { + docs: { + description: 'Components class name should start with `Sbb` and end with `Element`', + recommended: 'error', + }, + messages: { + customElementClassName: + 'Components class name should start with `Sbb` and end with `Element`', + }, + type: 'problem', + schema: [], + }, + defaultOptions: [], +}); diff --git a/tools/eslint/index.ts b/tools/eslint/index.ts index bde04c19b5..d8a54db92f 100644 --- a/tools/eslint/index.ts +++ b/tools/eslint/index.ts @@ -1,14 +1,17 @@ +import * as customElementClassName from './custom-element-class-name-rule'; import * as missingComponentDocumentation from './missing-component-documentation-rule'; export default { rules: { [missingComponentDocumentation.name]: missingComponentDocumentation.rule, + [customElementClassName.name]: customElementClassName.rule, }, configs: { all: { plugins: ['lyne'], rules: { [`lyne/${missingComponentDocumentation.name}`]: 'error', + [`lyne/${customElementClassName.name}`]: 'error', }, }, },