@jameswyse/oxc-config 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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/REFERENCE.md +134 -0
  4. package/dist/format.d.ts +5 -0
  5. package/dist/format.js +47 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +97 -0
  8. package/dist/lint.d.ts +33 -0
  9. package/dist/lint.js +493 -0
  10. package/dist/rules/companion-has-owner.d.ts +1 -0
  11. package/dist/rules/companion-has-owner.js +74 -0
  12. package/dist/rules/electron-no-raw-ipc-renderer-exposure.d.ts +1 -0
  13. package/dist/rules/electron-no-raw-ipc-renderer-exposure.js +127 -0
  14. package/dist/rules/electron-no-remote-module.d.ts +1 -0
  15. package/dist/rules/electron-no-remote-module.js +112 -0
  16. package/dist/rules/electron-secure-web-preferences.d.ts +1 -0
  17. package/dist/rules/electron-secure-web-preferences.js +108 -0
  18. package/dist/rules/explicit-api-states.d.ts +1 -0
  19. package/dist/rules/explicit-api-states.js +143 -0
  20. package/dist/rules/import-boundaries.d.ts +1 -0
  21. package/dist/rules/import-boundaries.js +99 -0
  22. package/dist/rules/no-ambient-clock.d.ts +1 -0
  23. package/dist/rules/no-ambient-clock.js +35 -0
  24. package/dist/rules/no-ambient-random.d.ts +1 -0
  25. package/dist/rules/no-ambient-random.js +71 -0
  26. package/dist/rules/no-comments.d.ts +1 -0
  27. package/dist/rules/no-comments.js +64 -0
  28. package/dist/rules/no-deep-ternary.d.ts +1 -0
  29. package/dist/rules/no-deep-ternary.js +32 -0
  30. package/dist/rules/no-edit-proof-assertions.d.ts +1 -0
  31. package/dist/rules/no-edit-proof-assertions.js +120 -0
  32. package/dist/rules/no-env-access.d.ts +1 -0
  33. package/dist/rules/no-env-access.js +35 -0
  34. package/dist/rules/no-fixed-test-delay.d.ts +1 -0
  35. package/dist/rules/no-fixed-test-delay.js +130 -0
  36. package/dist/rules/no-forwarding-module.d.ts +1 -0
  37. package/dist/rules/no-forwarding-module.js +158 -0
  38. package/dist/rules/no-generic-file-suffix.d.ts +1 -0
  39. package/dist/rules/no-generic-file-suffix.js +74 -0
  40. package/dist/rules/no-pass-through-function.d.ts +1 -0
  41. package/dist/rules/no-pass-through-function.js +106 -0
  42. package/dist/rules/no-swallowed-errors.d.ts +1 -0
  43. package/dist/rules/no-swallowed-errors.js +168 -0
  44. package/dist/rules/no-test-timeout-overrides.d.ts +1 -0
  45. package/dist/rules/no-test-timeout-overrides.js +105 -0
  46. package/dist/rules/no-vacuous-test-assertions.d.ts +1 -0
  47. package/dist/rules/no-vacuous-test-assertions.js +71 -0
  48. package/dist/rules/server-action-guard.d.ts +1 -0
  49. package/dist/rules/server-action-guard.js +109 -0
  50. package/dist/rules/statement-spacing.d.ts +1 -0
  51. package/dist/rules/statement-spacing.js +29 -0
  52. package/dist/rules/type-guard-name.d.ts +1 -0
  53. package/dist/rules/type-guard-name.js +59 -0
  54. package/dist/shared/index.d.ts +26 -0
  55. package/dist/shared/index.js +260 -0
  56. package/dist/shared/rule-options.d.ts +2 -0
  57. package/dist/shared/rule-options.js +8 -0
  58. package/dist/vendor/anti-slop/effect/rules/no-manual-effect-error-tag.d.ts +1 -0
  59. package/dist/vendor/anti-slop/effect/rules/no-manual-effect-error-tag.js +35 -0
  60. package/dist/vendor/anti-slop/effect/rules/no-service-constructor-imports.d.ts +1 -0
  61. package/dist/vendor/anti-slop/effect/rules/no-service-constructor-imports.js +48 -0
  62. package/dist/vendor/anti-slop/effect/shared/tagged-values.d.ts +9 -0
  63. package/dist/vendor/anti-slop/effect/shared/tagged-values.js +65 -0
  64. package/dist/vendor/anti-slop/rules/no-array-filter-map.d.ts +1 -0
  65. package/dist/vendor/anti-slop/rules/no-array-filter-map.js +40 -0
  66. package/dist/vendor/anti-slop/rules/no-chained-type-assertions.d.ts +1 -0
  67. package/dist/vendor/anti-slop/rules/no-chained-type-assertions.js +58 -0
  68. package/dist/vendor/anti-slop/rules/no-conditional-empty-object-spread.d.ts +1 -0
  69. package/dist/vendor/anti-slop/rules/no-conditional-empty-object-spread.js +41 -0
  70. package/dist/vendor/anti-slop/rules/no-known-value-widening.d.ts +1 -0
  71. package/dist/vendor/anti-slop/rules/no-known-value-widening.js +333 -0
  72. package/dist/vendor/anti-slop/rules/no-module-mocking.d.ts +1 -0
  73. package/dist/vendor/anti-slop/rules/no-module-mocking.js +74 -0
  74. package/dist/vendor/anti-slop/rules/no-object-parameters.d.ts +1 -0
  75. package/dist/vendor/anti-slop/rules/no-object-parameters.js +59 -0
  76. package/dist/vendor/anti-slop/rules/no-reduce-accumulator-copy.d.ts +1 -0
  77. package/dist/vendor/anti-slop/rules/no-reduce-accumulator-copy.js +124 -0
  78. package/dist/vendor/anti-slop/rules/no-reflect-apply.d.ts +1 -0
  79. package/dist/vendor/anti-slop/rules/no-reflect-apply.js +26 -0
  80. package/dist/vendor/anti-slop/rules/no-reflect-get.d.ts +1 -0
  81. package/dist/vendor/anti-slop/rules/no-reflect-get.js +26 -0
  82. package/dist/vendor/anti-slop/rules/no-runtime-typeof.d.ts +1 -0
  83. package/dist/vendor/anti-slop/rules/no-runtime-typeof.js +63 -0
  84. package/dist/vendor/anti-slop/rules/no-shape-in-symbol-names.d.ts +1 -0
  85. package/dist/vendor/anti-slop/rules/no-shape-in-symbol-names.js +37 -0
  86. package/dist/vendor/anti-slop/rules/no-unknown-returns.d.ts +1 -0
  87. package/dist/vendor/anti-slop/rules/no-unknown-returns.js +61 -0
  88. package/dist/vendor/anti-slop/rules/no-unknown-type-aliases.d.ts +1 -0
  89. package/dist/vendor/anti-slop/rules/no-unknown-type-aliases.js +38 -0
  90. package/dist/vendor/anti-slop/rules/no-unsafe-dictionary-type.d.ts +1 -0
  91. package/dist/vendor/anti-slop/rules/no-unsafe-dictionary-type.js +143 -0
  92. package/dist/vendor/anti-slop/rules/no-widen-then-assert.d.ts +1 -0
  93. package/dist/vendor/anti-slop/rules/no-widen-then-assert.js +288 -0
  94. package/dist/vendor/anti-slop/shared/array-method.d.ts +10 -0
  95. package/dist/vendor/anti-slop/shared/array-method.js +95 -0
  96. package/dist/vendor/anti-slop/shared/dictionary-types.d.ts +23 -0
  97. package/dist/vendor/anti-slop/shared/dictionary-types.js +408 -0
  98. package/dist/vendor/anti-slop/shared/function-parameters.d.ts +6 -0
  99. package/dist/vendor/anti-slop/shared/function-parameters.js +41 -0
  100. package/dist/vendor/anti-slop/shared/lexical-type-parameters.d.ts +4 -0
  101. package/dist/vendor/anti-slop/shared/lexical-type-parameters.js +32 -0
  102. package/dist/vendor/anti-slop/shared/reflect-method.d.ts +3 -0
  103. package/dist/vendor/anti-slop/shared/reflect-method.js +24 -0
  104. package/dist/vendor/anti-slop/shared/scope.d.ts +3 -0
  105. package/dist/vendor/anti-slop/shared/scope.js +12 -0
  106. package/dist/vendor/anti-slop/shared/type-alias-resolution.d.ts +21 -0
  107. package/dist/vendor/anti-slop/shared/type-alias-resolution.js +147 -0
  108. package/dist/vendor/eslint-stylistic/padding-line-ast.d.ts +14 -0
  109. package/dist/vendor/eslint-stylistic/padding-line-ast.js +19 -0
  110. package/dist/vendor/eslint-stylistic/padding-line-between-statements.d.ts +91 -0
  111. package/dist/vendor/eslint-stylistic/padding-line-between-statements.js +493 -0
  112. package/package.json +89 -0
  113. package/src/vendor/anti-slop/LICENSE +21 -0
  114. package/src/vendor/eslint-stylistic/LICENSE +22 -0
  115. package/tsconfig.base.json +10 -0
