@definitelytyped/eslint-plugin 0.0.166-next.4

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 (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/configs/all.d.ts +2 -0
  4. package/dist/configs/all.js +152 -0
  5. package/dist/configs/all.js.map +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.js +10 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/rules/dt-header.d.ts +2 -0
  10. package/dist/rules/dt-header.js +62 -0
  11. package/dist/rules/dt-header.js.map +1 -0
  12. package/dist/rules/export-just-namespace.d.ts +2 -0
  13. package/dist/rules/export-just-namespace.js +70 -0
  14. package/dist/rules/export-just-namespace.js.map +1 -0
  15. package/dist/rules/index.d.ts +38 -0
  16. package/dist/rules/index.js +61 -0
  17. package/dist/rules/index.js.map +1 -0
  18. package/dist/rules/no-any-union.d.ts +4 -0
  19. package/dist/rules/no-any-union.js +34 -0
  20. package/dist/rules/no-any-union.js.map +1 -0
  21. package/dist/rules/no-bad-reference.d.ts +2 -0
  22. package/dist/rules/no-bad-reference.js +55 -0
  23. package/dist/rules/no-bad-reference.js.map +1 -0
  24. package/dist/rules/no-const-enum.d.ts +4 -0
  25. package/dist/rules/no-const-enum.js +30 -0
  26. package/dist/rules/no-const-enum.js.map +1 -0
  27. package/dist/rules/no-dead-reference.d.ts +2 -0
  28. package/dist/rules/no-dead-reference.js +44 -0
  29. package/dist/rules/no-dead-reference.js.map +1 -0
  30. package/dist/rules/no-declare-current-package.d.ts +4 -0
  31. package/dist/rules/no-declare-current-package.js +43 -0
  32. package/dist/rules/no-declare-current-package.js.map +1 -0
  33. package/dist/rules/no-import-default-of-export-equals.d.ts +4 -0
  34. package/dist/rules/no-import-default-of-export-equals.js +87 -0
  35. package/dist/rules/no-import-default-of-export-equals.js.map +1 -0
  36. package/dist/rules/no-outside-dependencies.d.ts +2 -0
  37. package/dist/rules/no-outside-dependencies.js +41 -0
  38. package/dist/rules/no-outside-dependencies.js.map +1 -0
  39. package/dist/rules/no-self-import.d.ts +4 -0
  40. package/dist/rules/no-self-import.js +38 -0
  41. package/dist/rules/no-self-import.js.map +1 -0
  42. package/dist/rules/no-single-element-tuple-type.d.ts +5 -0
  43. package/dist/rules/no-single-element-tuple-type.js +30 -0
  44. package/dist/rules/no-single-element-tuple-type.js.map +1 -0
  45. package/dist/rules/no-unnecessary-generics.d.ts +8 -0
  46. package/dist/rules/no-unnecessary-generics.js +135 -0
  47. package/dist/rules/no-unnecessary-generics.js.map +1 -0
  48. package/dist/rules/no-useless-files.d.ts +2 -0
  49. package/dist/rules/no-useless-files.js +53 -0
  50. package/dist/rules/no-useless-files.js.map +1 -0
  51. package/dist/rules/prefer-declare-function.d.ts +5 -0
  52. package/dist/rules/prefer-declare-function.js +35 -0
  53. package/dist/rules/prefer-declare-function.js.map +1 -0
  54. package/dist/rules/redundant-undefined.d.ts +4 -0
  55. package/dist/rules/redundant-undefined.js +53 -0
  56. package/dist/rules/redundant-undefined.js.map +1 -0
  57. package/dist/rules/trim-file.d.ts +2 -0
  58. package/dist/rules/trim-file.js +43 -0
  59. package/dist/rules/trim-file.js.map +1 -0
  60. package/dist/util.d.ts +4 -0
  61. package/dist/util.js +38 -0
  62. package/dist/util.js.map +1 -0
  63. package/docs/rules/dt-header.md +88 -0
  64. package/docs/rules/export-just-namespace.md +29 -0
  65. package/docs/rules/no-any-union.md +27 -0
  66. package/docs/rules/no-bad-reference.md +28 -0
  67. package/docs/rules/no-const-enum.md +16 -0
  68. package/docs/rules/no-dead-reference.md +17 -0
  69. package/docs/rules/no-declare-current-package.md +35 -0
  70. package/docs/rules/no-import-default-of-export-equals.md +22 -0
  71. package/docs/rules/no-outside-dependencies.md +23 -0
  72. package/docs/rules/no-self-import.md +27 -0
  73. package/docs/rules/no-single-element-tuple-type.md +15 -0
  74. package/docs/rules/no-unnecessary-generics.md +69 -0
  75. package/docs/rules/no-useless-files.md +14 -0
  76. package/docs/rules/prefer-declare-function.md +15 -0
  77. package/docs/rules/redundant-undefined.md +15 -0
  78. package/docs/rules/trim-file.md +17 -0
  79. package/package.json +45 -0
  80. package/src/configs/all.ts +151 -0
  81. package/src/index.ts +6 -0
  82. package/src/rules/dt-header.ts +74 -0
  83. package/src/rules/export-just-namespace.ts +83 -0
  84. package/src/rules/index.ts +35 -0
  85. package/src/rules/no-any-union.ts +34 -0
  86. package/src/rules/no-bad-reference.ts +62 -0
  87. package/src/rules/no-const-enum.ts +30 -0
  88. package/src/rules/no-dead-reference.ts +46 -0
  89. package/src/rules/no-declare-current-package.ts +45 -0
  90. package/src/rules/no-import-default-of-export-equals.ts +68 -0
  91. package/src/rules/no-outside-dependencies.ts +42 -0
  92. package/src/rules/no-self-import.ts +40 -0
  93. package/src/rules/no-single-element-tuple-type.ts +31 -0
  94. package/src/rules/no-unnecessary-generics.ts +126 -0
  95. package/src/rules/no-useless-files.ts +58 -0
  96. package/src/rules/prefer-declare-function.ts +37 -0
  97. package/src/rules/redundant-undefined.ts +62 -0
  98. package/src/rules/trim-file.ts +45 -0
  99. package/src/util.ts +41 -0
  100. package/test/dt-header.test.ts +189 -0
  101. package/test/export-just-namespace.test.ts +70 -0
  102. package/test/no-any-union.test.ts +22 -0
  103. package/test/no-bad-reference.test.ts +66 -0
  104. package/test/no-const-enum.test.ts +22 -0
  105. package/test/no-dead-reference.test.ts +66 -0
  106. package/test/no-declare-current-package.test.ts +61 -0
  107. package/test/no-import-default-of-export-equals.test.ts +49 -0
  108. package/test/no-self-import.test.ts +47 -0
  109. package/test/no-single-element-tuple-type.test.ts +28 -0
  110. package/test/no-unnecessary-generics.test.ts +152 -0
  111. package/test/no-useless-files.test.ts +42 -0
  112. package/test/prefer-declare-function.test.ts +66 -0
  113. package/test/redundant-undefined.test.ts +39 -0
  114. package/test/trim-file.test.ts +46 -0
  115. package/test/tsconfig.json +10 -0
  116. package/test/tsconfig.no-declare-current-package.json +11 -0
  117. package/test/tsconfig.no-declare-current-package2.json +11 -0
  118. package/test/tsconfig.no-import-default-of-export-equals.json +11 -0
  119. package/test/tsconfig.no-self-import.json +7 -0
  120. package/tsconfig.json +9 -0
  121. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,151 @@
1
+ import { rules } from "../rules/index.js";
2
+ import { Linter } from "eslint";
3
+
4
+ export const all: Linter.BaseConfig = {
5
+ plugins: ["@definitelytyped", "@typescript-eslint", "jsdoc"],
6
+ settings: {
7
+ jsdoc: {
8
+ tagNamePreference: {
9
+ argument: "argument",
10
+ exception: "exception",
11
+ function: "function",
12
+ method: "method",
13
+ param: "param",
14
+ return: "return",
15
+ returns: "returns",
16
+ },
17
+ },
18
+ },
19
+ rules: {
20
+ "jsdoc/check-tag-names": [
21
+ "error",
22
+ {
23
+ // TODO: Some (but not all) of these tags should likely be removed from this list.
24
+ // Additionally, some may need to be contributed to eslint-plugin-jsdoc.
25
+ definedTags: [
26
+ "addVersion",
27
+ "also",
28
+ "api",
29
+ "author",
30
+ "beta",
31
+ "brief",
32
+ "category",
33
+ "cfg",
34
+ "chainable",
35
+ "check",
36
+ "checkReturnValue",
37
+ "classDescription",
38
+ "condparamprivilege",
39
+ "constraint",
40
+ "credits",
41
+ "declaration",
42
+ "defApiFeature",
43
+ "defaultValue",
44
+ "detail",
45
+ "end",
46
+ "eventproperty",
47
+ "experimental",
48
+ "export",
49
+ "expose",
50
+ "extendscript",
51
+ "factory",
52
+ "field",
53
+ "final",
54
+ "fixme",
55
+ "fluent",
56
+ "for",
57
+ "governance",
58
+ "header",
59
+ "hidden-property",
60
+ "hidden",
61
+ "id",
62
+ "jsx",
63
+ "jsxImportSource",
64
+ "label",
65
+ "language",
66
+ "legacy",
67
+ "link",
68
+ "listen",
69
+ "locus",
70
+ "methodOf",
71
+ "minVersion",
72
+ "ngdoc",
73
+ "nonstandard",
74
+ "note",
75
+ "npm",
76
+ "observable",
77
+ "option",
78
+ "optionobject",
79
+ "options",
80
+ "packageDocumentation",
81
+ "param",
82
+ "parent",
83
+ "platform",
84
+ "plugin",
85
+ "preserve",
86
+ "privateRemarks",
87
+ "privilegeLevel",
88
+ "privilegeName",
89
+ "proposed",
90
+ "range",
91
+ "readOnly",
92
+ "related",
93
+ "remark",
94
+ "remarks",
95
+ "required",
96
+ "requires",
97
+ "restriction",
98
+ "returnType",
99
+ "section",
100
+ "see",
101
+ "since",
102
+ "const",
103
+ "singleton",
104
+ "source",
105
+ "struct",
106
+ "suppress",
107
+ "targetfolder",
108
+ "enum",
109
+ "title",
110
+ "record",
111
+ "title",
112
+ "TODO",
113
+ "trigger",
114
+ "triggers",
115
+ "typeparam",
116
+ "typeParam",
117
+ "unsupported",
118
+ "url",
119
+ "usage",
120
+ "warn",
121
+ "warning",
122
+ "version",
123
+ ],
124
+ typed: true,
125
+ },
126
+ ],
127
+ },
128
+
129
+ overrides: [
130
+ {
131
+ files: ["*.cts", "*.mts", "*.ts", "*.tsx"],
132
+ parser: "@typescript-eslint/parser",
133
+ parserOptions: {
134
+ project: true,
135
+ warnOnUnsupportedTypeScriptVersion: false,
136
+ },
137
+ rules: {
138
+ ...Object.fromEntries(Object.keys(rules).map((name) => [`@definitelytyped/${name}`, "error"])),
139
+ "@typescript-eslint/ban-ts-comment": [
140
+ "error",
141
+ {
142
+ "ts-expect-error": false, // Used in tests.
143
+ "ts-ignore": "allow-with-description",
144
+ "ts-nocheck": true,
145
+ "ts-check": false,
146
+ },
147
+ ],
148
+ },
149
+ },
150
+ ],
151
+ };
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { all } from "./configs/all.js";
2
+ export { rules } from "./rules/index.js";
3
+
4
+ export const configs = {
5
+ all,
6
+ };
@@ -0,0 +1,74 @@
1
+ import { renderExpected, validate } from "@definitelytyped/header-parser";
2
+ import { createRule, isMainFile } from "../util";
3
+
4
+ type MessageId =
5
+ | "definitionsBy"
6
+ | "minimumTypeScriptVersion"
7
+ | "parseError"
8
+ | "typeDefinitionsFor"
9
+ | "typescriptVersion";
10
+
11
+ const rule = createRule({
12
+ name: "dt-header",
13
+ defaultOptions: [],
14
+ meta: {
15
+ type: "problem",
16
+ docs: {
17
+ description: "Ensure consistency of DefinitelyTyped headers.",
18
+ recommended: "error",
19
+ },
20
+ messages: {
21
+ definitionsBy: "Author name should be your name, not the default.",
22
+ minimumTypeScriptVersion: "TypeScript version should be specified under header in `index.d.ts`.",
23
+ parseError: "Error parsing header. Expected: {{expected}}",
24
+ typeDefinitionsFor: "Header should only be in `index.d.ts` of the root.",
25
+ typescriptVersion: "Minimum TypeScript version should be specified under header in `index.d.ts`.",
26
+ },
27
+ schema: [],
28
+ },
29
+ create(context) {
30
+ const sourceCode = context.getSourceCode();
31
+ const { lines, text } = sourceCode;
32
+
33
+ const lookFor = (search: string, messageId: MessageId) => {
34
+ for (let i = 0; i < lines.length; i += 1) {
35
+ if (lines[i].startsWith(search)) {
36
+ context.report({
37
+ loc: {
38
+ end: { line: i + 1, column: search.length },
39
+ start: { line: i + 1, column: 0 },
40
+ },
41
+ messageId,
42
+ });
43
+ }
44
+ }
45
+ };
46
+
47
+ if (!isMainFile(context.getFilename(), /*allowNested*/ true)) {
48
+ lookFor("// Type definitions for", "typeDefinitionsFor");
49
+ lookFor("// TypeScript Version", "typescriptVersion");
50
+ lookFor("// Minimum TypeScript Version", "minimumTypeScriptVersion");
51
+ return {};
52
+ }
53
+
54
+ lookFor("// Definitions by: My Self", "definitionsBy");
55
+
56
+ const error = validate(text);
57
+ if (error) {
58
+ context.report({
59
+ data: {
60
+ expected: renderExpected(error.expected),
61
+ },
62
+ loc: {
63
+ column: error.column,
64
+ line: error.line,
65
+ },
66
+ messageId: "parseError",
67
+ });
68
+ }
69
+
70
+ return {};
71
+ },
72
+ });
73
+
74
+ export = rule;
@@ -0,0 +1,83 @@
1
+ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils";
2
+ import { createRule } from "../util";
3
+
4
+ interface ExportAssignmentWithIdentifier extends TSESTree.TSExportAssignment {
5
+ expression: TSESTree.Identifier;
6
+ }
7
+
8
+ const rule = createRule({
9
+ name: "export-just-namespace",
10
+ defaultOptions: [],
11
+ meta: {
12
+ type: "problem",
13
+ docs: {
14
+ description:
15
+ "Forbids `export = foo` where `foo` is a namespace and isn't merged with a function/class/type/interface.",
16
+ recommended: "error",
17
+ },
18
+ messages: {
19
+ useTheBody: "Instead of `export =`-ing a namespace, use the body of the namespace as the module body.",
20
+ },
21
+ schema: [],
22
+ },
23
+ create(context) {
24
+ const ast = context.getSourceCode().ast;
25
+
26
+ const exportEqualsNode = ast.body.find(isExportEqualsWithIdentifier);
27
+ if (!exportEqualsNode) {
28
+ return {};
29
+ }
30
+
31
+ if (isJustNamespace(ast.body, exportEqualsNode.expression.name)) {
32
+ context.report({
33
+ messageId: "useTheBody",
34
+ node: exportEqualsNode,
35
+ });
36
+ }
37
+
38
+ return {};
39
+ },
40
+ });
41
+
42
+ /**
43
+ * @returns Where there is a namespace but there are no functions/classes/etc. with the same name.
44
+ */
45
+ function isJustNamespace(statements: TSESTree.ProgramStatement[], exportEqualsName: string): boolean {
46
+ let anyNamespace = false;
47
+
48
+ for (const statement of statements) {
49
+ switch (statement.type) {
50
+ case AST_NODE_TYPES.TSModuleDeclaration:
51
+ anyNamespace ||= nameMatches(statement.id);
52
+ break;
53
+ case AST_NODE_TYPES.VariableDeclaration:
54
+ if (statement.declarations.some((d) => nameMatches(d.id))) {
55
+ // OK. It's merged with a variable.
56
+ return false;
57
+ }
58
+ break;
59
+ case AST_NODE_TYPES.ClassDeclaration:
60
+ case AST_NODE_TYPES.FunctionDeclaration:
61
+ case AST_NODE_TYPES.TSDeclareFunction:
62
+ case AST_NODE_TYPES.TSTypeAliasDeclaration:
63
+ case AST_NODE_TYPES.TSInterfaceDeclaration:
64
+ if (nameMatches(statement.id)) {
65
+ // OK. It's merged with a function/class/type/interface.
66
+ return false;
67
+ }
68
+ break;
69
+ }
70
+ }
71
+
72
+ return anyNamespace;
73
+
74
+ function nameMatches(nameNode: TSESTree.Node | undefined | null): boolean {
75
+ return !!nameNode && nameNode.type === AST_NODE_TYPES.Identifier && nameNode.name === exportEqualsName;
76
+ }
77
+ }
78
+
79
+ function isExportEqualsWithIdentifier(node: TSESTree.Node): node is ExportAssignmentWithIdentifier {
80
+ return node.type === AST_NODE_TYPES.TSExportAssignment && node.expression.type === AST_NODE_TYPES.Identifier;
81
+ }
82
+
83
+ export = rule;
@@ -0,0 +1,35 @@
1
+ import * as dtHeader from "./dt-header";
2
+ import * as exportJustNamespace from "./export-just-namespace";
3
+ import * as noAnyUnion from "./no-any-union";
4
+ import * as noBadReference from "./no-bad-reference";
5
+ import * as noConstEnum from "./no-const-enum";
6
+ import * as noDeadReference from "./no-dead-reference";
7
+ import * as noDeclareCurrentPackage from "./no-declare-current-package";
8
+ import * as noImportDefaultOfExportEquals from "./no-import-default-of-export-equals";
9
+ import * as noOutsideDependencies from "./no-outside-dependencies";
10
+ import * as noSelfImport from "./no-self-import";
11
+ import * as noSingleElementTupleType from "./no-single-element-tuple-type";
12
+ import * as noUnnecessaryGenerics from "./no-unnecessary-generics";
13
+ import * as noUselessFiles from "./no-useless-files";
14
+ import * as preferDeclareFunction from "./prefer-declare-function";
15
+ import * as redundantUndefined from "./redundant-undefined";
16
+ import * as trimFile from "./trim-file";
17
+
18
+ export const rules = {
19
+ "dt-header": dtHeader,
20
+ "export-just-namespace": exportJustNamespace,
21
+ "no-any-union": noAnyUnion,
22
+ "no-bad-reference": noBadReference,
23
+ "no-const-enum": noConstEnum,
24
+ "no-dead-reference": noDeadReference,
25
+ "no-declare-current-package": noDeclareCurrentPackage,
26
+ "no-import-default-of-export-equals": noImportDefaultOfExportEquals,
27
+ "no-outside-dependencies": noOutsideDependencies,
28
+ "no-self-import": noSelfImport,
29
+ "no-single-element-tuple-type": noSingleElementTupleType,
30
+ "no-unnecessary-generics": noUnnecessaryGenerics,
31
+ "no-useless-files": noUselessFiles,
32
+ "prefer-declare-function": preferDeclareFunction,
33
+ "redundant-undefined": redundantUndefined,
34
+ "trim-file": trimFile,
35
+ };
@@ -0,0 +1,34 @@
1
+ import { createRule } from "../util";
2
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
+
4
+ const rule = createRule({
5
+ name: "no-any-union",
6
+ defaultOptions: [],
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description: "Forbid a union to contain `any`",
11
+ recommended: "error",
12
+ },
13
+ messages: {
14
+ anyUnion: "Including `any` in a union will override all other members of the union.",
15
+ },
16
+ schema: [],
17
+ },
18
+ create(context) {
19
+ return {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ TSUnionType(node) {
22
+ const hasAnyType = node.types.some((t) => t.type === AST_NODE_TYPES.TSAnyKeyword);
23
+ if (hasAnyType) {
24
+ context.report({
25
+ messageId: "anyUnion",
26
+ node,
27
+ });
28
+ }
29
+ },
30
+ };
31
+ },
32
+ });
33
+
34
+ export = rule;
@@ -0,0 +1,62 @@
1
+ import { TSESTree } from "@typescript-eslint/utils";
2
+ import { createRule } from "../util";
3
+
4
+ type MessageId = "referencePathPackage" | "referencePathTest";
5
+
6
+ const rule = createRule({
7
+ name: "no-bad-reference",
8
+ defaultOptions: [],
9
+ meta: {
10
+ type: "problem",
11
+ docs: {
12
+ description: `Forbids <reference path="../etc"/> in any file, and forbid <reference path> in test files.`,
13
+ recommended: "error",
14
+ },
15
+ messages: {
16
+ referencePathPackage:
17
+ "Don't use <reference path> to reference another package. Use an import or <reference types> instead.",
18
+ referencePathTest:
19
+ "Don't use <reference path> in test files. Use <reference types> or include the file in 'tsconfig.json'.",
20
+ },
21
+ schema: [],
22
+ },
23
+ create(context) {
24
+ const { comments } = context.getSourceCode().ast;
25
+ const isDeclarationFile = context.getFilename().endsWith(".d.ts");
26
+
27
+ for (const comment of comments) {
28
+ const referenceMatch = comment.value.match(/<reference\s+path\s*=\s*"(.+)"\s*\/>/)?.[1];
29
+ if (!referenceMatch) {
30
+ continue;
31
+ }
32
+
33
+ if (isDeclarationFile) {
34
+ if (referenceMatch.startsWith("..")) {
35
+ report(comment, "referencePathPackage");
36
+ }
37
+ } else {
38
+ report(comment, "referencePathTest");
39
+ }
40
+ }
41
+
42
+ return {};
43
+
44
+ function report(comment: TSESTree.Comment, messageId: MessageId) {
45
+ context.report({
46
+ loc: {
47
+ end: {
48
+ column: comment.value.lastIndexOf(`"`),
49
+ line: comment.loc.end.line,
50
+ },
51
+ start: {
52
+ column: comment.value.indexOf(`"`) + 1,
53
+ line: comment.loc.start.line,
54
+ },
55
+ },
56
+ messageId,
57
+ });
58
+ }
59
+ },
60
+ });
61
+
62
+ export = rule;
@@ -0,0 +1,30 @@
1
+ import { createRule } from "../util";
2
+
3
+ const rule = createRule({
4
+ name: "no-const-enum",
5
+ defaultOptions: [],
6
+ meta: {
7
+ type: "problem",
8
+ docs: {
9
+ description: "Forbid `const enum`",
10
+ recommended: "error",
11
+ },
12
+ messages: {
13
+ constEnum: "Use of `const enum` is forbidden.",
14
+ },
15
+ schema: [],
16
+ },
17
+ create(context) {
18
+ return {
19
+ // eslint-disable-next-line @typescript-eslint/naming-convention
20
+ "TSEnumDeclaration[const]"(node) {
21
+ context.report({
22
+ messageId: "constEnum",
23
+ node,
24
+ });
25
+ },
26
+ };
27
+ },
28
+ });
29
+
30
+ export = rule;
@@ -0,0 +1,46 @@
1
+ import { createRule } from "../util";
2
+
3
+ const rule = createRule({
4
+ name: "no-dead-reference",
5
+ defaultOptions: [],
6
+ meta: {
7
+ type: "problem",
8
+ docs: {
9
+ description: "Ensures that all `/// <reference>` comments go at the top of the file.",
10
+ recommended: "error",
11
+ },
12
+ messages: {
13
+ referenceAtTop: "`/// <reference>` directive must be at top of file to take effect.",
14
+ },
15
+ schema: [],
16
+ },
17
+ create(context) {
18
+ const source = context.getSourceCode();
19
+ if (source.ast.body.length) {
20
+ // 'm' flag makes it multiline, so `^` matches the beginning of any line.
21
+ // 'g' flag lets us set rgx.lastIndex
22
+ const rgx = /^\s*(\/\/\/ <reference)/gm;
23
+
24
+ // Start search at the first statement. (`/// <reference>` before that is OK.)
25
+ rgx.lastIndex = source.ast.body[0].range?.[0] ?? 0;
26
+
27
+ // eslint-disable-next-line no-constant-condition
28
+ while (true) {
29
+ const match = rgx.exec(source.text);
30
+ if (match === null) {
31
+ break;
32
+ }
33
+
34
+ const length = match[1].length;
35
+ const start = match.index + match[0].length - length;
36
+ context.report({
37
+ messageId: "referenceAtTop",
38
+ loc: source.getLocFromIndex(start),
39
+ });
40
+ }
41
+ }
42
+ return {};
43
+ },
44
+ });
45
+
46
+ export = rule;
@@ -0,0 +1,45 @@
1
+ import { getCommonDirectoryName, createRule } from "../util";
2
+ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
3
+ const rule = createRule({
4
+ name: "no-declare-current-package",
5
+ defaultOptions: [],
6
+ meta: {
7
+ type: "problem",
8
+ docs: {
9
+ description: "Don't use an ambient module declaration of the current package; use a normal module.",
10
+ recommended: "error",
11
+ },
12
+ messages: {
13
+ noDeclareCurrentPackage:
14
+ `Instead of declaring a module with \`declare module "{{ text }}"\`, ` +
15
+ `write its contents in directly in {{ preferred }}.`,
16
+ },
17
+ schema: [],
18
+ },
19
+ create(context) {
20
+ if (!context.getFilename().endsWith(".d.ts")) {
21
+ return {};
22
+ }
23
+ const parserServices = ESLintUtils.getParserServices(context);
24
+ const packageName = getCommonDirectoryName(parserServices.program.getRootFileNames());
25
+ return {
26
+ // eslint-disable-next-line @typescript-eslint/naming-convention
27
+ TSModuleDeclaration(node) {
28
+ if (
29
+ node.id.type === AST_NODE_TYPES.Literal &&
30
+ (node.id.value === packageName || node.id.value.startsWith(packageName + "/"))
31
+ ) {
32
+ const text = node.id.value;
33
+ const preferred = text === packageName ? '"index.d.ts"' : `"${text}.d.ts" or "${text}/index.d.ts`;
34
+ context.report({
35
+ messageId: "noDeclareCurrentPackage",
36
+ data: { text, preferred },
37
+ node,
38
+ });
39
+ }
40
+ },
41
+ };
42
+ },
43
+ });
44
+
45
+ export = rule;
@@ -0,0 +1,68 @@
1
+ import { createRule } from "../util";
2
+ import { ESLintUtils } from "@typescript-eslint/utils";
3
+ import * as ts from "typescript";
4
+
5
+ const rule = createRule({
6
+ name: "no-import-default-of-export-equals",
7
+ defaultOptions: [],
8
+ meta: {
9
+ type: "problem",
10
+ docs: {
11
+ description: "Forbid a default import to reference an `export =` module.",
12
+ recommended: "error",
13
+ },
14
+ messages: {
15
+ noImportDefaultOfExportEquals: `The module {{moduleName}} uses \`export = \`. Import with \`import {{importName}} = require({{moduleName}})\`.`,
16
+ },
17
+ schema: [],
18
+ },
19
+ create(context) {
20
+ const parserServices = ESLintUtils.getParserServices(context);
21
+ const checker = parserServices.program.getTypeChecker();
22
+ if (context.getFilename().endsWith(".d.ts")) {
23
+ return {
24
+ // eslint-disable-next-line @typescript-eslint/naming-convention
25
+ ImportDeclaration(node) {
26
+ const defaultName = node.specifiers.find((spec) => spec.type === "ImportDefaultSpecifier")?.local;
27
+ if (!defaultName) {
28
+ return;
29
+ }
30
+ const importName = defaultName.name;
31
+ const source = parserServices.esTreeNodeToTSNodeMap.get(node.source);
32
+ const sym = checker.getSymbolAtLocation(source);
33
+ if (
34
+ sym?.declarations?.some((d) =>
35
+ getStatements(d)?.some((s) => ts.isExportAssignment(s) && !!s.isExportEquals)
36
+ )
37
+ ) {
38
+ context.report({
39
+ messageId: "noImportDefaultOfExportEquals",
40
+ data: { moduleName: node.source.value, importName },
41
+ node: defaultName,
42
+ });
43
+ }
44
+ },
45
+ };
46
+ } else {
47
+ return {};
48
+ }
49
+ },
50
+ });
51
+
52
+ function getStatements(decl: ts.Declaration): readonly ts.Statement[] | undefined {
53
+ return ts.isSourceFile(decl)
54
+ ? decl.statements
55
+ : ts.isModuleDeclaration(decl)
56
+ ? getModuleDeclarationStatements(decl)
57
+ : undefined;
58
+ }
59
+
60
+ function getModuleDeclarationStatements(node: ts.ModuleDeclaration): readonly ts.Statement[] | undefined {
61
+ let { body } = node;
62
+ while (body && body.kind === ts.SyntaxKind.ModuleDeclaration) {
63
+ body = body.body;
64
+ }
65
+ return body && ts.isModuleBlock(body) ? body.statements : undefined;
66
+ }
67
+
68
+ export = rule;
@@ -0,0 +1,42 @@
1
+ import { createRule, isMainFile } from "../util";
2
+ import { ESLintUtils } from "@typescript-eslint/utils";
3
+ const rule = createRule({
4
+ name: "no-outside-dependencies",
5
+ defaultOptions: [],
6
+ meta: {
7
+ type: "problem",
8
+ docs: {
9
+ description: "Don't import things in `DefinitelyTyped/node_modules`.",
10
+ recommended: "error",
11
+ },
12
+ messages: {
13
+ noOutsideDependencies: `File {{fileName}} comes from a \`node_modules\` but is not declared in this type's \`package.json\`. `,
14
+ },
15
+ schema: [],
16
+ },
17
+ create(context) {
18
+ if (isMainFile(context.getFilename(), /*allowNested*/ true)) {
19
+ const parserServices = ESLintUtils.getParserServices(context);
20
+ const hasNodeReference = parserServices.program
21
+ .getSourceFiles()
22
+ .some((f) => f.typeReferenceDirectives.some((dir) => dir.fileName === "node"));
23
+ for (const sourceFile of parserServices.program.getSourceFiles()) {
24
+ const fileName = sourceFile.fileName;
25
+ if (
26
+ fileName.includes("/DefinitelyTyped/node_modules/") &&
27
+ !parserServices.program.isSourceFileDefaultLibrary(sourceFile) &&
28
+ !(hasNodeReference && fileName.includes("buffer"))
29
+ ) {
30
+ context.report({
31
+ messageId: "noOutsideDependencies",
32
+ data: { fileName },
33
+ loc: { column: 0, line: 1 },
34
+ });
35
+ }
36
+ }
37
+ }
38
+ return {};
39
+ },
40
+ });
41
+
42
+ export = rule;