UNPKG

eslint-plugin-obsidianmd

Version:

Validates guidelines for Obsidian plugins

97 lines (96 loc) 3.58 kB
import { ESLintUtils } from "@typescript-eslint/utils"; const ruleCreator = ESLintUtils.RuleCreator((name) => `https://github.com/obsidianmd/eslint-plugin/blob/master/docs/rules/${name}.md`); // We want to catch patterns like: // // const styleSheet = document.createElement('link'); // styleSheet.rel = 'stylesheet'; // styleSheet.href = this.app.vault.adapter.getResourcePath(`${this.manifest.dir}/styles.css`); // document.head.appendChild(styleSheet); // // or // // const style = document.createElement('style'); // style.textContent = `Some CSS here`; // document.head.appendChild(style); /** * Mapping from element tag name to expected type. */ const FORBIDDEN_ELEMENT_TYPES = ["link", "style"]; function isForbiddenCreateElementCall(node) { // we are looking for document.createElement(...) if (!(node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier" && node.callee.property.name === "createElement" && node.callee.object.type === "Identifier" && node.callee.object.name === "document")) { return undefined; } if (node.arguments.length === 0) { return undefined; } return isArgumentForbiddenElement(node.arguments[0]); } function isForbiddenCreateElCall(node) { // we are looking for foo.createEl(...) if (!(node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier" && node.callee.property.name === "createEl" && (node.callee.object.type === "Identifier" || node.callee.object.type === "MemberExpression"))) { return undefined; } if (node.arguments.length === 0) { return undefined; } return isArgumentForbiddenElement(node.arguments[0]); } function isArgumentForbiddenElement(arg) { if (arg.type === "Literal" && typeof arg.value === "string") { const tagName = arg.value.toLowerCase(); for (const forbiddenTagName of FORBIDDEN_ELEMENT_TYPES) { if (tagName === forbiddenTagName) { return tagName; } } } return undefined; } export default ruleCreator({ name: "no-forbidden-elements", meta: { type: "problem", docs: { description: "Disallow attachment of forbidden elements to the DOM in Obsidian plugins.", }, schema: [], messages: { doNotAttachForbiddenElements: "Creating and attaching \"{{element}}\" elements is not allowed.", doNotAttachForbiddenStyleElements: "Creating and attaching \"{{element}}\" elements is not allowed. For loading CSS, use a \"styles.css\" file instead, which Obsidian loads for you.", }, }, defaultOptions: [], create(context) { return { CallExpression(node) { const element = isForbiddenCreateElementCall(node) ?? isForbiddenCreateElCall(node); if (element === "style" || element === "link") { context.report({ node, messageId: "doNotAttachForbiddenStyleElements", data: { element, } }); } else if (element) { context.report({ node, messageId: "doNotAttachForbiddenElements", data: { element, } }); } }, }; }, });