@api-extractor-tools/eslint-plugin 0.1.0-alpha.0 → 0.1.0-alpha.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.
Files changed (104) hide show
  1. package/ARCHITECTURE.md +201 -0
  2. package/CHANGELOG.md +24 -0
  3. package/README.md +306 -10
  4. package/api-extractor.json +1 -0
  5. package/dist/configs/recommended.d.ts +1 -1
  6. package/dist/configs/recommended.d.ts.map +1 -1
  7. package/dist/configs/recommended.js +7 -1
  8. package/dist/configs/recommended.js.map +1 -1
  9. package/dist/index.d.ts +9 -16
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +11 -15
  12. package/dist/index.js.map +1 -1
  13. package/dist/node.d.ts +28 -0
  14. package/dist/node.d.ts.map +1 -0
  15. package/dist/node.js +41 -0
  16. package/dist/node.js.map +1 -0
  17. package/dist/rules/extra-release-tag.d.ts +24 -0
  18. package/dist/rules/extra-release-tag.d.ts.map +1 -0
  19. package/dist/rules/extra-release-tag.js +141 -0
  20. package/dist/rules/extra-release-tag.js.map +1 -0
  21. package/dist/rules/forgotten-export.d.ts +24 -0
  22. package/dist/rules/forgotten-export.d.ts.map +1 -0
  23. package/dist/rules/forgotten-export.js +212 -0
  24. package/dist/rules/forgotten-export.js.map +1 -0
  25. package/dist/rules/incompatible-release-tags.d.ts +25 -0
  26. package/dist/rules/incompatible-release-tags.d.ts.map +1 -0
  27. package/dist/rules/incompatible-release-tags.js +237 -0
  28. package/dist/rules/incompatible-release-tags.js.map +1 -0
  29. package/dist/rules/index.d.ts +2 -6
  30. package/dist/rules/index.d.ts.map +1 -1
  31. package/dist/rules/index.js +13 -1
  32. package/dist/rules/index.js.map +1 -1
  33. package/dist/rules/missing-release-tag.d.ts +4 -0
  34. package/dist/rules/missing-release-tag.d.ts.map +1 -1
  35. package/dist/rules/missing-release-tag.js +14 -21
  36. package/dist/rules/missing-release-tag.js.map +1 -1
  37. package/dist/rules/override-keyword.d.ts +4 -0
  38. package/dist/rules/override-keyword.d.ts.map +1 -1
  39. package/dist/rules/override-keyword.js +9 -11
  40. package/dist/rules/override-keyword.js.map +1 -1
  41. package/dist/rules/package-documentation.d.ts +1 -1
  42. package/dist/rules/package-documentation.d.ts.map +1 -1
  43. package/dist/rules/package-documentation.js +7 -28
  44. package/dist/rules/package-documentation.js.map +1 -1
  45. package/dist/rules/public-on-non-exported.d.ts +24 -0
  46. package/dist/rules/public-on-non-exported.d.ts.map +1 -0
  47. package/dist/rules/public-on-non-exported.js +191 -0
  48. package/dist/rules/public-on-non-exported.js.map +1 -0
  49. package/dist/rules/public-on-private-member.d.ts +24 -0
  50. package/dist/rules/public-on-private-member.d.ts.map +1 -0
  51. package/dist/rules/public-on-private-member.js +111 -0
  52. package/dist/rules/public-on-private-member.js.map +1 -0
  53. package/dist/rules/valid-enum-type.d.ts +17 -0
  54. package/dist/rules/valid-enum-type.d.ts.map +1 -0
  55. package/dist/rules/valid-enum-type.js +206 -0
  56. package/dist/rules/valid-enum-type.js.map +1 -0
  57. package/dist/types.d.ts +63 -35
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/types.js +4 -1
  60. package/dist/types.js.map +1 -1
  61. package/dist/utils/tsdoc-parser.d.ts +35 -0
  62. package/dist/utils/tsdoc-parser.d.ts.map +1 -1
  63. package/dist/utils/tsdoc-parser.js +40 -0
  64. package/dist/utils/tsdoc-parser.js.map +1 -1
  65. package/docs/rules/valid-enum-type.md +153 -0
  66. package/package.json +22 -8
  67. package/src/configs/recommended.ts +7 -1
  68. package/src/index.ts +21 -15
  69. package/src/node.ts +50 -0
  70. package/src/rules/extra-release-tag.ts +201 -0
  71. package/src/rules/forgotten-export.ts +274 -0
  72. package/src/rules/incompatible-release-tags.ts +331 -0
  73. package/src/rules/index.ts +13 -1
  74. package/src/rules/missing-release-tag.ts +11 -26
  75. package/src/rules/override-keyword.ts +6 -8
  76. package/src/rules/package-documentation.ts +5 -31
  77. package/src/rules/public-on-non-exported.ts +265 -0
  78. package/src/rules/public-on-private-member.ts +157 -0
  79. package/src/rules/valid-enum-type.ts +252 -0
  80. package/src/types.ts +60 -17
  81. package/src/utils/config-loader.ts +1 -0
  82. package/src/utils/entry-point.ts +1 -0
  83. package/src/utils/tsdoc-parser.ts +67 -0
  84. package/temp/eslint-plugin.api.md +96 -47
  85. package/test/index.test.ts +1 -0
  86. package/test/rules/extra-release-tag.test.ts +276 -0
  87. package/test/rules/forgotten-export.test.ts +190 -0
  88. package/test/rules/incompatible-release-tags.test.ts +340 -0
  89. package/test/rules/missing-release-tag.test.ts +2 -1
  90. package/test/rules/override-keyword.test.ts +2 -1
  91. package/test/rules/package-documentation.test.ts +8 -6
  92. package/test/rules/public-on-non-exported.test.ts +201 -0
  93. package/test/rules/public-on-private-member.test.ts +207 -0
  94. package/test/rules/valid-enum-type.test.ts +409 -0
  95. package/test/types.test-d.ts +20 -0
  96. package/test/utils/config-loader.test.ts +1 -0
  97. package/test/utils/tsdoc-parser.test.ts +117 -9
  98. package/tsconfig.json +1 -0
  99. package/vitest.config.mts +1 -0
  100. package/dist/utils/index.d.ts +0 -8
  101. package/dist/utils/index.d.ts.map +0 -1
  102. package/dist/utils/index.js +0 -21
  103. package/dist/utils/index.js.map +0 -1
  104. package/src/utils/index.ts +0 -17