@@ -0,0 +1,10 @@
1
+ import type { ESTree, SourceCode, Variable } from "@oxlint/plugins";
2
+ type ArrayMethodTarget = {
3
+ readonly name: string;
4
+ readonly object: ESTree.Expression;
5
+ };
6
+ declare function unwrapArrayExpression(expression: ESTree.Node): ESTree.Node;
7
+ declare function resolveArrayBinding(sourceCode: SourceCode, expression: ESTree.Node): Variable | null;
8
+ declare function arrayMethodTarget(expression: ESTree.Node): ArrayMethodTarget | null;
9
+ declare function isKnownArrayExpression(sourceCode: SourceCode, expression: ESTree.Node, visited?: Set<Variable>): boolean;
10
+ export { arrayMethodTarget, isKnownArrayExpression, resolveArrayBinding, unwrapArrayExpression };
@@ -0,0 +1,95 @@
1
+ import { resolveVariable } from "./scope.js";
2
+ function unwrapArrayExpression(expression) {
3
+ let node = expression;
4
+ while (node.type === "ParenthesizedExpression" ||
5
+ node.type === "ChainExpression" ||
6
+ node.type === "TSAsExpression" ||
7
+ node.type === "TSTypeAssertion" ||
8
+ node.type === "TSNonNullExpression" ||
9
+ node.type === "TSSatisfiesExpression") {
10
+ node = node.expression;
11
+ }
12
+ return node;
13
+ }
14
+ function resolveArrayBinding(sourceCode, expression) {
15
+ const node = unwrapArrayExpression(expression);
16
+ return node.type === "Identifier" ? resolveVariable(sourceCode, node) : null;
17
+ }
18
+ function arrayMethodTarget(expression) {
19
+ const node = unwrapArrayExpression(expression);
20
+ if (node.type !== "MemberExpression") {
21
+ return null;
22
+ }
23
+ const property = node.property;
24
+ if (!node.computed && property.type === "Identifier") {
25
+ return { name: property.name, object: node.object };
26
+ }
27
+ if (node.computed && property.type === "Literal" && typeof property.value === "string") {
28
+ return { name: property.value, object: node.object };
29
+ }
30
+ return null;
31
+ }
32
+ function isArrayAnnotation(type) {
33
+ if (type.type === "TSArrayType" || type.type === "TSTupleType") {
34
+ return true;
35
+ }
36
+ if (type.type === "TSParenthesizedType") {
37
+ return isArrayAnnotation(type.typeAnnotation);
38
+ }
39
+ if (type.type === "TSTypeOperator" && type.operator === "readonly") {
40
+ return isArrayAnnotation(type.typeAnnotation);
41
+ }
42
+ return (type.type === "TSTypeReference" &&
43
+ type.typeName.type === "Identifier" &&
44
+ (type.typeName.name === "Array" || type.typeName.name === "ReadonlyArray"));
45
+ }
46
+ function isKnownArrayExpression(sourceCode, expression, visited = new Set()) {
47
+ const node = unwrapArrayExpression(expression);
48
+ if (node.type === "ArrayExpression") {
49
+ return true;
50
+ }
51
+ if (node.type === "CallExpression") {
52
+ const method = arrayMethodTarget(node.callee);
53
+ return (method !== null &&
54
+ [
55
+ "map",
56
+ "filter",
57
+ "flatMap",
58
+ "slice",
59
+ "concat",
60
+ "toSorted",
61
+ "toReversed",
62
+ "toSpliced",
63
+ ].includes(method.name) &&
64
+ isKnownArrayExpression(sourceCode, method.object, visited));
65
+ }
66
+ if (node.type !== "Identifier") {
67
+ return false;
68
+ }
69
+ const variable = resolveArrayBinding(sourceCode, node);
70
+ if (variable === null || visited.has(variable)) {
71
+ return false;
72
+ }
73
+ visited.add(variable);
74
+ if (variable.references.some((reference) => reference.isWrite() && !reference.init)) {
75
+ return false;
76
+ }
77
+ for (const identifier of variable.identifiers) {
78
+ const annotation = identifier.typeAnnotation?.typeAnnotation;
79
+ if (annotation !== void 0) {
80
+ return isArrayAnnotation(annotation);
81
+ }
82
+ }
83
+ for (const definition of variable.defs) {
84
+ if (definition.type === "Variable" &&
85
+ definition.node.type === "VariableDeclarator" &&
86
+ definition.node.id.type === "Identifier" &&
87
+ definition.node.init !== null &&
88
+ definition.node.parent.type === "VariableDeclaration" &&
89
+ definition.node.parent.kind === "const") {
90
+ return isKnownArrayExpression(sourceCode, definition.node.init, visited);
91
+ }
92
+ }
93
+ return false;
94
+ }
95
+ export { arrayMethodTarget, isKnownArrayExpression, resolveArrayBinding, unwrapArrayExpression };
@@ -0,0 +1,23 @@
1
+ import type { ESTree, SourceCode } from "@oxlint/plugins";
2
+ import type { TypeAliasEnvironment } from "./type-alias-resolution.ts";
3
+ type UnsafeValue = "any" | "empty-object" | "object" | "union" | "unknown";
4
+ type UnsafeDictionary = {
5
+ readonly kind: "unsafe-dictionary";
6
+ readonly unsafeValue: UnsafeValue;
7
+ };
8
+ type WideningTargetKind = "anonymous object" | "generic container" | "object" | "open dictionary" | "unknown";
9
+ type WideningTarget = {
10
+ readonly kind: WideningTargetKind;
11
+ };
12
+ type TypeEnvironment = {
13
+ readonly interfaces: ReadonlyMap<string, readonly ESTree.TSInterfaceDeclaration[]>;
14
+ readonly typeAliases: TypeAliasEnvironment;
15
+ };
16
+ declare function createTypeEnvironment(program: ESTree.Program, visitorKeys: SourceCode["visitorKeys"]): TypeEnvironment;
17
+ declare function classifyUnsafeDictionaryValue(valueType: ESTree.TSType, environment: TypeEnvironment): UnsafeDictionary | null;
18
+ declare function classifyUnsafeDictionary(type: ESTree.TSType, environment: TypeEnvironment): UnsafeDictionary | null;
19
+ declare function classifyWideningTarget(type: ESTree.TSType, environment: TypeEnvironment): WideningTarget | null;
20
+ declare function isPopulatedObjectExpression(expression: ESTree.Node): boolean;
21
+ declare function isKnownEvidenceExpression(expression: ESTree.Node): boolean;
22
+ export type { TypeEnvironment, UnsafeDictionary, WideningTarget };
23
+ export { classifyUnsafeDictionary, classifyUnsafeDictionaryValue, classifyWideningTarget, createTypeEnvironment, isKnownEvidenceExpression, isPopulatedObjectExpression, };
@@ -0,0 +1,408 @@
1
+ import { createTypeAliasEnvironment, hasVisibleTypeBinding, visibleTypeAlias, } from "./type-alias-resolution.js";
2
+ const BUILT_INS = new Set([
3
+ "Record",
4
+ "Readonly",
5
+ "Partial",
6
+ "Required",
7
+ "Pick",
8
+ "Omit",
9
+ "PropertyKey",
10
+ "NonNullable",
11
+ ]);
12
+ const TRANSPARENT_WRAPPERS = new Set(["Readonly", "Partial", "Required", "NonNullable"]);
13
+ function declaredStatement(statement) {
14
+ return statement.type === "ExportNamedDeclaration" ||
15
+ statement.type === "ExportDefaultDeclaration"
16
+ ? (statement.declaration ?? null)
17
+ : statement;
18
+ }
19
+ function createTypeEnvironment(program, visitorKeys) {
20
+ const interfaces = new Map();
21
+ for (const statement of program.body) {
22
+ const declaration = declaredStatement(statement);
23
+ if (declaration?.type !== "TSInterfaceDeclaration") {
24
+ continue;
25
+ }
26
+ const declarations = interfaces.get(declaration.id.name) ?? [];
27
+ declarations.push(declaration);
28
+ interfaces.set(declaration.id.name, declarations);
29
+ }
30
+ return { interfaces, typeAliases: createTypeAliasEnvironment(program, visitorKeys) };
31
+ }
32
+ function typeReferenceName(type) {
33
+ return type.typeName.type === "Identifier" ? type.typeName.name : null;
34
+ }
35
+ function isBuiltIn(name, use, environment) {
36
+ return BUILT_INS.has(name) && !hasVisibleTypeBinding(name, use, environment.typeAliases);
37
+ }
38
+ function unwrapTransparentType(type) {
39
+ let current = type;
40
+ while (current.type === "TSParenthesizedType" ||
41
+ (current.type === "TSTypeOperator" && current.operator === "readonly")) {
42
+ current = current.typeAnnotation;
43
+ }
44
+ return current;
45
+ }
46
+ function isUnappliedReferenceTo(type, name) {
47
+ const unwrapped = unwrapTransparentType(type);
48
+ return (unwrapped.type === "TSTypeReference" &&
49
+ typeReferenceName(unwrapped) === name &&
50
+ (unwrapped.typeArguments === null || unwrapped.typeArguments.params.length === 0));
51
+ }
52
+ function isNeverType(type) {
53
+ return unwrapTransparentType(type).type === "TSNeverKeyword";
54
+ }
55
+ function isEffectivelyEmptyMember(member) {
56
+ return (member.type === "TSPropertySignature" &&
57
+ member.optional &&
58
+ member.typeAnnotation !== null &&
59
+ isNeverType(member.typeAnnotation.typeAnnotation));
60
+ }
61
+ function isEffectivelyEmptyTypeLiteral(type) {
62
+ return type.members.length === 0 || type.members.every(isEffectivelyEmptyMember);
63
+ }
64
+ function isEffectivelyEmptyInterface(declarations) {
65
+ if (declarations.length !== 1) {
66
+ return false;
67
+ }
68
+ const [type] = declarations;
69
+ return (type !== void 0 &&
70
+ type.extends.length === 0 &&
71
+ (type.body.body.length === 0 || type.body.body.every(isEffectivelyEmptyMember)));
72
+ }
73
+ function resolvedSubstitutionArgument(type, base, resolving = new Set()) {
74
+ const unwrapped = unwrapTransparentType(type);
75
+ if (unwrapped.type !== "TSTypeReference") {
76
+ return type;
77
+ }
78
+ const name = typeReferenceName(unwrapped);
79
+ if (name === null || resolving.has(name)) {
80
+ return type;
81
+ }
82
+ const substitution = base.get(name);
83
+ if (substitution === void 0) {
84
+ return type;
85
+ }
86
+ const nextResolving = new Set(resolving);
87
+ nextResolving.add(name);
88
+ return resolvedSubstitutionArgument(substitution, base, nextResolving);
89
+ }
90
+ function aliasSubstitution(alias, type, base) {
91
+ const parameters = alias.typeParameters?.params ?? [];
92
+ const arguments_ = type.typeArguments?.params ?? [];
93
+ const next = new Map(base);
94
+ for (const [index, parameter] of parameters.entries()) {
95
+ const argument = arguments_[index] ?? parameter.default;
96
+ if (argument === null) {
97
+ return null;
98
+ }
99
+ next.set(parameter.name.name, resolvedSubstitutionArgument(argument, next));
100
+ }
101
+ return next;
102
+ }
103
+ function unsafeDirectValue(type, environment, substitutions, resolvingAliases) {
104
+ const unwrapped = unwrapTransparentType(type);
105
+ if (unwrapped.type === "TSUnknownKeyword") {
106
+ return "unknown";
107
+ }
108
+ if (unwrapped.type === "TSAnyKeyword") {
109
+ return "any";
110
+ }
111
+ if (unwrapped.type === "TSObjectKeyword") {
112
+ return "object";
113
+ }
114
+ if (unwrapped.type === "TSTypeLiteral" && isEffectivelyEmptyTypeLiteral(unwrapped)) {
115
+ return "empty-object";
116
+ }
117
+ if (unwrapped.type === "TSUnionType") {
118
+ return unwrapped.types.some((member) => unsafeDirectValue(member, environment, substitutions, resolvingAliases) !== null)
119
+ ? "union"
120
+ : null;
121
+ }
122
+ if (unwrapped.type === "TSIntersectionType") {
123
+ const unsafeMembers = unwrapped.types.map((member) => unsafeDirectValue(member, environment, substitutions, resolvingAliases));
124
+ if (unsafeMembers.includes("any")) {
125
+ return "any";
126
+ }
127
+ const [firstUnsafeMember] = unsafeMembers;
128
+ return firstUnsafeMember !== undefined && unsafeMembers.every((member) => member !== null)
129
+ ? firstUnsafeMember
130
+ : null;
131
+ }
132
+ if (unwrapped.type !== "TSTypeReference") {
133
+ return null;
134
+ }
135
+ const name = typeReferenceName(unwrapped);
136
+ if (name === null) {
137
+ return null;
138
+ }
139
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
140
+ const wrapped = unwrapped.typeArguments?.params[0];
141
+ return wrapped === void 0
142
+ ? null
143
+ : unsafeDirectValue(wrapped, environment, substitutions, resolvingAliases);
144
+ }
145
+ const substitution = substitutions.get(name);
146
+ if (substitution !== void 0) {
147
+ return isUnappliedReferenceTo(substitution, name)
148
+ ? null
149
+ : unsafeDirectValue(substitution, environment, substitutions, resolvingAliases);
150
+ }
151
+ const interfaceDeclarations = environment.interfaces.get(name);
152
+ if (interfaceDeclarations !== void 0) {
153
+ return isEffectivelyEmptyInterface(interfaceDeclarations) ? "empty-object" : null;
154
+ }
155
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
156
+ if (alias === null || resolvingAliases.has(name)) {
157
+ return null;
158
+ }
159
+ const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
160
+ if (nextSubstitutions === null) {
161
+ return null;
162
+ }
163
+ const nextResolving = new Set(resolvingAliases);
164
+ nextResolving.add(name);
165
+ return unsafeDirectValue(alias.typeAnnotation, environment, nextSubstitutions, nextResolving);
166
+ }
167
+ function dictionaryValueTypes(type, environment, substitutions, resolvingAliases) {
168
+ const unwrapped = unwrapTransparentType(type);
169
+ if (unwrapped.type === "TSTypeLiteral") {
170
+ return unwrapped.members.flatMap((member) => member.type === "TSIndexSignature"
171
+ ? [{ type: member.typeAnnotation.typeAnnotation, substitutions }]
172
+ : []);
173
+ }
174
+ if (unwrapped.type === "TSMappedType") {
175
+ return unwrapped.typeAnnotation === null
176
+ ? []
177
+ : [{ type: unwrapped.typeAnnotation, substitutions }];
178
+ }
179
+ if (unwrapped.type !== "TSTypeReference") {
180
+ return [];
181
+ }
182
+ const name = typeReferenceName(unwrapped);
183
+ if (name === null) {
184
+ return [];
185
+ }
186
+ const substitution = substitutions.get(name);
187
+ if (substitution !== void 0) {
188
+ return isUnappliedReferenceTo(substitution, name)
189
+ ? []
190
+ : dictionaryValueTypes(substitution, environment, substitutions, resolvingAliases);
191
+ }
192
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
193
+ const wrapped = unwrapped.typeArguments?.params[0];
194
+ return wrapped === void 0
195
+ ? []
196
+ : dictionaryValueTypes(wrapped, environment, substitutions, resolvingAliases);
197
+ }
198
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) {
199
+ const value = unwrapped.typeArguments?.params[1] ?? null;
200
+ return value === null ? [] : [{ type: value, substitutions }];
201
+ }
202
+ if ((name === "Pick" || name === "Omit") && isBuiltIn(name, unwrapped, environment)) {
203
+ const source = unwrapped.typeArguments?.params[0];
204
+ return source === void 0
205
+ ? []
206
+ : dictionaryValueTypes(source, environment, substitutions, resolvingAliases);
207
+ }
208
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
209
+ if (alias === null || resolvingAliases.has(name)) {
210
+ return [];
211
+ }
212
+ const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
213
+ if (nextSubstitutions === null) {
214
+ return [];
215
+ }
216
+ const nextResolving = new Set(resolvingAliases);
217
+ nextResolving.add(name);
218
+ return dictionaryValueTypes(alias.typeAnnotation, environment, nextSubstitutions, nextResolving);
219
+ }
220
+ function classifyUnsafeDictionaryValue(valueType, environment) {
221
+ const unsafeValue = unsafeDirectValue(valueType, environment, new Map(), new Set());
222
+ return unsafeValue === null ? null : { kind: "unsafe-dictionary", unsafeValue };
223
+ }
224
+ function classifyUnsafeDictionary(type, environment) {
225
+ for (const valueType of dictionaryValueTypes(type, environment, new Map(), new Set())) {
226
+ const unsafeValue = unsafeDirectValue(valueType.type, environment, valueType.substitutions, new Set());
227
+ if (unsafeValue !== null) {
228
+ return { kind: "unsafe-dictionary", unsafeValue };
229
+ }
230
+ }
231
+ return null;
232
+ }
233
+ function isBroadMappedKey(type, environment, substitutions, visitedAliases = new Set()) {
234
+ const unwrapped = unwrapTransparentType(type);
235
+ if (unwrapped.type === "TSStringKeyword" ||
236
+ unwrapped.type === "TSNumberKeyword" ||
237
+ unwrapped.type === "TSSymbolKeyword") {
238
+ return true;
239
+ }
240
+ if (unwrapped.type === "TSUnionType") {
241
+ return unwrapped.types.some((member) => isBroadMappedKey(member, environment, substitutions, visitedAliases));
242
+ }
243
+ if (unwrapped.type !== "TSTypeReference") {
244
+ return false;
245
+ }
246
+ const name = typeReferenceName(unwrapped);
247
+ if (name === null) {
248
+ return false;
249
+ }
250
+ const substitution = substitutions.get(name);
251
+ if (substitution !== void 0 && !isUnappliedReferenceTo(substitution, name)) {
252
+ return isBroadMappedKey(substitution, environment, substitutions, visitedAliases);
253
+ }
254
+ if (name === "PropertyKey" && isBuiltIn(name, unwrapped, environment)) {
255
+ return true;
256
+ }
257
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
258
+ if (alias === null ||
259
+ (alias.typeParameters?.params.length ?? 0) > 0 ||
260
+ visitedAliases.has(name)) {
261
+ return false;
262
+ }
263
+ const nextVisited = new Set(visitedAliases);
264
+ nextVisited.add(name);
265
+ return isBroadMappedKey(alias.typeAnnotation, environment, substitutions, nextVisited);
266
+ }
267
+ function hasBroadRecordKey(type, environment, substitutions) {
268
+ const key = type.typeArguments?.params[0];
269
+ return key === void 0 || isBroadMappedKey(key, environment, substitutions);
270
+ }
271
+ function classifyAliasBroadTarget(type, environment, substitutions, resolvingAliases) {
272
+ const unwrapped = unwrapTransparentType(type);
273
+ if (unwrapped.type === "TSUnknownKeyword") {
274
+ return { kind: "unknown" };
275
+ }
276
+ if (unwrapped.type === "TSObjectKeyword") {
277
+ return { kind: "object" };
278
+ }
279
+ if (unwrapped.type === "TSTypeLiteral") {
280
+ return unwrapped.members.some((member) => member.type === "TSIndexSignature")
281
+ ? { kind: "open dictionary" }
282
+ : null;
283
+ }
284
+ if (unwrapped.type === "TSMappedType") {
285
+ return isBroadMappedKey(unwrapped.constraint, environment, substitutions)
286
+ ? { kind: "open dictionary" }
287
+ : null;
288
+ }
289
+ if (unwrapped.type !== "TSTypeReference") {
290
+ return null;
291
+ }
292
+ const name = typeReferenceName(unwrapped);
293
+ if (name === null) {
294
+ return null;
295
+ }
296
+ const substitution = substitutions.get(name);
297
+ if (substitution !== void 0) {
298
+ return isUnappliedReferenceTo(substitution, name)
299
+ ? null
300
+ : classifyAliasBroadTarget(substitution, environment, substitutions, resolvingAliases);
301
+ }
302
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
303
+ const wrapped = unwrapped.typeArguments?.params[0];
304
+ return wrapped === void 0
305
+ ? null
306
+ : classifyAliasBroadTarget(wrapped, environment, substitutions, resolvingAliases);
307
+ }
308
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) {
309
+ return hasBroadRecordKey(unwrapped, environment, substitutions)
310
+ ? { kind: "open dictionary" }
311
+ : null;
312
+ }
313
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
314
+ if (alias === null || resolvingAliases.has(name)) {
315
+ return null;
316
+ }
317
+ const nextSubstitutions = aliasSubstitution(alias, unwrapped, substitutions);
318
+ if (nextSubstitutions === null) {
319
+ return null;
320
+ }
321
+ const nextResolving = new Set(resolvingAliases);
322
+ nextResolving.add(name);
323
+ return classifyAliasBroadTarget(alias.typeAnnotation, environment, nextSubstitutions, nextResolving);
324
+ }
325
+ function classifyWideningTarget(type, environment) {
326
+ const unwrapped = unwrapTransparentType(type);
327
+ if (unwrapped.type === "TSUnknownKeyword") {
328
+ return { kind: "unknown" };
329
+ }
330
+ if (unwrapped.type === "TSObjectKeyword") {
331
+ return { kind: "object" };
332
+ }
333
+ if (unwrapped.type === "TSTypeLiteral") {
334
+ return unwrapped.members.some((member) => member.type === "TSIndexSignature")
335
+ ? { kind: "open dictionary" }
336
+ : unwrapped.members.length > 0
337
+ ? { kind: "anonymous object" }
338
+ : null;
339
+ }
340
+ if (unwrapped.type === "TSMappedType") {
341
+ return { kind: "open dictionary" };
342
+ }
343
+ if (unwrapped.type !== "TSTypeReference") {
344
+ return null;
345
+ }
346
+ const name = typeReferenceName(unwrapped);
347
+ if (name === null) {
348
+ return null;
349
+ }
350
+ if (TRANSPARENT_WRAPPERS.has(name) && isBuiltIn(name, unwrapped, environment)) {
351
+ const wrapped = unwrapped.typeArguments?.params[0];
352
+ return wrapped === void 0 ? null : classifyWideningTarget(wrapped, environment);
353
+ }
354
+ if (name === "Record" && isBuiltIn(name, unwrapped, environment)) {
355
+ return hasBroadRecordKey(unwrapped, environment, new Map())
356
+ ? { kind: "open dictionary" }
357
+ : null;
358
+ }
359
+ const alias = visibleTypeAlias(name, unwrapped, environment.typeAliases);
360
+ if (alias === null) {
361
+ return null;
362
+ }
363
+ if ((alias.typeParameters?.params.length ?? 0) > 0) {
364
+ const substitutions2 = aliasSubstitution(alias, unwrapped, new Map());
365
+ const resolved2 = substitutions2 === null
366
+ ? null
367
+ : classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions2, new Set([name]));
368
+ return resolved2?.kind === "open dictionary" ? { kind: "generic container" } : null;
369
+ }
370
+ const substitutions = aliasSubstitution(alias, unwrapped, new Map());
371
+ if (substitutions === null) {
372
+ return null;
373
+ }
374
+ const resolved = classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions, new Set([name]));
375
+ return resolved;
376
+ }
377
+ function isPopulatedObjectExpression(expression) {
378
+ let current = expression;
379
+ while (current.type === "ParenthesizedExpression" ||
380
+ current.type === "TSAsExpression" ||
381
+ current.type === "TSTypeAssertion" ||
382
+ current.type === "TSNonNullExpression") {
383
+ current = current.expression;
384
+ }
385
+ return current.type === "ObjectExpression" && current.properties.length > 0;
386
+ }
387
+ function isKnownEvidenceExpression(expression) {
388
+ let current = expression;
389
+ while (current.type === "ParenthesizedExpression" ||
390
+ current.type === "TSAsExpression" ||
391
+ current.type === "TSTypeAssertion" ||
392
+ current.type === "TSNonNullExpression" ||
393
+ current.type === "TSSatisfiesExpression") {
394
+ current = current.expression;
395
+ }
396
+ if (current.type === "ObjectExpression") {
397
+ return true;
398
+ }
399
+ return (current.type === "ArrayExpression" ||
400
+ current.type === "ArrowFunctionExpression" ||
401
+ current.type === "ClassExpression" ||
402
+ current.type === "FunctionExpression" ||
403
+ current.type === "NewExpression" ||
404
+ current.type === "Literal" ||
405
+ current.type === "TemplateLiteral" ||
406
+ current.type === "UnaryExpression");
407
+ }
408
+ export { classifyUnsafeDictionary, classifyUnsafeDictionaryValue, classifyWideningTarget, createTypeEnvironment, isKnownEvidenceExpression, isPopulatedObjectExpression, };
@@ -0,0 +1,6 @@
1
+ import type { ESTree, SourceCode } from "@oxlint/plugins";
2
+ type FunctionParameter = ESTree.ParamPattern | ESTree.BindingPattern;
3
+ declare function containsUnknownType(type: ESTree.TSType): boolean;
4
+ declare function functionParameterTypeAnnotation(parameter: FunctionParameter): ESTree.TSTypeAnnotation | null | undefined;
5
+ declare function functionParameterBindingName(parameter: FunctionParameter, sourceCode: SourceCode): string;
6
+ export { containsUnknownType, functionParameterBindingName, functionParameterTypeAnnotation };
@@ -0,0 +1,41 @@
1
+ function containsUnknownType(type) {
2
+ if (type.type === "TSUnknownKeyword") {
3
+ return true;
4
+ }
5
+ if (type.type === "TSParenthesizedType") {
6
+ return containsUnknownType(type.typeAnnotation);
7
+ }
8
+ return type.type === "TSUnionType" && type.types.some(containsUnknownType);
9
+ }
10
+ function functionParameterTypeAnnotation(parameter) {
11
+ if (parameter.type === "TSParameterProperty") {
12
+ return functionParameterTypeAnnotation(parameter.parameter);
13
+ }
14
+ if (parameter.type === "RestElement") {
15
+ return parameter.typeAnnotation ?? functionParameterTypeAnnotation(parameter.argument);
16
+ }
17
+ if (parameter.type === "AssignmentPattern") {
18
+ return parameter.typeAnnotation ?? functionParameterTypeAnnotation(parameter.left);
19
+ }
20
+ return parameter.typeAnnotation;
21
+ }
22
+ function functionParameterBindingName(parameter, sourceCode) {
23
+ if (parameter.type === "TSParameterProperty") {
24
+ return functionParameterBindingName(parameter.parameter, sourceCode);
25
+ }
26
+ if (parameter.type === "AssignmentPattern") {
27
+ return functionParameterBindingName(parameter.left, sourceCode);
28
+ }
29
+ if (parameter.type === "RestElement") {
30
+ return functionParameterBindingName(parameter.argument, sourceCode);
31
+ }
32
+ if (parameter.type === "Identifier") {
33
+ return parameter.name;
34
+ }
35
+ const sourceText = sourceCode.getText(parameter);
36
+ const annotationStart = parameter.typeAnnotation?.start;
37
+ return annotationStart === void 0
38
+ ? sourceText
39
+ : sourceText.slice(0, annotationStart - parameter.start).trimEnd();
40
+ }
41
+ export { containsUnknownType, functionParameterBindingName, functionParameterTypeAnnotation };
@@ -0,0 +1,4 @@
1
+ import type { ESTree, SourceCode } from "@oxlint/plugins";
2
+ type VisitorKeys = SourceCode["visitorKeys"];
3
+ declare function lexicalTypeParameterNames(node: ESTree.Node, visitorKeys: VisitorKeys): ReadonlySet<string>;
4
+ export { lexicalTypeParameterNames };
@@ -0,0 +1,32 @@
1
+ import { childNodes } from "../../../shared/index.js";
2
+ function collectInferTypeParameterNames(node, visitorKeys, names) {
3
+ if (node.type === "TSInferType") {
4
+ names.add(node.typeParameter.name.name);
5
+ }
6
+ for (const child of childNodes(node, visitorKeys)) {
7
+ collectInferTypeParameterNames(child, visitorKeys, names);
8
+ }
9
+ }
10
+ function lexicalTypeParameterNames(node, visitorKeys) {
11
+ const names = new Set();
12
+ let descendant = node;
13
+ let current = node;
14
+ while (current.type !== "Program") {
15
+ if ("typeParameters" in current) {
16
+ for (const parameter of current.typeParameters?.params ?? []) {
17
+ names.add(parameter.name.name);
18
+ }
19
+ }
20
+ if (current.type === "TSMappedType" &&
21
+ (descendant === current.nameType || descendant === current.typeAnnotation)) {
22
+ names.add(current.key.name);
23
+ }
24
+ if (current.type === "TSConditionalType" && descendant === current.trueType) {
25
+ collectInferTypeParameterNames(current.extendsType, visitorKeys, names);
26
+ }
27
+ descendant = current;
28
+ current = current.parent;
29
+ }
30
+ return names;
31
+ }
32
+ export { lexicalTypeParameterNames };
@@ -0,0 +1,3 @@
1
+ import type { ESTree, SourceCode } from "@oxlint/plugins";
2
+ declare function isGlobalReflectMethodCall(sourceCode: SourceCode, callee: ESTree.Node, methodName: string): boolean;
3
+ export { isGlobalReflectMethodCall };
@@ -0,0 +1,24 @@
1
+ import { resolveVariable } from "./scope.js";
2
+ function isGlobalReflect(sourceCode, expression) {
3
+ if (expression.type !== "Identifier" || expression.name !== "Reflect") {
4
+ return false;
5
+ }
6
+ if (sourceCode.isGlobalReference(expression)) {
7
+ return true;
8
+ }
9
+ const variable = resolveVariable(sourceCode, expression);
10
+ return variable === null || variable.defs.length === 0;
11
+ }
12
+ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
13
+ if (callee.type !== "MemberExpression") {
14
+ return false;
15
+ }
16
+ if (!isGlobalReflect(sourceCode, callee.object)) {
17
+ return false;
18
+ }
19
+ const property = callee.property;
20
+ return callee.computed
21
+ ? property.type === "Literal" && property.value === methodName
22
+ : property.type === "Identifier" && property.name === methodName;
23
+ }
24
+ export { isGlobalReflectMethodCall };
@@ -0,0 +1,3 @@
1
+ import type { ESTree, SourceCode, Variable } from "@oxlint/plugins";
2
+ declare function resolveVariable(sourceCode: SourceCode, identifier: ESTree.IdentifierReference | ESTree.BindingIdentifier): Variable | null;
3
+ export { resolveVariable };
@@ -0,0 +1,12 @@
1
+ function resolveVariable(sourceCode, identifier) {
2
+ let scope = sourceCode.getScope(identifier);
3
+ while (scope !== null) {
4
+ const variable = scope.set.get(identifier.name);
5
+ if (variable !== void 0) {
6
+ return variable;
7
+ }
8
+ scope = scope.upper;
9
+ }
10
+ return null;
11
+ }
12
+ export { resolveVariable };