Skip to content

Commit 317ed6f

Browse files
committed
Refactored eslint-plugin to use typescript-eslint
1 parent 0362e09 commit 317ed6f

File tree

7 files changed

+265
-125
lines changed

7 files changed

+265
-125
lines changed

common/config/rush/pnpm-lock.yaml

+99
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eslint-plugin/package.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,21 @@
3030
"@microsoft/tsdoc": "workspace:*",
3131
"@microsoft/tsdoc-config": "workspace:*"
3232
},
33+
"peerDependencies": {
34+
"@typescript-eslint/parser": "^8",
35+
"eslint": "^8"
36+
},
3337
"devDependencies": {
38+
"@typescript-eslint/rule-tester": "~8.3.0",
39+
"@typescript-eslint/utils": "~8.3.0",
3440
"@rushstack/heft-node-rig": "~2.6.11",
3541
"@rushstack/heft": "^0.66.13",
3642
"@types/eslint": "8.40.1",
3743
"@types/estree": "1.0.1",
3844
"@types/heft-jest": "1.0.3",
3945
"@types/node": "14.18.36",
4046
"eslint": "~8.57.0",
41-
"eslint-plugin-header": "~3.1.1"
47+
"eslint-plugin-header": "~3.1.1",
48+
"typescript": "~5.4.2"
4249
}
4350
}

eslint-plugin/src/SyntaxRule.ts

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import { TSDocParser, TextRange, TSDocConfiguration, type ParserContext } from '@microsoft/tsdoc';
5+
import type { TSDocConfigFile } from '@microsoft/tsdoc-config';
6+
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
7+
8+
const tsdocMessageIds: { [x: string]: string } = {};
9+
10+
const defaultTSDocConfiguration: TSDocConfiguration = new TSDocConfiguration();
11+
defaultTSDocConfiguration.allTsdocMessageIds.forEach((messageId: string) => {
12+
tsdocMessageIds[messageId] = `${messageId}: {{unformattedText}}`;
13+
});
14+
15+
import { Debug } from './Debug';
16+
import { ConfigCache } from './ConfigCache';
17+
18+
import { configMessages, createRule } from './utils';
19+
20+
export const rule: TSESLint.AnyRuleModule = createRule({
21+
name: 'syntax',
22+
meta: {
23+
messages: {
24+
...configMessages,
25+
...tsdocMessageIds
26+
},
27+
type: 'problem',
28+
docs: {
29+
description: 'Validates that TypeScript documentation comments conform to the TSDoc standard',
30+
// This package is experimental
31+
recommended: false,
32+
url: 'https://tsdoc.org/pages/packages/eslint-plugin-tsdoc'
33+
},
34+
schema: []
35+
},
36+
defaultOptions: [],
37+
create: (context: TSESLint.RuleContext<string, unknown[]>) => {
38+
const sourceFilePath: string = context.getFilename();
39+
Debug.log(`Linting: "${sourceFilePath}"`);
40+
41+
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();
42+
43+
try {
44+
const tsdocConfigFile: TSDocConfigFile = ConfigCache.getForSourceFile(sourceFilePath);
45+
if (!tsdocConfigFile.fileNotFound) {
46+
if (tsdocConfigFile.hasErrors) {
47+
context.report({
48+
loc: { line: 1, column: 1 },
49+
messageId: 'error-loading-config-file',
50+
data: {
51+
details: tsdocConfigFile.getErrorSummary()
52+
}
53+
});
54+
}
55+
56+
try {
57+
tsdocConfigFile.configureParser(tsdocConfiguration);
58+
} catch (e) {
59+
context.report({
60+
loc: { line: 1, column: 1 },
61+
messageId: 'error-applying-config',
62+
data: {
63+
details: e.message
64+
}
65+
});
66+
}
67+
}
68+
} catch (e) {
69+
context.report({
70+
loc: { line: 1, column: 1 },
71+
messageId: 'error-loading-config-file',
72+
data: {
73+
details: `Unexpected exception: ${e.message}`
74+
}
75+
});
76+
}
77+
78+
const tsdocParser: TSDocParser = new TSDocParser(tsdocConfiguration);
79+
80+
const sourceCode: TSESLint.SourceCode = context.sourceCode;
81+
const checkCommentBlocks: (node: TSESTree.Program) => void = function (node: TSESTree.Program) {
82+
for (const comment of sourceCode.getAllComments()) {
83+
if (comment.type !== 'Block') {
84+
continue;
85+
}
86+
if (!comment.range) {
87+
continue;
88+
}
89+
90+
const textRange: TextRange = TextRange.fromStringRange(
91+
sourceCode.text,
92+
comment.range[0],
93+
comment.range[1]
94+
);
95+
96+
// Smallest comment is "/***/"
97+
if (textRange.length < 5) {
98+
continue;
99+
}
100+
// Make sure it starts with "/**"
101+
if (textRange.buffer[textRange.pos + 2] !== '*') {
102+
continue;
103+
}
104+
105+
const parserContext: ParserContext = tsdocParser.parseRange(textRange);
106+
for (const message of parserContext.log.messages) {
107+
context.report({
108+
loc: {
109+
start: sourceCode.getLocFromIndex(message.textRange.pos),
110+
end: sourceCode.getLocFromIndex(message.textRange.end)
111+
},
112+
messageId: message.messageId,
113+
data: {
114+
unformattedText: message.unformattedText
115+
}
116+
});
117+
}
118+
}
119+
};
120+
121+
return {
122+
Program: checkCommentBlocks
123+
};
124+
}
125+
});

0 commit comments

Comments
 (0)