diff --git a/packages/eslint-plugin-orbit-components/src/__fixtures__/file.ts b/packages/eslint-plugin-orbit-components/src/__fixtures__/file.ts new file mode 100644 index 0000000000..172f1ae6a4 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/__fixtures__/file.ts @@ -0,0 +1 @@ +// noop diff --git a/packages/eslint-plugin-orbit-components/src/__fixtures__/react.tsx b/packages/eslint-plugin-orbit-components/src/__fixtures__/react.tsx new file mode 100644 index 0000000000..172f1ae6a4 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/__fixtures__/react.tsx @@ -0,0 +1 @@ +// noop diff --git a/packages/eslint-plugin-orbit-components/src/__tests__/tsconfig.json b/packages/eslint-plugin-orbit-components/src/__tests__/tsconfig.json new file mode 100644 index 0000000000..74a5ce9368 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/__tests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "strict": true, + "module": "ESNext", + "noEmit": true, + "moduleResolution": "node" + }, + "include": ["*.test.ts", "../__fixtures__"] +} diff --git a/packages/eslint-plugin-orbit-components/src/__tests__/useClient.test.ts b/packages/eslint-plugin-orbit-components/src/__tests__/useClient.test.ts new file mode 100644 index 0000000000..8abbdfad36 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/__tests__/useClient.test.ts @@ -0,0 +1,31 @@ +import dedent from "dedent"; +import ruleTester from "../ruleTester"; +import useClient from "../rules/useClient"; + +describe("use-client-directive", () => { + ruleTester.run("use-client-directive", useClient, { + valid: [ + { + code: dedent` + "use client"; + import React from "react"; + import styled from 'styled-components'; + `, + }, + ], + invalid: [ + { + code: dedent` + import React from "react"; + import styled from 'styled-components'; + `, + errors: [{ messageId: "error" }], + output: dedent` + "use client"; + import React from "react"; + import styled from 'styled-components'; + `, + }, + ], + }); +}); diff --git a/packages/eslint-plugin-orbit-components/src/consts.ts b/packages/eslint-plugin-orbit-components/src/consts.ts new file mode 100644 index 0000000000..9fa5fe4a95 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/consts.ts @@ -0,0 +1,2 @@ +export const RULE_URL = + "https://github.com/kiwicom/orbit/tree/master/packages/eslint-plugin-orbit-components/docs/rules"; diff --git a/packages/eslint-plugin-orbit-components/src/rules/useClient.ts b/packages/eslint-plugin-orbit-components/src/rules/useClient.ts new file mode 100644 index 0000000000..4b14e099e8 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/rules/useClient.ts @@ -0,0 +1,41 @@ +import { AST_NODE_TYPES, TSESTree as t, TSESLint } from "@typescript-eslint/utils"; +import ruleCreator from "../utils/ruleCreator"; + +const useClient = ruleCreator({ + name: "use-client-directive", + meta: { + type: "problem", + fixable: "code", + docs: { + description: "Prevents missing 'use client' directive in Orbit components", + }, + messages: { + error: "Missing 'use client' directive in Orbit components", + }, + schema: [], + }, + defaultOptions: [], + + create: context => { + return { + Program(node: t.Program) { + if (node.sourceType !== "module") return; + if (node.body.length === 0) return; + + const noDirective = node.body.some(n => n.type === AST_NODE_TYPES.ExpressionStatement); + + if (!noDirective) { + context.report({ + node, + messageId: "error", + fix: fixer => { + return fixer.insertTextBefore(node.body[0], `"use client";\n`); + }, + }); + } + }, + }; + }, +}); + +export default useClient; diff --git a/packages/eslint-plugin-orbit-components/src/utils/ruleCreator.ts b/packages/eslint-plugin-orbit-components/src/utils/ruleCreator.ts new file mode 100644 index 0000000000..ba9c52e533 --- /dev/null +++ b/packages/eslint-plugin-orbit-components/src/utils/ruleCreator.ts @@ -0,0 +1,5 @@ +import { ESLintUtils } from "@typescript-eslint/utils"; + +import { RULE_URL } from "../consts"; + +export default ESLintUtils.RuleCreator(name => `${RULE_URL}/${name}`);