Skip to content

Commit 49c1492

Browse files
Setup repo
0 parents  commit 49c1492

File tree

16 files changed

+3849
-0
lines changed

16 files changed

+3849
-0
lines changed

‎.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.yarn/*
2+
node_modules
3+
cjs
4+
*.tsbuildinfo
5+
!.yarn/releases

‎.yarn/releases/yarn-3.5.0.cjs

Lines changed: 873 additions & 0 deletions
Large diffs are not rendered by default.

‎.yarnrc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
yarnPath: .yarn/releases/yarn-3.5.0.cjs
2+
3+
nodeLinker: node-modules

‎Readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# ESLint TypeScript custom rule
2+
This is an example of an ESLint custom rule written with TypeScript
3+
4+
## How to test it
5+
- Run `yarn` to install the dependencies
6+
- Run `yarn workspace eslint-plugin-custom-rule build` to build the custom plugin
7+
- Run `yarn workspace app lint` to see the errors from the custom rule

‎package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "eslint-typescript-custom-rule",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"workspaces": [
7+
"packages/*"
8+
],
9+
"packageManager": "yarn@3.5.0"
10+
}

‎packages/app/.eslintrc.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
env: {
3+
node: true,
4+
es6: true,
5+
},
6+
parser: '@typescript-eslint/parser',
7+
parserOptions: {
8+
extraFileExtensions: ['.ts, .tsx'],
9+
},
10+
parserOptions: {
11+
project: './tsconfig.json',
12+
tsconfigRootDir: __dirname,
13+
},
14+
plugins: ['custom-rule'],
15+
rules: {
16+
'custom-rule/my-rule': 'error'
17+
},
18+
};

‎packages/app/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "app",
3+
"version": "1.0.0",
4+
"main": "cjs/index.js",
5+
"module": "esm/index.js",
6+
"private": true,
7+
"devDependencies": {
8+
"@typescript-eslint/parser": "^5.57.0",
9+
"eslint": "^8.37.0",
10+
"eslint-plugin-custom-rule": "workspace:*",
11+
"typescript": "^5.0.3"
12+
},
13+
"scripts": {
14+
"lint": "eslint --ext .ts ./src"
15+
}
16+
}

‎packages/app/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const foo = () => {}
2+
3+
const bar = () => {}
4+
5+
const fooBar = () => {}
6+
7+
8+
foo()
9+
bar()
10+
fooBar()

‎packages/app/tsconfig.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"compilerOptions": {
3+
"sourceMap": true,
4+
"inlineSources": true,
5+
"strict": true,
6+
"noUnusedLocals": true,
7+
"noUnusedParameters": true,
8+
"noImplicitReturns": true,
9+
"noFallthroughCasesInSwitch": true,
10+
"moduleResolution": "node",
11+
"esModuleInterop": true,
12+
"forceConsistentCasingInFileNames": true,
13+
"resolveJsonModule": true,
14+
"lib": ["esnext"],
15+
"composite": true,
16+
"incremental": true,
17+
"declaration": true,
18+
"declarationMap": true,
19+
"rootDir": "src",
20+
"skipLibCheck": true,
21+
"outDir": "cjs",
22+
"module": "commonjs",
23+
"target": "es6",
24+
"exactOptionalPropertyTypes": true,
25+
"noUncheckedIndexedAccess": true
26+
},
27+
"include": ["src"]
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "eslint-plugin-custom-rule",
3+
"version": "1.0.0",
4+
"main": "cjs/index.js",
5+
"private": true,
6+
"dependencies": {
7+
"@typescript-eslint/utils": "^5.57.0"
8+
},
9+
"devDependencies": {
10+
"@typescript-eslint/parser": "^5.57.0",
11+
"eslint": "^8.37.0",
12+
"typescript": "^5.0.3",
13+
"vitest": "^0.29.8"
14+
},
15+
"scripts": {
16+
"build": "yarn tsc -b",
17+
"test": "vitest"
18+
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import myRule from './myRule';
2+
3+
export const rules = {
4+
'my-rule': myRule,
5+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ESLintUtils } from '@typescript-eslint/utils';
2+
3+
import myRule from './myRule';
4+
5+
const parserResolver = require.resolve('@typescript-eslint/parser');
6+
7+
const ruleTester = new ESLintUtils.RuleTester({
8+
parser: parserResolver as any, // yarn 2+ shenanigans
9+
});
10+
11+
ruleTester.run('my-rule', myRule, {
12+
valid: ['notFooBar()', 'const foo = 2', 'const bar = 2'],
13+
invalid: [
14+
{
15+
code: 'foo()',
16+
errors: [{ messageId: 'messageIdForSomeFailure' }],
17+
},
18+
{
19+
code: 'bar()',
20+
errors: [{ messageId: 'messageIdForSomeOtherFailure' }],
21+
},
22+
],
23+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { TSESLint, AST_NODE_TYPES } from '@typescript-eslint/utils';
2+
3+
type MessageIds = 'messageIdForSomeFailure' | 'messageIdForSomeOtherFailure';
4+
5+
const myRule: TSESLint.RuleModule<MessageIds> = {
6+
defaultOptions: [],
7+
meta: {
8+
type: 'suggestion',
9+
messages: {
10+
messageIdForSomeFailure: 'Error message for some failure',
11+
messageIdForSomeOtherFailure: 'Error message for some other failure',
12+
},
13+
fixable: 'code',
14+
schema: [], // no options
15+
},
16+
create: context => ({
17+
CallExpression: node => {
18+
if (node.callee.type !== AST_NODE_TYPES.Identifier) {
19+
return;
20+
}
21+
22+
if (node.callee.name === 'foo') {
23+
return context.report({
24+
node: node.callee,
25+
messageId: 'messageIdForSomeFailure',
26+
});
27+
}
28+
if (node.callee.name === 'bar') {
29+
return context.report({
30+
node: node.callee,
31+
messageId: 'messageIdForSomeOtherFailure',
32+
});
33+
}
34+
35+
return;
36+
},
37+
}),
38+
};
39+
40+
export default myRule;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"compilerOptions": {
3+
"sourceMap": true,
4+
"inlineSources": true,
5+
"strict": true,
6+
"noUnusedLocals": true,
7+
"noUnusedParameters": true,
8+
"noImplicitReturns": true,
9+
"noFallthroughCasesInSwitch": true,
10+
"moduleResolution": "node",
11+
"esModuleInterop": true,
12+
"forceConsistentCasingInFileNames": true,
13+
"resolveJsonModule": true,
14+
"lib": ["esnext"],
15+
"composite": true,
16+
"incremental": true,
17+
"declaration": true,
18+
"declarationMap": true,
19+
"rootDir": "src",
20+
"skipLibCheck": true,
21+
"outDir": "cjs",
22+
"module": "commonjs",
23+
"target": "es6",
24+
"exactOptionalPropertyTypes": true,
25+
"noUncheckedIndexedAccess": true
26+
},
27+
"include": ["src"]
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineConfig } from 'vitest/config';
2+
3+
export default defineConfig({
4+
test: {
5+
globals: true,
6+
exclude: ['**/cjs/**'],
7+
},
8+
});

0 commit comments

Comments
 (0)