@@ -0,0 +1,340 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester'
2
+ import { describe, it, afterAll } from 'vitest'
3
+ import * as tseslintParser from '@typescript-eslint/parser'
4
+ import { incompatibleReleaseTags } from '../../src/rules/incompatible-release-tags'
5
+
6
+ RuleTester.afterAll = afterAll
7
+ RuleTester.describe = describe
8
+ RuleTester.it = it
9
+
10
+ const ruleTester = new RuleTester({
11
+ languageOptions: {
12
+ parser: tseslintParser,
13
+ parserOptions: {
14
+ ecmaVersion: 2022,
15
+ sourceType: 'module',
16
+ },
17
+ },
18
+ })
19
+
20
+ describe('incompatible-release-tags', () => {
21
+ ruleTester.run('incompatible-release-tags', incompatibleReleaseTags, {
22
+ valid: [
23
+ // Public API using public type
24
+ {
25
+ code: `
26
+ /**
27
+ * A public interface.
28
+ * @public
29
+ */
30
+ export interface MyInterface {
31
+ name: string;
32
+ }
33
+
34
+ /**
35
+ * A public function.
36
+ * @public
37
+ */
38
+ export function myFunction(param: MyInterface): void {}
39
+ `,
40
+ },
41
+ // Public API using beta type (beta is less visible, but this is OK since beta >= beta in some interpretations)
42
+ // Actually, let's make this more strict - public should only use public
43
+ {
44
+ code: `
45
+ /**
46
+ * A beta interface.
47
+ * @beta
48
+ */
49
+ export interface MyInterface {
50
+ name: string;
51
+ }
52
+
53
+ /**
54
+ * A beta function.
55
+ * @beta
56
+ */
57
+ export function myFunction(param: MyInterface): void {}
58
+ `,
59
+ },
60
+ // Alpha API using alpha type
61
+ {
62
+ code: `
63
+ /**
64
+ * An alpha interface.
65
+ * @alpha
66
+ */
67
+ export interface MyInterface {
68
+ name: string;
69
+ }
70
+
71
+ /**
72
+ * An alpha function.
73
+ * @alpha
74
+ */
75
+ export function myFunction(param: MyInterface): void {}
76
+ `,
77
+ },
78
+ // Internal API using internal type
79
+ {
80
+ code: `
81
+ /**
82
+ * An internal interface.
83
+ * @internal
84
+ */
85
+ export interface MyInterface {
86
+ name: string;
87
+ }
88
+
89
+ /**
90
+ * An internal function.
91
+ * @internal
92
+ */
93
+ export function myFunction(param: MyInterface): void {}
94
+ `,
95
+ },
96
+ // Beta API using public type (more visible)
97
+ {
98
+ code: `
99
+ /**
100
+ * A public interface.
101
+ * @public
102
+ */
103
+ export interface MyInterface {
104
+ name: string;
105
+ }
106
+
107
+ /**
108
+ * A beta function.
109
+ * @beta
110
+ */
111
+ export function myFunction(param: MyInterface): void {}
112
+ `,
113
+ },
114
+ // Alpha API using public type (more visible)
115
+ {
116
+ code: `
117
+ /**
118
+ * A public interface.
119
+ * @public
120
+ */
121
+ export interface MyInterface {
122
+ name: string;
123
+ }
124
+
125
+ /**
126
+ * An alpha function.
127
+ * @alpha
128
+ */
129
+ export function myFunction(param: MyInterface): void {}
130
+ `,
131
+ },
132
+ ],
133
+ invalid: [
134
+ // Public API using internal type
135
+ {
136
+ code: `
137
+ /**
138
+ * An internal interface.
139
+ * @internal
140
+ */
141
+ interface MyInterface {
142
+ name: string;
143
+ }
144
+
145
+ /**
146
+ * A public function.
147
+ * @public
148
+ */
149
+ export function myFunction(param: MyInterface): void {}
150
+ `,
151
+ errors: [
152
+ {
153
+ messageId: 'incompatibleReleaseTags',
154
+ data: {
155
+ exportedName: 'myFunction',
156
+ exportedTag: '@public',
157
+ referencedName: 'MyInterface',
158
+ referencedTag: '@internal',
159
+ },
160
+ },
161
+ ],
162
+ },
163
+ // Public API using alpha type
164
+ {
165
+ code: `
166
+ /**
167
+ * An alpha interface.
168
+ * @alpha
169
+ */
170
+ interface MyInterface {
171
+ name: string;
172
+ }
173
+
174
+ /**
175
+ * A public function.
176
+ * @public
177
+ */
178
+ export function myFunction(param: MyInterface): void {}
179
+ `,
180
+ errors: [
181
+ {
182
+ messageId: 'incompatibleReleaseTags',
183
+ data: {
184
+ exportedName: 'myFunction',
185
+ exportedTag: '@public',
186
+ referencedName: 'MyInterface',
187
+ referencedTag: '@alpha',
188
+ },
189
+ },
190
+ ],
191
+ },
192
+ // Beta API using internal type
193
+ {
194
+ code: `
195
+ /**
196
+ * An internal interface.
197
+ * @internal
198
+ */
199
+ interface MyInterface {
200
+ name: string;
201
+ }
202
+
203
+ /**
204
+ * A beta function.
205
+ * @beta
206
+ */
207
+ export function myFunction(param: MyInterface): void {}
208
+ `,
209
+ errors: [
210
+ {
211
+ messageId: 'incompatibleReleaseTags',
212
+ data: {
213
+ exportedName: 'myFunction',
214
+ exportedTag: '@beta',
215
+ referencedName: 'MyInterface',
216
+ referencedTag: '@internal',
217
+ },
218
+ },
219
+ ],
220
+ },
221
+ // Beta API using alpha type
222
+ {
223
+ code: `
224
+ /**
225
+ * An alpha interface.
226
+ * @alpha
227
+ */
228
+ interface MyInterface {
229
+ name: string;
230
+ }
231
+
232
+ /**
233
+ * A beta function.
234
+ * @beta
235
+ */
236
+ export function myFunction(param: MyInterface): void {}
237
+ `,
238
+ errors: [
239
+ {
240
+ messageId: 'incompatibleReleaseTags',
241
+ data: {
242
+ exportedName: 'myFunction',
243
+ exportedTag: '@beta',
244
+ referencedName: 'MyInterface',
245
+ referencedTag: '@alpha',
246
+ },
247
+ },
248
+ ],
249
+ },
250
+ // Alpha API using internal type
251
+ {
252
+ code: `
253
+ /**
254
+ * An internal interface.
255
+ * @internal
256
+ */
257
+ interface MyInterface {
258
+ name: string;
259
+ }
260
+
261
+ /**
262
+ * An alpha function.
263
+ * @alpha
264
+ */
265
+ export function myFunction(param: MyInterface): void {}
266
+ `,
267
+ errors: [
268
+ {
269
+ messageId: 'incompatibleReleaseTags',
270
+ data: {
271
+ exportedName: 'myFunction',
272
+ exportedTag: '@alpha',
273
+ referencedName: 'MyInterface',
274
+ referencedTag: '@internal',
275
+ },
276
+ },
277
+ ],
278
+ },
279
+ // Public interface with internal type property
280
+ {
281
+ code: `
282
+ /**
283
+ * An internal type.
284
+ * @internal
285
+ */
286
+ type InternalType = string;
287
+
288
+ /**
289
+ * A public interface.
290
+ * @public
291
+ */
292
+ export interface MyInterface {
293
+ value: InternalType;
294
+ }
295
+ `,
296
+ errors: [
297
+ {
298
+ messageId: 'incompatibleReleaseTags',
299
+ data: {
300
+ exportedName: 'MyInterface',
301
+ exportedTag: '@public',
302
+ referencedName: 'InternalType',
303
+ referencedTag: '@internal',
304
+ },
305
+ },
306
+ ],
307
+ },
308
+ ],
309
+ })
310
+
311
+ // Test with severity option
312
+ ruleTester.run(
313
+ 'incompatible-release-tags with severity=none',
314
+ incompatibleReleaseTags,
315
+ {
316
+ valid: [
317
+ // Should not report when severity is 'none'
318
+ {
319
+ code: `
320
+ /**
321
+ * An internal interface.
322
+ * @internal
323
+ */
324
+ interface MyInterface {
325
+ name: string;
326
+ }
327
+
328
+ /**
329
+ * A public function.
330
+ * @public
331
+ */
332
+ export function myFunction(param: MyInterface): void {}
333
+ `,
334
+ options: [{ severity: 'none' }],
335
+ },
336
+ ],
337
+ invalid: [],
338
+ },
339
+ )
340
+ })
@@ -1,5 +1,6 @@
1
1
  import { RuleTester } from '@typescript-eslint/rule-tester'
