@dvukovic/style-guide 0.10.3 → 0.11.0
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/dist/eslint/rules/document-todos/document-todos.d.ts +24 -0
- package/dist/eslint/rules/document-todos/document-todos.test.d.ts +1 -0
- package/package.json +1 -1
- package/src/eslint/plugins/dvukovic.js +3 -0
- package/src/eslint/plugins/rimac.js +0 -1
- package/src/eslint/rules/document-todos/document-todos.js +63 -0
- package/src/eslint/rules/document-todos/document-todos.test.js +174 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export namespace documentTodos {
|
|
2
|
+
function create(context: any): {
|
|
3
|
+
Program(): void;
|
|
4
|
+
};
|
|
5
|
+
namespace meta {
|
|
6
|
+
namespace docs {
|
|
7
|
+
let description: string;
|
|
8
|
+
}
|
|
9
|
+
namespace messages {
|
|
10
|
+
let _default: string;
|
|
11
|
+
export { _default as default };
|
|
12
|
+
}
|
|
13
|
+
let schema: {
|
|
14
|
+
additionalProperties: boolean;
|
|
15
|
+
properties: {
|
|
16
|
+
url: {
|
|
17
|
+
type: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
type: string;
|
|
21
|
+
}[];
|
|
22
|
+
let type: string;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { documentTodos } from "../rules/document-todos/document-todos.js"
|
|
1
2
|
import { noCommentedOutCode } from "../rules/no-commented-out-code/no-commented-out-code.js"
|
|
2
3
|
import { noT } from "../rules/no-t/no-t.js"
|
|
3
4
|
|
|
@@ -6,12 +7,14 @@ export const dvukovic = {
|
|
|
6
7
|
plugins: {
|
|
7
8
|
dvukovic: {
|
|
8
9
|
rules: {
|
|
10
|
+
"document-todos": documentTodos,
|
|
9
11
|
"no-commented-out-code": noCommentedOutCode,
|
|
10
12
|
"no-t": noT,
|
|
11
13
|
},
|
|
12
14
|
},
|
|
13
15
|
},
|
|
14
16
|
rules: {
|
|
17
|
+
"dvukovic/document-todos": ["error", { url: "http" }],
|
|
15
18
|
"dvukovic/no-commented-out-code": "error",
|
|
16
19
|
"dvukovic/no-t": "error",
|
|
17
20
|
},
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const documentTodos = {
|
|
2
|
+
create(context) {
|
|
3
|
+
const url = context.options[0]?.url
|
|
4
|
+
|
|
5
|
+
if (!url) {
|
|
6
|
+
throw new Error("URL not set for the document-todos rule. Please set the URL.")
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
Program() {
|
|
11
|
+
const sourceCode = context.sourceCode
|
|
12
|
+
const comments = sourceCode.getAllComments()
|
|
13
|
+
|
|
14
|
+
for (const comment of comments) {
|
|
15
|
+
const isTodo = comment.value.includes("TODO:")
|
|
16
|
+
const isFixme = comment.value.includes("FIXME:")
|
|
17
|
+
const hasLink = comment.value.includes(url.toLowerCase())
|
|
18
|
+
const startsWithTodo = comment.value
|
|
19
|
+
.trimStart()
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
.startsWith("todo")
|
|
22
|
+
const startsWithFixme = comment.value
|
|
23
|
+
.trimStart()
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.startsWith("fixme")
|
|
26
|
+
|
|
27
|
+
if ((isTodo || isFixme || startsWithFixme || startsWithTodo) && hasLink) {
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!isTodo && !isFixme && !startsWithFixme && !startsWithTodo) {
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
context.report({
|
|
36
|
+
loc: comment.loc,
|
|
37
|
+
messageId: "default",
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
meta: {
|
|
44
|
+
docs: {
|
|
45
|
+
description: "Ensure all TODOs and FIXMEs have an issue link attached to them",
|
|
46
|
+
},
|
|
47
|
+
messages: {
|
|
48
|
+
default: "All TODOs and FIXMEs must have an issue link attached to them",
|
|
49
|
+
},
|
|
50
|
+
schema: [
|
|
51
|
+
{
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
properties: {
|
|
54
|
+
url: {
|
|
55
|
+
type: "string",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
type: "object",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
type: "problem",
|
|
62
|
+
},
|
|
63
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { ESLint } from "eslint"
|
|
2
|
+
import tseslint from "typescript-eslint"
|
|
3
|
+
|
|
4
|
+
import { documentTodos } from "./document-todos.js"
|
|
5
|
+
|
|
6
|
+
const createEslint = (url = "http") => {
|
|
7
|
+
return new ESLint({
|
|
8
|
+
overrideConfig: [
|
|
9
|
+
{
|
|
10
|
+
files: ["**/*.ts"],
|
|
11
|
+
languageOptions: {
|
|
12
|
+
parser: tseslint.parser,
|
|
13
|
+
},
|
|
14
|
+
plugins: {
|
|
15
|
+
dvukovic: {
|
|
16
|
+
rules: {
|
|
17
|
+
"document-todos": documentTodos,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
"dvukovic/document-todos": ["error", { url }],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
overrideConfigFile: true,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("dvukovic/document-todos", () => {
|
|
31
|
+
test("reports TODO without URL", async () => {
|
|
32
|
+
const eslint = createEslint()
|
|
33
|
+
const code = `// TODO: fix this later\nconst y = 2\n`
|
|
34
|
+
|
|
35
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
36
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
37
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
expect(errors?.length).toBe(1)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test("reports FIXME without URL", async () => {
|
|
44
|
+
const eslint = createEslint()
|
|
45
|
+
const code = `// FIXME: broken feature\nconst y = 2\n`
|
|
46
|
+
|
|
47
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
48
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
49
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
expect(errors?.length).toBe(1)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("allows TODO with URL", async () => {
|
|
56
|
+
const eslint = createEslint()
|
|
57
|
+
const code = `// TODO: fix this later https://github.com/issue/1\nconst y = 2\n`
|
|
58
|
+
|
|
59
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
60
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
61
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
expect(errors?.length).toBe(0)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test("allows FIXME with URL", async () => {
|
|
68
|
+
const eslint = createEslint()
|
|
69
|
+
const code = `// FIXME: broken feature http://jira.com/123\nconst y = 2\n`
|
|
70
|
+
|
|
71
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
72
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
73
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
expect(errors?.length).toBe(0)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test("allows regular comments", async () => {
|
|
80
|
+
const eslint = createEslint()
|
|
81
|
+
const code = `// This is a regular comment\nconst y = 2\n`
|
|
82
|
+
|
|
83
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
84
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
85
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
expect(errors?.length).toBe(0)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test("reports lowercase todo without URL", async () => {
|
|
92
|
+
const eslint = createEslint()
|
|
93
|
+
const code = `// todo fix this later\nconst y = 2\n`
|
|
94
|
+
|
|
95
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
96
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
97
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
expect(errors?.length).toBe(1)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("reports lowercase fixme without URL", async () => {
|
|
104
|
+
const eslint = createEslint()
|
|
105
|
+
const code = `// fixme broken feature\nconst y = 2\n`
|
|
106
|
+
|
|
107
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
108
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
109
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
expect(errors?.length).toBe(1)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test("reports TODO in block comments without URL", async () => {
|
|
116
|
+
const eslint = createEslint()
|
|
117
|
+
const code = `/* TODO: fix this later */\nconst y = 2\n`
|
|
118
|
+
|
|
119
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
120
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
121
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
expect(errors?.length).toBe(1)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test("allows TODO in block comments with URL", async () => {
|
|
128
|
+
const eslint = createEslint()
|
|
129
|
+
const code = `/* TODO: fix this https://example.com/issue/1 */\nconst y = 2\n`
|
|
130
|
+
|
|
131
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
132
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
133
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
expect(errors?.length).toBe(0)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test("uses custom URL prefix", async () => {
|
|
140
|
+
const eslint = createEslint("https://jira.example.com")
|
|
141
|
+
const code = `// TODO: fix this https://jira.example.com/PROJ-123\nconst y = 2\n`
|
|
142
|
+
|
|
143
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
144
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
145
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
expect(errors?.length).toBe(0)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test("reports when URL does not match custom prefix", async () => {
|
|
152
|
+
const eslint = createEslint("https://jira.example.com")
|
|
153
|
+
const code = `// TODO: fix this https://github.com/issue/1\nconst y = 2\n`
|
|
154
|
+
|
|
155
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
156
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
157
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
expect(errors?.length).toBe(1)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test("reports multiple TODO comments without URLs", async () => {
|
|
164
|
+
const eslint = createEslint()
|
|
165
|
+
const code = `// TODO: first issue\n// TODO: second issue\nconst y = 2\n`
|
|
166
|
+
|
|
167
|
+
const results = await eslint.lintText(code, { filePath: "test.ts" })
|
|
168
|
+
const errors = results[0]?.messages.filter((message) => {
|
|
169
|
+
return message.ruleId === "dvukovic/document-todos"
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
expect(errors?.length).toBe(2)
|
|
173
|
+
})
|
|
174
|
+
})
|