@ornikar/eslint-plugin-ornikar 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "root": true,
3
+ "extends": ["@ornikar/eslint-config/node"]
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "eslint.workingDirectories": ["../../"]
3
+ }
package/configs/all.js ADDED
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ rules: {
5
+ '@ornikar/ornikar/forbid-fetch-import': 'error',
6
+ '@ornikar/ornikar/react-function-return-react-node': 'error',
7
+ },
8
+ };
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "preserve",
4
+ "target": "es5",
5
+ "module": "commonjs",
6
+ "strict": true
7
+ },
8
+ "include": ["**/*.ts", "**/*.tsx"]
9
+ }
package/index.js ADDED
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const allRulesEnabledConfig = require('./configs/all');
4
+ const loadRules = require('./loadRules');
5
+
6
+ const recommendedConfig = allRulesEnabledConfig;
7
+
8
+ module.exports = {
9
+ rules: {
10
+ ...loadRules(),
11
+ },
12
+ configs: {
13
+ recommended: recommendedConfig,
14
+ all: allRulesEnabledConfig,
15
+ },
16
+ };
package/loadRules.js ADDED
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ function loadRule(ruleId) {
7
+ // eslint-disable-next-line import/no-dynamic-require, global-require, security/detect-non-literal-require
8
+ const rule = require(path.resolve(__dirname, `./rules/${ruleId}`));
9
+
10
+ return {
11
+ meta: {
12
+ schema: [],
13
+ ...rule.meta,
14
+ docs: {
15
+ ...rule.meta.docs,
16
+ // url: getDocumentationUrl(ruleId),
17
+ },
18
+ },
19
+ create: rule.create,
20
+ };
21
+ }
22
+
23
+ module.exports = function loadRules() {
24
+ return Object.fromEntries(
25
+ fs
26
+ .readdirSync(path.resolve(__dirname, './rules'), { withFileTypes: true })
27
+ .filter((file) => file.isFile() && !file.name.endsWith('.test.js'))
28
+ .map((file) => {
29
+ const ruleId = path.basename(file.name, '.js');
30
+ return [ruleId, loadRule(ruleId)];
31
+ }),
32
+ );
33
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ornikar/eslint-plugin-ornikar",
3
+ "version": "0.0.1",
4
+ "description": "eslint plugin for ornikar",
5
+ "repository": {
6
+ "directory": "@ornikar/eslint-plugin-ornikar",
7
+ "type": "git",
8
+ "url": "https://github.com/ornikar/eslint-configs.git"
9
+ },
10
+ "main": "index.js",
11
+ "license": "ISC",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "ornikar": {
16
+ "entries": [],
17
+ "extraEntries": [
18
+ "."
19
+ ]
20
+ },
21
+ "peerDependencies": {
22
+ "eslint": "^8.39.0"
23
+ },
24
+ "scripts": {
25
+ "lint:eslint": "yarn ../.. eslint --report-unused-disable-directives --quiet @ornikar/eslint-plugin-ornikar"
26
+ },
27
+ "exports": {
28
+ "./package.json": "./package.json",
29
+ ".": "./index.js"
30
+ },
31
+ "dependencies": {
32
+ "eslint-plugin-react": "^7.33.2"
33
+ },
34
+ "devDependencies": {
35
+ "@typescript-eslint/rule-tester": "6.7.0",
36
+ "@typescript-eslint/utils": "6.7.0"
37
+ }
38
+ }
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ exports.meta = {
4
+ type: 'problem',
5
+
6
+ docs: {
7
+ description: 'Forbid node-fetch import now that fetch is available in node and browsers',
8
+ category: 'Best Practices',
9
+ recommended: true,
10
+ },
11
+
12
+ messages: {
13
+ forbidden: 'import from "{{value}}" is forbidden. Fetch is available in browsers and node since 18.0.0.',
14
+ },
15
+ };
16
+
17
+ const fetchLibs = ['node-fetch', 'cross-fetch', 'isomorphic-fetch'];
18
+
19
+ exports.create = (context) => {
20
+ const checkNode = (node) => {
21
+ const importSource = node.source.value.trim();
22
+
23
+ if (fetchLibs.includes(importSource)) {
24
+ context.report({
25
+ node,
26
+ messageId: 'forbidden',
27
+ data: { value: importSource },
28
+ });
29
+ }
30
+ };
31
+ return {
32
+ ImportDeclaration: checkNode,
33
+ ExportNamedDeclaration(node) {
34
+ if (node.source) {
35
+ checkNode(node);
36
+ }
37
+ },
38
+ ExportAllDeclaration: checkNode,
39
+ };
40
+ };
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ const { RuleTester } = require('eslint');
4
+ const rule = require('./forbid-fetch-import');
5
+
6
+ const parserOptions = {
7
+ ecmaVersion: 2018,
8
+ sourceType: 'module',
9
+ };
10
+
11
+ const ruleTester = new RuleTester({ parserOptions });
12
+
13
+ ruleTester.run('forbid-fetch-import', rule, {
14
+ valid: [
15
+ {
16
+ code: `
17
+ fetch('https://example.com');
18
+ `,
19
+ },
20
+ ],
21
+ invalid: [
22
+ {
23
+ code: `
24
+ import fetch from 'node-fetch';
25
+ fetch('https://example.com');
26
+ `,
27
+ errors: [
28
+ {
29
+ messageId: 'forbidden',
30
+ data: { value: 'node-fetch' },
31
+ },
32
+ ],
33
+ },
34
+ ],
35
+ });
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ const { AST_NODE_TYPES } = require('@typescript-eslint/utils');
4
+ const Components = require('eslint-plugin-react/lib/util/Components');
5
+
6
+ exports.meta = {
7
+ type: 'problem',
8
+
9
+ docs: {
10
+ description: 'Forbid returning ReactElement or ReactElement | null in function components',
11
+ category: 'Best Practices',
12
+ recommended: true,
13
+ },
14
+
15
+ messages: {
16
+ invalidReturnType: 'Returning "{{value}}" is forbidden. Return "ReactNode" instead.',
17
+ replaceReturnType: 'Replace "{{value}}" by "ReactNode"',
18
+ },
19
+
20
+ hasSuggestions: true,
21
+ };
22
+
23
+ function getSuggestionFixer(node, range, context) {
24
+ return (fixer) => {
25
+ return fixer.replaceTextRange(range, 'ReactNode');
26
+ };
27
+ }
28
+
29
+ function checkFunctionReturnType(node, onError) {
30
+ const { returnType } = node;
31
+ if (returnType == null) return;
32
+
33
+ const { typeAnnotation } = returnType;
34
+ if (typeAnnotation == null) return;
35
+
36
+ const { typeName } = typeAnnotation;
37
+ if (typeName == null) return;
38
+
39
+ if (typeName.name !== 'ReactNode') {
40
+ onError(typeName.name, typeName.range);
41
+ }
42
+ }
43
+
44
+ exports.create = Components.detect((context, components) => {
45
+ return {
46
+ FunctionDeclaration(node) {
47
+ if (!components.get(node)) return;
48
+
49
+ checkFunctionReturnType(node, (currentName, range) =>
50
+ context.report({
51
+ node,
52
+ loc: range,
53
+ messageId: 'invalidReturnType',
54
+ data: { value: currentName },
55
+ suggest: [
56
+ {
57
+ messageId: 'replaceReturnType',
58
+ data: { value: currentName },
59
+ fix: getSuggestionFixer(node, range, context),
60
+ },
61
+ ],
62
+ }),
63
+ );
64
+ },
65
+ };
66
+ });
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const rule = require('./react-function-return-react-node');
5
+ const { RuleTester } = require('./utils/RuleTester');
6
+
7
+ const ruleTester = new RuleTester({
8
+ parser: require.resolve('@typescript-eslint/parser'),
9
+ parserOptions: {
10
+ tsconfigRootDir: path.join(__dirname, '../fixtures'),
11
+ project: './tsconfig.json',
12
+ ecmaFeatures: {
13
+ jsx: true,
14
+ },
15
+ },
16
+ });
17
+
18
+ ruleTester.run('react-function-return-react-node', rule, {
19
+ valid: [
20
+ {
21
+ code: `
22
+ import type { ReactNode } from 'react';
23
+ export function SomeComponent(): ReactNode {
24
+ return <div />;
25
+ }
26
+ `,
27
+ },
28
+ ],
29
+ invalid: [
30
+ {
31
+ code: `
32
+ import type { ReactElement } from 'react';
33
+ export function SomeComponent(): ReactElement {
34
+ return <div />;
35
+ }`,
36
+ errors: [
37
+ {
38
+ messageId: 'invalidReturnType',
39
+ data: { value: 'ReactElement' },
40
+ suggestions: [
41
+ {
42
+ messageId: 'replaceReturnType',
43
+ data: { value: 'ReactElement' },
44
+ output: `
45
+ import type { ReactElement } from 'react';
46
+ export function SomeComponent(): ReactNode {
47
+ return <div />;
48
+ }`,
49
+ },
50
+ ],
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ });
@@ -0,0 +1,9 @@
1
+ const { after, describe, it } = require('node:test');
2
+ const { RuleTester } = require('@typescript-eslint/rule-tester');
3
+
4
+ RuleTester.afterAll = after;
5
+ RuleTester.describe = describe;
6
+ RuleTester.it = it;
7
+ RuleTester.itOnly = it.only;
8
+
9
+ exports.RuleTester = RuleTester;