2
2
  import { describe, it, afterAll } from 'vitest'
3
+ import * as tseslintParser from '@typescript-eslint/parser'
3
4
  import { missingReleaseTag } from '../../src/rules/missing-release-tag'
4
5
 
5
6
  RuleTester.afterAll = afterAll
@@ -8,7 +9,7 @@ RuleTester.it = it
8
9
 
9
10
  const ruleTester = new RuleTester({
10
11
  languageOptions: {
11
- parser: require('@typescript-eslint/parser'),
12
+ parser: tseslintParser,
12
13
  parserOptions: {
13
14
  ecmaVersion: 2022,
14
15
  sourceType: 'module',
@@ -1,5 +1,6 @@
1
1
  import { RuleTester } from '@typescript-eslint/rule-tester'
2
2
  import { describe, it, afterAll } from 'vitest'
3
+ import * as tseslintParser from '@typescript-eslint/parser'
3
4
  import { overrideKeyword } from '../../src/rules/override-keyword'
4
5
 
5
6
  RuleTester.afterAll = afterAll
@@ -8,7 +9,7 @@ RuleTester.it = it
8
9
 
9
10
  const ruleTester = new RuleTester({
10
11
  languageOptions: {
11
- parser: require('@typescript-eslint/parser'),
12
+ parser: tseslintParser,
12
13
  parserOptions: {
13
14
  ecmaVersion: 2022,
14
15
  sourceType: 'module',
@@ -2,13 +2,15 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
2
  import * as path from 'path'
3
3
  import * as fs from 'fs'
4
4
  import * as os from 'os'
5
- import { clearPackageJsonCache } from '../../src/utils/entry-point.js'
6
5
  import {
7
6
  findPackageJson,
8
7
  isEntryPoint,
8
+ clearPackageJsonCache,
9
+ } from '../../src/utils/entry-point.js'
10
+ import {
9
11
  hasPackageDocumentation,
10
12
  parseTSDocComment,
11
- } from '../../src/utils'
13
+ } from '../../src/utils/tsdoc-parser.js'
12
14
 
13
15
  describe('package-documentation', () => {
14
16
  let tempDir: string
@@ -72,7 +74,7 @@ describe('package-documentation', () => {
72
74
  */`
73
75
  const parsed = parseTSDocComment(comment)
74
76
  expect(parsed.docComment).toBeDefined()
75
- expect(hasPackageDocumentation(parsed.docComment!)).toBe(true)
77
+ expect(hasPackageDocumentation(parsed.docComment)).toBe(true)
76
78
  })
77
79
 
78
80
  it('should return false when @packageDocumentation is missing', () => {
@@ -81,7 +83,7 @@ describe('package-documentation', () => {
81
83
  */`
82
84
  const parsed = parseTSDocComment(comment)
83
85
  expect(parsed.docComment).toBeDefined()
84
- expect(hasPackageDocumentation(parsed.docComment!)).toBe(false)
86
+ expect(hasPackageDocumentation(parsed.docComment)).toBe(false)
85
87
  })
86
88
  })
87
89
 
@@ -108,7 +110,7 @@ export function foo() {}`
108
110
  * This is the main entry point.
109
111
  * @packageDocumentation
110
112
  */`)
111
- expect(hasPackageDocumentation(parsed.docComment!)).toBe(true)
113
+ expect(hasPackageDocumentation(parsed.docComment)).toBe(true)
112
114
  })
113
115
 
114
116
  it('should fail when entry point lacks @packageDocumentation', () => {
@@ -131,7 +133,7 @@ export function foo() {}`
131
133
  const parsed = parseTSDocComment(`/**
132
134
  * This is the main entry point.
133
135
  */`)
134
- expect(hasPackageDocumentation(parsed.docComment!)).toBe(false)
136
+ expect(hasPackageDocumentation(parsed.docComment)).toBe(false)
135
137
  })
136
138
 
137
139
  it('should not require @packageDocumentation for non-entry points', () => {
@@ -0,0 +1,201 @@
1
+ import { RuleTester } from '@typescript-eslint/rule-tester'
2
+ import { describe, it, afterAll } from 'vitest'
3
+ import * as tseslintParser from '@typescript-eslint/parser'
4
+ import { publicOnNonExported } from '../../src/rules/public-on-non-exported'
5
+
6
+ RuleTester.afterAll = afterAll
7
+ RuleTester.describe = describe
8
+ RuleTester.it = it
9
+
10
+ const ruleTester = new RuleTester({
11
+ languageOptions: {
12
+ parser: tseslintParser,
13
+ parserOptions: {
14
+ ecmaVersion: 2022,
15
+ sourceType: 'module',
16
+ },
17
+ },
18
+ })
19
+
20
+ describe('public-on-non-exported', () => {
21
+ ruleTester.run('public-on-non-exported', publicOnNonExported, {
22
+ valid: [
23
+ // Exported function with @public tag
24
+ {
25
+ code: `
26
+ /**
27
+ * A public function.
28
+ * @public
29
+ */
30
+ export function myFunction(): void {}
31
+ `,
32
+ },
33
+ // Exported class with @public tag
34
+ {
35
+ code: `
36
+ /**
37
+ * A public class.
38
+ * @public
39
+ */
40
+ export class MyClass {}
41
+ `,
42
+ },
43
+ // Exported interface with @public tag
44
+ {
45
+ code: `
46
+ /**
47
+ * A public interface.
48
+ * @public
49
+ */
50
+ export interface MyInterface {}
51
+ `,
52
+ },
53
+ // Exported type with @public tag
54
+ {
55
+ code: `
56
+ /**
57
+ * A public type.
58
+ * @public
59
+ */
60
+ export type MyType = string;
61
+ `,
62
+ },
63
+ // Exported via export statement
64
+ {
65
+ code: `
66
+ /**
67
+ * A public function.
68
+ * @public
69
+ */
70
+ function myFunction(): void {}
71
+
72
+ export { myFunction };
73
+ `,
74
+ },
75
+ // Non-exported function without @public tag
76
+ {
77
+ code: `
78
+ /**
79
+ * An internal function.
80
+ * @internal
81
+ */
82
+ function myFunction(): void {}
83
+ `,
84
+ },
85
+ ],
86
+ invalid: [
87
+ // Non-exported function with @public tag
88
+ {
89
+ code: `
90
+ /**
91
+ * A public function.
92
+ * @public
93
+ */
94
+ function myFunction(): void {}
95
+ `,
96
+ errors: [
97
+ {
98
+ messageId: 'publicOnNonExported',
99
+ data: {
100
+ name: 'myFunction',
101
+ },
102
+ },
103
+ ],
104
+ },
105
+ // Non-exported class with @public tag
106
+ {
107
+ code: `
108
+ /**
109
+ * A public class.
110
+ * @public
111
+ */
112
+ class MyClass {}
113
+ `,
114
+ errors: [
115
+ {
116
+ messageId: 'publicOnNonExported',
117
+ data: {
118
+ name: 'MyClass',
119
+ },
120
+ },
121
+ ],
122
+ },
123
+ // Non-exported interface with @public tag
124
+ {
125
+ code: `
126
+ /**
127
+ * A public interface.
128
+ * @public
129
+ */
130
+ interface MyInterface {}
131
+ `,
132
+ errors: [
133
+ {
134
+ messageId: 'publicOnNonExported',
135
+ data: {
136
+ name: 'MyInterface',
137
+ },
138
+ },
139
+ ],
140
+ },
141
+ // Non-exported type with @public tag
142
+ {
143
+ code: `
144
+ /**
145
+ * A public type.
146
+ * @public
147
+ */
148
+ type MyType = string;
149
+ `,
150
+ errors: [
151
+ {
152
+ messageId: 'publicOnNonExported',
153
+ data: {
154
+ name: 'MyType',
155
+ },
156
+ },
157
+ ],
158
+ },
159
+ // Non-exported enum with @public tag
160
+ {
161
+ code: `
162
+ /**
163
+ * A public enum.
164
+ * @public
165
+ */
166
+ enum MyEnum { A, B }
167
+ `,
168
+ errors: [
169
+ {
170
+ messageId: 'publicOnNonExported',
171
+ data: {
172
+ name: 'MyEnum',
173
+ },
174
+ },
175
+ ],
176
+ },
177
+ ],
178
+ })
179
+
180
+ // Test with severity option
181
+ ruleTester.run(
182
+ 'public-on-non-exported with severity=none',
183
+ publicOnNonExported,
184
+ {
185
+ valid: [
186
+ // Should not report when severity is 'none'
187
+ {
188
+ code: `
189
+ /**
190
+ * A public function.
191
+ * @public
192
+ */
193
+ function myFunction(): void {}
194
+ `,
195
+ options: [{ severity: 'none' }],
196
+ },
197
+ ],
198
+ invalid: [],
199
+ },
200
+ )
201
+ })