diff --git a/.oxlintrc.json b/.oxlintrc.json index facce6659..10163c3ff 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -29,6 +29,10 @@ "builtin": true }, "rules": { + "element-call/copyright-header": [ + "error", + "/*\nCopyright %%CURRENT_YEAR%% New Vector Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE in the repository root for full details.\n*/\n\n" + ], "element-call/no-observablescope-leak": "error", "jsdoc/empty-tags": "error", "jsdoc/check-property-names": "error", diff --git a/eslint/CopyrightHeader.js b/eslint/CopyrightHeader.js new file mode 100644 index 000000000..9ff60b8b4 --- /dev/null +++ b/eslint/CopyrightHeader.js @@ -0,0 +1,66 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { ESLintUtils } from "@typescript-eslint/utils"; + +const rule = ESLintUtils.RuleCreator( + () => "https://github.com/element-hq/element-call", +)({ + name: "copyright-header", + meta: { + type: "problem", + fixable: "code", + docs: { + description: "Require a copyright header in files.", + }, + messages: { + noHeader: "Copyright header is required.", + }, + schema: [{ type: "string" }], + }, + create(context) { + const code = context.getSourceCode(); + + return { + Program(node) { + const firstToken = code.getFirstToken(node, { includeComments: false }); + + if (!firstToken) { + return; + } + + const headComments = code.getCommentsBefore(firstToken); + const hasSomeCopyrightHeader = headComments?.some((comment) => + comment?.value?.includes("Copyright"), + ); + if (hasSomeCopyrightHeader) { + return; + } + const headerTemplate = context.options[0]; + const fix = headerTemplate + ? function (fixer) { + return fixer.insertTextBefore( + firstToken, + headerTemplate.replace( + /%%CURRENT_YEAR%%/g, + new Date().getFullYear(), + ), + ); + } + : undefined; + + context.report({ + messageId: "noHeader", + node, + fix, + }); + }, + }; + }, +}); + +export default rule; diff --git a/eslint/index.js b/eslint/index.js index 26bd7f3e8..ec050ad76 100644 --- a/eslint/index.js +++ b/eslint/index.js @@ -1,5 +1,6 @@ module.exports = { rules: { + "copyright-header": require("./CopyrightHeader").default, "no-observablescope-leak": require("./NoObservableScopeLeak").default, }, };