@api-extractor-tools/eslint-plugin 0.1.0-alpha.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +183 -0
  4. package/api-extractor.json +10 -0
  5. package/dist/configs/index.d.ts +6 -0
  6. package/dist/configs/index.d.ts.map +1 -0
  7. package/dist/configs/index.js +11 -0
  8. package/dist/configs/index.js.map +1 -0
  9. package/dist/configs/recommended.d.ts +31 -0
  10. package/dist/configs/recommended.d.ts.map +1 -0
  11. package/dist/configs/recommended.js +45 -0
  12. package/dist/configs/recommended.js.map +1 -0
  13. package/dist/index.d.ts +74 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +68 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/rules/index.d.ts +14 -0
  18. package/dist/rules/index.d.ts.map +1 -0
  19. package/dist/rules/index.js +20 -0
  20. package/dist/rules/index.js.map +1 -0
  21. package/dist/rules/missing-release-tag.d.ts +8 -0
  22. package/dist/rules/missing-release-tag.d.ts.map +1 -0
  23. package/dist/rules/missing-release-tag.js +148 -0
  24. package/dist/rules/missing-release-tag.js.map +1 -0
  25. package/dist/rules/override-keyword.d.ts +8 -0
  26. package/dist/rules/override-keyword.d.ts.map +1 -0
  27. package/dist/rules/override-keyword.js +106 -0
  28. package/dist/rules/override-keyword.js.map +1 -0
  29. package/dist/rules/package-documentation.d.ts +8 -0
  30. package/dist/rules/package-documentation.d.ts.map +1 -0
  31. package/dist/rules/package-documentation.js +70 -0
  32. package/dist/rules/package-documentation.js.map +1 -0
  33. package/dist/types.d.ts +90 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +19 -0
  36. package/dist/types.js.map +1 -0
  37. package/dist/utils/config-loader.d.ts +47 -0
  38. package/dist/utils/config-loader.d.ts.map +1 -0
  39. package/dist/utils/config-loader.js +163 -0
  40. package/dist/utils/config-loader.js.map +1 -0
  41. package/dist/utils/entry-point.d.ts +56 -0
  42. package/dist/utils/entry-point.d.ts.map +1 -0
  43. package/dist/utils/entry-point.js +198 -0
  44. package/dist/utils/entry-point.js.map +1 -0
  45. package/dist/utils/index.d.ts +8 -0
  46. package/dist/utils/index.d.ts.map +1 -0
  47. package/dist/utils/index.js +21 -0
  48. package/dist/utils/index.js.map +1 -0
  49. package/dist/utils/tsdoc-parser.d.ts +58 -0
  50. package/dist/utils/tsdoc-parser.d.ts.map +1 -0
  51. package/dist/utils/tsdoc-parser.js +137 -0
  52. package/dist/utils/tsdoc-parser.js.map +1 -0
  53. package/package.json +44 -0
  54. package/src/configs/index.ts +6 -0
  55. package/src/configs/recommended.ts +46 -0
  56. package/src/index.ts +111 -0
  57. package/src/rules/index.ts +18 -0
  58. package/src/rules/missing-release-tag.ts +203 -0
  59. package/src/rules/override-keyword.ts +139 -0
  60. package/src/rules/package-documentation.ts +90 -0
  61. package/src/types.ts +104 -0
  62. package/src/utils/config-loader.ts +194 -0
  63. package/src/utils/entry-point.ts +247 -0
  64. package/src/utils/index.ts +17 -0
  65. package/src/utils/tsdoc-parser.ts +163 -0
  66. package/temp/eslint-plugin.api.md +118 -0
  67. package/test/index.test.ts +66 -0
  68. package/test/rules/missing-release-tag.test.ts +184 -0
  69. package/test/rules/override-keyword.test.ts +171 -0
  70. package/test/rules/package-documentation.test.ts +152 -0
  71. package/test/tsconfig.json +11 -0
  72. package/test/utils/config-loader.test.ts +199 -0
  73. package/test/utils/entry-point.test.ts +172 -0
  74. package/test/utils/tsdoc-parser.test.ts +113 -0
  75. package/tsconfig.json +12 -0
  76. package/vitest.config.mts +25 -0
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * ESLint rule for detecting missing release tags on exported symbols.
4
+ * @internal
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.missingReleaseTag = void 0;
8
+ const utils_1 = require("@typescript-eslint/utils");
9
+ const utils_2 = require("../utils");
10
+ const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/mike-north/api-extractor-tools/blob/main/tools/eslint-plugin/docs/rules/${name}.md`);
11
+ exports.missingReleaseTag = createRule({
12
+ name: 'missing-release-tag',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Require exported symbols to have a release tag (@public, @beta, @alpha, or @internal)',
17
+ },
18
+ messages: {
19
+ missingReleaseTag: 'Exported symbol "{{name}}" is missing a release tag. Add @public, @beta, @alpha, or @internal to its TSDoc comment.',
20
+ },
21
+ schema: [
22
+ {
23
+ type: 'object',
24
+ properties: {
25
+ configPath: {
26
+ type: 'string',
27
+ description: 'Path to api-extractor.json configuration file',
28
+ },
29
+ },
30
+ additionalProperties: false,
31
+ },
32
+ ],
33
+ },
34
+ defaultOptions: [{}],
35
+ create(context) {
36
+ const options = context.options[0] ?? {};
37
+ const filename = context.filename;
38
+ const config = (0, utils_2.resolveConfig)(filename, options.configPath);
39
+ const logLevel = (0, utils_2.getMessageLogLevel)(config, 'ae-missing-release-tag');
40
+ // If configured to 'none', disable the rule
41
+ if (logLevel === 'none') {
42
+ return {};
43
+ }
44
+ const sourceCode = context.sourceCode;
45
+ /**
46
+ * Checks if a node has a release tag in its TSDoc comment.
47
+ */
48
+ function hasReleaseTag(node) {
49
+ const commentText = (0, utils_2.getLeadingTSDocComment)(sourceCode, node);
50
+ if (!commentText) {
51
+ return false;
52
+ }
53
+ const parsed = (0, utils_2.parseTSDocComment)(commentText);
54
+ if (parsed.docComment) {
55
+ const tag = (0, utils_2.extractReleaseTag)(parsed.docComment);
56
+ return tag !== undefined;
57
+ }
58
+ return false;
59
+ }
60
+ /**
61
+ * Gets the name of a declaration.
62
+ */
63
+ function getDeclarationName(node) {
64
+ if (node.type === utils_1.AST_NODE_TYPES.VariableDeclaration) {
65
+ const firstDeclarator = node.declarations[0];
66
+ if (firstDeclarator?.id.type === utils_1.AST_NODE_TYPES.Identifier) {
67
+ return firstDeclarator.id.name;
68
+ }
69
+ return '<unknown>';
70
+ }
71
+ if ('id' in node && node.id) {
72
+ return node.id.name;
73
+ }
74
+ return '<anonymous>';
75
+ }
76
+ /**
77
+ * Reports a missing release tag error.
78
+ */
79
+ function reportMissingTag(node, name) {
80
+ context.report({
81
+ node,
82
+ messageId: 'missingReleaseTag',
83
+ data: { name },
84
+ });
85
+ }
86
+ /**
87
+ * Checks if a node is exported.
88
+ */
89
+ function isExported(node) {
90
+ const parent = node.parent;
91
+ // Direct export: export function foo() {}
92
+ if (parent?.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration) {
93
+ return true;
94
+ }
95
+ // Default export: export default function foo() {}
96
+ if (parent?.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration) {
97
+ return true;
98
+ }
99
+ return false;
100
+ }
101
+ /**
102
+ * Checks a declaration node for missing release tag.
103
+ */
104
+ function checkDeclaration(node) {
105
+ if (!isExported(node)) {
106
+ return;
107
+ }
108
+ // For exported declarations, check the export statement for the comment
109
+ const exportNode = node.parent;
110
+ const nodeToCheck = exportNode ?? node;
111
+ if (!hasReleaseTag(nodeToCheck) && !hasReleaseTag(node)) {
112
+ const name = getDeclarationName(node);
113
+ reportMissingTag(node, name);
114
+ }
115
+ }
116
+ return {
117
+ // Check exported function declarations
118
+ FunctionDeclaration(node) {
119
+ checkDeclaration(node);
120
+ },
121
+ // Check exported class declarations
122
+ ClassDeclaration(node) {
123
+ checkDeclaration(node);
124
+ },
125
+ // Check exported interface declarations
126
+ TSInterfaceDeclaration(node) {
127
+ checkDeclaration(node);
128
+ },
129
+ // Check exported type alias declarations
130
+ TSTypeAliasDeclaration(node) {
131
+ checkDeclaration(node);
132
+ },
133
+ // Check exported enum declarations
134
+ TSEnumDeclaration(node) {
135
+ checkDeclaration(node);
136
+ },
137
+ // Check exported variable declarations
138
+ VariableDeclaration(node) {
139
+ checkDeclaration(node);
140
+ },
141
+ // Note: We intentionally don't handle ExportNamedDeclaration with specifiers
142
+ // (e.g., `export { foo }` or `export { foo } from './bar'`) because:
143
+ // - Re-exports should have release tags on the original declaration
144
+ // - Named exports reference declarations that are checked elsewhere
145
+ };
146
+ },
147
+ });
148
+ //# sourceMappingURL=missing-release-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing-release-tag.js","sourceRoot":"","sources":["../../src/rules/missing-release-tag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ESLint rule requiring the TypeScript `override` keyword when `@override` TSDoc tag is used.
3
+ * @internal
4
+ */
5
+ import { ESLintUtils } from '@typescript-eslint/utils';
6
+ import type { OverrideKeywordRuleOptions } from '../types';
7
+ export declare const overrideKeyword: ESLintUtils.RuleModule<"missingOverrideKeyword", [OverrideKeywordRuleOptions], unknown, ESLintUtils.RuleListener>;
8
+ //# sourceMappingURL=override-keyword.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"override-keyword.d.ts","sourceRoot":"","sources":["../../src/rules/override-keyword.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAkB,WAAW,EAAY,MAAM,0BAA0B,CAAA;AAMhF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAS1D,eAAO,MAAM,eAAe,mHAsH1B,CAAA"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * ESLint rule requiring the TypeScript `override` keyword when `@override` TSDoc tag is used.
4
+ * @internal
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.overrideKeyword = void 0;
8
+ const utils_1 = require("@typescript-eslint/utils");
9
+ const utils_2 = require("../utils");
10
+ const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/mike-north/api-extractor-tools/blob/main/tools/eslint-plugin/docs/rules/${name}.md`);
11
+ exports.overrideKeyword = createRule({
12
+ name: 'override-keyword',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Require the TypeScript `override` keyword when the `@override` TSDoc tag is present',
17
+ },
18
+ fixable: 'code',
19
+ messages: {
20
+ missingOverrideKeyword: 'Member "{{name}}" has @override TSDoc tag but is missing the TypeScript `override` keyword.',
21
+ },
22
+ schema: [
23
+ {
24
+ type: 'object',
25
+ properties: {
26
+ configPath: {
27
+ type: 'string',
28
+ description: 'Path to api-extractor.json configuration file',
29
+ },
30
+ },
31
+ additionalProperties: false,
32
+ },
33
+ ],
34
+ },
35
+ defaultOptions: [{}],
36
+ create(context) {
37
+ const sourceCode = context.sourceCode;
38
+ /**
39
+ * Checks if a node has the @override TSDoc tag.
40
+ */
41
+ function nodeHasOverrideTag(node) {
42
+ const commentText = (0, utils_2.getLeadingTSDocComment)(sourceCode, node);
43
+ if (!commentText) {
44
+ return false;
45
+ }
46
+ const parsed = (0, utils_2.parseTSDocComment)(commentText);
47
+ if (parsed.docComment) {
48
+ return (0, utils_2.hasOverrideTag)(parsed.docComment);
49
+ }
50
+ return false;
51
+ }
52
+ /**
53
+ * Checks if a method or property has the override keyword.
54
+ */
55
+ function hasOverrideModifier(node) {
56
+ return node.override === true;
57
+ }
58
+ /**
59
+ * Gets the name of a class member.
60
+ */
61
+ function getMemberName(node) {
62
+ if (node.key.type === utils_1.AST_NODE_TYPES.Identifier) {
63
+ return node.key.name;
64
+ }
65
+ if (node.key.type === utils_1.AST_NODE_TYPES.Literal) {
66
+ return String(node.key.value);
67
+ }
68
+ return '<computed>';
69
+ }
70
+ /**
71
+ * Checks a class member for missing override keyword.
72
+ */
73
+ function checkMember(node) {
74
+ // Skip constructors
75
+ if (node.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
76
+ node.kind === 'constructor') {
77
+ return;
78
+ }
79
+ if (!nodeHasOverrideTag(node)) {
80
+ return;
81
+ }
82
+ if (hasOverrideModifier(node)) {
83
+ return;
84
+ }
85
+ const name = getMemberName(node);
86
+ context.report({
87
+ node,
88
+ messageId: 'missingOverrideKeyword',
89
+ data: { name },
90
+ fix(fixer) {
91
+ // Insert override keyword at the start of the member declaration
92
+ return fixer.insertTextBefore(node, 'override ');
93
+ },
94
+ });
95
+ }
96
+ return {
97
+ MethodDefinition(node) {
98
+ checkMember(node);
99
+ },
100
+ PropertyDefinition(node) {
101
+ checkMember(node);
102
+ },
103
+ };
104
+ },
105
+ });
106
+ //# sourceMappingURL=override-keyword.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"override-keyword.js","sourceRoot":"","sources":["../../src/rules/override-keyword.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ESLint rule requiring @packageDocumentation in package entry point files.
3
+ * @internal
4
+ */
5
+ import { ESLintUtils } from '@typescript-eslint/utils';
6
+ import type { PackageDocumentationRuleOptions } from '../types';
7
+ export declare const packageDocumentation: ESLintUtils.RuleModule<"missingPackageDocumentation", [PackageDocumentationRuleOptions], unknown, ESLintUtils.RuleListener>;
8
+ //# sourceMappingURL=package-documentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-documentation.d.ts","sourceRoot":"","sources":["../../src/rules/package-documentation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAOtD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAA;AAS/D,eAAO,MAAM,oBAAoB,6HAoE/B,CAAA"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /**
3
+ * ESLint rule requiring @packageDocumentation in package entry point files.
4
+ * @internal
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.packageDocumentation = void 0;
8
+ const utils_1 = require("@typescript-eslint/utils");
9
+ const utils_2 = require("../utils");
10
+ const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/mike-north/api-extractor-tools/blob/main/tools/eslint-plugin/docs/rules/${name}.md`);
11
+ exports.packageDocumentation = createRule({
12
+ name: 'package-documentation',
13
+ meta: {
14
+ type: 'suggestion',
15
+ docs: {
16
+ description: 'Require @packageDocumentation tag in package entry point files',
17
+ },
18
+ messages: {
19
+ missingPackageDocumentation: 'Entry point file is missing a @packageDocumentation comment. Add a TSDoc comment with @packageDocumentation at the top of the file.',
20
+ },
21
+ schema: [
22
+ {
23
+ type: 'object',
24
+ properties: {
25
+ configPath: {
26
+ type: 'string',
27
+ description: 'Path to api-extractor.json configuration file',
28
+ },
29
+ },
30
+ additionalProperties: false,
31
+ },
32
+ ],
33
+ },
34
+ defaultOptions: [{}],
35
+ create(context) {
36
+ const filename = context.filename;
37
+ const sourceCode = context.sourceCode;
38
+ // Find package.json
39
+ const pkgPath = (0, utils_2.findPackageJson)(filename);
40
+ if (!pkgPath) {
41
+ // No package.json found, nothing to check
42
+ return {};
43
+ }
44
+ // Check if this file is an entry point
45
+ if (!(0, utils_2.isEntryPoint)(filename, pkgPath)) {
46
+ // Not an entry point, skip
47
+ return {};
48
+ }
49
+ return {
50
+ Program(node) {
51
+ // Look for @packageDocumentation in any TSDoc comment in the file
52
+ const tsdocComments = (0, utils_2.findAllTSDocComments)(sourceCode);
53
+ for (const { parsed } of tsdocComments) {
54
+ if (parsed.docComment && (0, utils_2.hasPackageDocumentation)(parsed.docComment)) {
55
+ // Found @packageDocumentation, all good
56
+ return;
57
+ }
58
+ }
59
+ // No @packageDocumentation found
60
+ // Report at the first line of the file
61
+ context.report({
62
+ node,
63
+ loc: { line: 1, column: 0 },
64
+ messageId: 'missingPackageDocumentation',
65
+ });
66
+ },
67
+ };
68
+ },
69
+ });
70
+ //# sourceMappingURL=package-documentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-documentation.js","sourceRoot":"","sources":["../../src/rules/package-documentation.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,oDAAsD;AACtD,oCAKiB;AAGjB,MAAM,UAAU,GAAG,mBAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CACP,8FAA8F,IAAI,KAAK,CAC1G,CAAA;AAIY,QAAA,oBAAoB,GAAG,UAAU,CAG5C;IACA,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,gEAAgE;SACnE;QACD,QAAQ,EAAE;YACR,2BAA2B,EACzB,qIAAqI;SACxI;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,+CAA+C;qBAC7D;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,cAAc,EAAE,CAAC,EAAE,CAAC;IACpB,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;QACjC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA;QAErC,oBAAoB;QACpB,MAAM,OAAO,GAAG,IAAA,uBAAe,EAAC,QAAQ,CAAC,CAAA;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,0CAA0C;YAC1C,OAAO,EAAE,CAAA;QACX,CAAC;QAED,uCAAuC;QACvC,IAAI,CAAC,IAAA,oBAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;YACrC,2BAA2B;YAC3B,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO;YACL,OAAO,CAAC,IAAI;gBACV,kEAAkE;gBAClE,MAAM,aAAa,GAAG,IAAA,4BAAoB,EAAC,UAAU,CAAC,CAAA;gBAEtD,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;oBACvC,IAAI,MAAM,CAAC,UAAU,IAAI,IAAA,+BAAuB,EAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;wBACpE,wCAAwC;wBACxC,OAAM;oBACR,CAAC;gBACH,CAAC;gBAED,iCAAiC;gBACjC,uCAAuC;gBACvC,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI;oBACJ,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;oBAC3B,SAAS,EAAE,6BAA6B;iBACzC,CAAC,CAAA;YACJ,CAAC;SACF,CAAA;IACH,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Types for the API Extractor ESLint plugin.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ /**
7
+ * Log levels supported by API Extractor message configuration.
8
+ * @public
9
+ */
10
+ export type ApiExtractorLogLevel = 'error' | 'warning' | 'none';
11
+ /**
12
+ * Configuration for a single message type in API Extractor.
13
+ * @public
14
+ */
15
+ export interface MessageConfig {
16
+ logLevel: ApiExtractorLogLevel;
17
+ addToApiReportFile?: boolean;
18
+ }
19
+ /**
20
+ * The messages configuration section from api-extractor.json.
21
+ * @public
22
+ */
23
+ export interface ApiExtractorMessagesConfig {
24
+ compilerMessageReporting?: {
25
+ default?: MessageConfig;
26
+ [messageId: string]: MessageConfig | undefined;
27
+ };
28
+ extractorMessageReporting?: {
29
+ default?: MessageConfig;
30
+ 'ae-missing-release-tag'?: MessageConfig;
31
+ 'ae-forgotten-export'?: MessageConfig;
32
+ 'ae-internal-missing-underscore'?: MessageConfig;
33
+ 'ae-incompatible-release-tags'?: MessageConfig;
34
+ [messageId: string]: MessageConfig | undefined;
35
+ };
36
+ tsdocMessageReporting?: {
37
+ default?: MessageConfig;
38
+ [messageId: string]: MessageConfig | undefined;
39
+ };
40
+ }
41
+ /**
42
+ * Partial representation of api-extractor.json relevant for this plugin.
43
+ * @public
44
+ */
45
+ export interface ApiExtractorConfig {
46
+ extends?: string;
47
+ mainEntryPointFilePath?: string;
48
+ messages?: ApiExtractorMessagesConfig;
49
+ }
50
+ /**
51
+ * Release tags recognized by API Extractor.
52
+ * @public
53
+ */
54
+ export type ReleaseTag = 'public' | 'beta' | 'alpha' | 'internal';
55
+ /**
56
+ * All valid release tags.
57
+ * @public
58
+ */
59
+ export declare const RELEASE_TAGS: readonly ReleaseTag[];
60
+ /**
61
+ * Options for the missing-release-tag rule.
62
+ * @public
63
+ */
64
+ export interface MissingReleaseTagRuleOptions {
65
+ configPath?: string;
66
+ }
67
+ /**
68
+ * Options for the override-keyword rule.
69
+ * @public
70
+ */
71
+ export interface OverrideKeywordRuleOptions {
72
+ configPath?: string;
73
+ }
74
+ /**
75
+ * Options for the package-documentation rule.
76
+ * @public
77
+ */
78
+ export interface PackageDocumentationRuleOptions {
79
+ configPath?: string;
80
+ }
81
+ /**
82
+ * Resolved entry points from package.json.
83
+ * @public
84
+ */
85
+ export interface ResolvedEntryPoints {
86
+ main?: string;
87
+ types?: string;
88
+ exports: string[];
89
+ }
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAE/D;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,oBAAoB,CAAA;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,wBAAwB,CAAC,EAAE;QACzB,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;KAC/C,CAAA;IACD,yBAAyB,CAAC,EAAE;QAC1B,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,wBAAwB,CAAC,EAAE,aAAa,CAAA;QACxC,qBAAqB,CAAC,EAAE,aAAa,CAAA;QACrC,gCAAgC,CAAC,EAAE,aAAa,CAAA;QAChD,8BAA8B,CAAC,EAAE,aAAa,CAAA;QAC9C,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;KAC/C,CAAA;IACD,qBAAqB,CAAC,EAAE;QACtB,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;KAC/C,CAAA;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,EAAE,0BAA0B,CAAA;CACtC;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAA;AAEjE;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAKpC,CAAA;AAEV;;;GAGG;AACH,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * Types for the API Extractor ESLint plugin.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.RELEASE_TAGS = void 0;
9
+ /**
10
+ * All valid release tags.
11
+ * @public
12
+ */
13
+ exports.RELEASE_TAGS = [
14
+ 'public',
15
+ 'beta',
16
+ 'alpha',
17
+ 'internal',
18
+ ];
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAwDH;;;GAGG;AACU,QAAA,YAAY,GAA0B;IACjD,QAAQ;IACR,MAAM;IACN,OAAO;IACP,UAAU;CACF,CAAA"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Utilities for discovering and loading API Extractor configuration.
3
+ * @internal
4
+ */
5
+ import type { ApiExtractorConfig, ApiExtractorLogLevel } from '../types';
6
+ /**
7
+ * Searches upward from the given directory to find api-extractor.json.
8
+ *
9
+ * @param startDir - Directory to start searching from
10
+ * @returns Path to api-extractor.json if found, undefined otherwise
11
+ */
12
+ export declare function findApiExtractorConfig(startDir: string): string | undefined;
13
+ /**
14
+ * Loads and parses an api-extractor.json file.
15
+ *
16
+ * @param configPath - Path to the api-extractor.json file
17
+ * @returns Parsed configuration or null if file cannot be read
18
+ */
19
+ export declare function loadApiExtractorConfig(configPath: string): ApiExtractorConfig | null;
20
+ /**
21
+ * Gets the log level for a specific message ID from the configuration.
22
+ *
23
+ * @param config - API Extractor configuration
24
+ * @param messageId - The message ID (e.g., 'ae-missing-release-tag')
25
+ * @returns The configured log level, or 'warning' as default
26
+ */
27
+ export declare function getMessageLogLevel(config: ApiExtractorConfig | null, messageId: string): ApiExtractorLogLevel;
28
+ /**
29
+ * Resolves configuration for a file, using auto-discovery or explicit path.
30
+ *
31
+ * @param filePath - Path to the file being linted
32
+ * @param explicitConfigPath - Optional explicit path to api-extractor.json
33
+ * @returns The resolved configuration or null
34
+ */
35
+ export declare function resolveConfig(filePath: string, explicitConfigPath?: string): ApiExtractorConfig | null;
36
+ /**
37
+ * Maps API Extractor log level to ESLint severity.
38
+ *
39
+ * @param logLevel - API Extractor log level
40
+ * @returns ESLint severity (0 = off, 1 = warn, 2 = error)
41
+ */
42
+ export declare function logLevelToSeverity(logLevel: ApiExtractorLogLevel): 0 | 1 | 2;
43
+ /**
44
+ * Clears the configuration cache. Useful for testing.
45
+ */
46
+ export declare function clearConfigCache(): void;
47
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,UAAU,CAAA;AAiBjB;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAa3E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GACjB,kBAAkB,GAAG,IAAI,CAkC3B;AA6BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,kBAAkB,GAAG,IAAI,EACjC,SAAS,EAAE,MAAM,GAChB,oBAAoB,CAgBtB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,kBAAkB,GAAG,IAAI,CAW3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAS5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}