eslint-plugin-comment-rules 0.1.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/README.md +117 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +678 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# eslint-plugin-comment-rules
|
|
2
|
+
|
|
3
|
+
Express a comment policy as ESLint configuration. One rule, `comment-rules/no-restricted-comments`, filters every comment kind (line, block, JSDoc, shebang) by kind, position, content, AST selector, and more, with fixers that delete or rewrite.
|
|
4
|
+
|
|
5
|
+
For JSDoc *content* (tags, types, descriptions), use [`eslint-plugin-jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc) as a companion. This package owns whether a comment may exist and where.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -D eslint-plugin-comment-rules
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires ESLint 9 or 10 and Node `^18.18.0 || ^20.9.0 || >=21.1.0`. Flat config only.
|
|
14
|
+
|
|
15
|
+
## Configure
|
|
16
|
+
|
|
17
|
+
### Named policy
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// eslint.config.js
|
|
21
|
+
import commentRules from "eslint-plugin-comment-rules";
|
|
22
|
+
|
|
23
|
+
export default [
|
|
24
|
+
{
|
|
25
|
+
plugins: {
|
|
26
|
+
"comment-rules": commentRules,
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
"comment-rules/no-restricted-comments": ["error", "docs"],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or use a shipped flat config:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import commentRules from "eslint-plugin-comment-rules";
|
|
39
|
+
|
|
40
|
+
export default [
|
|
41
|
+
commentRules.configs.docs,
|
|
42
|
+
];
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Policies: `none` (ban everything), `safe` (shebang + ESLint inline config), `docs` (`safe` plus `FIX`/`TODO`, machine directives, and multiline JSDoc in doc position).
|
|
46
|
+
|
|
47
|
+
### Custom entries
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
"comment-rules/no-restricted-comments": ["error", [
|
|
51
|
+
{ action: "delete" },
|
|
52
|
+
{ shebang: true, action: "allow" },
|
|
53
|
+
{ terms: ["TODO"], location: "start", action: "allow" },
|
|
54
|
+
]]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Last matching entry wins. Criteria within an entry conjoin.
|
|
58
|
+
|
|
59
|
+
### CommonJS projects
|
|
60
|
+
|
|
61
|
+
On Node below the `require(esm)` range, name the config `eslint.config.mjs` so ESLint loads it as ESM and can default-import this package.
|
|
62
|
+
|
|
63
|
+
### Mixed severity
|
|
64
|
+
|
|
65
|
+
Register the plugin under two keys:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
plugins: {
|
|
69
|
+
comments: commentRules,
|
|
70
|
+
"comments-warn": commentRules,
|
|
71
|
+
},
|
|
72
|
+
rules: {
|
|
73
|
+
"comments/no-restricted-comments": ["error", [/* hard bans */]],
|
|
74
|
+
"comments-warn/no-restricted-comments": ["warn", [/* soft ones */]],
|
|
75
|
+
},
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Capabilities
|
|
79
|
+
|
|
80
|
+
| Capability | Key / form | Covered by tests |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| Line comments | `line: true` | yes |
|
|
83
|
+
| Block comments | `block: true` | yes |
|
|
84
|
+
| JSDoc blocks | `jsdoc: true` | yes |
|
|
85
|
+
| Shebang | `shebang: true` | yes |
|
|
86
|
+
| Single / multi line | `lines: "single" \| "multi"` | yes |
|
|
87
|
+
| Position facts | `position: "above" \| "beside" \| "file-start" \| "dangling"` (or array, all required) | yes |
|
|
88
|
+
| Terms | `terms`, `location`, `decoration` (same model as `no-warning-comments`) | yes |
|
|
89
|
+
| Markers | `markers` (match after the opener) | yes |
|
|
90
|
+
| Pattern | `pattern` (regex source) | yes |
|
|
91
|
+
| AST selector | `selector` (esquery on the leading node) | yes |
|
|
92
|
+
| Inline config | `inlineConfig: true` | yes |
|
|
93
|
+
| Commented-out code | `code: true` | yes |
|
|
94
|
+
| Custom message | `message` | yes |
|
|
95
|
+
| Allow | `action: "allow"` | yes |
|
|
96
|
+
| Report | `action: "report"` | yes |
|
|
97
|
+
| Delete (fix) | `action: "delete"` | yes |
|
|
98
|
+
| Replace (fix) | `action: "replace"`, `replacement` with `$1` | yes |
|
|
99
|
+
| Policy `none` | option `"none"` | yes |
|
|
100
|
+
| Policy `safe` | option `"safe"` | yes |
|
|
101
|
+
| Policy `docs` | option `"docs"` | yes |
|
|
102
|
+
| Schema: missing option | throws | yes |
|
|
103
|
+
| Schema: unknown policy | throws | yes |
|
|
104
|
+
| Schema: unknown key | throws | yes |
|
|
105
|
+
| `require()` / default `import` interop | package entry | yes (integration) |
|
|
106
|
+
|
|
107
|
+
## Policies in detail
|
|
108
|
+
|
|
109
|
+
| Policy | Permits |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| `none` | nothing |
|
|
112
|
+
| `safe` | shebang; ESLint inline config (`eslint-disable*`, `globals`, `exported`, …) |
|
|
113
|
+
| `docs` | `safe`, plus `FIX`/`TODO` at start, markers (`@ts-expect-error`, `prettier-ignore`, `istanbul ignore`, …), and multiline JSDoc leading a module/class/interface/type/namespace/enum member |
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
ISC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as eslint from 'eslint';
|
|
2
|
+
import { Linter } from 'eslint';
|
|
3
|
+
|
|
4
|
+
declare const plugin: {
|
|
5
|
+
meta: {
|
|
6
|
+
name: string;
|
|
7
|
+
version: string;
|
|
8
|
+
};
|
|
9
|
+
rules: {
|
|
10
|
+
"no-restricted-comments": eslint.Rule.RuleModule;
|
|
11
|
+
};
|
|
12
|
+
configs: Record<string, Linter.Config>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { plugin as "module.exports", plugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
// src/anchor.ts
|
|
2
|
+
function ancestryOf(node) {
|
|
3
|
+
const ancestry = [];
|
|
4
|
+
let current = node.parent;
|
|
5
|
+
while (current !== void 0) {
|
|
6
|
+
ancestry.push(current);
|
|
7
|
+
current = current.parent ?? void 0;
|
|
8
|
+
}
|
|
9
|
+
return ancestry;
|
|
10
|
+
}
|
|
11
|
+
function resolveAnchor(sourceCode, facts) {
|
|
12
|
+
if (!facts.startsLine) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const token = sourceCode.getTokenAfter(facts.comment, { includeComments: false });
|
|
16
|
+
if (token === null) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const found = sourceCode.getNodeByRangeIndex(token.range[0]);
|
|
20
|
+
if (found === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
let node = found;
|
|
24
|
+
if (node.range?.[0] !== token.range[0]) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
let parent = node.parent;
|
|
28
|
+
while (parent !== void 0 && parent.type !== "Program" && parent.range?.[0] === node.range?.[0]) {
|
|
29
|
+
node = parent;
|
|
30
|
+
parent = node.parent;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
node,
|
|
34
|
+
ancestry: ancestryOf(node)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/code.ts
|
|
39
|
+
var structuralTypes = /* @__PURE__ */ new Set([
|
|
40
|
+
"FunctionDeclaration",
|
|
41
|
+
"VariableDeclaration",
|
|
42
|
+
"ClassDeclaration",
|
|
43
|
+
"ImportDeclaration",
|
|
44
|
+
"ExportNamedDeclaration",
|
|
45
|
+
"ExportDefaultDeclaration",
|
|
46
|
+
"ExportAllDeclaration",
|
|
47
|
+
"AssignmentExpression",
|
|
48
|
+
"CallExpression",
|
|
49
|
+
"NewExpression",
|
|
50
|
+
"MemberExpression",
|
|
51
|
+
"OptionalMemberExpression",
|
|
52
|
+
"IfStatement",
|
|
53
|
+
"ForStatement",
|
|
54
|
+
"ForInStatement",
|
|
55
|
+
"ForOfStatement",
|
|
56
|
+
"WhileStatement",
|
|
57
|
+
"DoWhileStatement",
|
|
58
|
+
"SwitchStatement",
|
|
59
|
+
"TryStatement",
|
|
60
|
+
"ThrowStatement",
|
|
61
|
+
"ReturnStatement",
|
|
62
|
+
"BreakStatement",
|
|
63
|
+
"ContinueStatement",
|
|
64
|
+
"WithStatement",
|
|
65
|
+
"DebuggerStatement",
|
|
66
|
+
"TSTypeAliasDeclaration",
|
|
67
|
+
"TSInterfaceDeclaration",
|
|
68
|
+
"TSEnumDeclaration",
|
|
69
|
+
"TSModuleDeclaration",
|
|
70
|
+
"TSImportEqualsDeclaration",
|
|
71
|
+
"TSExportAssignment"
|
|
72
|
+
]);
|
|
73
|
+
function isNode(value) {
|
|
74
|
+
return value !== null && typeof value === "object" && "type" in value && typeof value.type === "string";
|
|
75
|
+
}
|
|
76
|
+
function hasStructuralNode(node) {
|
|
77
|
+
if (structuralTypes.has(node.type)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
for (const value of Object.values(node)) {
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
for (const item of value) {
|
|
83
|
+
if (isNode(item) && hasStructuralNode(item)) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (isNode(value) && hasStructuralNode(value)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
function unwrapParser(parser) {
|
|
96
|
+
for (const symbol of Object.getOwnPropertySymbols(parser)) {
|
|
97
|
+
if (!String(symbol).includes("RuleTester.parser")) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const underlying = parser[symbol];
|
|
101
|
+
if (underlying !== void 0) {
|
|
102
|
+
return underlying;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return parser;
|
|
106
|
+
}
|
|
107
|
+
function parseFragment(parser, source, parserOptions) {
|
|
108
|
+
const active = unwrapParser(parser);
|
|
109
|
+
if ("parseForESLint" in active && typeof active.parseForESLint === "function") {
|
|
110
|
+
const result = active.parseForESLint(source, parserOptions);
|
|
111
|
+
return result.ast;
|
|
112
|
+
}
|
|
113
|
+
if ("parse" in active && typeof active.parse === "function") {
|
|
114
|
+
return active.parse(source, parserOptions);
|
|
115
|
+
}
|
|
116
|
+
throw new Error("parser exposes neither parseForESLint nor parse");
|
|
117
|
+
}
|
|
118
|
+
function groupComments(facts) {
|
|
119
|
+
const groups = [];
|
|
120
|
+
let current = [];
|
|
121
|
+
const flush = () => {
|
|
122
|
+
if (current.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
groups.push({
|
|
126
|
+
members: current,
|
|
127
|
+
source: current.map((member) => member.comment.value).join("\n")
|
|
128
|
+
});
|
|
129
|
+
current = [];
|
|
130
|
+
};
|
|
131
|
+
for (const fact of facts) {
|
|
132
|
+
if (!fact.startsLine) {
|
|
133
|
+
flush();
|
|
134
|
+
groups.push({
|
|
135
|
+
members: [fact],
|
|
136
|
+
source: fact.comment.value
|
|
137
|
+
});
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const previous = current[current.length - 1];
|
|
141
|
+
if (previous === void 0) {
|
|
142
|
+
current = [fact];
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const previousEnd = previous.comment.loc?.end.line;
|
|
146
|
+
const factStart = fact.comment.loc?.start.line;
|
|
147
|
+
const blankLineBetween = previousEnd !== void 0 && factStart !== void 0 && factStart - previousEnd > 1;
|
|
148
|
+
const sameKind = fact.kind === previous.kind;
|
|
149
|
+
if (sameKind && !blankLineBetween) {
|
|
150
|
+
current.push(fact);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
flush();
|
|
154
|
+
current = [fact];
|
|
155
|
+
}
|
|
156
|
+
flush();
|
|
157
|
+
return groups;
|
|
158
|
+
}
|
|
159
|
+
function containsCode(group, parser, parserOptions) {
|
|
160
|
+
try {
|
|
161
|
+
const program = parseFragment(parser, group.source, parserOptions);
|
|
162
|
+
return hasStructuralNode(program);
|
|
163
|
+
} catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/comment.ts
|
|
169
|
+
var closingTokens = /* @__PURE__ */ new Set([")", "]", "}"]);
|
|
170
|
+
function kindOf(comment) {
|
|
171
|
+
if (comment.type === "Shebang") {
|
|
172
|
+
return "shebang";
|
|
173
|
+
}
|
|
174
|
+
if (comment.type === "Line") {
|
|
175
|
+
return "line";
|
|
176
|
+
}
|
|
177
|
+
if (comment.value.startsWith("*")) {
|
|
178
|
+
return "jsdoc";
|
|
179
|
+
}
|
|
180
|
+
return "block";
|
|
181
|
+
}
|
|
182
|
+
function describeComment(sourceCode, comment) {
|
|
183
|
+
const start = comment.loc?.start;
|
|
184
|
+
const end = comment.loc?.end;
|
|
185
|
+
if (start === void 0 || end === void 0) {
|
|
186
|
+
throw new Error("comment is missing location information");
|
|
187
|
+
}
|
|
188
|
+
const startLineText = sourceCode.lines[start.line - 1] ?? "";
|
|
189
|
+
const endLineText = sourceCode.lines[end.line - 1] ?? "";
|
|
190
|
+
const before = startLineText.slice(0, start.column);
|
|
191
|
+
const after = endLineText.slice(end.column);
|
|
192
|
+
const startsLine = /^\s*$/.test(before);
|
|
193
|
+
const ownsLine = startsLine && /^\s*$/.test(after);
|
|
194
|
+
const lines = start.line === end.line ? "single" : "multi";
|
|
195
|
+
const position = /* @__PURE__ */ new Set();
|
|
196
|
+
if (startsLine) {
|
|
197
|
+
position.add("above");
|
|
198
|
+
} else {
|
|
199
|
+
position.add("beside");
|
|
200
|
+
}
|
|
201
|
+
const firstToken = sourceCode.getFirstToken(sourceCode.ast, { includeComments: false });
|
|
202
|
+
const commentEnd = comment.range?.[1];
|
|
203
|
+
if (firstToken === null || commentEnd === void 0 || commentEnd <= firstToken.range[0]) {
|
|
204
|
+
position.add("file-start");
|
|
205
|
+
}
|
|
206
|
+
const nextToken = sourceCode.getTokenAfter(comment, { includeComments: false });
|
|
207
|
+
if (nextToken === null || closingTokens.has(nextToken.value)) {
|
|
208
|
+
position.add("dangling");
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
comment,
|
|
212
|
+
kind: kindOf(comment),
|
|
213
|
+
lines,
|
|
214
|
+
position,
|
|
215
|
+
startsLine,
|
|
216
|
+
ownsLine
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/criteria.ts
|
|
221
|
+
import esquery from "esquery";
|
|
222
|
+
function escapeRegExp(value) {
|
|
223
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
224
|
+
}
|
|
225
|
+
function termToRegExp(term, location, decoration) {
|
|
226
|
+
const escaped = escapeRegExp(term);
|
|
227
|
+
const wordBoundary = "\\b";
|
|
228
|
+
if (location === "start") {
|
|
229
|
+
const decorationClass = decoration.map(escapeRegExp).join("");
|
|
230
|
+
const prefix2 = `^[\\s${decorationClass}]*`;
|
|
231
|
+
const suffix2 = /\w$/u.test(term) ? wordBoundary : "";
|
|
232
|
+
return new RegExp(`${prefix2}${escaped}${suffix2}`, "iu");
|
|
233
|
+
}
|
|
234
|
+
const prefix = /^\w/u.test(term) ? wordBoundary : "";
|
|
235
|
+
const suffix = /\w$/u.test(term) ? wordBoundary : "";
|
|
236
|
+
return new RegExp(`${prefix}${escaped}${suffix}`, "iu");
|
|
237
|
+
}
|
|
238
|
+
function markerRegExp(markers) {
|
|
239
|
+
const body = markers.map((marker) => escapeRegExp(marker)).join("|");
|
|
240
|
+
return new RegExp(`^\\s*(?:${body})`, "u");
|
|
241
|
+
}
|
|
242
|
+
function compileKinds(entry) {
|
|
243
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
244
|
+
if (entry.line === true) {
|
|
245
|
+
kinds.add("line");
|
|
246
|
+
}
|
|
247
|
+
if (entry.shebang === true) {
|
|
248
|
+
kinds.add("shebang");
|
|
249
|
+
}
|
|
250
|
+
if (entry.jsdoc === true) {
|
|
251
|
+
kinds.add("jsdoc");
|
|
252
|
+
} else if (entry.block === true) {
|
|
253
|
+
kinds.add("block");
|
|
254
|
+
kinds.add("jsdoc");
|
|
255
|
+
}
|
|
256
|
+
return kinds.size === 0 ? null : kinds;
|
|
257
|
+
}
|
|
258
|
+
function compileEntries(entries) {
|
|
259
|
+
return entries.map((entry) => {
|
|
260
|
+
const location = entry.location ?? "start";
|
|
261
|
+
const decoration = entry.decoration ?? [];
|
|
262
|
+
const termPatterns = entry.terms === void 0 ? null : entry.terms.map((term) => termToRegExp(term, location, decoration));
|
|
263
|
+
const positions = entry.position === void 0 ? null : Array.isArray(entry.position) ? entry.position : [entry.position];
|
|
264
|
+
return {
|
|
265
|
+
kinds: compileKinds(entry),
|
|
266
|
+
lines: entry.lines ?? null,
|
|
267
|
+
positions,
|
|
268
|
+
termPatterns,
|
|
269
|
+
markerPattern: entry.markers === void 0 ? null : markerRegExp(entry.markers),
|
|
270
|
+
pattern: entry.pattern === void 0 ? null : new RegExp(entry.pattern, "u"),
|
|
271
|
+
selector: entry.selector === void 0 ? null : esquery.parse(entry.selector),
|
|
272
|
+
inlineConfig: entry.inlineConfig,
|
|
273
|
+
code: entry.code,
|
|
274
|
+
action: entry.action,
|
|
275
|
+
message: entry.message,
|
|
276
|
+
replacement: entry.replacement
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function matchesEntry(compiled, facts, matchContext) {
|
|
281
|
+
if (compiled.kinds !== null && !compiled.kinds.has(facts.kind)) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
if (compiled.lines !== null && facts.lines !== compiled.lines) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
if (compiled.positions !== null) {
|
|
288
|
+
const hit = compiled.positions.every((position) => facts.position.has(position));
|
|
289
|
+
if (!hit) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (compiled.termPatterns !== null) {
|
|
294
|
+
const value = facts.comment.value;
|
|
295
|
+
const hit = compiled.termPatterns.some((pattern) => pattern.test(value));
|
|
296
|
+
if (!hit) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (compiled.markerPattern !== null && !compiled.markerPattern.test(facts.comment.value)) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
if (compiled.pattern !== null && !compiled.pattern.test(facts.comment.value)) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
if (compiled.inlineConfig !== void 0) {
|
|
307
|
+
if (matchContext.isInlineConfig(facts.comment) !== compiled.inlineConfig) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (compiled.selector !== null) {
|
|
312
|
+
const anchor = matchContext.getAnchor(facts);
|
|
313
|
+
if (anchor === null || !esquery.matches(anchor.node, compiled.selector, anchor.ancestry)) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (compiled.code !== void 0) {
|
|
318
|
+
if (matchContext.isCode(facts) !== compiled.code) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
function decide(compiled, facts, matchContext) {
|
|
325
|
+
for (let index = compiled.length - 1; index >= 0; index -= 1) {
|
|
326
|
+
const entry = compiled[index];
|
|
327
|
+
if (entry !== void 0 && matchesEntry(entry, facts, matchContext)) {
|
|
328
|
+
return entry;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/policies.ts
|
|
335
|
+
var docSelector = "Program > *, ClassBody > *, TSInterfaceBody > *, TSTypeLiteral > *, TSModuleBlock > *, TSEnumBody > *";
|
|
336
|
+
var docsMarkers = [
|
|
337
|
+
"@ts-expect-error",
|
|
338
|
+
"@ts-ignore",
|
|
339
|
+
"@ts-nocheck",
|
|
340
|
+
"prettier-ignore",
|
|
341
|
+
"istanbul ignore",
|
|
342
|
+
"v8 ignore",
|
|
343
|
+
"c8 ignore",
|
|
344
|
+
"#__PURE__",
|
|
345
|
+
"webpackChunkName",
|
|
346
|
+
"@vite-ignore"
|
|
347
|
+
];
|
|
348
|
+
var none = [{ action: "delete" }];
|
|
349
|
+
var safe = [
|
|
350
|
+
{ action: "delete" },
|
|
351
|
+
{ shebang: true, action: "allow" },
|
|
352
|
+
{ inlineConfig: true, action: "allow" }
|
|
353
|
+
];
|
|
354
|
+
var docs = [
|
|
355
|
+
{ action: "delete" },
|
|
356
|
+
{ shebang: true, action: "allow" },
|
|
357
|
+
{ inlineConfig: true, action: "allow" },
|
|
358
|
+
{ terms: ["FIX", "TODO"], location: "start", action: "allow" },
|
|
359
|
+
{ markers: [...docsMarkers], action: "allow" },
|
|
360
|
+
{
|
|
361
|
+
jsdoc: true,
|
|
362
|
+
lines: "multi",
|
|
363
|
+
selector: docSelector,
|
|
364
|
+
action: "allow"
|
|
365
|
+
}
|
|
366
|
+
];
|
|
367
|
+
var policies = {
|
|
368
|
+
none,
|
|
369
|
+
safe,
|
|
370
|
+
docs
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// src/rule.ts
|
|
374
|
+
var positionEnum = ["above", "beside", "file-start", "dangling"];
|
|
375
|
+
var policyNames = ["none", "safe", "docs"];
|
|
376
|
+
var actionEnum = ["allow", "report", "delete", "replace"];
|
|
377
|
+
var entrySchema = {
|
|
378
|
+
type: "object",
|
|
379
|
+
properties: {
|
|
380
|
+
line: { type: "boolean" },
|
|
381
|
+
block: { type: "boolean" },
|
|
382
|
+
jsdoc: { type: "boolean" },
|
|
383
|
+
shebang: { type: "boolean" },
|
|
384
|
+
lines: { enum: ["single", "multi"] },
|
|
385
|
+
position: {
|
|
386
|
+
oneOf: [
|
|
387
|
+
{ enum: [...positionEnum] },
|
|
388
|
+
{
|
|
389
|
+
type: "array",
|
|
390
|
+
items: { enum: [...positionEnum] },
|
|
391
|
+
minItems: 1,
|
|
392
|
+
uniqueItems: true
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
},
|
|
396
|
+
terms: {
|
|
397
|
+
type: "array",
|
|
398
|
+
items: { type: "string" },
|
|
399
|
+
minItems: 1
|
|
400
|
+
},
|
|
401
|
+
location: { enum: ["start", "anywhere"] },
|
|
402
|
+
decoration: {
|
|
403
|
+
type: "array",
|
|
404
|
+
items: { type: "string", pattern: "^\\S$" },
|
|
405
|
+
minItems: 1
|
|
406
|
+
},
|
|
407
|
+
markers: {
|
|
408
|
+
type: "array",
|
|
409
|
+
items: { type: "string" },
|
|
410
|
+
minItems: 1
|
|
411
|
+
},
|
|
412
|
+
pattern: { type: "string" },
|
|
413
|
+
selector: { type: "string" },
|
|
414
|
+
inlineConfig: { type: "boolean" },
|
|
415
|
+
code: { type: "boolean" },
|
|
416
|
+
message: { type: "string" },
|
|
417
|
+
action: { enum: [...actionEnum] },
|
|
418
|
+
replacement: { type: "string" }
|
|
419
|
+
},
|
|
420
|
+
required: ["action"],
|
|
421
|
+
additionalProperties: false
|
|
422
|
+
};
|
|
423
|
+
function resolveEntries(option) {
|
|
424
|
+
if (typeof option === "string") {
|
|
425
|
+
return policies[option];
|
|
426
|
+
}
|
|
427
|
+
return option;
|
|
428
|
+
}
|
|
429
|
+
function contentRange(comment) {
|
|
430
|
+
const range = comment.range;
|
|
431
|
+
if (range === void 0) {
|
|
432
|
+
throw new Error("comment is missing range information");
|
|
433
|
+
}
|
|
434
|
+
if (comment.type === "Shebang" || comment.type === "Line") {
|
|
435
|
+
return [range[0] + 2, range[1]];
|
|
436
|
+
}
|
|
437
|
+
return [range[0] + 2, range[1] - 2];
|
|
438
|
+
}
|
|
439
|
+
function deleteRange(sourceText, facts) {
|
|
440
|
+
const range = facts.comment.range;
|
|
441
|
+
if (range === void 0) {
|
|
442
|
+
throw new Error("comment is missing range information");
|
|
443
|
+
}
|
|
444
|
+
let start = range[0];
|
|
445
|
+
while (start > 0) {
|
|
446
|
+
const previous = sourceText[start - 1];
|
|
447
|
+
if (previous !== " " && previous !== " ") {
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
start -= 1;
|
|
451
|
+
}
|
|
452
|
+
let end = range[1];
|
|
453
|
+
if (facts.ownsLine) {
|
|
454
|
+
if (sourceText[end] === "\r" && sourceText[end + 1] === "\n") {
|
|
455
|
+
end += 2;
|
|
456
|
+
} else if (sourceText[end] === "\n" || sourceText[end] === "\r") {
|
|
457
|
+
end += 1;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return [start, end];
|
|
461
|
+
}
|
|
462
|
+
function replacedContents(facts, compiled) {
|
|
463
|
+
if (compiled.replacement === void 0) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
if (compiled.pattern === null) {
|
|
467
|
+
return compiled.replacement;
|
|
468
|
+
}
|
|
469
|
+
return facts.comment.value.replace(compiled.pattern, compiled.replacement);
|
|
470
|
+
}
|
|
471
|
+
function reportLoc(comment) {
|
|
472
|
+
return comment.loc ?? { start: { line: 1, column: 0 }, end: { line: 1, column: 0 } };
|
|
473
|
+
}
|
|
474
|
+
var rule = {
|
|
475
|
+
meta: {
|
|
476
|
+
type: "suggestion",
|
|
477
|
+
docs: {
|
|
478
|
+
description: "Disallow comments that match a configured restriction policy"
|
|
479
|
+
},
|
|
480
|
+
fixable: "code",
|
|
481
|
+
schema: {
|
|
482
|
+
type: "array",
|
|
483
|
+
minItems: 1,
|
|
484
|
+
maxItems: 1,
|
|
485
|
+
items: [
|
|
486
|
+
{
|
|
487
|
+
oneOf: [
|
|
488
|
+
{ enum: [...policyNames] },
|
|
489
|
+
{
|
|
490
|
+
type: "array",
|
|
491
|
+
items: entrySchema,
|
|
492
|
+
minItems: 1
|
|
493
|
+
}
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
},
|
|
498
|
+
messages: {
|
|
499
|
+
restricted: "{{message}}"
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
create(context) {
|
|
503
|
+
const option = context.options[0];
|
|
504
|
+
if (option === void 0) {
|
|
505
|
+
throw new Error("comment-rules/no-restricted-comments requires a policy name or entry array");
|
|
506
|
+
}
|
|
507
|
+
const compiled = compileEntries(resolveEntries(option));
|
|
508
|
+
const needsCode = compiled.some((entry) => entry.code !== void 0);
|
|
509
|
+
const parser = context.languageOptions.parser;
|
|
510
|
+
const parserOptions = {
|
|
511
|
+
...context.languageOptions.parserOptions,
|
|
512
|
+
ecmaVersion: context.languageOptions.ecmaVersion ?? "latest",
|
|
513
|
+
sourceType: context.languageOptions.sourceType ?? "module"
|
|
514
|
+
};
|
|
515
|
+
const listeners = {};
|
|
516
|
+
listeners["Program:exit"] = () => {
|
|
517
|
+
const sourceCode = context.sourceCode;
|
|
518
|
+
const comments = sourceCode.getAllComments();
|
|
519
|
+
const allFacts = comments.map((comment) => describeComment(sourceCode, comment));
|
|
520
|
+
const groups = needsCode ? groupComments(allFacts) : [];
|
|
521
|
+
const groupByComment = /* @__PURE__ */ new Map();
|
|
522
|
+
for (const group of groups) {
|
|
523
|
+
for (const member of group.members) {
|
|
524
|
+
groupByComment.set(member.comment, group);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
let inlineConfigSet;
|
|
528
|
+
const anchorCache = /* @__PURE__ */ new Map();
|
|
529
|
+
const codeCache = /* @__PURE__ */ new Map();
|
|
530
|
+
const sourceCodeWithInline = sourceCode;
|
|
531
|
+
const matchContext = {
|
|
532
|
+
getAnchor(facts) {
|
|
533
|
+
if (anchorCache.has(facts.comment)) {
|
|
534
|
+
return anchorCache.get(facts.comment) ?? null;
|
|
535
|
+
}
|
|
536
|
+
const anchor = resolveAnchor(sourceCode, facts);
|
|
537
|
+
anchorCache.set(facts.comment, anchor);
|
|
538
|
+
return anchor;
|
|
539
|
+
},
|
|
540
|
+
isInlineConfig(comment) {
|
|
541
|
+
if (inlineConfigSet === void 0) {
|
|
542
|
+
const nodes = typeof sourceCodeWithInline.getInlineConfigNodes === "function" ? sourceCodeWithInline.getInlineConfigNodes() : [];
|
|
543
|
+
inlineConfigSet = new Set(nodes);
|
|
544
|
+
}
|
|
545
|
+
return inlineConfigSet.has(comment);
|
|
546
|
+
},
|
|
547
|
+
isCode(facts) {
|
|
548
|
+
const group = groupByComment.get(facts.comment);
|
|
549
|
+
if (group === void 0) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
const cached = codeCache.get(group);
|
|
553
|
+
if (cached !== void 0) {
|
|
554
|
+
return cached;
|
|
555
|
+
}
|
|
556
|
+
if (parser === void 0) {
|
|
557
|
+
codeCache.set(group, false);
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
const result = containsCode(group, parser, parserOptions);
|
|
561
|
+
codeCache.set(group, result);
|
|
562
|
+
return result;
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
const sourceText = sourceCode.text;
|
|
566
|
+
const outcomes = [];
|
|
567
|
+
for (const facts of allFacts) {
|
|
568
|
+
const match = decide(compiled, facts, matchContext);
|
|
569
|
+
if (match === null || match.action === "allow") {
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
outcomes.push({
|
|
573
|
+
facts,
|
|
574
|
+
match,
|
|
575
|
+
deleteRange: match.action === "delete" ? deleteRange(sourceText, facts) : null
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
const deleteFixRange = /* @__PURE__ */ new Map();
|
|
579
|
+
let runStart = 0;
|
|
580
|
+
while (runStart < outcomes.length) {
|
|
581
|
+
const current = outcomes[runStart];
|
|
582
|
+
if (current?.deleteRange === null || !current?.facts.ownsLine) {
|
|
583
|
+
if (current?.deleteRange !== null && current !== void 0) {
|
|
584
|
+
deleteFixRange.set(current.facts.comment, current.deleteRange);
|
|
585
|
+
}
|
|
586
|
+
runStart += 1;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
let runEnd = runStart;
|
|
590
|
+
let range = current.deleteRange;
|
|
591
|
+
while (runEnd + 1 < outcomes.length) {
|
|
592
|
+
const next = outcomes[runEnd + 1];
|
|
593
|
+
if (next?.deleteRange === null || next === void 0 || !next.facts.ownsLine || next.deleteRange[0] !== range[1]) {
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
range = [range[0], next.deleteRange[1]];
|
|
597
|
+
runEnd += 1;
|
|
598
|
+
}
|
|
599
|
+
deleteFixRange.set(current.facts.comment, range);
|
|
600
|
+
runStart = runEnd + 1;
|
|
601
|
+
}
|
|
602
|
+
for (const outcome of outcomes) {
|
|
603
|
+
const message = outcome.match.message ?? "This comment is restricted by the comment policy.";
|
|
604
|
+
const loc = reportLoc(outcome.facts.comment);
|
|
605
|
+
if (outcome.match.action === "report") {
|
|
606
|
+
context.report({
|
|
607
|
+
loc,
|
|
608
|
+
messageId: "restricted",
|
|
609
|
+
data: { message }
|
|
610
|
+
});
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (outcome.match.action === "delete") {
|
|
614
|
+
const range2 = deleteFixRange.get(outcome.facts.comment);
|
|
615
|
+
context.report({
|
|
616
|
+
loc,
|
|
617
|
+
messageId: "restricted",
|
|
618
|
+
data: { message },
|
|
619
|
+
fix: range2 === void 0 ? void 0 : (fixer) => fixer.removeRange(range2)
|
|
620
|
+
});
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
const next = replacedContents(outcome.facts, outcome.match);
|
|
624
|
+
if (next === null) {
|
|
625
|
+
context.report({
|
|
626
|
+
loc,
|
|
627
|
+
messageId: "restricted",
|
|
628
|
+
data: { message }
|
|
629
|
+
});
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const range = contentRange(outcome.facts.comment);
|
|
633
|
+
context.report({
|
|
634
|
+
loc,
|
|
635
|
+
messageId: "restricted",
|
|
636
|
+
data: { message },
|
|
637
|
+
fix(fixer) {
|
|
638
|
+
return fixer.replaceTextRange(range, next);
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
return listeners;
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
var rule_default = rule;
|
|
647
|
+
|
|
648
|
+
// src/index.ts
|
|
649
|
+
var plugin = {
|
|
650
|
+
meta: {
|
|
651
|
+
name: "eslint-plugin-comment-rules",
|
|
652
|
+
version: "0.1.0"
|
|
653
|
+
},
|
|
654
|
+
rules: {
|
|
655
|
+
"no-restricted-comments": rule_default
|
|
656
|
+
},
|
|
657
|
+
configs: {}
|
|
658
|
+
};
|
|
659
|
+
function policyConfig(name) {
|
|
660
|
+
return {
|
|
661
|
+
name: `comment-rules/${name}`,
|
|
662
|
+
plugins: {
|
|
663
|
+
"comment-rules": plugin
|
|
664
|
+
},
|
|
665
|
+
rules: {
|
|
666
|
+
"comment-rules/no-restricted-comments": ["error", name]
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
plugin.configs.none = policyConfig("none");
|
|
671
|
+
plugin.configs.safe = policyConfig("safe");
|
|
672
|
+
plugin.configs.docs = policyConfig("docs");
|
|
673
|
+
var index_default = plugin;
|
|
674
|
+
export {
|
|
675
|
+
index_default as default,
|
|
676
|
+
plugin as "module.exports"
|
|
677
|
+
};
|
|
678
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/anchor.ts","../src/code.ts","../src/comment.ts","../src/criteria.ts","../src/policies.ts","../src/rule.ts","../src/index.ts"],"sourcesContent":["import type { CommentFacts } from \"./comment\";\nimport type { SourceCode } from \"eslint\";\nimport type { Node } from \"estree\";\n\nexport interface Anchor {\n\tnode: Node;\n\tancestry: Array<Node>;\n}\n\ntype NodeWithParent = Node & {\n\tparent?: NodeWithParent;\n\trange?: [number, number];\n};\n\nfunction ancestryOf(node: NodeWithParent): Array<Node> {\n\tconst ancestry: Array<Node> = [];\n\tlet current: NodeWithParent | null | undefined = node.parent;\n\n\twhile (current !== undefined) {\n\t\tancestry.push(current);\n\t\tcurrent = current.parent ?? undefined;\n\t}\n\n\treturn ancestry;\n}\n\nexport function resolveAnchor(sourceCode: SourceCode, facts: CommentFacts): Anchor | null {\n\tif (!facts.startsLine) {\n\t\treturn null;\n\t}\n\n\tconst token = sourceCode.getTokenAfter(facts.comment, { includeComments: false });\n\n\tif (token === null) {\n\t\treturn null;\n\t}\n\n\tconst found = sourceCode.getNodeByRangeIndex(token.range[0]);\n\n\tif (found === null) {\n\t\treturn null;\n\t}\n\n\tlet node = found as NodeWithParent;\n\n\tif (node.range?.[0] !== token.range[0]) {\n\t\treturn null;\n\t}\n\n\tlet parent = node.parent;\n\n\twhile (parent !== undefined && parent.type !== \"Program\" && parent.range?.[0] === node.range?.[0]) {\n\t\tnode = parent;\n\t\tparent = node.parent;\n\t}\n\n\treturn {\n\t\tnode,\n\t\tancestry: ancestryOf(node),\n\t};\n}\n","import type { CommentFacts } from \"./comment\";\nimport type { Linter } from \"eslint\";\nimport type { Node } from \"estree\";\n\nexport interface CommentGroup {\n\tmembers: ReadonlyArray<CommentFacts>;\n\tsource: string;\n}\n\nconst structuralTypes = new Set([\n\t\"FunctionDeclaration\",\n\t\"VariableDeclaration\",\n\t\"ClassDeclaration\",\n\t\"ImportDeclaration\",\n\t\"ExportNamedDeclaration\",\n\t\"ExportDefaultDeclaration\",\n\t\"ExportAllDeclaration\",\n\t\"AssignmentExpression\",\n\t\"CallExpression\",\n\t\"NewExpression\",\n\t\"MemberExpression\",\n\t\"OptionalMemberExpression\",\n\t\"IfStatement\",\n\t\"ForStatement\",\n\t\"ForInStatement\",\n\t\"ForOfStatement\",\n\t\"WhileStatement\",\n\t\"DoWhileStatement\",\n\t\"SwitchStatement\",\n\t\"TryStatement\",\n\t\"ThrowStatement\",\n\t\"ReturnStatement\",\n\t\"BreakStatement\",\n\t\"ContinueStatement\",\n\t\"WithStatement\",\n\t\"DebuggerStatement\",\n\t\"TSTypeAliasDeclaration\",\n\t\"TSInterfaceDeclaration\",\n\t\"TSEnumDeclaration\",\n\t\"TSModuleDeclaration\",\n\t\"TSImportEqualsDeclaration\",\n\t\"TSExportAssignment\",\n]);\n\nfunction isNode(value: unknown): value is Node {\n\treturn value !== null && typeof value === \"object\" && \"type\" in value && typeof value.type === \"string\";\n}\n\nfunction hasStructuralNode(node: Node): boolean {\n\tif (structuralTypes.has(node.type)) {\n\t\treturn true;\n\t}\n\n\tfor (const value of Object.values(node)) {\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const item of value) {\n\t\t\t\tif (isNode(item) && hasStructuralNode(item)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isNode(value) && hasStructuralNode(value)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nfunction unwrapParser(parser: Linter.Parser): Linter.Parser {\n\tfor (const symbol of Object.getOwnPropertySymbols(parser)) {\n\t\tif (!String(symbol).includes(\"RuleTester.parser\")) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst underlying = (parser as unknown as Record<symbol, Linter.Parser | undefined>)[symbol];\n\n\t\tif (underlying !== undefined) {\n\t\t\treturn underlying;\n\t\t}\n\t}\n\n\treturn parser;\n}\n\nfunction parseFragment(parser: Linter.Parser, source: string, parserOptions: Linter.ParserOptions): Node {\n\tconst active = unwrapParser(parser);\n\n\tif (\"parseForESLint\" in active && typeof active.parseForESLint === \"function\") {\n\t\tconst result = active.parseForESLint(source, parserOptions) as { ast: Node };\n\n\t\treturn result.ast;\n\t}\n\n\tif (\"parse\" in active && typeof active.parse === \"function\") {\n\t\treturn active.parse(source, parserOptions) as Node;\n\t}\n\n\tthrow new Error(\"parser exposes neither parseForESLint nor parse\");\n}\n\nexport function groupComments(facts: ReadonlyArray<CommentFacts>): ReadonlyArray<CommentGroup> {\n\tconst groups: Array<CommentGroup> = [];\n\tlet current: Array<CommentFacts> = [];\n\n\tconst flush = (): void => {\n\t\tif (current.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tgroups.push({\n\t\t\tmembers: current,\n\t\t\tsource: current.map((member) => member.comment.value).join(\"\\n\"),\n\t\t});\n\t\tcurrent = [];\n\t};\n\n\tfor (const fact of facts) {\n\t\tif (!fact.startsLine) {\n\t\t\tflush();\n\t\t\tgroups.push({\n\t\t\t\tmembers: [fact],\n\t\t\t\tsource: fact.comment.value,\n\t\t\t});\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst previous = current[current.length - 1];\n\n\t\tif (previous === undefined) {\n\t\t\tcurrent = [fact];\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst previousEnd = previous.comment.loc?.end.line;\n\t\tconst factStart = fact.comment.loc?.start.line;\n\t\tconst blankLineBetween = previousEnd !== undefined && factStart !== undefined && factStart - previousEnd > 1;\n\t\tconst sameKind = fact.kind === previous.kind;\n\n\t\tif (sameKind && !blankLineBetween) {\n\t\t\tcurrent.push(fact);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tflush();\n\t\tcurrent = [fact];\n\t}\n\n\tflush();\n\n\treturn groups;\n}\n\nexport function containsCode(group: CommentGroup, parser: Linter.Parser, parserOptions: Linter.ParserOptions): boolean {\n\ttry {\n\t\tconst program = parseFragment(parser, group.source, parserOptions);\n\n\t\treturn hasStructuralNode(program);\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import type { SourceCode } from \"eslint\";\nimport type { Comment } from \"estree\";\n\nexport interface CommentFacts {\n\tcomment: Comment;\n\tkind: \"line\" | \"block\" | \"jsdoc\" | \"shebang\";\n\tlines: \"single\" | \"multi\";\n\tposition: ReadonlySet<\"above\" | \"beside\" | \"file-start\" | \"dangling\">;\n\tstartsLine: boolean;\n\townsLine: boolean;\n}\n\nconst closingTokens = new Set([\")\", \"]\", \"}\"]);\n\nfunction kindOf(comment: Comment): CommentFacts[\"kind\"] {\n\tif ((comment.type as string) === \"Shebang\") {\n\t\treturn \"shebang\";\n\t}\n\n\tif (comment.type === \"Line\") {\n\t\treturn \"line\";\n\t}\n\n\tif (comment.value.startsWith(\"*\")) {\n\t\treturn \"jsdoc\";\n\t}\n\n\treturn \"block\";\n}\n\nexport function describeComment(sourceCode: SourceCode, comment: Comment): CommentFacts {\n\tconst start = comment.loc?.start;\n\tconst end = comment.loc?.end;\n\n\tif (start === undefined || end === undefined) {\n\t\tthrow new Error(\"comment is missing location information\");\n\t}\n\n\tconst startLineText = sourceCode.lines[start.line - 1] ?? \"\";\n\tconst endLineText = sourceCode.lines[end.line - 1] ?? \"\";\n\tconst before = startLineText.slice(0, start.column);\n\tconst after = endLineText.slice(end.column);\n\tconst startsLine = /^\\s*$/.test(before);\n\tconst ownsLine = startsLine && /^\\s*$/.test(after);\n\tconst lines: CommentFacts[\"lines\"] = start.line === end.line ? \"single\" : \"multi\";\n\tconst position = new Set<\"above\" | \"beside\" | \"file-start\" | \"dangling\">();\n\n\tif (startsLine) {\n\t\tposition.add(\"above\");\n\t} else {\n\t\tposition.add(\"beside\");\n\t}\n\n\tconst firstToken = sourceCode.getFirstToken(sourceCode.ast, { includeComments: false });\n\tconst commentEnd = comment.range?.[1];\n\n\tif (firstToken === null || commentEnd === undefined || commentEnd <= firstToken.range[0]) {\n\t\tposition.add(\"file-start\");\n\t}\n\n\tconst nextToken = sourceCode.getTokenAfter(comment, { includeComments: false });\n\n\tif (nextToken === null || closingTokens.has(nextToken.value)) {\n\t\tposition.add(\"dangling\");\n\t}\n\n\treturn {\n\t\tcomment,\n\t\tkind: kindOf(comment),\n\t\tlines,\n\t\tposition,\n\t\tstartsLine,\n\t\townsLine,\n\t};\n}\n","import esquery from \"esquery\";\nimport type { Anchor } from \"./anchor\";\nimport type { CommentFacts } from \"./comment\";\nimport type { Comment } from \"estree\";\n\ntype Action = \"allow\" | \"report\" | \"delete\" | \"replace\";\n\ntype Position = \"above\" | \"beside\" | \"file-start\" | \"dangling\";\n\ntype Kind = \"line\" | \"block\" | \"jsdoc\" | \"shebang\";\n\nexport interface Entry {\n\tline?: boolean;\n\tblock?: boolean;\n\tjsdoc?: boolean;\n\tshebang?: boolean;\n\tlines?: \"single\" | \"multi\";\n\tposition?: Position | ReadonlyArray<Position>;\n\tterms?: ReadonlyArray<string>;\n\tlocation?: \"start\" | \"anywhere\";\n\tdecoration?: ReadonlyArray<string>;\n\tmarkers?: ReadonlyArray<string>;\n\tpattern?: string;\n\tselector?: string;\n\tinlineConfig?: boolean;\n\tcode?: boolean;\n\tmessage?: string;\n\taction: Action;\n\treplacement?: string;\n}\n\nexport interface CompiledEntry {\n\tkinds: ReadonlySet<Kind> | null;\n\tlines: \"single\" | \"multi\" | null;\n\tpositions: ReadonlyArray<Position> | null;\n\ttermPatterns: ReadonlyArray<RegExp> | null;\n\tmarkerPattern: RegExp | null;\n\tpattern: RegExp | null;\n\tselector: ReturnType<typeof esquery.parse> | null;\n\tinlineConfig: boolean | undefined;\n\tcode: boolean | undefined;\n\taction: Action;\n\tmessage: string | undefined;\n\treplacement: string | undefined;\n}\n\nexport interface MatchContext {\n\tgetAnchor: (facts: CommentFacts) => Anchor | null;\n\tisInlineConfig: (comment: Comment) => boolean;\n\tisCode: (facts: CommentFacts) => boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n}\n\nfunction termToRegExp(term: string, location: \"start\" | \"anywhere\", decoration: ReadonlyArray<string>): RegExp {\n\tconst escaped = escapeRegExp(term);\n\tconst wordBoundary = \"\\\\b\";\n\n\tif (location === \"start\") {\n\t\tconst decorationClass = decoration.map(escapeRegExp).join(\"\");\n\t\tconst prefix = `^[\\\\s${decorationClass}]*`;\n\t\tconst suffix = /\\w$/u.test(term) ? wordBoundary : \"\";\n\n\t\treturn new RegExp(`${prefix}${escaped}${suffix}`, \"iu\");\n\t}\n\n\tconst prefix = /^\\w/u.test(term) ? wordBoundary : \"\";\n\tconst suffix = /\\w$/u.test(term) ? wordBoundary : \"\";\n\n\treturn new RegExp(`${prefix}${escaped}${suffix}`, \"iu\");\n}\n\nfunction markerRegExp(markers: ReadonlyArray<string>): RegExp {\n\tconst body = markers.map((marker) => escapeRegExp(marker)).join(\"|\");\n\n\treturn new RegExp(`^\\\\s*(?:${body})`, \"u\");\n}\n\nfunction compileKinds(entry: Entry): ReadonlySet<Kind> | null {\n\tconst kinds = new Set<Kind>();\n\n\tif (entry.line === true) {\n\t\tkinds.add(\"line\");\n\t}\n\n\tif (entry.shebang === true) {\n\t\tkinds.add(\"shebang\");\n\t}\n\n\tif (entry.jsdoc === true) {\n\t\tkinds.add(\"jsdoc\");\n\t} else if (entry.block === true) {\n\t\tkinds.add(\"block\");\n\t\tkinds.add(\"jsdoc\");\n\t}\n\n\treturn kinds.size === 0 ? null : kinds;\n}\n\nexport function compileEntries(entries: ReadonlyArray<Entry>): ReadonlyArray<CompiledEntry> {\n\treturn entries.map((entry) => {\n\t\tconst location = entry.location ?? \"start\";\n\t\tconst decoration = entry.decoration ?? [];\n\t\tconst termPatterns =\n\t\t\tentry.terms === undefined ? null : entry.terms.map((term) => termToRegExp(term, location, decoration));\n\t\tconst positions =\n\t\t\tentry.position === undefined ? null : Array.isArray(entry.position) ? entry.position : [entry.position];\n\n\t\treturn {\n\t\t\tkinds: compileKinds(entry),\n\t\t\tlines: entry.lines ?? null,\n\t\t\tpositions,\n\t\t\ttermPatterns,\n\t\t\tmarkerPattern: entry.markers === undefined ? null : markerRegExp(entry.markers),\n\t\t\tpattern: entry.pattern === undefined ? null : new RegExp(entry.pattern, \"u\"),\n\t\t\tselector: entry.selector === undefined ? null : esquery.parse(entry.selector),\n\t\t\tinlineConfig: entry.inlineConfig,\n\t\t\tcode: entry.code,\n\t\t\taction: entry.action,\n\t\t\tmessage: entry.message,\n\t\t\treplacement: entry.replacement,\n\t\t};\n\t});\n}\n\nfunction matchesEntry(compiled: CompiledEntry, facts: CommentFacts, matchContext: MatchContext): boolean {\n\tif (compiled.kinds !== null && !compiled.kinds.has(facts.kind)) {\n\t\treturn false;\n\t}\n\n\tif (compiled.lines !== null && facts.lines !== compiled.lines) {\n\t\treturn false;\n\t}\n\n\tif (compiled.positions !== null) {\n\t\tconst hit = compiled.positions.every((position) => facts.position.has(position));\n\n\t\tif (!hit) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (compiled.termPatterns !== null) {\n\t\tconst value = facts.comment.value;\n\t\tconst hit = compiled.termPatterns.some((pattern) => pattern.test(value));\n\n\t\tif (!hit) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (compiled.markerPattern !== null && !compiled.markerPattern.test(facts.comment.value)) {\n\t\treturn false;\n\t}\n\n\tif (compiled.pattern !== null && !compiled.pattern.test(facts.comment.value)) {\n\t\treturn false;\n\t}\n\n\tif (compiled.inlineConfig !== undefined) {\n\t\tif (matchContext.isInlineConfig(facts.comment) !== compiled.inlineConfig) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (compiled.selector !== null) {\n\t\tconst anchor = matchContext.getAnchor(facts);\n\n\t\tif (anchor === null || !esquery.matches(anchor.node, compiled.selector, anchor.ancestry)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (compiled.code !== undefined) {\n\t\tif (matchContext.isCode(facts) !== compiled.code) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nexport function decide(\n\tcompiled: ReadonlyArray<CompiledEntry>,\n\tfacts: CommentFacts,\n\tmatchContext: MatchContext,\n): CompiledEntry | null {\n\tfor (let index = compiled.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = compiled[index];\n\n\t\tif (entry !== undefined && matchesEntry(entry, facts, matchContext)) {\n\t\t\treturn entry;\n\t\t}\n\t}\n\n\treturn null;\n}\n","import type { Entry } from \"./criteria\";\n\nconst docSelector =\n\t\"Program > *, ClassBody > *, TSInterfaceBody > *, TSTypeLiteral > *, TSModuleBlock > *, TSEnumBody > *\";\n\nconst docsMarkers = [\n\t\"@ts-expect-error\",\n\t\"@ts-ignore\",\n\t\"@ts-nocheck\",\n\t\"prettier-ignore\",\n\t\"istanbul ignore\",\n\t\"v8 ignore\",\n\t\"c8 ignore\",\n\t\"#__PURE__\",\n\t\"webpackChunkName\",\n\t\"@vite-ignore\",\n] as const;\n\nconst none: ReadonlyArray<Entry> = [{ action: \"delete\" }];\n\nconst safe: ReadonlyArray<Entry> = [\n\t{ action: \"delete\" },\n\t{ shebang: true, action: \"allow\" },\n\t{ inlineConfig: true, action: \"allow\" },\n];\n\nconst docs: ReadonlyArray<Entry> = [\n\t{ action: \"delete\" },\n\t{ shebang: true, action: \"allow\" },\n\t{ inlineConfig: true, action: \"allow\" },\n\t{ terms: [\"FIX\", \"TODO\"], location: \"start\", action: \"allow\" },\n\t{ markers: [...docsMarkers], action: \"allow\" },\n\t{\n\t\tjsdoc: true,\n\t\tlines: \"multi\",\n\t\tselector: docSelector,\n\t\taction: \"allow\",\n\t},\n];\n\nexport const policies = {\n\tnone,\n\tsafe,\n\tdocs,\n} as const;\n\nexport type PolicyName = keyof typeof policies;\n","import { resolveAnchor } from \"./anchor\";\nimport { containsCode, groupComments } from \"./code\";\nimport { describeComment } from \"./comment\";\nimport { compileEntries, decide, type CompiledEntry, type Entry, type MatchContext } from \"./criteria\";\nimport { policies, type PolicyName } from \"./policies\";\nimport type { Rule, SourceCode } from \"eslint\";\nimport type { Comment } from \"estree\";\n\nconst positionEnum = [\"above\", \"beside\", \"file-start\", \"dangling\"] as const;\nconst policyNames = [\"none\", \"safe\", \"docs\"] as const;\nconst actionEnum = [\"allow\", \"report\", \"delete\", \"replace\"] as const;\n\nconst entrySchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tline: { type: \"boolean\" },\n\t\tblock: { type: \"boolean\" },\n\t\tjsdoc: { type: \"boolean\" },\n\t\tshebang: { type: \"boolean\" },\n\t\tlines: { enum: [\"single\", \"multi\"] },\n\t\tposition: {\n\t\t\toneOf: [\n\t\t\t\t{ enum: [...positionEnum] },\n\t\t\t\t{\n\t\t\t\t\ttype: \"array\",\n\t\t\t\t\titems: { enum: [...positionEnum] },\n\t\t\t\t\tminItems: 1,\n\t\t\t\t\tuniqueItems: true,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tterms: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t\tminItems: 1,\n\t\t},\n\t\tlocation: { enum: [\"start\", \"anywhere\"] },\n\t\tdecoration: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\", pattern: \"^\\\\S$\" },\n\t\t\tminItems: 1,\n\t\t},\n\t\tmarkers: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t\tminItems: 1,\n\t\t},\n\t\tpattern: { type: \"string\" },\n\t\tselector: { type: \"string\" },\n\t\tinlineConfig: { type: \"boolean\" },\n\t\tcode: { type: \"boolean\" },\n\t\tmessage: { type: \"string\" },\n\t\taction: { enum: [...actionEnum] },\n\t\treplacement: { type: \"string\" },\n\t},\n\trequired: [\"action\"],\n\tadditionalProperties: false,\n} as const;\n\nfunction resolveEntries(option: PolicyName | ReadonlyArray<Entry>): ReadonlyArray<Entry> {\n\tif (typeof option === \"string\") {\n\t\treturn policies[option];\n\t}\n\n\treturn option;\n}\n\nfunction contentRange(comment: Comment): [number, number] {\n\tconst range = comment.range;\n\n\tif (range === undefined) {\n\t\tthrow new Error(\"comment is missing range information\");\n\t}\n\n\tif ((comment.type as string) === \"Shebang\" || comment.type === \"Line\") {\n\t\treturn [range[0] + 2, range[1]];\n\t}\n\n\treturn [range[0] + 2, range[1] - 2];\n}\n\nfunction deleteRange(sourceText: string, facts: ReturnType<typeof describeComment>): [number, number] {\n\tconst range = facts.comment.range;\n\n\tif (range === undefined) {\n\t\tthrow new Error(\"comment is missing range information\");\n\t}\n\n\tlet start = range[0];\n\n\twhile (start > 0) {\n\t\tconst previous = sourceText[start - 1];\n\n\t\tif (previous !== \" \" && previous !== \"\\t\") {\n\t\t\tbreak;\n\t\t}\n\n\t\tstart -= 1;\n\t}\n\n\tlet end = range[1];\n\n\tif (facts.ownsLine) {\n\t\tif (sourceText[end] === \"\\r\" && sourceText[end + 1] === \"\\n\") {\n\t\t\tend += 2;\n\t\t} else if (sourceText[end] === \"\\n\" || sourceText[end] === \"\\r\") {\n\t\t\tend += 1;\n\t\t}\n\t}\n\n\treturn [start, end];\n}\n\nfunction replacedContents(facts: ReturnType<typeof describeComment>, compiled: CompiledEntry): string | null {\n\tif (compiled.replacement === undefined) {\n\t\treturn null;\n\t}\n\n\tif (compiled.pattern === null) {\n\t\treturn compiled.replacement;\n\t}\n\n\treturn facts.comment.value.replace(compiled.pattern, compiled.replacement);\n}\n\nfunction reportLoc(comment: Comment): {\n\tstart: { line: number; column: number };\n\tend: { line: number; column: number };\n} {\n\treturn comment.loc ?? { start: { line: 1, column: 0 }, end: { line: 1, column: 0 } };\n}\n\nconst rule: Rule.RuleModule = {\n\tmeta: {\n\t\ttype: \"suggestion\",\n\t\tdocs: {\n\t\t\tdescription: \"Disallow comments that match a configured restriction policy\",\n\t\t},\n\t\tfixable: \"code\",\n\t\tschema: {\n\t\t\ttype: \"array\",\n\t\t\tminItems: 1,\n\t\t\tmaxItems: 1,\n\t\t\titems: [\n\t\t\t\t{\n\t\t\t\t\toneOf: [\n\t\t\t\t\t\t{ enum: [...policyNames] },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\titems: entrySchema,\n\t\t\t\t\t\t\tminItems: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tmessages: {\n\t\t\trestricted: \"{{message}}\",\n\t\t},\n\t},\n\n\tcreate(context) {\n\t\tconst option = context.options[0] as PolicyName | ReadonlyArray<Entry> | undefined;\n\n\t\tif (option === undefined) {\n\t\t\tthrow new Error(\"comment-rules/no-restricted-comments requires a policy name or entry array\");\n\t\t}\n\n\t\tconst compiled = compileEntries(resolveEntries(option));\n\t\tconst needsCode = compiled.some((entry) => entry.code !== undefined);\n\t\tconst parser = context.languageOptions.parser;\n\t\tconst parserOptions = {\n\t\t\t...context.languageOptions.parserOptions,\n\t\t\tecmaVersion: context.languageOptions.ecmaVersion ?? \"latest\",\n\t\t\tsourceType: context.languageOptions.sourceType ?? \"module\",\n\t\t};\n\n\t\tconst listeners: Rule.RuleListener = {};\n\n\t\tlisteners[\"Program:exit\"] = () => {\n\t\t\tconst sourceCode = context.sourceCode;\n\t\t\tconst comments = sourceCode.getAllComments();\n\t\t\tconst allFacts = comments.map((comment) => describeComment(sourceCode, comment));\n\t\t\tconst groups = needsCode ? groupComments(allFacts) : [];\n\t\t\tconst groupByComment = new Map<Comment, (typeof groups)[number]>();\n\n\t\t\tfor (const group of groups) {\n\t\t\t\tfor (const member of group.members) {\n\t\t\t\t\tgroupByComment.set(member.comment, group);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet inlineConfigSet: Set<Comment> | undefined;\n\t\t\tconst anchorCache = new Map<Comment, ReturnType<typeof resolveAnchor>>();\n\t\t\tconst codeCache = new Map<(typeof groups)[number], boolean>();\n\t\t\tconst sourceCodeWithInline = sourceCode as SourceCode & {\n\t\t\t\tgetInlineConfigNodes?: () => Array<Comment>;\n\t\t\t};\n\n\t\t\tconst matchContext: MatchContext = {\n\t\t\t\tgetAnchor(facts) {\n\t\t\t\t\tif (anchorCache.has(facts.comment)) {\n\t\t\t\t\t\treturn anchorCache.get(facts.comment) ?? null;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst anchor = resolveAnchor(sourceCode, facts);\n\n\t\t\t\t\tanchorCache.set(facts.comment, anchor);\n\n\t\t\t\t\treturn anchor;\n\t\t\t\t},\n\t\t\t\tisInlineConfig(comment) {\n\t\t\t\t\tif (inlineConfigSet === undefined) {\n\t\t\t\t\t\tconst nodes =\n\t\t\t\t\t\t\ttypeof sourceCodeWithInline.getInlineConfigNodes === \"function\"\n\t\t\t\t\t\t\t\t? sourceCodeWithInline.getInlineConfigNodes()\n\t\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\t\tinlineConfigSet = new Set(nodes);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inlineConfigSet.has(comment);\n\t\t\t\t},\n\t\t\t\tisCode(facts) {\n\t\t\t\t\tconst group = groupByComment.get(facts.comment);\n\n\t\t\t\t\tif (group === undefined) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst cached = codeCache.get(group);\n\n\t\t\t\t\tif (cached !== undefined) {\n\t\t\t\t\t\treturn cached;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (parser === undefined) {\n\t\t\t\t\t\tcodeCache.set(group, false);\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = containsCode(group, parser, parserOptions);\n\n\t\t\t\t\tcodeCache.set(group, result);\n\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tconst sourceText = sourceCode.text;\n\t\t\tconst outcomes: Array<{\n\t\t\t\tfacts: ReturnType<typeof describeComment>;\n\t\t\t\tmatch: NonNullable<ReturnType<typeof decide>>;\n\t\t\t\tdeleteRange: [number, number] | null;\n\t\t\t}> = [];\n\n\t\t\tfor (const facts of allFacts) {\n\t\t\t\tconst match = decide(compiled, facts, matchContext);\n\n\t\t\t\tif (match === null || match.action === \"allow\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\toutcomes.push({\n\t\t\t\t\tfacts,\n\t\t\t\t\tmatch,\n\t\t\t\t\tdeleteRange: match.action === \"delete\" ? deleteRange(sourceText, facts) : null,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst deleteFixRange = new Map<Comment, [number, number]>();\n\t\t\tlet runStart = 0;\n\n\t\t\twhile (runStart < outcomes.length) {\n\t\t\t\tconst current = outcomes[runStart];\n\n\t\t\t\tif (current?.deleteRange === null || !current?.facts.ownsLine) {\n\t\t\t\t\tif (current?.deleteRange !== null && current !== undefined) {\n\t\t\t\t\t\tdeleteFixRange.set(current.facts.comment, current.deleteRange);\n\t\t\t\t\t}\n\n\t\t\t\t\trunStart += 1;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet runEnd = runStart;\n\t\t\t\tlet range: [number, number] = current.deleteRange;\n\n\t\t\t\twhile (runEnd + 1 < outcomes.length) {\n\t\t\t\t\tconst next = outcomes[runEnd + 1];\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tnext?.deleteRange === null ||\n\t\t\t\t\t\tnext === undefined ||\n\t\t\t\t\t\t!next.facts.ownsLine ||\n\t\t\t\t\t\tnext.deleteRange[0] !== range[1]\n\t\t\t\t\t) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\trange = [range[0], next.deleteRange[1]];\n\t\t\t\t\trunEnd += 1;\n\t\t\t\t}\n\n\t\t\t\tdeleteFixRange.set(current.facts.comment, range);\n\t\t\t\trunStart = runEnd + 1;\n\t\t\t}\n\n\t\t\tfor (const outcome of outcomes) {\n\t\t\t\tconst message = outcome.match.message ?? \"This comment is restricted by the comment policy.\";\n\t\t\t\tconst loc = reportLoc(outcome.facts.comment);\n\n\t\t\t\tif (outcome.match.action === \"report\") {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tloc,\n\t\t\t\t\t\tmessageId: \"restricted\",\n\t\t\t\t\t\tdata: { message },\n\t\t\t\t\t});\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (outcome.match.action === \"delete\") {\n\t\t\t\t\tconst range = deleteFixRange.get(outcome.facts.comment);\n\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tloc,\n\t\t\t\t\t\tmessageId: \"restricted\",\n\t\t\t\t\t\tdata: { message },\n\t\t\t\t\t\tfix: range === undefined ? undefined : (fixer) => fixer.removeRange(range),\n\t\t\t\t\t});\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst next = replacedContents(outcome.facts, outcome.match);\n\n\t\t\t\tif (next === null) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tloc,\n\t\t\t\t\t\tmessageId: \"restricted\",\n\t\t\t\t\t\tdata: { message },\n\t\t\t\t\t});\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst range = contentRange(outcome.facts.comment);\n\n\t\t\t\tcontext.report({\n\t\t\t\t\tloc,\n\t\t\t\t\tmessageId: \"restricted\",\n\t\t\t\t\tdata: { message },\n\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\treturn fixer.replaceTextRange(range, next);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\treturn listeners;\n\t},\n};\n\nexport default rule;\n","import rule from \"./rule\";\nimport type { ESLint, Linter } from \"eslint\";\n\nconst plugin = {\n\tmeta: {\n\t\tname: \"eslint-plugin-comment-rules\",\n\t\tversion: \"0.1.0\",\n\t},\n\trules: {\n\t\t\"no-restricted-comments\": rule,\n\t},\n\tconfigs: {} as Record<string, Linter.Config>,\n} satisfies ESLint.Plugin;\n\nfunction policyConfig(name: \"none\" | \"safe\" | \"docs\"): Linter.Config {\n\treturn {\n\t\tname: `comment-rules/${name}`,\n\t\tplugins: {\n\t\t\t\"comment-rules\": plugin,\n\t\t},\n\t\trules: {\n\t\t\t\"comment-rules/no-restricted-comments\": [\"error\", name],\n\t\t},\n\t};\n}\n\nplugin.configs.none = policyConfig(\"none\");\nplugin.configs.safe = policyConfig(\"safe\");\nplugin.configs.docs = policyConfig(\"docs\");\n\nexport default plugin;\nexport { plugin as \"module.exports\" };\n"],"mappings":"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","names":["prefix","suffix","range"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eslint-plugin-comment-rules",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ESLint plugin for expressing a comment policy as configuration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"scripts": {
|
|
18
|
+
"check": "concurrently \"eslint . --fix --cache\" \"tsc --noEmit\"",
|
|
19
|
+
"lint": "eslint . --fix --cache",
|
|
20
|
+
"lint:fix": "eslint . --fix",
|
|
21
|
+
"format": "prettier --write .",
|
|
22
|
+
"unit": "vitest run unit",
|
|
23
|
+
"integration": "vitest run integration",
|
|
24
|
+
"build": "tsup"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"eslint",
|
|
28
|
+
"eslintplugin",
|
|
29
|
+
"eslint-plugin",
|
|
30
|
+
"comments"
|
|
31
|
+
],
|
|
32
|
+
"author": "Matt Cavender",
|
|
33
|
+
"license": "ISC",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/visionsofparadise/eslint-plugin-comment-rules.git"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"eslint": "^9.0.0 || ^10.0.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"esquery": "^1.7.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/compat": "^2.1.0",
|
|
52
|
+
"@eslint/js": "^10.0.1",
|
|
53
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
54
|
+
"@types/esquery": "^1.5.4",
|
|
55
|
+
"@types/estree": "^1.0.9",
|
|
56
|
+
"@types/node": "^26.1.1",
|
|
57
|
+
"@typescript-eslint/parser": "^8.65.0",
|
|
58
|
+
"concurrently": "^10.0.4",
|
|
59
|
+
"eslint": "^10.8.0",
|
|
60
|
+
"eslint-config-prettier": "^10.1.8",
|
|
61
|
+
"eslint-import-resolver-typescript": "^4.4.5",
|
|
62
|
+
"eslint-plugin-barrel-files": "^3.0.1",
|
|
63
|
+
"eslint-plugin-check-file": "^3.3.2",
|
|
64
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
65
|
+
"espree": "^11.2.0",
|
|
66
|
+
"globals": "^17.7.0",
|
|
67
|
+
"knip": "^6.29.0",
|
|
68
|
+
"prettier": "^3.9.6",
|
|
69
|
+
"tsup": "^8.5.1",
|
|
70
|
+
"typescript": "~5.9.0",
|
|
71
|
+
"typescript-eslint": "^8.65.0",
|
|
72
|
+
"vitest": "^4.1.10"
|
|
73
|
+
},
|
|
74
|
+
"allowScripts": {
|
|
75
|
+
"esbuild@0.27.7": true,
|
|
76
|
+
"unrs-resolver@1.12.2": true
|
|
77
|
+
}
|
|
78
|
+
}
|