oxlint-plugin-arch 0.12.6 → 0.13.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.
- package/CHANGELOG.md +121 -0
- package/README.md +4 -4
- package/dist/index.js +1059 -306
- package/dist/preset/preset-effect.d.ts +3 -0
- package/dist/preset/preset-recipes.d.ts +10 -0
- package/dist/preset/preset.constants.d.ts +21 -2
- package/dist/preset/preset.d.ts +11 -1
- package/dist/preset/preset.js +715 -223
- package/dist/preset/preset.utils.d.ts +6 -0
- package/dist/rules/code/code-delegate.d.ts +1 -0
- package/dist/rules/layout/layout-type-arguments.d.ts +1 -0
- package/dist/rules/react/react-query-props.d.ts +1 -0
- package/dist/types/backend.types.d.ts +2 -3
- package/dist/types/boundaries.types.d.ts +26 -1
- package/dist/types/code.types.d.ts +7 -0
- package/dist/types/comments.types.d.ts +1 -0
- package/dist/types/dillon-anti-slop.types.d.ts +6 -0
- package/dist/types/effect.types.d.ts +1 -0
- package/dist/types/files.types.d.ts +3 -2
- package/dist/types/layout.types.d.ts +16 -0
- package/dist/types/naming.types.d.ts +4 -0
- package/dist/types/preset.types.d.ts +26 -24
- package/dist/types/react.types.d.ts +17 -0
- package/dist/types/types.types.d.ts +8 -0
- package/dist/utils/ast.utils.d.ts +1 -2
- package/dist/utils/boundaries.utils.d.ts +72 -4
- package/dist/utils/options.utils.d.ts +1 -0
- package/dist/vendor/dillon-anti-slop/index.js +38 -16
- package/package.json +15 -1
- package/src/vendor/dillon-anti-slop/UPSTREAM.md +3 -0
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ function optionsPatternsTest(patterns, value) {
|
|
|
37
37
|
function optionsGlob(pattern) {
|
|
38
38
|
const negated = [];
|
|
39
39
|
const source = pattern.replaceAll(/!\(([^()]*)\)/g, (_, options) => {
|
|
40
|
-
negated.push(options.split("|").map((option) => option.replaceAll(/[.+^$()|[\]
|
|
40
|
+
negated.push(options.split("|").map((option) => option.replaceAll(/[.+^$()|[\]\\?{}]/g, "\\$&").replaceAll("*", "[^/]*")).join("|"));
|
|
41
41
|
return `\x02${negated.length - 1}\x03`;
|
|
42
42
|
}).replaceAll(/[.+^$()|[\]\\]/g, "\\$&").replaceAll("?", "[^/]").replaceAll("**/", "\x00").replaceAll("**", "\x01").replaceAll("*", "[^/]*").replaceAll("\x00", "(?:.*/)?").replaceAll("\x01", ".*").replaceAll(/\{([^}]*)\}/g, (_, options) => `(?:${options.split(",").join("|")})`);
|
|
43
43
|
return new RegExp(`^${negated.reduce((text, names, index) => text.replace(`\x02${index}\x03`, `(?!(?:${names})(?:/|$))[^/]*`), source)}$`);
|
|
@@ -50,6 +50,9 @@ function optionsAssertMockingApis(patterns) {
|
|
|
50
50
|
throw new OptionsError("Test mocking APIs must be `*` or `<vi|jest|*>.<method|*>`.");
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
function optionsEscape(value) {
|
|
54
|
+
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
55
|
+
}
|
|
53
56
|
|
|
54
57
|
// src/utils/ast.utils.ts
|
|
55
58
|
var astSkippedKeys = new Set(["parent", "type", "start", "end", "range", "loc", "tokens", "comments"]);
|
|
@@ -237,9 +240,6 @@ function astIsInlineFunction(node) {
|
|
|
237
240
|
function astIsCall(node) {
|
|
238
241
|
return node.type === "CallExpression" || node.type === "NewExpression";
|
|
239
242
|
}
|
|
240
|
-
function astIsPipe(node) {
|
|
241
|
-
return node.callee.type === "MemberExpression" && astMemberName(node.callee) === "pipe";
|
|
242
|
-
}
|
|
243
243
|
function astChildren(node) {
|
|
244
244
|
return Object.entries(node).filter(([key]) => !astSkippedKeys.has(key)).map(([, child]) => child);
|
|
245
245
|
}
|
|
@@ -249,17 +249,20 @@ function astSome(value, test, enter = () => true) {
|
|
|
249
249
|
}
|
|
250
250
|
return astIsNode(value) && (test(value) || enter(value) && astChildren(value).some((child) => astSome(child, test, enter)));
|
|
251
251
|
}
|
|
252
|
-
function astCallDepth(value) {
|
|
252
|
+
function astCallDepth(value, callbacks = false) {
|
|
253
253
|
if (Array.isArray(value)) {
|
|
254
|
-
return Math.max(0, ...value.map(astCallDepth));
|
|
254
|
+
return Math.max(0, ...value.map((item) => astCallDepth(item, callbacks)));
|
|
255
255
|
}
|
|
256
|
-
if (!astIsNode(value)
|
|
256
|
+
if (!astIsNode(value)) {
|
|
257
257
|
return 0;
|
|
258
258
|
}
|
|
259
|
+
if (astIsInlineFunction(value)) {
|
|
260
|
+
return callbacks ? astCallDepth(value.body, callbacks) : 0;
|
|
261
|
+
}
|
|
259
262
|
if (astIsCall(value)) {
|
|
260
|
-
return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments), astCallDepth(value.callee));
|
|
263
|
+
return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments, callbacks), astCallDepth(value.callee, callbacks));
|
|
261
264
|
}
|
|
262
|
-
return astCallDepth(astChildren(value));
|
|
265
|
+
return astCallDepth(astChildren(value), callbacks);
|
|
263
266
|
}
|
|
264
267
|
|
|
265
268
|
// src/rules/backend/backend-orpc-output.ts
|
|
@@ -283,16 +286,14 @@ var backendOrpcOutput = defineRule2({
|
|
|
283
286
|
type: "object",
|
|
284
287
|
additionalProperties: false,
|
|
285
288
|
properties: {
|
|
286
|
-
composers: { type: "array", items: { type: "string" } },
|
|
287
289
|
handler: { type: "string" },
|
|
288
290
|
output: { type: "string" }
|
|
289
|
-
}
|
|
290
|
-
required: ["composers"]
|
|
291
|
+
}
|
|
291
292
|
}
|
|
292
293
|
],
|
|
293
294
|
messages: {
|
|
294
295
|
missing: "oRPC procedures must declare .output() before .handler().",
|
|
295
|
-
invalid: "oRPC .output() must use a named schema or
|
|
296
|
+
invalid: "oRPC .output() must use a named schema or a plain function called with a named schema."
|
|
296
297
|
}
|
|
297
298
|
},
|
|
298
299
|
createOnce(context) {
|
|
@@ -301,7 +302,7 @@ var backendOrpcOutput = defineRule2({
|
|
|
301
302
|
if (node.callee.type !== "MemberExpression") {
|
|
302
303
|
return;
|
|
303
304
|
}
|
|
304
|
-
const {
|
|
305
|
+
const { handler: handlerMethod = "handler", output: outputMethod = "output" } = optionsFirst(context, {});
|
|
305
306
|
if (astMemberName(node.callee) !== handlerMethod) {
|
|
306
307
|
return;
|
|
307
308
|
}
|
|
@@ -311,7 +312,7 @@ var backendOrpcOutput = defineRule2({
|
|
|
311
312
|
return;
|
|
312
313
|
}
|
|
313
314
|
const schema = output.arguments.at(0);
|
|
314
|
-
const named = schema?.type === "Identifier" || schema?.type === "CallExpression" && schema.callee.type === "Identifier" &&
|
|
315
|
+
const named = schema?.type === "Identifier" || schema?.type === "CallExpression" && schema.callee.type === "Identifier" && schema.arguments[0]?.type === "Identifier";
|
|
315
316
|
if (!named) {
|
|
316
317
|
context.report({ node: output, messageId: "invalid" });
|
|
317
318
|
}
|
|
@@ -844,6 +845,27 @@ import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
|
844
845
|
// src/utils/boundaries.utils.ts
|
|
845
846
|
import { builtinModules } from "node:module";
|
|
846
847
|
import { dirname, resolve } from "node:path";
|
|
848
|
+
var boundariesRuntimeConventions = {
|
|
849
|
+
server: ["server"],
|
|
850
|
+
rsc: ["rsc"],
|
|
851
|
+
actions: ["action"],
|
|
852
|
+
client: ["client"],
|
|
853
|
+
clientOnly: ["client-only"],
|
|
854
|
+
hooks: ["hooks"],
|
|
855
|
+
shared: ["utils", "constants"],
|
|
856
|
+
lib: "lib"
|
|
857
|
+
};
|
|
858
|
+
var boundariesSuffixList = { type: "array", items: { type: "string", minLength: 1 } };
|
|
859
|
+
function boundariesConventionsFor(options) {
|
|
860
|
+
return { ...boundariesRuntimeConventions, ...options.conventions };
|
|
861
|
+
}
|
|
862
|
+
function boundariesHasSuffix(suffixes, path, optionalExtension = false) {
|
|
863
|
+
const extension = optionalExtension ? "(?:\\.[cm]?[jt]sx?)?" : "\\.[cm]?[jt]sx?";
|
|
864
|
+
return suffixes.length > 0 && new RegExp(`\\.(?:${suffixes.map(optionsEscape).join("|")})${extension}$`).test(path);
|
|
865
|
+
}
|
|
866
|
+
function boundariesIsClientOnly(conventions, target) {
|
|
867
|
+
return conventions.hooks.some((folder) => target.includes(`/${folder}/`)) || conventions.clientOnly.some((suffix) => new RegExp(`\\.${optionsEscape(suffix)}(?:\\.|$)`).test(target));
|
|
868
|
+
}
|
|
847
869
|
var boundariesServerGlobals = ["process", "Bun", "Deno", "Buffer", "__dirname", "__filename", "require"];
|
|
848
870
|
var boundariesBrowserGlobals = [
|
|
849
871
|
"window",
|
|
@@ -879,7 +901,21 @@ var boundariesRuntimeProperties = {
|
|
|
879
901
|
dynamic: { type: "array", items: { type: "string" } },
|
|
880
902
|
serverPackages: { type: "array", items: { type: "string" } },
|
|
881
903
|
clientPackages: { type: "array", items: { type: "string" } },
|
|
882
|
-
hookPackages: { type: "array", items: { type: "string" } }
|
|
904
|
+
hookPackages: { type: "array", items: { type: "string" } },
|
|
905
|
+
conventions: {
|
|
906
|
+
type: "object",
|
|
907
|
+
additionalProperties: false,
|
|
908
|
+
properties: {
|
|
909
|
+
server: boundariesSuffixList,
|
|
910
|
+
rsc: boundariesSuffixList,
|
|
911
|
+
actions: boundariesSuffixList,
|
|
912
|
+
client: boundariesSuffixList,
|
|
913
|
+
clientOnly: boundariesSuffixList,
|
|
914
|
+
hooks: boundariesSuffixList,
|
|
915
|
+
shared: boundariesSuffixList,
|
|
916
|
+
lib: { type: "string", minLength: 1 }
|
|
917
|
+
}
|
|
918
|
+
}
|
|
883
919
|
};
|
|
884
920
|
var boundariesServerPackages = ["@orpc/server", "react-dom/server"];
|
|
885
921
|
var boundariesRuntimeMessages = {
|
|
@@ -910,16 +946,21 @@ function boundariesReport(context, node, source, reason) {
|
|
|
910
946
|
data: { source, reason }
|
|
911
947
|
});
|
|
912
948
|
}
|
|
913
|
-
function
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
949
|
+
function boundariesRuntimeImportVisitors(context, check, allowComputed) {
|
|
950
|
+
return {
|
|
951
|
+
...boundariesExportVisitors(check),
|
|
952
|
+
ImportExpression(node) {
|
|
953
|
+
const source = boundariesLiteralSource(node);
|
|
954
|
+
if (source !== undefined) {
|
|
955
|
+
check(node, source, false, false);
|
|
956
|
+
} else if (!allowComputed()) {
|
|
957
|
+
context.report({ node, messageId: "computed" });
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
};
|
|
920
961
|
}
|
|
921
|
-
function boundariesIsSharedFile(options, file) {
|
|
922
|
-
return
|
|
962
|
+
function boundariesIsSharedFile(options, conventions, file) {
|
|
963
|
+
return boundariesHasSuffix(conventions.shared, file) || options.web.some((path) => file.startsWith(`${path}/${conventions.lib}/`));
|
|
923
964
|
}
|
|
924
965
|
function boundariesDeclaredVariable(start, name) {
|
|
925
966
|
for (let scope = start;scope; scope = scope.upper) {
|
|
@@ -948,7 +989,7 @@ function boundariesMemberName(node) {
|
|
|
948
989
|
}
|
|
949
990
|
return node.computed && node.property.type === "Literal" && typeof node.property.value === "string" ? node.property.value : null;
|
|
950
991
|
}
|
|
951
|
-
function boundariesResolveTarget(options, file, source) {
|
|
992
|
+
function boundariesResolveTarget(options, file, source, services = "services") {
|
|
952
993
|
const owner = [...options.web, ...options.backend].sort((a, b) => b.length - a.length).find((root) => file.startsWith(`${root}/`));
|
|
953
994
|
const web = owner && options.web.includes(owner) ? owner : undefined;
|
|
954
995
|
const alias = Object.entries(options.aliases).sort(([a], [b]) => b.length - a.length).find(([prefix]) => source === prefix || source.startsWith(`${prefix}/`));
|
|
@@ -959,18 +1000,24 @@ function boundariesResolveTarget(options, file, source) {
|
|
|
959
1000
|
return resolve(dirname(file), source).replaceAll("\\", "/");
|
|
960
1001
|
}
|
|
961
1002
|
if (source.startsWith("@/") && web) {
|
|
962
|
-
return
|
|
1003
|
+
return resolve(web, source.slice(2)).replaceAll("\\", "/");
|
|
963
1004
|
}
|
|
964
1005
|
if (source.startsWith("#/") && owner) {
|
|
965
|
-
return
|
|
1006
|
+
return resolve(owner, source.slice(2)).replaceAll("\\", "/");
|
|
966
1007
|
}
|
|
967
1008
|
if (source.startsWith("#services/") && owner) {
|
|
968
|
-
return
|
|
1009
|
+
return resolve(owner, services, source.slice("#services/".length)).replaceAll("\\", "/");
|
|
969
1010
|
}
|
|
970
1011
|
return source;
|
|
971
1012
|
}
|
|
972
1013
|
|
|
973
1014
|
// src/rules/backend/backend-sql-like.ts
|
|
1015
|
+
var backendSqlLikeDefaults = {
|
|
1016
|
+
methods: ["like", "ilike"],
|
|
1017
|
+
sanitizers: ["escapeLikeWildcards"],
|
|
1018
|
+
bindings: true,
|
|
1019
|
+
operators: ["where"]
|
|
1020
|
+
};
|
|
974
1021
|
var backendSqlLike = defineRule5({
|
|
975
1022
|
meta: {
|
|
976
1023
|
type: "problem",
|
|
@@ -983,17 +1030,16 @@ var backendSqlLike = defineRule5({
|
|
|
983
1030
|
sanitizers: { type: "array", items: { type: "string" } },
|
|
984
1031
|
bindings: { type: "boolean" },
|
|
985
1032
|
operators: { type: "array", items: { type: "string" } }
|
|
986
|
-
}
|
|
987
|
-
required: ["methods", "sanitizers"]
|
|
1033
|
+
}
|
|
988
1034
|
}
|
|
989
1035
|
],
|
|
990
1036
|
messages: { unescaped: ".{{method}}() values must use a configured sanitizer." }
|
|
991
1037
|
},
|
|
992
1038
|
createOnce(context) {
|
|
993
|
-
let options =
|
|
1039
|
+
let options = backendSqlLikeDefaults;
|
|
994
1040
|
const seen = new Set;
|
|
995
1041
|
function sanitizedBinding(identifier, name) {
|
|
996
|
-
const variable = options.bindings
|
|
1042
|
+
const variable = options.bindings ? boundariesDeclaredVariable(context.sourceCode.getScope(identifier), name) : null;
|
|
997
1043
|
const declarator = variable?.defs.length === 1 && variable.defs[0].type === "Variable" ? variable.defs[0].node : undefined;
|
|
998
1044
|
const statement = declarator?.parent?.parent;
|
|
999
1045
|
if (!variable || declarator?.type !== "VariableDeclarator" || seen.has(variable) || !(statement?.type === "Program" || statement?.type === "ExportNamedDeclaration" && statement.parent.type === "Program") || variable.references.some((reference) => reference.isWrite() && !reference.init)) {
|
|
@@ -1034,8 +1080,8 @@ var backendSqlLike = defineRule5({
|
|
|
1034
1080
|
if (node.callee.type !== "MemberExpression") {
|
|
1035
1081
|
return;
|
|
1036
1082
|
}
|
|
1037
|
-
options = optionsFirst(context);
|
|
1038
|
-
const { methods, operators: operatorMethods
|
|
1083
|
+
options = { ...backendSqlLikeDefaults, ...optionsFirst(context, {}) };
|
|
1084
|
+
const { methods, operators: operatorMethods } = options;
|
|
1039
1085
|
const method = astMemberName(node.callee);
|
|
1040
1086
|
if (!method) {
|
|
1041
1087
|
return;
|
|
@@ -1142,7 +1188,25 @@ var boundariesDeny = defineRule6({
|
|
|
1142
1188
|
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1143
1189
|
import { basename, resolve as resolve2 } from "node:path";
|
|
1144
1190
|
var boundariesSurfaces = ["service", "client", "server", "rsc", "utils"];
|
|
1145
|
-
var
|
|
1191
|
+
var boundariesConventions = {
|
|
1192
|
+
services: "services",
|
|
1193
|
+
registry: "service",
|
|
1194
|
+
types: "types",
|
|
1195
|
+
lib: "lib",
|
|
1196
|
+
contracts: ["types", "constants"],
|
|
1197
|
+
implementations: ["service", "utils"],
|
|
1198
|
+
implementationFolders: ["core"],
|
|
1199
|
+
operations: ["action", "query"],
|
|
1200
|
+
operationFolders: ["actions", "queries"],
|
|
1201
|
+
domainFiles: ["action", "query", "driver"],
|
|
1202
|
+
clients: ["client"]
|
|
1203
|
+
};
|
|
1204
|
+
function boundariesAny(values) {
|
|
1205
|
+
return values.length === 0 ? "(?!)" : `(?:${values.map(optionsEscape).join("|")})`;
|
|
1206
|
+
}
|
|
1207
|
+
function boundariesIsOperation(conventions, path) {
|
|
1208
|
+
return new RegExp(`/[^/]+-${boundariesAny(conventions.operations)}\\.`).test(path);
|
|
1209
|
+
}
|
|
1146
1210
|
function boundariesContains(directory, candidate) {
|
|
1147
1211
|
return candidate === directory || candidate.startsWith(`${directory}/`);
|
|
1148
1212
|
}
|
|
@@ -1152,44 +1216,56 @@ function boundariesIsSurface(options, stem) {
|
|
|
1152
1216
|
function boundariesStripExtension(path) {
|
|
1153
1217
|
return path.replace(/\.[cm]?[jt]sx?$/, "");
|
|
1154
1218
|
}
|
|
1219
|
+
function boundariesConventionsOf(options) {
|
|
1220
|
+
return { ...boundariesConventions, ...options.conventions };
|
|
1221
|
+
}
|
|
1155
1222
|
function boundariesServiceFolder(options, root) {
|
|
1156
1223
|
const nested = [...options.web, ...options.backend].filter((other) => other.length > root.length && boundariesContains(root, other));
|
|
1157
|
-
return options.services?.find((folder) => folder.startsWith(`${root}/`) && !nested.some((other) => boundariesContains(other, folder))) ?? `${root}
|
|
1224
|
+
return options.services?.find((folder) => folder.startsWith(`${root}/`) && !nested.some((other) => boundariesContains(other, folder))) ?? `${root}/${boundariesConventionsOf(options).services}`;
|
|
1158
1225
|
}
|
|
1159
|
-
function boundariesDomain(path, appRoot, services) {
|
|
1226
|
+
function boundariesDomain(conventions, path, appRoot, services) {
|
|
1160
1227
|
const relative = path.slice(appRoot.length + 1);
|
|
1161
|
-
if (relative.startsWith(
|
|
1162
|
-
return relative.slice(
|
|
1228
|
+
if (relative.startsWith(`${conventions.types}/`) && relative.endsWith(`.${conventions.types}.ts`)) {
|
|
1229
|
+
return relative.slice(conventions.types.length + 1).split(".")[0];
|
|
1163
1230
|
}
|
|
1164
1231
|
if (!boundariesContains(services, path) || path === services) {
|
|
1165
1232
|
return;
|
|
1166
1233
|
}
|
|
1167
1234
|
const parts = path.slice(services.length + 1).split("/");
|
|
1168
|
-
return parts.length > 1 ? parts[0] : parts[0].split(".")[0].replace(
|
|
1235
|
+
return parts.length > 1 ? parts[0] : parts[0].split(".")[0].replace(new RegExp(`-${boundariesAny(conventions.domainFiles)}$`), "");
|
|
1169
1236
|
}
|
|
1170
1237
|
function boundariesPrivateDomain({ options, file, target, reExport, roots, owner }) {
|
|
1171
1238
|
const roles = options.roles;
|
|
1239
|
+
const conventions = boundariesConventionsOf(options);
|
|
1172
1240
|
if (!roles?.length) {
|
|
1173
1241
|
return;
|
|
1174
1242
|
}
|
|
1175
1243
|
const targetOwner = roots.find((path) => boundariesContains(path, target));
|
|
1176
|
-
const fileDomain = owner ? boundariesDomain(file, owner, boundariesServiceFolder(options, owner)) : undefined;
|
|
1177
|
-
const targetDomain = targetOwner ? boundariesDomain(target, targetOwner, boundariesServiceFolder(options, targetOwner)) : undefined;
|
|
1244
|
+
const fileDomain = owner ? boundariesDomain(conventions, file, owner, boundariesServiceFolder(options, owner)) : undefined;
|
|
1245
|
+
const targetDomain = targetOwner ? boundariesDomain(conventions, target, targetOwner, boundariesServiceFolder(options, targetOwner)) : undefined;
|
|
1178
1246
|
const sameDomain = owner && owner === targetOwner && fileDomain && fileDomain === targetDomain;
|
|
1179
1247
|
const targetStem = boundariesStripExtension(target);
|
|
1180
|
-
const publicSurface = boundariesIsSurface(options, targetStem) && !
|
|
1181
|
-
const privateTarget = roles.some((role) => targetStem.endsWith(`.${role}`)) || targetDomain && !publicSurface &&
|
|
1248
|
+
const publicSurface = boundariesIsSurface(options, targetStem) && !boundariesIsOperation(conventions, targetStem);
|
|
1249
|
+
const privateTarget = roles.some((role) => targetStem.endsWith(`.${role}`)) || targetDomain && !publicSurface && !new RegExp(`\\.${boundariesAny(conventions.contracts)}$`).test(targetStem);
|
|
1182
1250
|
if (!privateTarget) {
|
|
1183
1251
|
return;
|
|
1184
1252
|
}
|
|
1185
|
-
if (reExport && file.endsWith(".ts") && boundariesIsSurface(options, file.slice(0, -".ts".length)) && !
|
|
1253
|
+
if (reExport && file.endsWith(".ts") && boundariesIsSurface(options, file.slice(0, -".ts".length)) && !boundariesIsOperation(conventions, file)) {
|
|
1186
1254
|
return "public service and utility surfaces must not re-export private domain internals";
|
|
1187
1255
|
}
|
|
1188
1256
|
return sameDomain ? undefined : "private domain files stay in the same domain and application; use its service API or shared utilities";
|
|
1189
1257
|
}
|
|
1258
|
+
function boundariesPortableFolder(options) {
|
|
1259
|
+
if (!options.portable) {
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
return typeof options.portable === "string" ? options.portable : boundariesConventionsOf(options).lib;
|
|
1263
|
+
}
|
|
1190
1264
|
function boundariesPortableLib(check) {
|
|
1191
1265
|
const { options, file, source, target, typeOnly, reExport, roots, web, backendImport } = check;
|
|
1192
|
-
|
|
1266
|
+
const { types } = boundariesConventionsOf(options);
|
|
1267
|
+
const lib = boundariesPortableFolder(options);
|
|
1268
|
+
if (!lib || !web || !boundariesContains(`${web}/${lib}`, file) || boundariesServiceFolder(options, web) === `${web}/${lib}`) {
|
|
1193
1269
|
return;
|
|
1194
1270
|
}
|
|
1195
1271
|
const portableTarget = target.startsWith("/") ? resolve2(target).replaceAll("\\", "/") : target;
|
|
@@ -1199,11 +1275,11 @@ function boundariesPortableLib(check) {
|
|
|
1199
1275
|
if (backendImport || backendTarget || appService || appPackage) {
|
|
1200
1276
|
return "portable frontend lib does not import application services or application APIs";
|
|
1201
1277
|
}
|
|
1202
|
-
const appType = roots.some((path) => boundariesContains(`${path}
|
|
1278
|
+
const appType = roots.some((path) => boundariesContains(`${path}/${types}`, portableTarget));
|
|
1203
1279
|
const stem = boundariesStripExtension(basename(file)).replace(/\.utils$/, "");
|
|
1204
|
-
const ownType = typeOnly && !reExport && boundariesStripExtension(portableTarget) === `${web}
|
|
1280
|
+
const ownType = typeOnly && !reExport && boundariesStripExtension(portableTarget) === `${web}/${types}/${stem}.${types}`;
|
|
1205
1281
|
if (appType && !ownType) {
|
|
1206
|
-
return `portable frontend lib may only type-import its own contract '${web}
|
|
1282
|
+
return `portable frontend lib may only type-import its own contract '${web}/${types}/${stem}.${types}.ts'; app type re-exports are forbidden`;
|
|
1207
1283
|
}
|
|
1208
1284
|
return;
|
|
1209
1285
|
}
|
|
@@ -1222,7 +1298,24 @@ var boundariesImports = defineRule7({
|
|
|
1222
1298
|
roles: { type: "array", items: { type: "string" } },
|
|
1223
1299
|
surfaces: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesSurfaces },
|
|
1224
1300
|
services: { type: "array", items: { type: "string" } },
|
|
1225
|
-
portable: { type: "boolean" },
|
|
1301
|
+
portable: { anyOf: [{ type: "boolean" }, { type: "string", minLength: 1 }] },
|
|
1302
|
+
conventions: {
|
|
1303
|
+
type: "object",
|
|
1304
|
+
additionalProperties: false,
|
|
1305
|
+
properties: {
|
|
1306
|
+
services: { type: "string", minLength: 1 },
|
|
1307
|
+
registry: { type: "string", minLength: 1 },
|
|
1308
|
+
types: { type: "string", minLength: 1 },
|
|
1309
|
+
lib: { type: "string", minLength: 1 },
|
|
1310
|
+
contracts: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1311
|
+
implementations: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1312
|
+
implementationFolders: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1313
|
+
operations: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1314
|
+
operationFolders: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1315
|
+
domainFiles: { type: "array", items: { type: "string", minLength: 1 } },
|
|
1316
|
+
clients: { type: "array", items: { type: "string", minLength: 1 } }
|
|
1317
|
+
}
|
|
1318
|
+
},
|
|
1226
1319
|
backendPackages: { type: "array", items: { type: "string" } },
|
|
1227
1320
|
entrypoints: { type: "array", items: { type: "string" } },
|
|
1228
1321
|
appPackages: { type: "array", items: { type: "string" } },
|
|
@@ -1241,7 +1334,8 @@ var boundariesImports = defineRule7({
|
|
|
1241
1334
|
const file = context.filename.replaceAll("\\", "/");
|
|
1242
1335
|
const roots = [...options.web, ...options.backend].sort((a, b) => b.length - a.length);
|
|
1243
1336
|
const owner = roots.find((path) => boundariesContains(path, file));
|
|
1244
|
-
const
|
|
1337
|
+
const conventions = boundariesConventionsOf(options);
|
|
1338
|
+
const target = boundariesResolveTarget(options, file, source, conventions.services);
|
|
1245
1339
|
const web = owner && options.web.includes(owner) ? owner : undefined;
|
|
1246
1340
|
const backendImport = options.backend.some((path) => boundariesContains(path, target)) || boundariesMatchesImport(options.backendPackages, source);
|
|
1247
1341
|
const imported = { options, file, source, target, typeOnly, reExport, roots, owner, web, backendImport };
|
|
@@ -1250,13 +1344,16 @@ var boundariesImports = defineRule7({
|
|
|
1250
1344
|
const serviceFolders = roots.map((path) => boundariesServiceFolder(options, path));
|
|
1251
1345
|
const serviceTarget = serviceFolders.find((folder) => boundariesContains(folder, target));
|
|
1252
1346
|
const serviceFile = serviceFolders.find((folder) => boundariesContains(folder, file));
|
|
1253
|
-
const
|
|
1347
|
+
const implementation = `(?:\\.${boundariesAny(conventions.implementations)}|-${boundariesAny(conventions.operations)}\\.|/${boundariesAny(conventions.operationFolders)}/)`;
|
|
1348
|
+
const services = optionsEscape(conventions.services);
|
|
1349
|
+
const domainContract = new RegExp(`\\.${boundariesAny(conventions.contracts)}\\.ts$`).test(file) && !typeOnly && (new RegExp(`/(?:${boundariesAny(conventions.implementationFolders)}/|${services}/.*${implementation})`).test(target) || serviceTarget !== undefined && new RegExp(`/.*${implementation}`).test(target.slice(serviceTarget.length)));
|
|
1350
|
+
const registry = `/${optionsEscape(conventions.registry)}(?:\\.ts)?$`;
|
|
1254
1351
|
const reason = [
|
|
1255
1352
|
web && backendImport && !options.entrypoints.includes(source) ? "frontend code uses only public backend entry points" : undefined,
|
|
1256
1353
|
inPackage && appTarget ? "shared packages do not import app internals" : undefined,
|
|
1257
|
-
(file.includes(
|
|
1354
|
+
(file.includes(`/${conventions.services}/`) && new RegExp(`/${services}${registry}`).test(target) || serviceFile !== undefined && new RegExp(`^${registry}`).test(target.slice(serviceFile.length))) && !typeOnly ? "service dependencies are injected rather than read from the registry" : undefined,
|
|
1258
1355
|
domainContract ? "domain types/constants use type-only imports from implementations" : undefined,
|
|
1259
|
-
file.endsWith(
|
|
1356
|
+
conventions.clients.some((client) => file.endsWith(`.${client}.ts`)) && !typeOnly && boundariesMatchesImport(options.uiPackages ?? ["react", "react-dom"], source) ? "client services are React-free; use hooks for React behavior" : undefined,
|
|
1260
1357
|
boundariesPrivateDomain(imported),
|
|
1261
1358
|
boundariesPortableLib(imported)
|
|
1262
1359
|
].findLast((candidate) => candidate !== undefined);
|
|
@@ -1297,7 +1394,8 @@ var boundariesImports = defineRule7({
|
|
|
1297
1394
|
TSImportType(node) {
|
|
1298
1395
|
const options = { ...boundariesImportsDefaults, ...optionsFirst(context) };
|
|
1299
1396
|
const file = context.filename.replaceAll("\\", "/");
|
|
1300
|
-
|
|
1397
|
+
const lib = boundariesPortableFolder(options);
|
|
1398
|
+
if (lib && options.web.some((path) => file.startsWith(`${path}/${lib}/`) && boundariesServiceFolder(options, path) !== `${path}/${lib}`)) {
|
|
1301
1399
|
check(node, node.source.value, true);
|
|
1302
1400
|
}
|
|
1303
1401
|
}
|
|
@@ -1341,6 +1439,7 @@ var boundariesNext = defineRule8({
|
|
|
1341
1439
|
},
|
|
1342
1440
|
createOnce(context) {
|
|
1343
1441
|
let options;
|
|
1442
|
+
let conventions = boundariesConventionsFor({});
|
|
1344
1443
|
let file = "";
|
|
1345
1444
|
let server = false;
|
|
1346
1445
|
let client = false;
|
|
@@ -1352,12 +1451,12 @@ var boundariesNext = defineRule8({
|
|
|
1352
1451
|
return;
|
|
1353
1452
|
}
|
|
1354
1453
|
const target = boundariesResolveTarget(options, file, source);
|
|
1355
|
-
const clientOnly =
|
|
1454
|
+
const clientOnly = boundariesIsClientOnly(conventions, target) || boundariesMatchesImport(options.clientPackages, source) || boundariesMatchesImport(options.client, source);
|
|
1356
1455
|
if (clientOnly && (server || shared)) {
|
|
1357
1456
|
boundariesReport(context, node, source, "browser-only dependencies do not belong in server, RSC or shared modules");
|
|
1358
1457
|
return;
|
|
1359
1458
|
}
|
|
1360
|
-
const serverOnly = boundariesIsServerPlatformImport(source, options.serverPackages) || boundariesIsBackendImport(options, target, source) ||
|
|
1459
|
+
const serverOnly = boundariesIsServerPlatformImport(source, options.serverPackages) || boundariesIsBackendImport(options, target, source) || boundariesHasSuffix([...conventions.server, ...conventions.rsc], target, true) || boundariesMatchesImport(options.server, source);
|
|
1361
1460
|
if (!serverOnly || server) {
|
|
1362
1461
|
return;
|
|
1363
1462
|
}
|
|
@@ -1366,6 +1465,7 @@ var boundariesNext = defineRule8({
|
|
|
1366
1465
|
return {
|
|
1367
1466
|
Program(program) {
|
|
1368
1467
|
options = { ...boundariesNextDefaults, ...optionsFirst(context) };
|
|
1468
|
+
conventions = boundariesConventionsFor(options);
|
|
1369
1469
|
reactNamespaces.clear();
|
|
1370
1470
|
file = context.filename.replaceAll("\\", "/");
|
|
1371
1471
|
const directives = new Map;
|
|
@@ -1376,9 +1476,9 @@ var boundariesNext = defineRule8({
|
|
|
1376
1476
|
}
|
|
1377
1477
|
const useServer = directives.get("use server");
|
|
1378
1478
|
const useClient = directives.get("use client");
|
|
1379
|
-
const serverName =
|
|
1380
|
-
const clientName =
|
|
1381
|
-
shared = boundariesIsSharedFile(options, file);
|
|
1479
|
+
const serverName = boundariesHasSuffix([...conventions.server, ...conventions.rsc, ...conventions.actions], file);
|
|
1480
|
+
const clientName = boundariesHasSuffix(conventions.client, file);
|
|
1481
|
+
shared = boundariesIsSharedFile(options, conventions, file);
|
|
1382
1482
|
server = !useClient && (serverName || Boolean(useServer));
|
|
1383
1483
|
client = clientName || Boolean(useClient);
|
|
1384
1484
|
if (useClient && serverName) {
|
|
@@ -1395,7 +1495,7 @@ var boundariesNext = defineRule8({
|
|
|
1395
1495
|
data: { directive: "use server", side: "client" }
|
|
1396
1496
|
});
|
|
1397
1497
|
}
|
|
1398
|
-
if (
|
|
1498
|
+
if (boundariesHasSuffix(conventions.actions, file) && !useServer) {
|
|
1399
1499
|
context.report({ node: program, messageId: "action" });
|
|
1400
1500
|
}
|
|
1401
1501
|
},
|
|
@@ -1425,10 +1525,7 @@ var boundariesNext = defineRule8({
|
|
|
1425
1525
|
boundariesReport(context, node, `${node.object.name}.${name}`, boundariesClientHookReason);
|
|
1426
1526
|
}
|
|
1427
1527
|
},
|
|
1428
|
-
...
|
|
1429
|
-
ImportExpression(node) {
|
|
1430
|
-
boundariesImportExpression(context, node, Boolean(options.dynamic?.includes(file)), (source) => check(node, source, false));
|
|
1431
|
-
},
|
|
1528
|
+
...boundariesRuntimeImportVisitors(context, check, () => Boolean(options.dynamic?.includes(file))),
|
|
1432
1529
|
"Program:exit"() {
|
|
1433
1530
|
const scope = context.sourceCode.scopeManager.scopes.at(0);
|
|
1434
1531
|
if (!scope) {
|
|
@@ -1545,11 +1642,9 @@ var boundariesTanstackDefaults = {
|
|
|
1545
1642
|
hookPackages: ["react", "@tanstack/react-query", "@tanstack/react-router"],
|
|
1546
1643
|
startPackages: ["@tanstack/react-start"],
|
|
1547
1644
|
rscPackages: ["@tanstack/react-start/rsc", "@tanstack/react-start-rsc"],
|
|
1548
|
-
renderers: ["renderServerComponent", "renderToReadableStream"]
|
|
1645
|
+
renderers: ["renderServerComponent", "renderToReadableStream"],
|
|
1646
|
+
serverHooks: ["useId"]
|
|
1549
1647
|
};
|
|
1550
|
-
function boundariesIsClientHook(name) {
|
|
1551
|
-
return /^use[A-Z]/.test(name) && name !== "useId";
|
|
1552
|
-
}
|
|
1553
1648
|
var boundariesTanstack = defineRule10({
|
|
1554
1649
|
meta: {
|
|
1555
1650
|
type: "problem",
|
|
@@ -1562,7 +1657,8 @@ var boundariesTanstack = defineRule10({
|
|
|
1562
1657
|
rpc: { type: "array", items: { type: "string" } },
|
|
1563
1658
|
startPackages: { type: "array", items: { type: "string" } },
|
|
1564
1659
|
rscPackages: { type: "array", items: { type: "string" } },
|
|
1565
|
-
renderers: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesTanstackDefaults.renderers }
|
|
1660
|
+
renderers: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesTanstackDefaults.renderers },
|
|
1661
|
+
serverHooks: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesTanstackDefaults.serverHooks }
|
|
1566
1662
|
}
|
|
1567
1663
|
}
|
|
1568
1664
|
],
|
|
@@ -1570,6 +1666,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1570
1666
|
},
|
|
1571
1667
|
createOnce(context) {
|
|
1572
1668
|
let options;
|
|
1669
|
+
let conventions = boundariesConventionsFor({});
|
|
1573
1670
|
let file = "";
|
|
1574
1671
|
let serverFile = false;
|
|
1575
1672
|
let rscFile = false;
|
|
@@ -1578,6 +1675,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1578
1675
|
let referenced;
|
|
1579
1676
|
let imports = new Map;
|
|
1580
1677
|
const boundaries = [];
|
|
1678
|
+
const clientHook = (name) => /^use[A-Z]/.test(name) && !options.serverHooks.includes(name);
|
|
1581
1679
|
function imported(node) {
|
|
1582
1680
|
const entry = imports.get(node.name);
|
|
1583
1681
|
const variable = entry ? boundariesDeclaredVariable(context.sourceCode.getScope(node), node.name) : null;
|
|
@@ -1620,7 +1718,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1620
1718
|
return;
|
|
1621
1719
|
}
|
|
1622
1720
|
const target = boundariesResolveTarget(options, file, source);
|
|
1623
|
-
const clientImport =
|
|
1721
|
+
const clientImport = boundariesIsClientOnly(conventions, target) || boundariesMatchesImport(options.clientPackages, source) || boundariesMatchesImport(options.client, source);
|
|
1624
1722
|
if (clientImport && (serverFile || rscFile || shared) && !clientSide(node.start)) {
|
|
1625
1723
|
const references = node.type === "ImportDeclaration" ? runtimeReferences(node) : [];
|
|
1626
1724
|
if (shared || references.length === 0 || !references.every(clientSide)) {
|
|
@@ -1628,7 +1726,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1628
1726
|
}
|
|
1629
1727
|
return;
|
|
1630
1728
|
}
|
|
1631
|
-
const serverImport = boundariesIsServerPlatformImport(source, options.serverPackages) || boundariesIsBackendImport(options, target, source) ||
|
|
1729
|
+
const serverImport = boundariesIsServerPlatformImport(source, options.serverPackages) || boundariesIsBackendImport(options, target, source) || boundariesHasSuffix(conventions.server, target, true) || boundariesMatchesImport(options.server, source);
|
|
1632
1730
|
if (!renderer && !serverImport) {
|
|
1633
1731
|
return;
|
|
1634
1732
|
}
|
|
@@ -1656,10 +1754,11 @@ var boundariesTanstack = defineRule10({
|
|
|
1656
1754
|
return {
|
|
1657
1755
|
Program(program) {
|
|
1658
1756
|
options = { ...boundariesTanstackDefaults, ...optionsFirst(context) };
|
|
1757
|
+
conventions = boundariesConventionsFor(options);
|
|
1659
1758
|
file = context.filename.replaceAll("\\", "/");
|
|
1660
|
-
serverFile =
|
|
1661
|
-
rscFile =
|
|
1662
|
-
shared = boundariesIsSharedFile(options, file);
|
|
1759
|
+
serverFile = boundariesHasSuffix(conventions.server, file);
|
|
1760
|
+
rscFile = boundariesHasSuffix(conventions.rsc, file);
|
|
1761
|
+
shared = boundariesIsSharedFile(options, conventions, file);
|
|
1663
1762
|
runtimeIdentifiers.clear();
|
|
1664
1763
|
referenced = undefined;
|
|
1665
1764
|
boundaries.length = 0;
|
|
@@ -1726,7 +1825,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1726
1825
|
return;
|
|
1727
1826
|
}
|
|
1728
1827
|
for (const specifier of node.specifiers) {
|
|
1729
|
-
if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type" || specifier.imported.type !== "Identifier" || !
|
|
1828
|
+
if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type" || specifier.imported.type !== "Identifier" || !clientHook(specifier.imported.name)) {
|
|
1730
1829
|
continue;
|
|
1731
1830
|
}
|
|
1732
1831
|
const references = runtimeReferences(node, specifier.local.name);
|
|
@@ -1735,10 +1834,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1735
1834
|
}
|
|
1736
1835
|
}
|
|
1737
1836
|
},
|
|
1738
|
-
...
|
|
1739
|
-
ImportExpression(node) {
|
|
1740
|
-
boundariesImportExpression(context, node, Boolean(options.dynamic?.includes(file)), (source) => check(node, source, false));
|
|
1741
|
-
},
|
|
1837
|
+
...boundariesRuntimeImportVisitors(context, check, () => Boolean(options.dynamic?.includes(file))),
|
|
1742
1838
|
MemberExpression(node) {
|
|
1743
1839
|
const name = boundariesMemberName(node);
|
|
1744
1840
|
if (!name || node.object.type !== "Identifier") {
|
|
@@ -1748,7 +1844,7 @@ var boundariesTanstack = defineRule10({
|
|
|
1748
1844
|
if (kind === "rsc-renderers" && options.renderers.includes(name) && (shared || !serverPosition(node.start, true))) {
|
|
1749
1845
|
boundariesReport(context, node, name, "server renderers require a server execution boundary");
|
|
1750
1846
|
}
|
|
1751
|
-
if ((serverFile || rscFile) && kind === "client-hooks" &&
|
|
1847
|
+
if ((serverFile || rscFile) && kind === "client-hooks" && clientHook(name) && !clientSide(node.start)) {
|
|
1752
1848
|
boundariesReport(context, node, name, boundariesClientHookReason2);
|
|
1753
1849
|
}
|
|
1754
1850
|
},
|
|
@@ -2016,12 +2112,82 @@ var codeConstructor = defineRule13({
|
|
|
2016
2112
|
}
|
|
2017
2113
|
});
|
|
2018
2114
|
|
|
2115
|
+
// src/rules/code/code-delegate.ts
|
|
2116
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
2117
|
+
var codeDelegate = defineRule14({
|
|
2118
|
+
meta: {
|
|
2119
|
+
type: "suggestion",
|
|
2120
|
+
schema: [
|
|
2121
|
+
{
|
|
2122
|
+
type: "object",
|
|
2123
|
+
additionalProperties: false,
|
|
2124
|
+
properties: {
|
|
2125
|
+
methods: { type: "array", items: { type: "string" } },
|
|
2126
|
+
reads: { type: "array", items: { type: "string" } },
|
|
2127
|
+
max: { type: "integer", minimum: 0 }
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
],
|
|
2131
|
+
messages: {
|
|
2132
|
+
statement: "A handler only delegates: read services, make one call, return. Move this to an action.",
|
|
2133
|
+
calls: "A handler's yielded or awaited calls are limited to {{max}}; move the rest into the action it calls.",
|
|
2134
|
+
ternary: "A handler does not branch; move the condition into the action it calls.",
|
|
2135
|
+
nested: "A handler holds no function; move it into the action it calls."
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
createOnce(context) {
|
|
2139
|
+
return {
|
|
2140
|
+
CallExpression(node) {
|
|
2141
|
+
const { methods = ["handler", "effect"], reads = ["Effect.serviceOption"], max = 1 } = optionsFirst(context, {});
|
|
2142
|
+
if (!methods.includes(astCallName(node) ?? "")) {
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
const awaited = (value) => value?.type === "YieldExpression" || value?.type === "AwaitExpression";
|
|
2146
|
+
for (const handler of node.arguments.filter(astIsInlineFunction)) {
|
|
2147
|
+
let calls = 0;
|
|
2148
|
+
const scan = (value) => astSome(value, (child) => {
|
|
2149
|
+
if (child.type === "ConditionalExpression") {
|
|
2150
|
+
context.report({ node: child, messageId: "ternary" });
|
|
2151
|
+
}
|
|
2152
|
+
if (child.type === "FunctionDeclaration" || astIsInlineFunction(child)) {
|
|
2153
|
+
context.report({ node: child, messageId: "nested" });
|
|
2154
|
+
}
|
|
2155
|
+
const target = awaited(child) && "argument" in child ? child.argument : null;
|
|
2156
|
+
if (target?.type === "CallExpression" && !reads.includes(astDottedName(target.callee) ?? "")) {
|
|
2157
|
+
calls += 1;
|
|
2158
|
+
if (calls > max) {
|
|
2159
|
+
context.report({
|
|
2160
|
+
node: child,
|
|
2161
|
+
messageId: "calls",
|
|
2162
|
+
data: { max: String(max) }
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
return false;
|
|
2167
|
+
}, (child) => child.type !== "FunctionDeclaration" && !astIsInlineFunction(child));
|
|
2168
|
+
const { body } = handler;
|
|
2169
|
+
if (body && body.type !== "BlockStatement") {
|
|
2170
|
+
scan(body);
|
|
2171
|
+
}
|
|
2172
|
+
for (const statement of body?.type === "BlockStatement" ? body.body : []) {
|
|
2173
|
+
const allowed = statement.type === "ReturnStatement" || statement.type === "VariableDeclaration" && statement.declarations.every((declarator) => awaited(declarator.init)) || statement.type === "ExpressionStatement" && awaited(statement.expression) && "argument" in statement.expression && statement.expression.argument?.type === "CallExpression";
|
|
2174
|
+
if (!allowed) {
|
|
2175
|
+
context.report({ node: statement, messageId: "statement" });
|
|
2176
|
+
}
|
|
2177
|
+
scan(statement);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
});
|
|
2184
|
+
|
|
2019
2185
|
// src/rules/code/code-double-negation.ts
|
|
2020
2186
|
var codeDoubleNegation = astSelectorRule('UnaryExpression[operator="!"] > UnaryExpression[operator="!"]', "Use Boolean(value) or an explicit comparison.");
|
|
2021
2187
|
|
|
2022
2188
|
// src/rules/code/code-function-nesting.ts
|
|
2023
|
-
import { defineRule as
|
|
2024
|
-
var codeFunctionNesting =
|
|
2189
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
2190
|
+
var codeFunctionNesting = defineRule15({
|
|
2025
2191
|
meta: {
|
|
2026
2192
|
type: "suggestion",
|
|
2027
2193
|
schema: [
|
|
@@ -2062,7 +2228,7 @@ var codeFunctionNesting = defineRule14({
|
|
|
2062
2228
|
});
|
|
2063
2229
|
|
|
2064
2230
|
// src/rules/code/code-inline.ts
|
|
2065
|
-
import { defineRule as
|
|
2231
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
2066
2232
|
|
|
2067
2233
|
// src/utils/source.utils.ts
|
|
2068
2234
|
var sourceDirective = /^\s*(?:\/\s*<(?:reference\b|amd-[\w-]+\b)|@ts-(?:check|ignore|expect-error|nocheck)\b|(?:#|@)__(?:PURE|NO_SIDE_EFFECTS)__\b|@jsx(?:ImportSource|Runtime|Frag)?\b|@vite-ignore\b|(?:[#@]\s*)?sourceMappingURL=|(?:es|ox)lint-(?:disable|enable)|prettier-ignore|biome-ignore|[cv]8 ignore|istanbul ignore|webpack[A-Z])/;
|
|
@@ -2147,7 +2313,7 @@ var codeInlineEffects = new Set([
|
|
|
2147
2313
|
function codeInlineEffectBetween(program, start, end) {
|
|
2148
2314
|
return astSome(program, (node) => node.range[0] >= start && node.range[1] <= end && (codeInlineEffects.has(node.type) || node.type === "UnaryExpression" && node.operator === "delete"), (node) => node.range[1] > start && node.range[0] < end && !(node.range[0] >= start && (node.type === "FunctionDeclaration" || astIsInlineFunction(node))));
|
|
2149
2315
|
}
|
|
2150
|
-
var codeInline =
|
|
2316
|
+
var codeInline = defineRule16({
|
|
2151
2317
|
meta: {
|
|
2152
2318
|
type: "suggestion",
|
|
2153
2319
|
schema: [
|
|
@@ -2157,6 +2323,7 @@ var codeInline = defineRule15({
|
|
|
2157
2323
|
properties: {
|
|
2158
2324
|
max: { type: "integer", minimum: 1, default: 160 },
|
|
2159
2325
|
nesting: { type: "integer", minimum: 1, default: 2 },
|
|
2326
|
+
callbacks: { type: "boolean", default: false },
|
|
2160
2327
|
allow: optionsPatternSchema,
|
|
2161
2328
|
keep: optionsPatternSchema,
|
|
2162
2329
|
services: { type: "array", items: { type: "string" } }
|
|
@@ -2185,7 +2352,8 @@ var codeInline = defineRule15({
|
|
|
2185
2352
|
return;
|
|
2186
2353
|
}
|
|
2187
2354
|
if (uses.length === 1) {
|
|
2188
|
-
|
|
2355
|
+
const use = uses[0].identifier;
|
|
2356
|
+
if (init && (codeInlineEffectBetween(context.sourceCode.ast, node.range[1], use.range[0]) || codeInlineEnclosingCalls(use) + astCallDepth(init, options.callbacks ?? false) > (options.nesting ?? 2))) {
|
|
2189
2357
|
return;
|
|
2190
2358
|
}
|
|
2191
2359
|
context.report({
|
|
@@ -2197,7 +2365,12 @@ var codeInline = defineRule15({
|
|
|
2197
2365
|
}
|
|
2198
2366
|
const arrow = init?.type === "ArrowFunctionExpression" && init.body.type !== "BlockStatement" && !astSome(init.body, astIsInlineFunction);
|
|
2199
2367
|
const call = init?.type === "CallExpression" && !astSome(init.arguments, astIsInlineFunction) && astCallDepth(init) <= 2;
|
|
2200
|
-
|
|
2368
|
+
const text = context.sourceCode.text;
|
|
2369
|
+
const fits = init !== null && uses.every(({ identifier }) => {
|
|
2370
|
+
const line = text.slice(sourceLineStart(text, identifier.range[0]), sourceLineEnd(text, identifier.range[0]));
|
|
2371
|
+
return line.length - id.name.length + context.sourceCode.getText(init).length <= (options.max ?? 160) && codeInlineEnclosingCalls(identifier) + astCallDepth(init, options.callbacks ?? false) <= (options.nesting ?? 2);
|
|
2372
|
+
});
|
|
2373
|
+
if (!optionsPatternsTest(kept, id.name) && (arrow || call) && fits) {
|
|
2201
2374
|
context.report({
|
|
2202
2375
|
node: id,
|
|
2203
2376
|
messageId: "trivial",
|
|
@@ -2225,7 +2398,7 @@ var codeInline = defineRule15({
|
|
|
2225
2398
|
deferred ||= current.type === "FunctionDeclaration" || astIsInlineFunction(current);
|
|
2226
2399
|
}
|
|
2227
2400
|
const wrapped = codeInlineWrapped.has(init.type) && use.parent.type === "MemberExpression" && use.parent.object === use;
|
|
2228
|
-
if (service || wrapped || deferred || codeInlineEnclosingCalls(use) + astCallDepth(init) > (options.nesting ?? 2) || line.length - id.name.length + context.sourceCode.getText(init).length > (options.max ?? 160) || codeInlineEffectBetween(context.sourceCode.ast, declarator.range[1], use.range[0])) {
|
|
2401
|
+
if (service || wrapped || deferred || codeInlineEnclosingCalls(use) + astCallDepth(init, options.callbacks ?? false) > (options.nesting ?? 2) || line.length - id.name.length + context.sourceCode.getText(init).length > (options.max ?? 160) || codeInlineEffectBetween(context.sourceCode.ast, declarator.range[1], use.range[0])) {
|
|
2229
2402
|
return;
|
|
2230
2403
|
}
|
|
2231
2404
|
context.report({
|
|
@@ -2260,8 +2433,8 @@ var codeInline = defineRule15({
|
|
|
2260
2433
|
});
|
|
2261
2434
|
|
|
2262
2435
|
// src/rules/code/code-justified-call.ts
|
|
2263
|
-
import { defineRule as
|
|
2264
|
-
var codeJustifiedCall =
|
|
2436
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
2437
|
+
var codeJustifiedCall = defineRule17({
|
|
2265
2438
|
meta: {
|
|
2266
2439
|
type: "problem",
|
|
2267
2440
|
schema: [
|
|
@@ -2315,8 +2488,8 @@ var codeJustifiedCall = defineRule16({
|
|
|
2315
2488
|
});
|
|
2316
2489
|
|
|
2317
2490
|
// src/rules/code/code-literal-in.ts
|
|
2318
|
-
import { defineRule as
|
|
2319
|
-
var codeLiteralIn =
|
|
2491
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
2492
|
+
var codeLiteralIn = defineRule18({
|
|
2320
2493
|
meta: {
|
|
2321
2494
|
type: "suggestion",
|
|
2322
2495
|
schema: [
|
|
@@ -2357,7 +2530,7 @@ var codeLiteralIn = defineRule17({
|
|
|
2357
2530
|
});
|
|
2358
2531
|
|
|
2359
2532
|
// src/rules/code/code-mutable-state.ts
|
|
2360
|
-
import { defineRule as
|
|
2533
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
2361
2534
|
var functionScopes = new Set([
|
|
2362
2535
|
"FunctionDeclaration",
|
|
2363
2536
|
"FunctionExpression",
|
|
@@ -2374,7 +2547,7 @@ function hasAncestor(node, test) {
|
|
|
2374
2547
|
}
|
|
2375
2548
|
return false;
|
|
2376
2549
|
}
|
|
2377
|
-
var codeMutableState =
|
|
2550
|
+
var codeMutableState = defineRule19({
|
|
2378
2551
|
meta: {
|
|
2379
2552
|
type: "problem",
|
|
2380
2553
|
schema: [
|
|
@@ -2432,7 +2605,7 @@ var codeMutableState = defineRule18({
|
|
|
2432
2605
|
});
|
|
2433
2606
|
|
|
2434
2607
|
// src/rules/code/code-object-params.ts
|
|
2435
|
-
import { defineRule as
|
|
2608
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
2436
2609
|
function isObjectParam(node) {
|
|
2437
2610
|
if (node.type === "ObjectPattern") {
|
|
2438
2611
|
return true;
|
|
@@ -2446,7 +2619,7 @@ function isObjectParam(node) {
|
|
|
2446
2619
|
const annotation = node.typeAnnotation?.typeAnnotation;
|
|
2447
2620
|
return !annotation || annotation.type === "TSTypeReference" || annotation.type === "TSTypeLiteral" || annotation.type === "TSIntersectionType";
|
|
2448
2621
|
}
|
|
2449
|
-
var codeObjectParams =
|
|
2622
|
+
var codeObjectParams = defineRule20({
|
|
2450
2623
|
meta: {
|
|
2451
2624
|
type: "problem",
|
|
2452
2625
|
schema: [
|
|
@@ -2495,8 +2668,8 @@ var codeObjectParams = defineRule19({
|
|
|
2495
2668
|
});
|
|
2496
2669
|
|
|
2497
2670
|
// src/rules/code/code-paired-call.ts
|
|
2498
|
-
import { defineRule as
|
|
2499
|
-
var codePairedCall =
|
|
2671
|
+
import { defineRule as defineRule21 } from "@oxlint/plugins";
|
|
2672
|
+
var codePairedCall = defineRule21({
|
|
2500
2673
|
meta: {
|
|
2501
2674
|
type: "problem",
|
|
2502
2675
|
schema: [
|
|
@@ -2563,7 +2736,7 @@ var codePairedCall = defineRule20({
|
|
|
2563
2736
|
});
|
|
2564
2737
|
|
|
2565
2738
|
// src/rules/code/code-promise-mutation.ts
|
|
2566
|
-
import { defineRule as
|
|
2739
|
+
import { defineRule as defineRule22 } from "@oxlint/plugins";
|
|
2567
2740
|
function mutationBinding(node) {
|
|
2568
2741
|
if (node.type === "Identifier") {
|
|
2569
2742
|
return node;
|
|
@@ -2592,7 +2765,7 @@ function mutationBindings(node) {
|
|
|
2592
2765
|
const binding = mutationBinding(node);
|
|
2593
2766
|
return binding ? [binding] : [];
|
|
2594
2767
|
}
|
|
2595
|
-
var codePromiseMutation =
|
|
2768
|
+
var codePromiseMutation = defineRule22({
|
|
2596
2769
|
meta: {
|
|
2597
2770
|
type: "problem",
|
|
2598
2771
|
schema: [
|
|
@@ -2685,8 +2858,8 @@ var codePromiseMutation = defineRule21({
|
|
|
2685
2858
|
var codeSwitch = astSelectorRule("SwitchStatement", "Avoid switch statements.");
|
|
2686
2859
|
|
|
2687
2860
|
// src/rules/code/code-traced.ts
|
|
2688
|
-
import { defineRule as
|
|
2689
|
-
var codeTraced =
|
|
2861
|
+
import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
2862
|
+
var codeTraced = defineRule23({
|
|
2690
2863
|
meta: {
|
|
2691
2864
|
type: "problem",
|
|
2692
2865
|
schema: [
|
|
@@ -2773,7 +2946,7 @@ var codeTraced = defineRule22({
|
|
|
2773
2946
|
});
|
|
2774
2947
|
|
|
2775
2948
|
// src/rules/code/code-trivial-functions.ts
|
|
2776
|
-
import { defineRule as
|
|
2949
|
+
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
2777
2950
|
var codeTrivialFunctionsBanned = [
|
|
2778
2951
|
"isRecord",
|
|
2779
2952
|
"isPlainObject",
|
|
@@ -2903,7 +3076,35 @@ function guardStatement(node, state) {
|
|
|
2903
3076
|
return guardFallback(declaration.init);
|
|
2904
3077
|
});
|
|
2905
3078
|
}
|
|
2906
|
-
|
|
3079
|
+
function codeTrivialFunctionsDefaults(program) {
|
|
3080
|
+
const starts = [];
|
|
3081
|
+
const names = new Set;
|
|
3082
|
+
for (const statement of program.body) {
|
|
3083
|
+
const declaration = statement.type === "ExportDefaultDeclaration" ? statement.declaration : undefined;
|
|
3084
|
+
if (declaration?.type === "FunctionDeclaration" || declaration && astIsInlineFunction(declaration)) {
|
|
3085
|
+
starts.push(declaration.start);
|
|
3086
|
+
} else if (declaration?.type === "Identifier") {
|
|
3087
|
+
names.add(declaration.name);
|
|
3088
|
+
} else if (statement.type === "ExportNamedDeclaration" && !statement.source) {
|
|
3089
|
+
const specifier = statement.specifiers.find((item) => astModuleName(item.exported) === "default");
|
|
3090
|
+
if (specifier) {
|
|
3091
|
+
names.add(astModuleName(specifier.local));
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
for (const statement of program.body) {
|
|
3096
|
+
if (statement.type === "FunctionDeclaration" && statement.id && names.has(statement.id.name)) {
|
|
3097
|
+
starts.push(statement.start);
|
|
3098
|
+
}
|
|
3099
|
+
for (const declarator of statement.type === "VariableDeclaration" ? statement.declarations : []) {
|
|
3100
|
+
if (declarator.id.type === "Identifier" && names.has(declarator.id.name) && declarator.init && astIsInlineFunction(declarator.init)) {
|
|
3101
|
+
starts.push(declarator.init.start);
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
return starts;
|
|
3106
|
+
}
|
|
3107
|
+
var codeTrivialFunctions = defineRule24({
|
|
2907
3108
|
meta: {
|
|
2908
3109
|
type: "problem",
|
|
2909
3110
|
schema: [
|
|
@@ -2917,7 +3118,8 @@ var codeTrivialFunctions = defineRule23({
|
|
|
2917
3118
|
services: { type: "boolean" },
|
|
2918
3119
|
mode: { type: "string", enum: ["legacy", "precise"] },
|
|
2919
3120
|
deny: { type: "array", items: { type: "string" }, uniqueItems: true },
|
|
2920
|
-
guards: { type: "boolean" }
|
|
3121
|
+
guards: { type: "boolean" },
|
|
3122
|
+
defaults: { type: "boolean" }
|
|
2921
3123
|
}
|
|
2922
3124
|
}
|
|
2923
3125
|
],
|
|
@@ -2937,8 +3139,10 @@ var codeTrivialFunctions = defineRule23({
|
|
|
2937
3139
|
let checkServiceMethods = false;
|
|
2938
3140
|
const reported = new Set;
|
|
2939
3141
|
const checked = new Set;
|
|
3142
|
+
const defaults = new Set;
|
|
3143
|
+
let checkDefaults = true;
|
|
2940
3144
|
function checkHelper(node) {
|
|
2941
|
-
if (bannedNames.size === 0 && !checkGenericGuards || checked.has(node.start)) {
|
|
3145
|
+
if (bannedNames.size === 0 && !checkGenericGuards || checked.has(node.start) || defaults.has(node.start)) {
|
|
2942
3146
|
return;
|
|
2943
3147
|
}
|
|
2944
3148
|
checked.add(node.start);
|
|
@@ -3003,12 +3207,20 @@ var codeTrivialFunctions = defineRule23({
|
|
|
3003
3207
|
allowAsync = options.async ?? false;
|
|
3004
3208
|
reported.clear();
|
|
3005
3209
|
checked.clear();
|
|
3210
|
+
defaults.clear();
|
|
3211
|
+
checkDefaults = options.defaults ?? true;
|
|
3006
3212
|
},
|
|
3007
3213
|
FunctionDeclaration: checkHelper,
|
|
3008
3214
|
FunctionExpression: checkHelper,
|
|
3009
3215
|
ArrowFunctionExpression: checkHelper,
|
|
3010
3216
|
Program(program) {
|
|
3217
|
+
for (const start of checkDefaults ? [] : codeTrivialFunctionsDefaults(program)) {
|
|
3218
|
+
defaults.add(start);
|
|
3219
|
+
}
|
|
3011
3220
|
for (const { name, node } of exportsCheckedFunctions(program, true, checkServiceMethods, allowed)) {
|
|
3221
|
+
if (defaults.has(node.start)) {
|
|
3222
|
+
continue;
|
|
3223
|
+
}
|
|
3012
3224
|
checkHelper(node);
|
|
3013
3225
|
if (reported.has(node.start) || node.returnType?.typeAnnotation.type === "TSTypePredicate") {
|
|
3014
3226
|
continue;
|
|
@@ -3034,8 +3246,8 @@ var codeTrivialFunctions = defineRule23({
|
|
|
3034
3246
|
});
|
|
3035
3247
|
|
|
3036
3248
|
// src/rules/code/code-yield-argument.ts
|
|
3037
|
-
import { defineRule as
|
|
3038
|
-
var codeYieldArgument =
|
|
3249
|
+
import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
3250
|
+
var codeYieldArgument = defineRule25({
|
|
3039
3251
|
meta: {
|
|
3040
3252
|
type: "suggestion",
|
|
3041
3253
|
messages: {
|
|
@@ -3057,7 +3269,7 @@ var codeYieldArgument = defineRule24({
|
|
|
3057
3269
|
});
|
|
3058
3270
|
|
|
3059
3271
|
// src/rules/comments/comments-code.ts
|
|
3060
|
-
import { defineRule as
|
|
3272
|
+
import { defineRule as defineRule26 } from "@oxlint/plugins";
|
|
3061
3273
|
var commentsLineGap = /^[\t \r\n\u2028\u2029]*$/;
|
|
3062
3274
|
var commentsLineTerminator = /\r\n|[\n\r\u2028\u2029]/;
|
|
3063
3275
|
var commentsUnicodeTerminator = /[\u2028\u2029]/;
|
|
@@ -3108,7 +3320,7 @@ function commentsFollowsOpeningBrace(text, offset) {
|
|
|
3108
3320
|
}
|
|
3109
3321
|
return false;
|
|
3110
3322
|
}
|
|
3111
|
-
var commentsCode =
|
|
3323
|
+
var commentsCode = defineRule26({
|
|
3112
3324
|
meta: {
|
|
3113
3325
|
type: "suggestion",
|
|
3114
3326
|
fixable: "code",
|
|
@@ -3120,7 +3332,8 @@ var commentsCode = defineRule25({
|
|
|
3120
3332
|
why: { anyOf: [{ type: "boolean" }, { type: "string", minLength: 1 }], default: true },
|
|
3121
3333
|
allow: { type: "array", items: { type: "string" } },
|
|
3122
3334
|
jsdoc: { type: "boolean", default: false },
|
|
3123
|
-
members: { type: "string", enum: ["off", "also", "only"] }
|
|
3335
|
+
members: { type: "string", enum: ["off", "also", "only"] },
|
|
3336
|
+
steps: { type: "boolean", default: false }
|
|
3124
3337
|
}
|
|
3125
3338
|
}
|
|
3126
3339
|
],
|
|
@@ -3135,9 +3348,31 @@ var commentsCode = defineRule25({
|
|
|
3135
3348
|
let allowJsdoc = false;
|
|
3136
3349
|
let allowed = [];
|
|
3137
3350
|
let members = "off";
|
|
3351
|
+
let steps = false;
|
|
3352
|
+
let functionDepth = 0;
|
|
3138
3353
|
const memberComments = new Set;
|
|
3354
|
+
const stepStarts = new Set;
|
|
3355
|
+
function enterFunction() {
|
|
3356
|
+
functionDepth++;
|
|
3357
|
+
}
|
|
3358
|
+
function exitFunction() {
|
|
3359
|
+
functionDepth--;
|
|
3360
|
+
}
|
|
3361
|
+
function addSteps(nodes, inFunction) {
|
|
3362
|
+
if (steps && inFunction) {
|
|
3363
|
+
for (const node of nodes) {
|
|
3364
|
+
stepStarts.add(node.range[0]);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
function isStep(comment) {
|
|
3369
|
+
const source = context.sourceCode;
|
|
3370
|
+
const before = source.getTokenBefore(comment, { includeComments: true });
|
|
3371
|
+
const after = source.getTokenAfter(comment, { includeComments: true });
|
|
3372
|
+
return comment.type === "Line" && before?.loc.end.line !== comment.loc.start.line && !(before && (before.type === "Line" || before.type === "Block") && before.loc.end.line === comment.loc.start.line - 1) && after !== null && after.type !== "Line" && after.type !== "Block" && after.loc.start.line === comment.loc.end.line + 1 && stepStarts.has(after.range[0]);
|
|
3373
|
+
}
|
|
3139
3374
|
function keepComment(comment, value, isWhy) {
|
|
3140
|
-
return allowWhy && isWhy || sourceIsDirective(value) || allowJsdoc && comment.type === "Block" && context.sourceCode.text.startsWith("/**", comment.range[0]) || allowed.some((pattern) => pattern.test(value.trim()));
|
|
3375
|
+
return allowWhy && isWhy || sourceIsDirective(value) || allowJsdoc && comment.type === "Block" && context.sourceCode.text.startsWith("/**", comment.range[0]) || allowed.some((pattern) => pattern.test(value.trim())) || steps && isStep(comment);
|
|
3141
3376
|
}
|
|
3142
3377
|
function checkMember(node) {
|
|
3143
3378
|
const parent = node.parent;
|
|
@@ -3161,7 +3396,10 @@ var commentsCode = defineRule25({
|
|
|
3161
3396
|
allowJsdoc = options.jsdoc ?? false;
|
|
3162
3397
|
allowed = (options.allow ?? []).map((pattern) => new RegExp(pattern));
|
|
3163
3398
|
members = options.members ?? "off";
|
|
3399
|
+
steps = options.steps ?? false;
|
|
3400
|
+
functionDepth = 0;
|
|
3164
3401
|
memberComments.clear();
|
|
3402
|
+
stepStarts.clear();
|
|
3165
3403
|
},
|
|
3166
3404
|
TSPropertySignature: checkMember,
|
|
3167
3405
|
TSMethodSignature: checkMember,
|
|
@@ -3170,6 +3408,17 @@ var commentsCode = defineRule25({
|
|
|
3170
3408
|
TSConstructSignatureDeclaration: checkMember,
|
|
3171
3409
|
Property: checkMember,
|
|
3172
3410
|
SpreadElement: checkMember,
|
|
3411
|
+
FunctionDeclaration: enterFunction,
|
|
3412
|
+
"FunctionDeclaration:exit": exitFunction,
|
|
3413
|
+
FunctionExpression: enterFunction,
|
|
3414
|
+
"FunctionExpression:exit": exitFunction,
|
|
3415
|
+
ArrowFunctionExpression: enterFunction,
|
|
3416
|
+
"ArrowFunctionExpression:exit": exitFunction,
|
|
3417
|
+
BlockStatement: (node) => addSteps(node.body, functionDepth > 0),
|
|
3418
|
+
SwitchCase: (node) => addSteps(node.consequent, functionDepth > 0),
|
|
3419
|
+
IfStatement: (node) => addSteps([node.consequent, ...node.alternate ? [node.alternate] : []], functionDepth > 0),
|
|
3420
|
+
"ForStatement, ForInStatement, ForOfStatement, WhileStatement, DoWhileStatement, LabeledStatement": (node) => addSteps([node.body], functionDepth > 0),
|
|
3421
|
+
ObjectExpression: (node) => addSteps(node.properties, true),
|
|
3173
3422
|
"Program:exit"(program) {
|
|
3174
3423
|
const text = context.sourceCode.text;
|
|
3175
3424
|
const found = [];
|
|
@@ -3274,9 +3523,9 @@ var commentsCode = defineRule25({
|
|
|
3274
3523
|
});
|
|
3275
3524
|
|
|
3276
3525
|
// src/rules/comments/comments-directives.ts
|
|
3277
|
-
import { defineRule as
|
|
3526
|
+
import { defineRule as defineRule27 } from "@oxlint/plugins";
|
|
3278
3527
|
var directive = /^\s*(?:oxlint|eslint)-disable(?:-next-line|-line)?\b(.*)$/s;
|
|
3279
|
-
var commentsDirectives =
|
|
3528
|
+
var commentsDirectives = defineRule27({
|
|
3280
3529
|
meta: {
|
|
3281
3530
|
type: "problem",
|
|
3282
3531
|
schema: [],
|
|
@@ -3304,9 +3553,9 @@ var commentsDirectives = defineRule26({
|
|
|
3304
3553
|
});
|
|
3305
3554
|
|
|
3306
3555
|
// src/rules/copy/copy-dashes.ts
|
|
3307
|
-
import { defineRule as
|
|
3556
|
+
import { defineRule as defineRule28 } from "@oxlint/plugins";
|
|
3308
3557
|
var copyDashesMessage = "Use a comma, colon, period or parentheses instead.";
|
|
3309
|
-
var copyDashes =
|
|
3558
|
+
var copyDashes = defineRule28({
|
|
3310
3559
|
meta: {
|
|
3311
3560
|
type: "suggestion",
|
|
3312
3561
|
schema: [
|
|
@@ -3362,7 +3611,7 @@ var copyDashes = defineRule27({
|
|
|
3362
3611
|
});
|
|
3363
3612
|
|
|
3364
3613
|
// src/rules/effect/effect-layer-file.ts
|
|
3365
|
-
import { defineRule as
|
|
3614
|
+
import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
3366
3615
|
|
|
3367
3616
|
// src/utils/effect.utils.ts
|
|
3368
3617
|
var effectBuilders = ["Effect.gen", "Effect.fn", "Effect.fnUntraced"];
|
|
@@ -3404,7 +3653,7 @@ var effectLayerFileDefaultConstructors = [
|
|
|
3404
3653
|
"Layer.sync",
|
|
3405
3654
|
"Layer.unwrap"
|
|
3406
3655
|
];
|
|
3407
|
-
var effectLayerFile =
|
|
3656
|
+
var effectLayerFile = defineRule29({
|
|
3408
3657
|
meta: {
|
|
3409
3658
|
type: "problem",
|
|
3410
3659
|
schema: [
|
|
@@ -3415,6 +3664,7 @@ var effectLayerFile = defineRule28({
|
|
|
3415
3664
|
layer: { type: "string" },
|
|
3416
3665
|
make: { type: "string" },
|
|
3417
3666
|
prefix: { type: "string" },
|
|
3667
|
+
suffix: { type: "string" },
|
|
3418
3668
|
builders: { type: "array", items: { type: "string" } },
|
|
3419
3669
|
layers: optionsPatternSchema,
|
|
3420
3670
|
services: optionsPatternSchema,
|
|
@@ -3427,8 +3677,8 @@ var effectLayerFile = defineRule28({
|
|
|
3427
3677
|
notLayer: "`{{layer}}` is built with Layer: a Layer call, a Layer pipe, or a function returning one.",
|
|
3428
3678
|
builderName: "The Effect that builds the service is named `{{make}}`, one per layer file.",
|
|
3429
3679
|
moduleMethod: "Only `{{make}}` is an Effect at module level; move this into `{{make}}`, or into a utils file if two files use it.",
|
|
3430
|
-
moduleHelper: "A layer file holds only `{{make}}`, {{prefix}}<Role> layers and `{{layer}}`; move this into `{{make}}`, or into a utils file if two files use it.",
|
|
3431
|
-
localLayer: "A Layer other than `{{layer}}` is named {{prefix}}<Role> and is not exported.",
|
|
3680
|
+
moduleHelper: "A layer file holds only `{{make}}`, {{prefix}}<Role>{{suffix}} layers and `{{layer}}`; move this into `{{make}}`, or into a utils file if two files use it.",
|
|
3681
|
+
localLayer: "A Layer other than `{{layer}}` is named {{prefix}}<Role>{{suffix}} and is not exported.",
|
|
3432
3682
|
makeReturn: "`{{make}}` returns the service through its tag (Tag.of({ … })), a Context, or a Layer.",
|
|
3433
3683
|
inlineBuilder: "Build this layer from `{{make}}`, not an inline Effect: Layer.effect(Tag, {{make}}). One built layer per file."
|
|
3434
3684
|
}
|
|
@@ -3437,6 +3687,7 @@ var effectLayerFile = defineRule28({
|
|
|
3437
3687
|
let layer = "layer";
|
|
3438
3688
|
let make = "make";
|
|
3439
3689
|
let prefix = "layer";
|
|
3690
|
+
let suffix = "";
|
|
3440
3691
|
let builders = new Set(effectBuilders);
|
|
3441
3692
|
let layers = [];
|
|
3442
3693
|
let services = [];
|
|
@@ -3453,14 +3704,15 @@ var effectLayerFile = defineRule28({
|
|
|
3453
3704
|
const options = optionsFirst(context, {});
|
|
3454
3705
|
layer = options.layer ?? "layer";
|
|
3455
3706
|
make = options.make ?? "make";
|
|
3456
|
-
|
|
3707
|
+
suffix = options.suffix ?? "";
|
|
3708
|
+
prefix = options.prefix ?? (suffix ? "" : "layer");
|
|
3457
3709
|
builders = new Set(options.builders ?? effectBuilders);
|
|
3458
3710
|
constructors = new Set(options.constructors ?? effectLayerFileDefaultConstructors);
|
|
3459
|
-
layers = optionsPatterns(options.layers ?? effectLayerFileDefaultLayers);
|
|
3711
|
+
layers = optionsPatterns(options.layers ?? [...effectLayerFileDefaultLayers, ...suffix ? [`(?:^|\\.)\\w+${optionsEscape(suffix)}$`] : []]);
|
|
3460
3712
|
services = [...optionsPatterns(options.services ?? effectLayerFileDefaultServices), ...layers];
|
|
3461
3713
|
},
|
|
3462
3714
|
Program(program) {
|
|
3463
|
-
const data = { layer, make, prefix };
|
|
3715
|
+
const data = { layer, make, prefix, suffix };
|
|
3464
3716
|
const declarators = program.body.flatMap((statement) => {
|
|
3465
3717
|
const declaration = astDeclaration(statement);
|
|
3466
3718
|
const exported = statement.type === "ExportNamedDeclaration";
|
|
@@ -3520,7 +3772,8 @@ var effectLayerFile = defineRule28({
|
|
|
3520
3772
|
data
|
|
3521
3773
|
});
|
|
3522
3774
|
}
|
|
3523
|
-
|
|
3775
|
+
const role = name.endsWith(suffix) ? name.slice(prefix.length, name.length - suffix.length) : "";
|
|
3776
|
+
if (isLayer && name !== layer && (exported || !name.startsWith(prefix) || !/^[A-Z]\w*$/.test(role))) {
|
|
3524
3777
|
context.report({
|
|
3525
3778
|
node,
|
|
3526
3779
|
messageId: "localLayer",
|
|
@@ -3557,7 +3810,7 @@ var effectLayerFile = defineRule28({
|
|
|
3557
3810
|
context.report({
|
|
3558
3811
|
node: argument,
|
|
3559
3812
|
messageId: "inlineBuilder",
|
|
3560
|
-
data: { layer, make, prefix }
|
|
3813
|
+
data: { layer, make, prefix, suffix }
|
|
3561
3814
|
});
|
|
3562
3815
|
}
|
|
3563
3816
|
}
|
|
@@ -3567,7 +3820,7 @@ var effectLayerFile = defineRule28({
|
|
|
3567
3820
|
});
|
|
3568
3821
|
|
|
3569
3822
|
// src/rules/effect/effect-layers.ts
|
|
3570
|
-
import { defineRule as
|
|
3823
|
+
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3571
3824
|
var effectLayersDefaultMerge = ["Layer.mergeAll"];
|
|
3572
3825
|
var effectLayersDefaultProvide = ["Effect.provide", "Layer.provide", "Layer.provideMerge"];
|
|
3573
3826
|
var effectLayersDefaultMin = 2;
|
|
@@ -3579,7 +3832,7 @@ var effectLayersGroupSchema = {
|
|
|
3579
3832
|
min: { type: "integer", minimum: 1 }
|
|
3580
3833
|
}
|
|
3581
3834
|
};
|
|
3582
|
-
var effectLayers =
|
|
3835
|
+
var effectLayers = defineRule30({
|
|
3583
3836
|
meta: {
|
|
3584
3837
|
type: "layout",
|
|
3585
3838
|
fixable: "whitespace",
|
|
@@ -3661,11 +3914,11 @@ var effectLayers = defineRule29({
|
|
|
3661
3914
|
});
|
|
3662
3915
|
|
|
3663
3916
|
// src/rules/effect/effect-merge-pipe.ts
|
|
3664
|
-
import { defineRule as
|
|
3917
|
+
import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
3665
3918
|
var effectMergePipeDefaultMerge = ["Layer.mergeAll"];
|
|
3666
3919
|
var effectMergePipeDefaultPipe = ["pipe", "Function.pipe"];
|
|
3667
3920
|
var effectMergePipeDefaultMethods = ["pipe"];
|
|
3668
|
-
var effectMergePipe =
|
|
3921
|
+
var effectMergePipe = defineRule31({
|
|
3669
3922
|
meta: {
|
|
3670
3923
|
type: "layout",
|
|
3671
3924
|
schema: [
|
|
@@ -3710,7 +3963,7 @@ var effectMergePipe = defineRule30({
|
|
|
3710
3963
|
});
|
|
3711
3964
|
|
|
3712
3965
|
// src/rules/effect/effect-schema-first.ts
|
|
3713
|
-
import { defineRule as
|
|
3966
|
+
import { defineRule as defineRule32 } from "@oxlint/plugins";
|
|
3714
3967
|
var effectSchemaFirstDefaultRuntime = [
|
|
3715
3968
|
"Effect",
|
|
3716
3969
|
"Layer",
|
|
@@ -3772,7 +4025,7 @@ function effectSchemaFirstReference(node) {
|
|
|
3772
4025
|
}
|
|
3773
4026
|
return node.type === "TSInterfaceHeritage" ? astDottedName(node.expression) : undefined;
|
|
3774
4027
|
}
|
|
3775
|
-
var effectSchemaFirst =
|
|
4028
|
+
var effectSchemaFirst = defineRule32({
|
|
3776
4029
|
meta: {
|
|
3777
4030
|
type: "suggestion",
|
|
3778
4031
|
schema: [
|
|
@@ -3945,7 +4198,7 @@ var effectSchemaFirst = defineRule31({
|
|
|
3945
4198
|
});
|
|
3946
4199
|
|
|
3947
4200
|
// src/rules/effect/effect-values-first.ts
|
|
3948
|
-
import { defineRule as
|
|
4201
|
+
import { defineRule as defineRule33 } from "@oxlint/plugins";
|
|
3949
4202
|
var effectValuesFirstDefaultPinned = [
|
|
3950
4203
|
"^Layer\\.",
|
|
3951
4204
|
"^Context\\.",
|
|
@@ -3954,7 +4207,7 @@ var effectValuesFirstDefaultPinned = [
|
|
|
3954
4207
|
"(?:^|\\.)layer[^.]*$",
|
|
3955
4208
|
"^Schema\\.(?:asserts|decode\\w*|encode\\w*|is|isSchema|isSchemaError|resolveAnnotations)$"
|
|
3956
4209
|
];
|
|
3957
|
-
var effectValuesFirst =
|
|
4210
|
+
var effectValuesFirst = defineRule33({
|
|
3958
4211
|
meta: {
|
|
3959
4212
|
type: "suggestion",
|
|
3960
4213
|
schema: [
|
|
@@ -4037,7 +4290,7 @@ var effectValuesFirst = defineRule32({
|
|
|
4037
4290
|
});
|
|
4038
4291
|
|
|
4039
4292
|
// src/rules/files/files-components-only.ts
|
|
4040
|
-
import { defineRule as
|
|
4293
|
+
import { defineRule as defineRule34 } from "@oxlint/plugins";
|
|
4041
4294
|
|
|
4042
4295
|
// src/utils/react.utils.ts
|
|
4043
4296
|
function reactReturnsOutput(program, node) {
|
|
@@ -4109,7 +4362,7 @@ function reactIsComponent(program, candidate) {
|
|
|
4109
4362
|
function componentName(basename2) {
|
|
4110
4363
|
return basename2.replace(/\.(tsx?|jsx?)$/, "").replaceAll(/(?:^[-.]*|[-.]+)(.?)/g, (_, char) => char.toUpperCase());
|
|
4111
4364
|
}
|
|
4112
|
-
var filesComponentsOnly =
|
|
4365
|
+
var filesComponentsOnly = defineRule34({
|
|
4113
4366
|
meta: {
|
|
4114
4367
|
type: "problem",
|
|
4115
4368
|
schema: [
|
|
@@ -4197,7 +4450,7 @@ var filesComponentsOnly = defineRule33({
|
|
|
4197
4450
|
});
|
|
4198
4451
|
|
|
4199
4452
|
// src/rules/files/files-constants-only.ts
|
|
4200
|
-
import { defineRule as
|
|
4453
|
+
import { defineRule as defineRule35 } from "@oxlint/plugins";
|
|
4201
4454
|
function unwrap(expression) {
|
|
4202
4455
|
if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "TSInstantiationExpression") {
|
|
4203
4456
|
return unwrap(expression.expression);
|
|
@@ -4252,7 +4505,7 @@ function collectBindings(program) {
|
|
|
4252
4505
|
}
|
|
4253
4506
|
return bindings;
|
|
4254
4507
|
}
|
|
4255
|
-
var filesConstantsOnly =
|
|
4508
|
+
var filesConstantsOnly = defineRule35({
|
|
4256
4509
|
meta: {
|
|
4257
4510
|
type: "problem",
|
|
4258
4511
|
schema: [
|
|
@@ -4351,7 +4604,7 @@ var filesConstantsOnly = defineRule34({
|
|
|
4351
4604
|
});
|
|
4352
4605
|
|
|
4353
4606
|
// src/rules/files/files-domain-constants.ts
|
|
4354
|
-
import { defineRule as
|
|
4607
|
+
import { defineRule as defineRule36 } from "@oxlint/plugins";
|
|
4355
4608
|
import { basename as basename2, dirname as dirname2 } from "node:path";
|
|
4356
4609
|
function isData(expression) {
|
|
4357
4610
|
const value = astUnwrap(expression);
|
|
@@ -4369,7 +4622,7 @@ function isData(expression) {
|
|
|
4369
4622
|
}
|
|
4370
4623
|
return value.type === "NewExpression" && value.callee.type === "Identifier" && ["Map", "Set"].includes(value.callee.name) && value.arguments[0]?.type === "ArrayExpression" && value.arguments[0].elements.length > 0;
|
|
4371
4624
|
}
|
|
4372
|
-
var filesDomainConstants =
|
|
4625
|
+
var filesDomainConstants = defineRule36({
|
|
4373
4626
|
meta: {
|
|
4374
4627
|
type: "problem",
|
|
4375
4628
|
schema: [
|
|
@@ -4434,11 +4687,9 @@ var filesDomainConstants = defineRule35({
|
|
|
4434
4687
|
});
|
|
4435
4688
|
|
|
4436
4689
|
// src/rules/files/files-exports.ts
|
|
4437
|
-
import { defineRule as
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
}
|
|
4441
|
-
var filesExports = defineRule36({
|
|
4690
|
+
import { defineRule as defineRule37 } from "@oxlint/plugins";
|
|
4691
|
+
import { posix as posix2 } from "node:path";
|
|
4692
|
+
var filesExports = defineRule37({
|
|
4442
4693
|
meta: {
|
|
4443
4694
|
type: "problem",
|
|
4444
4695
|
schema: [
|
|
@@ -4448,7 +4699,8 @@ var filesExports = defineRule36({
|
|
|
4448
4699
|
properties: {
|
|
4449
4700
|
names: { type: "array", items: { type: "string" } },
|
|
4450
4701
|
patterns: { type: "array", items: { type: "string" } },
|
|
4451
|
-
stem: { type: "string", enum: [...namingStemModes] },
|
|
4702
|
+
stem: { type: "string", enum: [...namingStemModes, "folder"] },
|
|
4703
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
4452
4704
|
roles: { type: "array", items: { type: "string" } },
|
|
4453
4705
|
separators: { type: "array", items: { type: "string" } },
|
|
4454
4706
|
types: { type: "boolean" },
|
|
@@ -4491,12 +4743,14 @@ var filesExports = defineRule36({
|
|
|
4491
4743
|
if (options.names === undefined && options.patterns === undefined) {
|
|
4492
4744
|
return;
|
|
4493
4745
|
}
|
|
4494
|
-
const
|
|
4746
|
+
const read = options.stem === "folder" ? namingBasename(posix2.dirname(context.filename.replaceAll("\\", "/"))) : namingFileStem(basename3, options.stem, options.roles, options.separators);
|
|
4747
|
+
const last = read.split(/[-_]+/).at(-1) ?? "";
|
|
4748
|
+
const domain = options.singularize === "trailing-s" && last.length > 1 && last.endsWith("s") ? read.slice(0, -1) : read;
|
|
4495
4749
|
const pascalDomain = namingPascalCase(domain);
|
|
4496
4750
|
const camelDomain = namingCamelCase(domain);
|
|
4497
4751
|
const allowed = (options.names ?? []).map((template) => template.replaceAll("{Domain}", pascalDomain).replaceAll("{domain}", camelDomain));
|
|
4498
4752
|
const patterns = (options.patterns ?? []).map((template) => {
|
|
4499
|
-
const source = template.replaceAll("{Domain}",
|
|
4753
|
+
const source = template.replaceAll("{Domain}", optionsEscape(pascalDomain)).replaceAll("{domain}", optionsEscape(camelDomain));
|
|
4500
4754
|
return new RegExp(`^(?:${source})$`);
|
|
4501
4755
|
});
|
|
4502
4756
|
const allowedLabel = [...allowed, ...patterns.map((pattern) => pattern.toString())].join(", ");
|
|
@@ -4519,12 +4773,12 @@ var filesExports = defineRule36({
|
|
|
4519
4773
|
});
|
|
4520
4774
|
|
|
4521
4775
|
// src/rules/files/files-externals.ts
|
|
4522
|
-
import { defineRule as
|
|
4776
|
+
import { defineRule as defineRule38 } from "@oxlint/plugins";
|
|
4523
4777
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
4524
4778
|
import { builtinModules as builtinModules2 } from "node:module";
|
|
4525
4779
|
import { dirname as dirname3, join as join2 } from "node:path";
|
|
4526
4780
|
var filesExternalsConfigs = "^(?:vite|next)\\.config\\.[cm]?[jt]s$";
|
|
4527
|
-
var filesExternals =
|
|
4781
|
+
var filesExternals = defineRule38({
|
|
4528
4782
|
meta: {
|
|
4529
4783
|
type: "problem",
|
|
4530
4784
|
schema: [
|
|
@@ -4617,7 +4871,7 @@ var filesExternals = defineRule37({
|
|
|
4617
4871
|
});
|
|
4618
4872
|
|
|
4619
4873
|
// src/rules/files/files-factory-keys.ts
|
|
4620
|
-
import { defineRule as
|
|
4874
|
+
import { defineRule as defineRule39 } from "@oxlint/plugins";
|
|
4621
4875
|
function returnedObject(expression) {
|
|
4622
4876
|
if (expression?.type === "TSAsExpression" || expression?.type === "TSSatisfiesExpression" || expression?.type === "TSTypeAssertion" || expression?.type === "TSNonNullExpression") {
|
|
4623
4877
|
return returnedObject(expression.expression);
|
|
@@ -4628,7 +4882,7 @@ function compileKeys(pattern, keys, requireKeys) {
|
|
|
4628
4882
|
const allowedList = keys.concat(requireKeys.filter((key) => !keys.includes(key)));
|
|
4629
4883
|
return { patterns: optionsPatternsWithEmpty(pattern), allowed: new Set(allowedList), allowedList, required: requireKeys };
|
|
4630
4884
|
}
|
|
4631
|
-
var filesFactoryKeys =
|
|
4885
|
+
var filesFactoryKeys = defineRule39({
|
|
4632
4886
|
meta: {
|
|
4633
4887
|
type: "problem",
|
|
4634
4888
|
schema: [
|
|
@@ -4746,8 +5000,8 @@ var filesFactoryKeys = defineRule38({
|
|
|
4746
5000
|
});
|
|
4747
5001
|
|
|
4748
5002
|
// src/rules/files/files-helpers.ts
|
|
4749
|
-
import { defineRule as
|
|
4750
|
-
var filesHelpers =
|
|
5003
|
+
import { defineRule as defineRule40 } from "@oxlint/plugins";
|
|
5004
|
+
var filesHelpers = defineRule40({
|
|
4751
5005
|
meta: {
|
|
4752
5006
|
type: "problem",
|
|
4753
5007
|
schema: [
|
|
@@ -4795,8 +5049,8 @@ var filesHelpers = defineRule39({
|
|
|
4795
5049
|
});
|
|
4796
5050
|
|
|
4797
5051
|
// src/rules/files/files-no-functions.ts
|
|
4798
|
-
import { defineRule as
|
|
4799
|
-
var filesNoFunctions =
|
|
5052
|
+
import { defineRule as defineRule41 } from "@oxlint/plugins";
|
|
5053
|
+
var filesNoFunctions = defineRule41({
|
|
4800
5054
|
meta: {
|
|
4801
5055
|
type: "problem",
|
|
4802
5056
|
schema: [
|
|
@@ -4850,8 +5104,8 @@ var filesNoFunctions = defineRule40({
|
|
|
4850
5104
|
});
|
|
4851
5105
|
|
|
4852
5106
|
// src/rules/files/files-restricted.ts
|
|
4853
|
-
import { defineRule as
|
|
4854
|
-
var filesRestricted =
|
|
5107
|
+
import { defineRule as defineRule42 } from "@oxlint/plugins";
|
|
5108
|
+
var filesRestricted = defineRule42({
|
|
4855
5109
|
meta: {
|
|
4856
5110
|
type: "problem",
|
|
4857
5111
|
schema: [
|
|
@@ -4883,7 +5137,7 @@ var filesRestricted = defineRule41({
|
|
|
4883
5137
|
});
|
|
4884
5138
|
|
|
4885
5139
|
// src/rules/files/files-route.ts
|
|
4886
|
-
import { defineRule as
|
|
5140
|
+
import { defineRule as defineRule43 } from "@oxlint/plugins";
|
|
4887
5141
|
function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
|
|
4888
5142
|
astVisit(item.node.body, [item.node], (node) => {
|
|
4889
5143
|
if (banIntrinsicJsx && node.type === "JSXOpeningElement" && node.name.type === "JSXIdentifier" && /^[a-z]/.test(node.name.name)) {
|
|
@@ -4903,7 +5157,7 @@ function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
|
|
|
4903
5157
|
}
|
|
4904
5158
|
});
|
|
4905
5159
|
}
|
|
4906
|
-
var filesRoute =
|
|
5160
|
+
var filesRoute = defineRule43({
|
|
4907
5161
|
meta: {
|
|
4908
5162
|
type: "problem",
|
|
4909
5163
|
schema: [
|
|
@@ -4973,7 +5227,7 @@ var filesRoute = defineRule42({
|
|
|
4973
5227
|
});
|
|
4974
5228
|
|
|
4975
5229
|
// src/rules/files/files-types-only.ts
|
|
4976
|
-
import { defineRule as
|
|
5230
|
+
import { defineRule as defineRule44 } from "@oxlint/plugins";
|
|
4977
5231
|
function runtimeImportLocalNames(statement) {
|
|
4978
5232
|
return statement.specifiers.flatMap((specifier) => specifier.type !== "ImportSpecifier" || specifier.importKind !== "type" ? [specifier.local.name] : []);
|
|
4979
5233
|
}
|
|
@@ -5142,7 +5396,7 @@ function runtimeKind(node) {
|
|
|
5142
5396
|
}
|
|
5143
5397
|
return node.type === "FunctionDeclaration" ? "function" : "variable";
|
|
5144
5398
|
}
|
|
5145
|
-
var filesTypesOnly =
|
|
5399
|
+
var filesTypesOnly = defineRule44({
|
|
5146
5400
|
meta: {
|
|
5147
5401
|
type: "problem",
|
|
5148
5402
|
schema: [
|
|
@@ -5250,8 +5504,8 @@ var filesTypesOnly = defineRule43({
|
|
|
5250
5504
|
});
|
|
5251
5505
|
|
|
5252
5506
|
// src/rules/layout/layout-arrow-body.ts
|
|
5253
|
-
import { defineRule as
|
|
5254
|
-
var layoutArrowBody =
|
|
5507
|
+
import { defineRule as defineRule45 } from "@oxlint/plugins";
|
|
5508
|
+
var layoutArrowBody = defineRule45({
|
|
5255
5509
|
meta: {
|
|
5256
5510
|
type: "layout",
|
|
5257
5511
|
fixable: "whitespace",
|
|
@@ -5303,12 +5557,12 @@ var layoutArrowBody = defineRule44({
|
|
|
5303
5557
|
});
|
|
5304
5558
|
|
|
5305
5559
|
// src/rules/layout/layout-call-arguments.ts
|
|
5306
|
-
import { defineRule as
|
|
5560
|
+
import { defineRule as defineRule46 } from "@oxlint/plugins";
|
|
5307
5561
|
function layoutCallArgumentsHuggable(node) {
|
|
5308
5562
|
return astIsInlineFunction(node) || node.type === "ObjectExpression" || node.type === "ArrayExpression" || astIsCall(node) && node.arguments.length === 1 && (node.callee.type !== "MemberExpression" || astIsOneLine(node.callee)) && node.arguments.every(layoutCallArgumentsHuggable);
|
|
5309
5563
|
}
|
|
5310
5564
|
var layoutCallArgumentsMax = { type: "integer", minimum: 1 };
|
|
5311
|
-
var layoutCallArguments =
|
|
5565
|
+
var layoutCallArguments = defineRule46({
|
|
5312
5566
|
meta: {
|
|
5313
5567
|
type: "layout",
|
|
5314
5568
|
fixable: "whitespace",
|
|
@@ -5327,6 +5581,12 @@ var layoutCallArguments = defineRule45({
|
|
|
5327
5581
|
type: "boolean",
|
|
5328
5582
|
default: true
|
|
5329
5583
|
},
|
|
5584
|
+
pipe: {
|
|
5585
|
+
type: "object",
|
|
5586
|
+
additionalProperties: false,
|
|
5587
|
+
required: ["min"],
|
|
5588
|
+
properties: { min: { type: "integer", minimum: 2 }, methods: { type: "array", items: { type: "string" } } }
|
|
5589
|
+
},
|
|
5330
5590
|
hug: {
|
|
5331
5591
|
type: "object",
|
|
5332
5592
|
additionalProperties: false,
|
|
@@ -5349,6 +5609,7 @@ var layoutCallArguments = defineRule45({
|
|
|
5349
5609
|
],
|
|
5350
5610
|
messages: {
|
|
5351
5611
|
multiline: "A call with {{min}}+ arguments puts each argument on its own line.",
|
|
5612
|
+
pipe: "A pipe with {{min}}+ steps puts each step on its own line.",
|
|
5352
5613
|
hug: "Put every argument on its own line. Only a last callback, object or array may hug the call, after simple arguments.",
|
|
5353
5614
|
prefer: "Hug the last argument: it is a callback, object or array after simple arguments.",
|
|
5354
5615
|
join: "This fits on one line, so keep it on one line."
|
|
@@ -5358,11 +5619,13 @@ var layoutCallArguments = defineRule45({
|
|
|
5358
5619
|
let options = {};
|
|
5359
5620
|
let minArguments = 3;
|
|
5360
5621
|
let indentUnit = sourceIndentUnit();
|
|
5361
|
-
|
|
5622
|
+
let pipeMethods = new Set;
|
|
5623
|
+
const isPipe = (node) => node.callee.type === "MemberExpression" && pipeMethods.has(astMemberName(node.callee) ?? "");
|
|
5624
|
+
const split = (node, min, messageId) => {
|
|
5362
5625
|
const args = node.arguments;
|
|
5363
5626
|
const last = args.at(-1);
|
|
5364
5627
|
const source = context.sourceCode;
|
|
5365
|
-
if (args.length <
|
|
5628
|
+
if (args.length < min || !last || args.some((arg) => (arg.type === "ArrowFunctionExpression" || arg.type === "FunctionExpression") && arg.loc.start.line !== arg.loc.end.line)) {
|
|
5366
5629
|
return;
|
|
5367
5630
|
}
|
|
5368
5631
|
const text = source.text;
|
|
@@ -5384,8 +5647,8 @@ var layoutCallArguments = defineRule45({
|
|
|
5384
5647
|
const argumentIndent = `${baseIndent}${indentUnit}`;
|
|
5385
5648
|
context.report({
|
|
5386
5649
|
node,
|
|
5387
|
-
messageId
|
|
5388
|
-
data: { min: String(
|
|
5650
|
+
messageId,
|
|
5651
|
+
data: { min: String(min) },
|
|
5389
5652
|
fix: unsafe ? undefined : (fixer) => gaps.map((gap, index) => {
|
|
5390
5653
|
if (index === 0) {
|
|
5391
5654
|
return fixer.replaceTextRange(gap, `${newline}${argumentIndent}`);
|
|
@@ -5403,11 +5666,23 @@ var layoutCallArguments = defineRule45({
|
|
|
5403
5666
|
const last = args.at(-1);
|
|
5404
5667
|
const open = source.getTokenAfter(node.typeArguments ?? node.callee);
|
|
5405
5668
|
const close = source.getLastToken(node);
|
|
5406
|
-
if (!first || !last || !open || !close ||
|
|
5669
|
+
if (!first || !last || !open || !close || source.getCommentsInside(node).length > 0) {
|
|
5670
|
+
return;
|
|
5671
|
+
}
|
|
5672
|
+
if (args.every(astIsOneLine)) {
|
|
5673
|
+
if (first.loc.start.line > open.loc.end.line && close.loc.start.line === last.loc.end.line) {
|
|
5674
|
+
const newline2 = sourceNewline(text);
|
|
5675
|
+
const base2 = sourceLineIndent(text, open.range[0]);
|
|
5676
|
+
context.report({
|
|
5677
|
+
node,
|
|
5678
|
+
messageId: "hug",
|
|
5679
|
+
fix: (fixer) => sourceRespace(fixer, text, sourceItemGaps(open.range[1], args, close.range[0]), (_, end) => `${newline2}${end ? base2 : `${base2}${indentUnit}`}`)
|
|
5680
|
+
});
|
|
5681
|
+
}
|
|
5407
5682
|
return;
|
|
5408
5683
|
}
|
|
5409
5684
|
const leading = args.slice(0, -1);
|
|
5410
|
-
const canHug = !
|
|
5685
|
+
const canHug = !isPipe(node) && leading.every((arg) => astIsOneLine(arg) && astCallDepth(arg) <= 1) && layoutCallArgumentsHuggable(last);
|
|
5411
5686
|
const gaps = sourceItemGaps(open.range[1], args, close.range[0]);
|
|
5412
5687
|
if (first.loc.start.line > open.loc.end.line) {
|
|
5413
5688
|
const head = [...leading.map((arg) => source.getText(arg)), text.slice(last.range[0], sourceLineEnd(text, last.range[0]))];
|
|
@@ -5453,13 +5728,15 @@ var layoutCallArguments = defineRule45({
|
|
|
5453
5728
|
};
|
|
5454
5729
|
const call = (node) => {
|
|
5455
5730
|
const source = context.sourceCode;
|
|
5456
|
-
if (options.
|
|
5457
|
-
split(node);
|
|
5731
|
+
if (options.pipe && isPipe(node)) {
|
|
5732
|
+
split(node, options.pipe.min, "pipe");
|
|
5733
|
+
} else if (options.split !== false) {
|
|
5734
|
+
split(node, minArguments, "multiline");
|
|
5458
5735
|
}
|
|
5459
5736
|
if (options.hug) {
|
|
5460
5737
|
hug(node, options.hug.max);
|
|
5461
5738
|
}
|
|
5462
|
-
if (options.join && !(options.join.keep ?? []).includes(source.getText(node.callee)) && !(
|
|
5739
|
+
if (options.join && !(options.join.keep ?? []).includes(source.getText(node.callee)) && !(isPipe(node) && (node.arguments.length > 1 || options.pipe)) && astCallDepth(node) <= (options.join.nesting ?? Number.POSITIVE_INFINITY)) {
|
|
5463
5740
|
join3(node, node.arguments, source.getTokenAfter(node.typeArguments ?? node.callee), source.getLastToken(node));
|
|
5464
5741
|
}
|
|
5465
5742
|
};
|
|
@@ -5477,6 +5754,7 @@ var layoutCallArguments = defineRule45({
|
|
|
5477
5754
|
options = optionsFirst(context, {});
|
|
5478
5755
|
minArguments = options.min ?? 3;
|
|
5479
5756
|
indentUnit = sourceIndentUnit(options.indent);
|
|
5757
|
+
pipeMethods = new Set(options.pipe?.methods ?? ["pipe"]);
|
|
5480
5758
|
},
|
|
5481
5759
|
CallExpression: call,
|
|
5482
5760
|
NewExpression: call,
|
|
@@ -5490,12 +5768,12 @@ var layoutCallArguments = defineRule45({
|
|
|
5490
5768
|
});
|
|
5491
5769
|
|
|
5492
5770
|
// src/rules/layout/layout-call-array.ts
|
|
5493
|
-
import { defineRule as
|
|
5771
|
+
import { defineRule as defineRule47 } from "@oxlint/plugins";
|
|
5494
5772
|
var layoutCallArrayDefaultCallees = ["Promise.all", "Promise.allSettled"];
|
|
5495
5773
|
function layoutCallArrayRoot(node) {
|
|
5496
5774
|
return node.type === "MemberExpression" ? layoutCallArrayRoot(node.object) : node;
|
|
5497
5775
|
}
|
|
5498
|
-
var layoutCallArray =
|
|
5776
|
+
var layoutCallArray = defineRule47({
|
|
5499
5777
|
meta: {
|
|
5500
5778
|
type: "layout",
|
|
5501
5779
|
fixable: "whitespace",
|
|
@@ -5611,22 +5889,29 @@ var layoutCallArray = defineRule46({
|
|
|
5611
5889
|
});
|
|
5612
5890
|
|
|
5613
5891
|
// src/rules/layout/layout-call-depth.ts
|
|
5614
|
-
import { defineRule as
|
|
5615
|
-
function layoutCallDepthOuter(node) {
|
|
5892
|
+
import { defineRule as defineRule48 } from "@oxlint/plugins";
|
|
5893
|
+
function layoutCallDepthOuter(node, callbacks) {
|
|
5616
5894
|
const parent = node.parent;
|
|
5617
|
-
if (!parent || parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression"
|
|
5895
|
+
if (!parent || !callbacks && (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression")) {
|
|
5618
5896
|
return;
|
|
5619
5897
|
}
|
|
5620
|
-
|
|
5898
|
+
if (parent.type.endsWith("Statement")) {
|
|
5899
|
+
let owner = parent;
|
|
5900
|
+
while (owner?.type.endsWith("Statement")) {
|
|
5901
|
+
owner = owner.parent;
|
|
5902
|
+
}
|
|
5903
|
+
return callbacks && owner && astIsInlineFunction(owner) ? layoutCallDepthOuter(owner, callbacks) : undefined;
|
|
5904
|
+
}
|
|
5905
|
+
return astIsCall(parent) && parent.arguments.some((argument) => argument === node) ? parent : layoutCallDepthOuter(parent, callbacks);
|
|
5621
5906
|
}
|
|
5622
|
-
var layoutCallDepth =
|
|
5907
|
+
var layoutCallDepth = defineRule48({
|
|
5623
5908
|
meta: {
|
|
5624
5909
|
type: "layout",
|
|
5625
5910
|
schema: [
|
|
5626
5911
|
{
|
|
5627
5912
|
type: "object",
|
|
5628
5913
|
additionalProperties: false,
|
|
5629
|
-
properties: { max: { type: "integer", minimum: 1, default: 2 } }
|
|
5914
|
+
properties: { max: { type: "integer", minimum: 1, default: 2 }, callbacks: { type: "boolean", default: false } }
|
|
5630
5915
|
}
|
|
5631
5916
|
],
|
|
5632
5917
|
messages: {
|
|
@@ -5635,10 +5920,11 @@ var layoutCallDepth = defineRule47({
|
|
|
5635
5920
|
},
|
|
5636
5921
|
createOnce(context) {
|
|
5637
5922
|
let max = 2;
|
|
5923
|
+
let callbacks = false;
|
|
5638
5924
|
const check = (node) => {
|
|
5639
|
-
const depth = astCallDepth(node);
|
|
5640
|
-
const outer = layoutCallDepthOuter(node);
|
|
5641
|
-
if (!astIsOneLine(node) || depth <= max || outer !== undefined && astIsOneLine(outer) && astCallDepth(outer) > max) {
|
|
5925
|
+
const depth = astCallDepth(node, callbacks);
|
|
5926
|
+
const outer = layoutCallDepthOuter(node, callbacks);
|
|
5927
|
+
if (!astIsOneLine(node) || depth <= max || outer !== undefined && astIsOneLine(outer) && astCallDepth(outer, callbacks) > max) {
|
|
5642
5928
|
return;
|
|
5643
5929
|
}
|
|
5644
5930
|
context.report({
|
|
@@ -5649,7 +5935,9 @@ var layoutCallDepth = defineRule47({
|
|
|
5649
5935
|
};
|
|
5650
5936
|
return {
|
|
5651
5937
|
before() {
|
|
5652
|
-
|
|
5938
|
+
const options = optionsFirst(context, {});
|
|
5939
|
+
max = options.max ?? 2;
|
|
5940
|
+
callbacks = options.callbacks ?? false;
|
|
5653
5941
|
},
|
|
5654
5942
|
CallExpression: check,
|
|
5655
5943
|
NewExpression: check
|
|
@@ -5658,8 +5946,8 @@ var layoutCallDepth = defineRule47({
|
|
|
5658
5946
|
});
|
|
5659
5947
|
|
|
5660
5948
|
// src/rules/layout/layout-chain.ts
|
|
5661
|
-
import { defineRule as
|
|
5662
|
-
var layoutChain =
|
|
5949
|
+
import { defineRule as defineRule49 } from "@oxlint/plugins";
|
|
5950
|
+
var layoutChain = defineRule49({
|
|
5663
5951
|
meta: {
|
|
5664
5952
|
type: "layout",
|
|
5665
5953
|
fixable: "whitespace",
|
|
@@ -5778,8 +6066,8 @@ var layoutChain = defineRule48({
|
|
|
5778
6066
|
});
|
|
5779
6067
|
|
|
5780
6068
|
// src/rules/layout/layout-items.ts
|
|
5781
|
-
import { defineRule as
|
|
5782
|
-
var layoutItems =
|
|
6069
|
+
import { defineRule as defineRule50 } from "@oxlint/plugins";
|
|
6070
|
+
var layoutItems = defineRule50({
|
|
5783
6071
|
meta: {
|
|
5784
6072
|
type: "layout",
|
|
5785
6073
|
fixable: "whitespace",
|
|
@@ -5834,8 +6122,8 @@ var layoutItems = defineRule49({
|
|
|
5834
6122
|
});
|
|
5835
6123
|
|
|
5836
6124
|
// src/rules/layout/layout-jsx-attributes.ts
|
|
5837
|
-
import { defineRule as
|
|
5838
|
-
var layoutJsxAttributes =
|
|
6125
|
+
import { defineRule as defineRule51 } from "@oxlint/plugins";
|
|
6126
|
+
var layoutJsxAttributes = defineRule51({
|
|
5839
6127
|
meta: {
|
|
5840
6128
|
type: "layout",
|
|
5841
6129
|
fixable: "whitespace",
|
|
@@ -5923,8 +6211,8 @@ var layoutJsxAttributes = defineRule50({
|
|
|
5923
6211
|
});
|
|
5924
6212
|
|
|
5925
6213
|
// src/rules/layout/layout-key-value.ts
|
|
5926
|
-
import { defineRule as
|
|
5927
|
-
var layoutKeyValue =
|
|
6214
|
+
import { defineRule as defineRule52 } from "@oxlint/plugins";
|
|
6215
|
+
var layoutKeyValue = defineRule52({
|
|
5928
6216
|
meta: {
|
|
5929
6217
|
type: "layout",
|
|
5930
6218
|
fixable: "whitespace",
|
|
@@ -5960,7 +6248,7 @@ var layoutKeyValue = defineRule51({
|
|
|
5960
6248
|
});
|
|
5961
6249
|
|
|
5962
6250
|
// src/rules/layout/layout-object.ts
|
|
5963
|
-
import { defineRule as
|
|
6251
|
+
import { defineRule as defineRule53 } from "@oxlint/plugins";
|
|
5964
6252
|
function layoutObjectIsWhitespace(text) {
|
|
5965
6253
|
return /^[\t\n\r\f ]*$/.test(text);
|
|
5966
6254
|
}
|
|
@@ -5968,7 +6256,7 @@ function layoutObjectIsFlat(property) {
|
|
|
5968
6256
|
const value = property.type === "SpreadElement" ? property.argument : property.value;
|
|
5969
6257
|
return astIsOneLine(property) && (property.type === "SpreadElement" || !property.method && property.kind === "init") && value.type !== "ObjectExpression" && value.type !== "ArrayExpression" && !astIsInlineFunction(value);
|
|
5970
6258
|
}
|
|
5971
|
-
var layoutObject =
|
|
6259
|
+
var layoutObject = defineRule53({
|
|
5972
6260
|
meta: {
|
|
5973
6261
|
type: "layout",
|
|
5974
6262
|
fixable: "whitespace",
|
|
@@ -5980,6 +6268,10 @@ var layoutObject = defineRule52({
|
|
|
5980
6268
|
min: { type: "integer", minimum: 1, default: 3 },
|
|
5981
6269
|
scope: { type: "string", enum: ["call-args", "all"], default: "call-args" },
|
|
5982
6270
|
indent: { ...sourceIndentSchema, default: 2 },
|
|
6271
|
+
params: { type: "boolean", default: false },
|
|
6272
|
+
nested: { type: "boolean", default: false },
|
|
6273
|
+
siblings: { type: "boolean", default: false },
|
|
6274
|
+
inner: { type: "integer", minimum: 1 },
|
|
5983
6275
|
join: {
|
|
5984
6276
|
type: "object",
|
|
5985
6277
|
additionalProperties: false,
|
|
@@ -5995,6 +6287,11 @@ var layoutObject = defineRule52({
|
|
|
5995
6287
|
messages: {
|
|
5996
6288
|
callArgs: "Object with {{min}}+ properties in a call should have each property on its own line.",
|
|
5997
6289
|
always: "Object with {{min}}+ properties should have each property on its own line.",
|
|
6290
|
+
nested: "An object holding an object or function should have each property on its own line.",
|
|
6291
|
+
nestedName: "An object holding an object or function should have each property on its own line. Name this call first: split here, it would break a chained call or a ternary.",
|
|
6292
|
+
siblings: "A sibling call in this list splits its object; split this one too.",
|
|
6293
|
+
inner: "An object with {{inner}}+ entries inside a split object should have each entry on its own line.",
|
|
6294
|
+
params: "Destructured parameter with {{min}}+ properties should have each property on its own line.",
|
|
5998
6295
|
join: "This object fits on one line, so keep it on one line."
|
|
5999
6296
|
}
|
|
6000
6297
|
},
|
|
@@ -6005,6 +6302,119 @@ var layoutObject = defineRule52({
|
|
|
6005
6302
|
let newline = `
|
|
6006
6303
|
`;
|
|
6007
6304
|
let join3;
|
|
6305
|
+
let params = false;
|
|
6306
|
+
let nested = false;
|
|
6307
|
+
let siblings = false;
|
|
6308
|
+
let inner;
|
|
6309
|
+
const splitCounts = new WeakMap;
|
|
6310
|
+
function holdsNested(node) {
|
|
6311
|
+
return nested && astIsOneLine(node) && node.properties.some((property) => property.type === "Property" && (property.value.type === "ObjectExpression" && property.value.properties.length > 0 || astIsInlineFunction(property.value))) && !insideOneLineObject(node.parent);
|
|
6312
|
+
}
|
|
6313
|
+
function insideOneLineObject(start) {
|
|
6314
|
+
for (let ancestor = start;ancestor && !ancestor.type.endsWith("Statement"); ancestor = ancestor.parent) {
|
|
6315
|
+
if (ancestor.type === "ObjectExpression" && astIsOneLine(ancestor)) {
|
|
6316
|
+
return true;
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
return false;
|
|
6320
|
+
}
|
|
6321
|
+
function breaksAround(node) {
|
|
6322
|
+
for (let child = node, parent = node.parent;parent; child = parent, parent = parent.parent) {
|
|
6323
|
+
if (parent.type === "ConditionalExpression" || parent.type === "MemberExpression" && parent.object === child && astIsCall(child)) {
|
|
6324
|
+
return true;
|
|
6325
|
+
}
|
|
6326
|
+
if (astIsInlineFunction(parent) || parent.type.endsWith("Statement") || parent.type.endsWith("Declaration")) {
|
|
6327
|
+
return false;
|
|
6328
|
+
}
|
|
6329
|
+
}
|
|
6330
|
+
return false;
|
|
6331
|
+
}
|
|
6332
|
+
function keptByInner(node) {
|
|
6333
|
+
const parent = node.parent;
|
|
6334
|
+
return inner !== undefined && node.properties.length >= inner && parent.type === "Property" && parent.value === node && !astIsOneLine(parent.parent);
|
|
6335
|
+
}
|
|
6336
|
+
function splitSiblings(node) {
|
|
6337
|
+
const call = node.parent;
|
|
6338
|
+
const list = call.parent;
|
|
6339
|
+
if (!siblings || node.properties.length === 0 || !astIsCall(call) || list?.type !== "ArrayExpression") {
|
|
6340
|
+
return 0;
|
|
6341
|
+
}
|
|
6342
|
+
let counts = splitCounts.get(list);
|
|
6343
|
+
if (!counts) {
|
|
6344
|
+
counts = new Map;
|
|
6345
|
+
for (const element of list.elements) {
|
|
6346
|
+
if (!element || !astIsCall(element)) {
|
|
6347
|
+
continue;
|
|
6348
|
+
}
|
|
6349
|
+
for (const [index, argument] of element.arguments.entries()) {
|
|
6350
|
+
if (argument.type === "ObjectExpression" && !astIsOneLine(argument)) {
|
|
6351
|
+
const key = `${context.sourceCode.getText(element.callee)}#${index}`;
|
|
6352
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
splitCounts.set(list, counts);
|
|
6357
|
+
}
|
|
6358
|
+
return counts.get(`${context.sourceCode.getText(call.callee)}#${call.arguments.indexOf(node)}`) ?? 0;
|
|
6359
|
+
}
|
|
6360
|
+
function joinBlocked(node, call) {
|
|
6361
|
+
const callee = call && astIsCall(call) ? astDottedName(call.callee) : undefined;
|
|
6362
|
+
const kept = callee !== undefined && (join3?.keep ?? []).some((name) => callee === name || callee.endsWith(`.${name}`));
|
|
6363
|
+
return kept || keptByInner(node) || splitSiblings(node) > 1 || node.properties.length === 0 || !node.properties.every(layoutObjectIsFlat) || context.sourceCode.getCommentsInside(node).length > 0;
|
|
6364
|
+
}
|
|
6365
|
+
function reportSplit(node, properties, open, close, messageId) {
|
|
6366
|
+
const source = context.sourceCode;
|
|
6367
|
+
const text = source.text;
|
|
6368
|
+
const baseIndent = sourceLineIndent(text, open);
|
|
6369
|
+
const propertyIndent = `${baseIndent}${indentUnit}`;
|
|
6370
|
+
context.report({
|
|
6371
|
+
node,
|
|
6372
|
+
messageId,
|
|
6373
|
+
data: { min: String(minProperties), inner: String(inner ?? "") },
|
|
6374
|
+
fix: (fixer) => {
|
|
6375
|
+
if (messageId === "nestedName" || properties.length === 0 || source.getCommentsInside(node).length > 0 || !layoutObjectIsWhitespace(text.slice(open + 1, properties[0].range[0]))) {
|
|
6376
|
+
return null;
|
|
6377
|
+
}
|
|
6378
|
+
const gaps = [[open + 1, properties[0].range[0]]];
|
|
6379
|
+
for (const [index, property] of properties.entries()) {
|
|
6380
|
+
const next = properties.at(index + 1);
|
|
6381
|
+
const after = property.range[1];
|
|
6382
|
+
const limit = next ? next.range[0] : close;
|
|
6383
|
+
const between = text.slice(after, limit);
|
|
6384
|
+
const comma = between.indexOf(",");
|
|
6385
|
+
if (comma === -1) {
|
|
6386
|
+
if (next || !layoutObjectIsWhitespace(between)) {
|
|
6387
|
+
return null;
|
|
6388
|
+
}
|
|
6389
|
+
gaps.push([after, close]);
|
|
6390
|
+
continue;
|
|
6391
|
+
}
|
|
6392
|
+
if (!layoutObjectIsWhitespace(between.slice(0, comma)) || !layoutObjectIsWhitespace(between.slice(comma + 1))) {
|
|
6393
|
+
return null;
|
|
6394
|
+
}
|
|
6395
|
+
gaps.push([after + comma + 1, limit]);
|
|
6396
|
+
}
|
|
6397
|
+
return gaps.map((gap, index) => fixer.replaceTextRange(gap, index === gaps.length - 1 ? `${newline}${baseIndent}` : `${newline}${propertyIndent}`));
|
|
6398
|
+
}
|
|
6399
|
+
});
|
|
6400
|
+
}
|
|
6401
|
+
function checkParams(node) {
|
|
6402
|
+
if (!params) {
|
|
6403
|
+
return;
|
|
6404
|
+
}
|
|
6405
|
+
for (const param of node.params) {
|
|
6406
|
+
const pattern = param.type === "AssignmentPattern" ? param.left : param;
|
|
6407
|
+
if (pattern.type !== "ObjectPattern" || pattern.properties.length < minProperties) {
|
|
6408
|
+
continue;
|
|
6409
|
+
}
|
|
6410
|
+
const text = context.sourceCode.text;
|
|
6411
|
+
const close = text.lastIndexOf("}", (pattern.typeAnnotation?.range[0] ?? pattern.range[1]) - 1);
|
|
6412
|
+
if (!text.slice(pattern.range[0], close).includes(`
|
|
6413
|
+
`)) {
|
|
6414
|
+
reportSplit(pattern, pattern.properties, pattern.range[0], close, "params");
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6008
6418
|
return {
|
|
6009
6419
|
before() {
|
|
6010
6420
|
const options = optionsFirst(context, {});
|
|
@@ -6013,24 +6423,39 @@ var layoutObject = defineRule52({
|
|
|
6013
6423
|
indentUnit = sourceIndentUnit(options.indent);
|
|
6014
6424
|
newline = sourceNewline(context.sourceCode.text);
|
|
6015
6425
|
join3 = options.join;
|
|
6426
|
+
params = options.params ?? false;
|
|
6427
|
+
nested = options.nested ?? false;
|
|
6428
|
+
siblings = options.siblings ?? false;
|
|
6429
|
+
inner = options.inner;
|
|
6016
6430
|
},
|
|
6431
|
+
FunctionDeclaration: checkParams,
|
|
6432
|
+
FunctionExpression: checkParams,
|
|
6433
|
+
ArrowFunctionExpression: checkParams,
|
|
6017
6434
|
ObjectExpression(node) {
|
|
6018
6435
|
const source = context.sourceCode;
|
|
6019
6436
|
const text = source.text;
|
|
6020
6437
|
const properties = node.properties;
|
|
6021
|
-
const
|
|
6438
|
+
const parent = node.parent;
|
|
6439
|
+
const full = properties.length >= minProperties;
|
|
6440
|
+
const holds = !full && holdsNested(node);
|
|
6441
|
+
if (!full && !holds && astIsOneLine(node) && splitSiblings(node) > 0) {
|
|
6442
|
+
reportSplit(node, properties, node.range[0], node.range[1] - 1, "siblings");
|
|
6443
|
+
return;
|
|
6444
|
+
}
|
|
6445
|
+
if (astIsOneLine(node) && keptByInner(node)) {
|
|
6446
|
+
reportSplit(node, properties, node.range[0], node.range[1] - 1, "inner");
|
|
6447
|
+
return;
|
|
6448
|
+
}
|
|
6449
|
+
const split = full || holds;
|
|
6022
6450
|
if (split ? !astIsOneLine(node) : !join3 || astIsOneLine(node)) {
|
|
6023
6451
|
return;
|
|
6024
6452
|
}
|
|
6025
|
-
const parent = node.parent;
|
|
6026
6453
|
const call = (parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node) ? parent : undefined;
|
|
6027
6454
|
if (scope === "call-args" && !call) {
|
|
6028
6455
|
return;
|
|
6029
6456
|
}
|
|
6030
6457
|
if (!split) {
|
|
6031
|
-
|
|
6032
|
-
const kept = callee !== undefined && (join3?.keep ?? []).some((name) => callee === name || callee.endsWith(`.${name}`));
|
|
6033
|
-
if (kept || properties.length === 0 || !properties.every(layoutObjectIsFlat) || source.getCommentsInside(node).length > 0) {
|
|
6458
|
+
if (joinBlocked(node, call)) {
|
|
6034
6459
|
return;
|
|
6035
6460
|
}
|
|
6036
6461
|
const gaps = sourceItemGaps(node.range[0] + 1, properties, node.range[1] - 1);
|
|
@@ -6046,46 +6471,16 @@ var layoutObject = defineRule52({
|
|
|
6046
6471
|
});
|
|
6047
6472
|
return;
|
|
6048
6473
|
}
|
|
6049
|
-
const
|
|
6050
|
-
const
|
|
6051
|
-
|
|
6052
|
-
context.report({
|
|
6053
|
-
node,
|
|
6054
|
-
messageId: scope === "all" ? "always" : "callArgs",
|
|
6055
|
-
data: { min: String(minProperties) },
|
|
6056
|
-
fix: (fixer) => {
|
|
6057
|
-
if (source.getCommentsInside(node).length > 0 || !layoutObjectIsWhitespace(text.slice(node.range[0] + 1, properties[0].range[0]))) {
|
|
6058
|
-
return null;
|
|
6059
|
-
}
|
|
6060
|
-
const gaps = [[node.range[0] + 1, properties[0].range[0]]];
|
|
6061
|
-
for (const [index, property] of properties.entries()) {
|
|
6062
|
-
const next = properties.at(index + 1);
|
|
6063
|
-
const after = property.range[1];
|
|
6064
|
-
const limit = next ? next.range[0] : close;
|
|
6065
|
-
const between = text.slice(after, limit);
|
|
6066
|
-
const comma = between.indexOf(",");
|
|
6067
|
-
if (comma === -1) {
|
|
6068
|
-
if (next || !layoutObjectIsWhitespace(between)) {
|
|
6069
|
-
return null;
|
|
6070
|
-
}
|
|
6071
|
-
gaps.push([after, close]);
|
|
6072
|
-
continue;
|
|
6073
|
-
}
|
|
6074
|
-
if (!layoutObjectIsWhitespace(between.slice(0, comma)) || !layoutObjectIsWhitespace(between.slice(comma + 1))) {
|
|
6075
|
-
return null;
|
|
6076
|
-
}
|
|
6077
|
-
gaps.push([after + comma + 1, limit]);
|
|
6078
|
-
}
|
|
6079
|
-
return gaps.map((gap, index) => fixer.replaceTextRange(gap, index === gaps.length - 1 ? `${newline}${baseIndent}` : `${newline}${propertyIndent}`));
|
|
6080
|
-
}
|
|
6081
|
-
});
|
|
6474
|
+
const messageId = scope === "all" ? "always" : "callArgs";
|
|
6475
|
+
const nestedId = breaksAround(node) ? "nestedName" : "nested";
|
|
6476
|
+
reportSplit(node, properties, node.range[0], node.range[1] - 1, holds ? nestedId : messageId);
|
|
6082
6477
|
}
|
|
6083
6478
|
};
|
|
6084
6479
|
}
|
|
6085
6480
|
});
|
|
6086
6481
|
|
|
6087
6482
|
// src/rules/layout/layout-padding.ts
|
|
6088
|
-
import { defineRule as
|
|
6483
|
+
import { defineRule as defineRule54 } from "@oxlint/plugins";
|
|
6089
6484
|
var layoutPaddingControl = new Set([
|
|
6090
6485
|
"IfStatement",
|
|
6091
6486
|
"ForStatement",
|
|
@@ -6114,7 +6509,7 @@ function layoutPaddingKind(node) {
|
|
|
6114
6509
|
function layoutPaddingIsMultilineVariable(node, kind) {
|
|
6115
6510
|
return kind === "variable" && node.loc.start.line !== node.loc.end.line;
|
|
6116
6511
|
}
|
|
6117
|
-
var layoutPadding =
|
|
6512
|
+
var layoutPadding = defineRule54({
|
|
6118
6513
|
meta: {
|
|
6119
6514
|
type: "layout",
|
|
6120
6515
|
fixable: "whitespace",
|
|
@@ -6203,23 +6598,33 @@ var layoutPadding = defineRule53({
|
|
|
6203
6598
|
});
|
|
6204
6599
|
|
|
6205
6600
|
// src/rules/layout/layout-pipe.ts
|
|
6206
|
-
import { defineRule as
|
|
6207
|
-
var layoutPipe =
|
|
6601
|
+
import { defineRule as defineRule55 } from "@oxlint/plugins";
|
|
6602
|
+
var layoutPipe = defineRule55({
|
|
6208
6603
|
meta: {
|
|
6209
6604
|
type: "layout",
|
|
6605
|
+
schema: [{ type: "object", additionalProperties: false, properties: { methods: { type: "array", items: { type: "string" } } } }],
|
|
6210
6606
|
messages: {
|
|
6211
|
-
after: "No ).
|
|
6607
|
+
after: "No ).{{method}}( after a call that spans lines. Name the value and pipe the name, or pass the call to the step data-first.",
|
|
6212
6608
|
step: "A pipe step may span lines only through a callback, object or array. Name this call first, then pass the name."
|
|
6213
6609
|
}
|
|
6214
6610
|
},
|
|
6215
6611
|
createOnce(context) {
|
|
6612
|
+
let methods = new Set;
|
|
6216
6613
|
return {
|
|
6614
|
+
before() {
|
|
6615
|
+
methods = new Set(optionsFirst(context, {}).methods ?? ["pipe"]);
|
|
6616
|
+
},
|
|
6217
6617
|
CallExpression(node) {
|
|
6218
6618
|
const callee = node.callee;
|
|
6219
|
-
|
|
6220
|
-
|
|
6619
|
+
const piped = callee.type === "MemberExpression" && methods.has(astMemberName(callee) ?? "");
|
|
6620
|
+
if (piped && astIsCall(callee.object) && !astIsOneLine(callee.object) && callee.property.loc.start.line === callee.object.loc.end.line) {
|
|
6621
|
+
context.report({
|
|
6622
|
+
node: callee.property,
|
|
6623
|
+
messageId: "after",
|
|
6624
|
+
data: { method: astMemberName(callee) ?? "pipe" }
|
|
6625
|
+
});
|
|
6221
6626
|
}
|
|
6222
|
-
if (!
|
|
6627
|
+
if (!piped) {
|
|
6223
6628
|
return;
|
|
6224
6629
|
}
|
|
6225
6630
|
for (const step of node.arguments) {
|
|
@@ -6235,7 +6640,7 @@ var layoutPipe = defineRule54({
|
|
|
6235
6640
|
});
|
|
6236
6641
|
|
|
6237
6642
|
// src/rules/layout/layout-ternary.ts
|
|
6238
|
-
import { defineRule as
|
|
6643
|
+
import { defineRule as defineRule56 } from "@oxlint/plugins";
|
|
6239
6644
|
function layoutTernaryLines(node) {
|
|
6240
6645
|
return node.loc.end.line - node.loc.start.line + 1;
|
|
6241
6646
|
}
|
|
@@ -6243,7 +6648,7 @@ function layoutTernaryBreak(between, operator, newline) {
|
|
|
6243
6648
|
const at = between.indexOf(operator);
|
|
6244
6649
|
return `${between.slice(0, at).trimEnd()}${newline}${operator} ${between.slice(at + 1).trimStart()}`;
|
|
6245
6650
|
}
|
|
6246
|
-
var layoutTernary =
|
|
6651
|
+
var layoutTernary = defineRule56({
|
|
6247
6652
|
meta: {
|
|
6248
6653
|
type: "layout",
|
|
6249
6654
|
fixable: "whitespace",
|
|
@@ -6358,10 +6763,70 @@ var layoutTernary = defineRule55({
|
|
|
6358
6763
|
}
|
|
6359
6764
|
});
|
|
6360
6765
|
|
|
6766
|
+
// src/rules/layout/layout-type-arguments.ts
|
|
6767
|
+
import { defineRule as defineRule57 } from "@oxlint/plugins";
|
|
6768
|
+
var layoutTypeArguments = defineRule57({
|
|
6769
|
+
meta: {
|
|
6770
|
+
type: "layout",
|
|
6771
|
+
fixable: "code",
|
|
6772
|
+
schema: [
|
|
6773
|
+
{
|
|
6774
|
+
type: "object",
|
|
6775
|
+
additionalProperties: false,
|
|
6776
|
+
properties: {
|
|
6777
|
+
min: { type: "integer", minimum: 2, default: 3 },
|
|
6778
|
+
indent: { ...sourceIndentSchema, default: 2 }
|
|
6779
|
+
}
|
|
6780
|
+
}
|
|
6781
|
+
],
|
|
6782
|
+
messages: {
|
|
6783
|
+
union: "A union of {{min}}+ types in type arguments puts each type on its own line."
|
|
6784
|
+
}
|
|
6785
|
+
},
|
|
6786
|
+
createOnce(context) {
|
|
6787
|
+
let minMembers = 3;
|
|
6788
|
+
let indentUnit = sourceIndentUnit();
|
|
6789
|
+
return {
|
|
6790
|
+
before() {
|
|
6791
|
+
const options = optionsFirst(context, {});
|
|
6792
|
+
minMembers = options.min ?? 3;
|
|
6793
|
+
indentUnit = sourceIndentUnit(options.indent);
|
|
6794
|
+
},
|
|
6795
|
+
TSTypeParameterInstantiation(node) {
|
|
6796
|
+
const unions = node.params.flatMap((param) => param.type === "TSUnionType" && param.types.length >= minMembers ? [param] : []);
|
|
6797
|
+
if (unions.length === 0 || !astIsOneLine(node)) {
|
|
6798
|
+
return;
|
|
6799
|
+
}
|
|
6800
|
+
const source = context.sourceCode;
|
|
6801
|
+
const text = source.text;
|
|
6802
|
+
const items = node.params.flatMap((param) => param.type === "TSUnionType" && unions.includes(param) ? param.types : [param]);
|
|
6803
|
+
const gaps = sourceItemGaps(node.range[0] + 1, items, node.range[1] - 1);
|
|
6804
|
+
const firsts = new Set(unions.map((union) => union.types[0]));
|
|
6805
|
+
const matches = gaps.map((gap) => /^\s*(,?)\s*(\|?)\s*$/.exec(text.slice(...gap)));
|
|
6806
|
+
const newline = sourceNewline(text);
|
|
6807
|
+
const base = sourceLineIndent(text, node.range[0]);
|
|
6808
|
+
const inner = `${base}${indentUnit}`;
|
|
6809
|
+
const unsafe = text[node.range[0]] !== "<" || text[node.range[1] - 1] !== ">" || source.getCommentsInside(node).length > 0 || matches.some((match) => !match);
|
|
6810
|
+
context.report({
|
|
6811
|
+
node,
|
|
6812
|
+
messageId: "union",
|
|
6813
|
+
data: { min: String(minMembers) },
|
|
6814
|
+
fix: unsafe ? undefined : (fixer) => gaps.map((gap, index) => {
|
|
6815
|
+
const comma = matches[index]?.[1] ?? "";
|
|
6816
|
+
const next = items.at(index);
|
|
6817
|
+
const bar = matches[index]?.[2] || next && firsts.has(next) ? "| " : "";
|
|
6818
|
+
return fixer.replaceTextRange(gap, next ? `${comma}${newline}${inner}${bar}` : `${comma}${newline}${base}`);
|
|
6819
|
+
})
|
|
6820
|
+
});
|
|
6821
|
+
}
|
|
6822
|
+
};
|
|
6823
|
+
}
|
|
6824
|
+
});
|
|
6825
|
+
|
|
6361
6826
|
// src/rules/naming/naming-declarations.ts
|
|
6362
|
-
import { defineRule as
|
|
6827
|
+
import { defineRule as defineRule58 } from "@oxlint/plugins";
|
|
6363
6828
|
var namingDeclarationsKinds = ["function", "const", "let", "var", "class", "type", "interface", "enum"];
|
|
6364
|
-
var namingDeclarations =
|
|
6829
|
+
var namingDeclarations = defineRule58({
|
|
6365
6830
|
meta: {
|
|
6366
6831
|
type: "problem",
|
|
6367
6832
|
schema: [
|
|
@@ -6438,7 +6903,7 @@ var namingDeclarations = defineRule56({
|
|
|
6438
6903
|
});
|
|
6439
6904
|
|
|
6440
6905
|
// src/rules/naming/naming-exports.ts
|
|
6441
|
-
import { defineRule as
|
|
6906
|
+
import { defineRule as defineRule59 } from "@oxlint/plugins";
|
|
6442
6907
|
var namingExportsScopeProperties = {
|
|
6443
6908
|
scope: { type: "string", enum: ["exports", "functions", "declarations"] },
|
|
6444
6909
|
types: { type: "boolean" },
|
|
@@ -6464,7 +6929,7 @@ function matchTemplate(basename3, template, placeholder = "[a-z0-9-]+") {
|
|
|
6464
6929
|
}
|
|
6465
6930
|
return new RegExp(`^${pattern}$`).exec(basename3)?.groups ?? null;
|
|
6466
6931
|
}
|
|
6467
|
-
var namingExports =
|
|
6932
|
+
var namingExports = defineRule59({
|
|
6468
6933
|
meta: {
|
|
6469
6934
|
type: "problem",
|
|
6470
6935
|
schema: {
|
|
@@ -6601,10 +7066,10 @@ var namingExports = defineRule57({
|
|
|
6601
7066
|
});
|
|
6602
7067
|
|
|
6603
7068
|
// src/rules/naming/naming-file.ts
|
|
6604
|
-
import { defineRule as
|
|
7069
|
+
import { defineRule as defineRule60 } from "@oxlint/plugins";
|
|
6605
7070
|
import { readdirSync as readdirSync2 } from "node:fs";
|
|
6606
7071
|
import { dirname as dirname4 } from "node:path";
|
|
6607
|
-
var namingFile =
|
|
7072
|
+
var namingFile = defineRule60({
|
|
6608
7073
|
meta: {
|
|
6609
7074
|
type: "problem",
|
|
6610
7075
|
schema: {
|
|
@@ -6674,9 +7139,9 @@ var namingFile = defineRule58({
|
|
|
6674
7139
|
});
|
|
6675
7140
|
|
|
6676
7141
|
// src/rules/naming/naming-folder.ts
|
|
6677
|
-
import { defineRule as
|
|
6678
|
-
import { posix as
|
|
6679
|
-
var namingFolder =
|
|
7142
|
+
import { defineRule as defineRule61 } from "@oxlint/plugins";
|
|
7143
|
+
import { posix as posix3 } from "node:path";
|
|
7144
|
+
var namingFolder = defineRule61({
|
|
6680
7145
|
meta: {
|
|
6681
7146
|
type: "problem",
|
|
6682
7147
|
schema: [
|
|
@@ -6699,7 +7164,7 @@ var namingFolder = defineRule59({
|
|
|
6699
7164
|
return {
|
|
6700
7165
|
Program(program) {
|
|
6701
7166
|
const { singularize = "trailing-s", separators = ["-"], after, prefixes: stripPrefixes = [] } = optionsFirst(context, {});
|
|
6702
|
-
const all =
|
|
7167
|
+
const all = posix3.dirname(context.filename.replaceAll("\\", "/")).split("/").filter((part) => part && part !== ".");
|
|
6703
7168
|
const parent = [all.at(-1) ?? ""];
|
|
6704
7169
|
let folders = after ? undefined : parent;
|
|
6705
7170
|
const marker = (after ?? "").split("/").filter(Boolean);
|
|
@@ -6741,45 +7206,174 @@ var namingFolder = defineRule59({
|
|
|
6741
7206
|
});
|
|
6742
7207
|
|
|
6743
7208
|
// src/rules/naming/naming-types.ts
|
|
6744
|
-
|
|
7209
|
+
import { defineRule as defineRule62 } from "@oxlint/plugins";
|
|
7210
|
+
var namingTypes = defineRule62({
|
|
7211
|
+
meta: {
|
|
7212
|
+
type: "problem",
|
|
7213
|
+
schema: [{ type: "object", additionalProperties: false, properties: { pattern: optionsPatternSchema, message: { type: "string" } } }],
|
|
7214
|
+
messages: { forbidden: "{{message}}" }
|
|
7215
|
+
},
|
|
7216
|
+
createOnce(context) {
|
|
7217
|
+
let patterns = [];
|
|
7218
|
+
let message = "";
|
|
7219
|
+
return {
|
|
7220
|
+
before() {
|
|
7221
|
+
const options = optionsFirst(context, {});
|
|
7222
|
+
patterns = optionsPatterns(options.pattern ?? "^[A-Z][a-zA-Z0-9]*$");
|
|
7223
|
+
message = options.message ?? "Use PascalCase for interfaces.";
|
|
7224
|
+
},
|
|
7225
|
+
TSInterfaceDeclaration(node) {
|
|
7226
|
+
if (!optionsPatternsTest(patterns, node.id.name)) {
|
|
7227
|
+
context.report({
|
|
7228
|
+
node,
|
|
7229
|
+
messageId: "forbidden",
|
|
7230
|
+
data: { message }
|
|
7231
|
+
});
|
|
7232
|
+
}
|
|
7233
|
+
}
|
|
7234
|
+
};
|
|
7235
|
+
}
|
|
7236
|
+
});
|
|
6745
7237
|
|
|
6746
7238
|
// src/rules/react/react-dynamic-classes.ts
|
|
6747
|
-
|
|
7239
|
+
import { defineRule as defineRule63 } from "@oxlint/plugins";
|
|
7240
|
+
var reactDynamicClasses = defineRule63({
|
|
7241
|
+
meta: {
|
|
7242
|
+
type: "problem",
|
|
7243
|
+
schema: [
|
|
7244
|
+
{
|
|
7245
|
+
type: "object",
|
|
7246
|
+
additionalProperties: false,
|
|
7247
|
+
properties: { attributes: { type: "array", items: { type: "string" } }, message: { type: "string" } }
|
|
7248
|
+
}
|
|
7249
|
+
],
|
|
7250
|
+
messages: { forbidden: "{{message}}" }
|
|
7251
|
+
},
|
|
7252
|
+
createOnce(context) {
|
|
7253
|
+
let attributes = new Set;
|
|
7254
|
+
let message = "";
|
|
7255
|
+
const check = (node) => {
|
|
7256
|
+
for (let parent = node.parent;parent; parent = parent.parent) {
|
|
7257
|
+
if (parent.type === "JSXAttribute" && parent.name.type === "JSXIdentifier" && attributes.has(parent.name.name)) {
|
|
7258
|
+
context.report({
|
|
7259
|
+
node,
|
|
7260
|
+
messageId: "forbidden",
|
|
7261
|
+
data: { message }
|
|
7262
|
+
});
|
|
7263
|
+
return;
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7266
|
+
};
|
|
7267
|
+
return {
|
|
7268
|
+
before() {
|
|
7269
|
+
const options = optionsFirst(context, {});
|
|
7270
|
+
attributes = new Set(options.attributes ?? ["className"]);
|
|
7271
|
+
message = options.message ?? "Write complete class names instead of constructing them dynamically.";
|
|
7272
|
+
},
|
|
7273
|
+
"JSXAttribute TemplateLiteral[expressions.length>0]": check,
|
|
7274
|
+
'JSXAttribute BinaryExpression[operator="+"]': check
|
|
7275
|
+
};
|
|
7276
|
+
}
|
|
7277
|
+
});
|
|
6748
7278
|
|
|
6749
7279
|
// src/rules/react/react-empty-effect.ts
|
|
6750
|
-
|
|
7280
|
+
import { defineRule as defineRule64 } from "@oxlint/plugins";
|
|
7281
|
+
var reactEmptyEffect = defineRule64({
|
|
7282
|
+
meta: {
|
|
7283
|
+
type: "problem",
|
|
7284
|
+
schema: [
|
|
7285
|
+
{
|
|
7286
|
+
type: "object",
|
|
7287
|
+
additionalProperties: false,
|
|
7288
|
+
properties: { hooks: { type: "array", items: { type: "string" } }, message: { type: "string" } }
|
|
7289
|
+
}
|
|
7290
|
+
],
|
|
7291
|
+
messages: { forbidden: "{{message}}" }
|
|
7292
|
+
},
|
|
7293
|
+
createOnce(context) {
|
|
7294
|
+
let hooks = new Set;
|
|
7295
|
+
let message = "";
|
|
7296
|
+
return {
|
|
7297
|
+
before() {
|
|
7298
|
+
const options = optionsFirst(context, {});
|
|
7299
|
+
hooks = new Set(options.hooks ?? ["useEffect", "useLayoutEffect", "React.useEffect", "React.useLayoutEffect"]);
|
|
7300
|
+
message = options.message ?? "Remove the empty effect.";
|
|
7301
|
+
},
|
|
7302
|
+
CallExpression(node) {
|
|
7303
|
+
if (!hooks.has(astDottedName(node.callee) ?? "")) {
|
|
7304
|
+
return;
|
|
7305
|
+
}
|
|
7306
|
+
for (const argument of node.arguments) {
|
|
7307
|
+
if (astIsInlineFunction(argument) && argument.body?.type === "BlockStatement" && argument.body.body.length === 0) {
|
|
7308
|
+
context.report({
|
|
7309
|
+
node: argument.body,
|
|
7310
|
+
messageId: "forbidden",
|
|
7311
|
+
data: { message }
|
|
7312
|
+
});
|
|
7313
|
+
}
|
|
7314
|
+
}
|
|
7315
|
+
}
|
|
7316
|
+
};
|
|
7317
|
+
}
|
|
7318
|
+
});
|
|
6751
7319
|
|
|
6752
7320
|
// src/rules/react/react-memo.ts
|
|
6753
|
-
import { defineRule as
|
|
6754
|
-
var
|
|
6755
|
-
var reactMemo = defineRule60({
|
|
7321
|
+
import { defineRule as defineRule65 } from "@oxlint/plugins";
|
|
7322
|
+
var reactMemo = defineRule65({
|
|
6756
7323
|
meta: {
|
|
6757
7324
|
type: "problem",
|
|
6758
|
-
schema: [
|
|
7325
|
+
schema: [
|
|
7326
|
+
{
|
|
7327
|
+
type: "object",
|
|
7328
|
+
additionalProperties: false,
|
|
7329
|
+
properties: {
|
|
7330
|
+
names: { type: "array", items: { type: "string" } },
|
|
7331
|
+
sources: { type: "array", items: { type: "string" } },
|
|
7332
|
+
message: { type: "string" }
|
|
7333
|
+
}
|
|
7334
|
+
}
|
|
7335
|
+
],
|
|
6759
7336
|
messages: {
|
|
6760
|
-
memo: "
|
|
7337
|
+
memo: "{{message}}"
|
|
6761
7338
|
}
|
|
6762
7339
|
},
|
|
6763
7340
|
createOnce(context) {
|
|
7341
|
+
let names = [];
|
|
7342
|
+
let sources = [];
|
|
7343
|
+
let message = "";
|
|
6764
7344
|
return {
|
|
7345
|
+
before() {
|
|
7346
|
+
const options = optionsFirst(context, {});
|
|
7347
|
+
names = options.names ?? ["memo", "useMemo", "useCallback"];
|
|
7348
|
+
sources = options.sources ?? ["react"];
|
|
7349
|
+
message = options.message ?? "Use the React Compiler rather than manual memoization.";
|
|
7350
|
+
},
|
|
6765
7351
|
ImportDeclaration(node) {
|
|
6766
|
-
if (node.source.value
|
|
7352
|
+
if (!sources.includes(node.source.value)) {
|
|
6767
7353
|
return;
|
|
6768
7354
|
}
|
|
6769
7355
|
for (const specifier of node.specifiers) {
|
|
6770
|
-
if (specifier.type === "ImportSpecifier" &&
|
|
6771
|
-
context.report({
|
|
7356
|
+
if (specifier.type === "ImportSpecifier" && names.includes(astModuleName(specifier.imported))) {
|
|
7357
|
+
context.report({
|
|
7358
|
+
node: specifier,
|
|
7359
|
+
messageId: "memo",
|
|
7360
|
+
data: { message }
|
|
7361
|
+
});
|
|
6772
7362
|
}
|
|
6773
7363
|
}
|
|
6774
7364
|
},
|
|
6775
7365
|
MemberExpression(node) {
|
|
6776
|
-
if (node.object.type !== "Identifier" || !
|
|
7366
|
+
if (node.object.type !== "Identifier" || !names.includes(boundariesMemberName(node) ?? "")) {
|
|
6777
7367
|
return;
|
|
6778
7368
|
}
|
|
6779
7369
|
const variable = boundariesDeclaredVariable(context.sourceCode.getScope(node), node.object.name);
|
|
6780
|
-
const isReact = variable ? variable.defs.some((def) => def.type === "ImportBinding" && def.node.type !== "ImportSpecifier" && def.parent?.type === "ImportDeclaration" && def.parent.source.value
|
|
7370
|
+
const isReact = variable ? variable.defs.some((def) => def.type === "ImportBinding" && (def.node.type !== "ImportSpecifier" || astModuleName(def.node.imported) === "default") && def.parent?.type === "ImportDeclaration" && sources.includes(def.parent.source.value)) : node.object.name === "React" && sources.includes("react");
|
|
6781
7371
|
if (isReact) {
|
|
6782
|
-
context.report({
|
|
7372
|
+
context.report({
|
|
7373
|
+
node,
|
|
7374
|
+
messageId: "memo",
|
|
7375
|
+
data: { message }
|
|
7376
|
+
});
|
|
6783
7377
|
}
|
|
6784
7378
|
}
|
|
6785
7379
|
};
|
|
@@ -6787,7 +7381,7 @@ var reactMemo = defineRule60({
|
|
|
6787
7381
|
});
|
|
6788
7382
|
|
|
6789
7383
|
// src/rules/react/react-props.ts
|
|
6790
|
-
import { defineRule as
|
|
7384
|
+
import { defineRule as defineRule66 } from "@oxlint/plugins";
|
|
6791
7385
|
function reactPropsTarget(node) {
|
|
6792
7386
|
if (node?.type === "FunctionDeclaration" || node?.type === "FunctionExpression" || node?.type === "ArrowFunctionExpression") {
|
|
6793
7387
|
return { fn: node };
|
|
@@ -6814,7 +7408,7 @@ function reactIsPassThrough(type) {
|
|
|
6814
7408
|
const argument = type.typeArguments?.params.length === 1 ? type.typeArguments.params[0] : undefined;
|
|
6815
7409
|
return name.type === "Identifier" && name.name === "ComponentProps" && (argument?.type === "TSTypeQuery" || argument?.type === "TSLiteralType" && argument.literal.type === "Literal" && typeof argument.literal.value === "string");
|
|
6816
7410
|
}
|
|
6817
|
-
var reactProps =
|
|
7411
|
+
var reactProps = defineRule66({
|
|
6818
7412
|
meta: {
|
|
6819
7413
|
type: "problem",
|
|
6820
7414
|
schema: [
|
|
@@ -6912,8 +7506,90 @@ var reactProps = defineRule61({
|
|
|
6912
7506
|
}
|
|
6913
7507
|
});
|
|
6914
7508
|
|
|
7509
|
+
// src/rules/react/react-query-props.ts
|
|
7510
|
+
import { defineRule as defineRule67 } from "@oxlint/plugins";
|
|
7511
|
+
var reactQueryProps = defineRule67({
|
|
7512
|
+
meta: {
|
|
7513
|
+
type: "problem",
|
|
7514
|
+
schema: [
|
|
7515
|
+
{
|
|
7516
|
+
type: "object",
|
|
7517
|
+
additionalProperties: false,
|
|
7518
|
+
properties: {
|
|
7519
|
+
hooks: { type: "array", items: { type: "string" } },
|
|
7520
|
+
functions: { type: "array", items: { type: "string" } }
|
|
7521
|
+
}
|
|
7522
|
+
}
|
|
7523
|
+
],
|
|
7524
|
+
messages: {
|
|
7525
|
+
options: "Build the {{hook}} options here from props; ready-made options hide where the data comes from.",
|
|
7526
|
+
source: "{{key}} must be a prop or call one; pass the data function in from the app."
|
|
7527
|
+
}
|
|
7528
|
+
},
|
|
7529
|
+
createOnce(context) {
|
|
7530
|
+
return {
|
|
7531
|
+
CallExpression(node) {
|
|
7532
|
+
const { hooks = ["useQuery", "useMutation", "useInfiniteQuery", "useSuspenseQuery"], functions = ["queryFn", "mutationFn"] } = optionsFirst(context, {});
|
|
7533
|
+
const hook = astCallName(node);
|
|
7534
|
+
let owner = node.parent;
|
|
7535
|
+
while (owner && owner.type !== "FunctionDeclaration" && !astIsInlineFunction(owner)) {
|
|
7536
|
+
owner = owner.parent;
|
|
7537
|
+
}
|
|
7538
|
+
if (!hook || !hooks.includes(hook) || !owner || owner.type !== "FunctionDeclaration" && !astIsInlineFunction(owner)) {
|
|
7539
|
+
return;
|
|
7540
|
+
}
|
|
7541
|
+
const component = owner;
|
|
7542
|
+
const first = component.params.at(0);
|
|
7543
|
+
const parameter = first?.type === "AssignmentPattern" ? first.left : first;
|
|
7544
|
+
const definition = (identifier) => boundariesDeclaredVariable(context.sourceCode.getScope(identifier), identifier.name)?.defs.at(0);
|
|
7545
|
+
const isProps = (value) => {
|
|
7546
|
+
const found = value?.type === "Identifier" ? definition(value) : undefined;
|
|
7547
|
+
return found?.type === "Parameter" && found.node === component && parameter?.type === "Identifier";
|
|
7548
|
+
};
|
|
7549
|
+
const isProp = (value) => {
|
|
7550
|
+
if (value.type === "MemberExpression") {
|
|
7551
|
+
return isProps(value.object);
|
|
7552
|
+
}
|
|
7553
|
+
const found = value.type === "Identifier" ? definition(value) : undefined;
|
|
7554
|
+
if (found?.type === "Parameter") {
|
|
7555
|
+
return found.node === component && parameter?.type === "ObjectPattern";
|
|
7556
|
+
}
|
|
7557
|
+
return found?.type === "Variable" && found.node.type === "VariableDeclarator" && found.node.id.type === "ObjectPattern" && isProps(found.node.init);
|
|
7558
|
+
};
|
|
7559
|
+
const options = node.arguments.at(0);
|
|
7560
|
+
if (options?.type !== "ObjectExpression" || options.properties.some((property) => property.type === "SpreadElement")) {
|
|
7561
|
+
context.report({
|
|
7562
|
+
node: options ?? node,
|
|
7563
|
+
messageId: "options",
|
|
7564
|
+
data: { hook }
|
|
7565
|
+
});
|
|
7566
|
+
return;
|
|
7567
|
+
}
|
|
7568
|
+
for (const property of options.properties) {
|
|
7569
|
+
if (property.type !== "Property") {
|
|
7570
|
+
continue;
|
|
7571
|
+
}
|
|
7572
|
+
const key = property.key.type === "Identifier" && !property.computed ? property.key.name : astStaticString(property.key);
|
|
7573
|
+
if (key === undefined || !functions.includes(key)) {
|
|
7574
|
+
continue;
|
|
7575
|
+
}
|
|
7576
|
+
const { value } = property;
|
|
7577
|
+
const calls = astIsInlineFunction(value) && astSome(value.body, (child) => child.type === "CallExpression" && isProp(child.callee));
|
|
7578
|
+
if (!isProp(value) && !calls) {
|
|
7579
|
+
context.report({
|
|
7580
|
+
node: value,
|
|
7581
|
+
messageId: "source",
|
|
7582
|
+
data: { key }
|
|
7583
|
+
});
|
|
7584
|
+
}
|
|
7585
|
+
}
|
|
7586
|
+
}
|
|
7587
|
+
};
|
|
7588
|
+
}
|
|
7589
|
+
});
|
|
7590
|
+
|
|
6915
7591
|
// src/rules/schemas/schemas-inline.ts
|
|
6916
|
-
import { defineRule as
|
|
7592
|
+
import { defineRule as defineRule68 } from "@oxlint/plugins";
|
|
6917
7593
|
|
|
6918
7594
|
// src/utils/schemas.utils.ts
|
|
6919
7595
|
var schemasElementOptionsSchema = {
|
|
@@ -6949,7 +7625,7 @@ function schemasIsAllowedElement(node, allowScalars, namespaces, structuralMetho
|
|
|
6949
7625
|
}
|
|
6950
7626
|
|
|
6951
7627
|
// src/rules/schemas/schemas-inline.ts
|
|
6952
|
-
var schemasInline =
|
|
7628
|
+
var schemasInline = defineRule68({
|
|
6953
7629
|
meta: {
|
|
6954
7630
|
type: "problem",
|
|
6955
7631
|
schema: [schemasElementOptionsSchema],
|
|
@@ -6998,11 +7674,11 @@ var schemasInline = defineRule62({
|
|
|
6998
7674
|
});
|
|
6999
7675
|
|
|
7000
7676
|
// src/rules/schemas/schemas-local.ts
|
|
7001
|
-
import { defineRule as
|
|
7677
|
+
import { defineRule as defineRule69 } from "@oxlint/plugins";
|
|
7002
7678
|
var schemasLocalImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
|
|
7003
7679
|
var schemasLocalConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
|
|
7004
7680
|
var schemasLocalCalls = ["config", "prettifyError", "treeifyError", "flattenError", "formatError"];
|
|
7005
|
-
var schemasLocal =
|
|
7681
|
+
var schemasLocal = defineRule69({
|
|
7006
7682
|
meta: {
|
|
7007
7683
|
type: "problem",
|
|
7008
7684
|
schema: [
|
|
@@ -7151,8 +7827,8 @@ var schemasLocal = defineRule63({
|
|
|
7151
7827
|
});
|
|
7152
7828
|
|
|
7153
7829
|
// src/rules/schemas/schemas-rederive.ts
|
|
7154
|
-
import { defineRule as
|
|
7155
|
-
var schemasRederive =
|
|
7830
|
+
import { defineRule as defineRule70 } from "@oxlint/plugins";
|
|
7831
|
+
var schemasRederive = defineRule70({
|
|
7156
7832
|
meta: {
|
|
7157
7833
|
type: "problem",
|
|
7158
7834
|
schema: [
|
|
@@ -7198,7 +7874,7 @@ var schemasRederive = defineRule64({
|
|
|
7198
7874
|
});
|
|
7199
7875
|
|
|
7200
7876
|
// src/rules/schemas/schemas-single-use.ts
|
|
7201
|
-
import { defineRule as
|
|
7877
|
+
import { defineRule as defineRule71 } from "@oxlint/plugins";
|
|
7202
7878
|
function isScalarSchema(node, namespaces, structuralMethods) {
|
|
7203
7879
|
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
|
|
7204
7880
|
return false;
|
|
@@ -7212,7 +7888,7 @@ function isScalarSchema(node, namespaces, structuralMethods) {
|
|
|
7212
7888
|
}
|
|
7213
7889
|
return node.callee.object.type === "CallExpression" && isScalarSchema(node.callee.object, namespaces, structuralMethods);
|
|
7214
7890
|
}
|
|
7215
|
-
var schemasSingleUse =
|
|
7891
|
+
var schemasSingleUse = defineRule71({
|
|
7216
7892
|
meta: {
|
|
7217
7893
|
type: "suggestion",
|
|
7218
7894
|
schema: [schemasElementOptionsSchema],
|
|
@@ -7288,7 +7964,7 @@ var schemasSingleUse = defineRule65({
|
|
|
7288
7964
|
});
|
|
7289
7965
|
|
|
7290
7966
|
// src/rules/tests/tests-assertions.ts
|
|
7291
|
-
import { defineRule as
|
|
7967
|
+
import { defineRule as defineRule72 } from "@oxlint/plugins";
|
|
7292
7968
|
var testsAssertionsModifiers = new Set(["for", "each", "concurrent", "sequential", "only", "skip"]);
|
|
7293
7969
|
var testsAssertionsFunctions = [
|
|
7294
7970
|
"expect",
|
|
@@ -7478,7 +8154,7 @@ function isAssertedTest(registration, sourceCode, state) {
|
|
|
7478
8154
|
}
|
|
7479
8155
|
return rows.length > 0 && rows.every((row) => hasAssertion(callback, row.bindings, new Set, state));
|
|
7480
8156
|
}
|
|
7481
|
-
var testsAssertions =
|
|
8157
|
+
var testsAssertions = defineRule72({
|
|
7482
8158
|
meta: {
|
|
7483
8159
|
type: "problem",
|
|
7484
8160
|
schema: [
|
|
@@ -7604,8 +8280,8 @@ var testsAssertions = defineRule66({
|
|
|
7604
8280
|
});
|
|
7605
8281
|
|
|
7606
8282
|
// src/rules/tests/tests-concurrent-db.ts
|
|
7607
|
-
import { defineRule as
|
|
7608
|
-
var testsConcurrentDb =
|
|
8283
|
+
import { defineRule as defineRule73 } from "@oxlint/plugins";
|
|
8284
|
+
var testsConcurrentDb = defineRule73({
|
|
7609
8285
|
meta: {
|
|
7610
8286
|
type: "problem",
|
|
7611
8287
|
schema: [
|
|
@@ -7661,7 +8337,7 @@ var testsConcurrentDb = defineRule67({
|
|
|
7661
8337
|
});
|
|
7662
8338
|
|
|
7663
8339
|
// src/rules/tests/tests-modifiers.ts
|
|
7664
|
-
import { defineRule as
|
|
8340
|
+
import { defineRule as defineRule74 } from "@oxlint/plugins";
|
|
7665
8341
|
var testsModifiersNames = ["test", "it", "describe", "suite"];
|
|
7666
8342
|
var testsModifiersPackages = new Set(["vitest", "bun:test", "@playwright/test", "@jest/globals"]);
|
|
7667
8343
|
var testsModifiersBanned = ["only", "skip", "todo"];
|
|
@@ -7680,7 +8356,7 @@ function modifierName(node) {
|
|
|
7680
8356
|
const property = astMemberName(node);
|
|
7681
8357
|
return object && property ? `${object}.${property}` : undefined;
|
|
7682
8358
|
}
|
|
7683
|
-
var testsModifiers =
|
|
8359
|
+
var testsModifiers = defineRule74({
|
|
7684
8360
|
meta: {
|
|
7685
8361
|
type: "problem",
|
|
7686
8362
|
schema: [
|
|
@@ -7734,9 +8410,9 @@ var testsModifiers = defineRule68({
|
|
|
7734
8410
|
});
|
|
7735
8411
|
|
|
7736
8412
|
// src/rules/tests/tests-titles.ts
|
|
7737
|
-
import { defineRule as
|
|
8413
|
+
import { defineRule as defineRule75 } from "@oxlint/plugins";
|
|
7738
8414
|
var testsTitlesModifiers = ["only", "skip", "concurrent", "sequential", "todo", "each", "for"];
|
|
7739
|
-
var testsTitles =
|
|
8415
|
+
var testsTitles = defineRule75({
|
|
7740
8416
|
meta: {
|
|
7741
8417
|
type: "suggestion",
|
|
7742
8418
|
schema: [
|
|
@@ -7814,11 +8490,11 @@ var testsTitles = defineRule69({
|
|
|
7814
8490
|
});
|
|
7815
8491
|
|
|
7816
8492
|
// src/rules/types/types-declarations.ts
|
|
7817
|
-
import { defineRule as
|
|
8493
|
+
import { defineRule as defineRule76 } from "@oxlint/plugins";
|
|
7818
8494
|
function isValuePattern(source) {
|
|
7819
8495
|
return /^\^?=/.test(source);
|
|
7820
8496
|
}
|
|
7821
|
-
var typesDeclarations =
|
|
8497
|
+
var typesDeclarations = defineRule76({
|
|
7822
8498
|
meta: {
|
|
7823
8499
|
type: "problem",
|
|
7824
8500
|
schema: [
|
|
@@ -7826,7 +8502,8 @@ var typesDeclarations = defineRule70({
|
|
|
7826
8502
|
type: "object",
|
|
7827
8503
|
additionalProperties: false,
|
|
7828
8504
|
properties: {
|
|
7829
|
-
allow: optionsPatternSchema
|
|
8505
|
+
allow: optionsPatternSchema,
|
|
8506
|
+
modules: { type: "boolean" }
|
|
7830
8507
|
}
|
|
7831
8508
|
}
|
|
7832
8509
|
],
|
|
@@ -7837,8 +8514,14 @@ var typesDeclarations = defineRule70({
|
|
|
7837
8514
|
createOnce(context) {
|
|
7838
8515
|
let allowedNames = [];
|
|
7839
8516
|
let allowedValues = [];
|
|
8517
|
+
let allowModules = false;
|
|
7840
8518
|
function check(node) {
|
|
7841
|
-
|
|
8519
|
+
let ancestor = node.parent;
|
|
8520
|
+
while (allowModules && ancestor && ancestor.type !== "TSModuleDeclaration") {
|
|
8521
|
+
ancestor = ancestor.parent;
|
|
8522
|
+
}
|
|
8523
|
+
const ambient = ancestor?.type === "TSModuleDeclaration" && (ancestor.kind === "global" || ancestor.id.type === "Literal");
|
|
8524
|
+
if (allowModules && ambient || optionsPatternsTest(allowedNames, node.id.name) || node.type === "TSTypeAliasDeclaration" && allowedValues.length > 0 && optionsPatternsTest(allowedValues, `= ${context.sourceCode.getText(node.typeAnnotation)}`)) {
|
|
7842
8525
|
return;
|
|
7843
8526
|
}
|
|
7844
8527
|
context.report({
|
|
@@ -7849,7 +8532,8 @@ var typesDeclarations = defineRule70({
|
|
|
7849
8532
|
}
|
|
7850
8533
|
return {
|
|
7851
8534
|
before() {
|
|
7852
|
-
const { allow: allowPattern } = optionsFirst(context, {});
|
|
8535
|
+
const { allow: allowPattern, modules = false } = optionsFirst(context, {});
|
|
8536
|
+
allowModules = modules;
|
|
7853
8537
|
const sources = allowPattern === undefined ? [] : [allowPattern].flat();
|
|
7854
8538
|
allowedNames = optionsPatterns(sources.filter((source) => !isValuePattern(source)));
|
|
7855
8539
|
allowedValues = optionsPatterns(sources.filter(isValuePattern));
|
|
@@ -7861,8 +8545,8 @@ var typesDeclarations = defineRule70({
|
|
|
7861
8545
|
});
|
|
7862
8546
|
|
|
7863
8547
|
// src/rules/types/types-duplicate.ts
|
|
7864
|
-
import { defineRule as
|
|
7865
|
-
var typesDuplicate =
|
|
8548
|
+
import { defineRule as defineRule77 } from "@oxlint/plugins";
|
|
8549
|
+
var typesDuplicate = defineRule77({
|
|
7866
8550
|
meta: {
|
|
7867
8551
|
type: "suggestion",
|
|
7868
8552
|
schema: [
|
|
@@ -7926,7 +8610,7 @@ var typesDuplicate = defineRule71({
|
|
|
7926
8610
|
});
|
|
7927
8611
|
|
|
7928
8612
|
// src/rules/types/types-imported-alias.ts
|
|
7929
|
-
import { defineRule as
|
|
8613
|
+
import { defineRule as defineRule78 } from "@oxlint/plugins";
|
|
7930
8614
|
function importedAliasTarget(declaration, imports) {
|
|
7931
8615
|
if (declaration?.type !== "TSTypeAliasDeclaration") {
|
|
7932
8616
|
return;
|
|
@@ -7938,7 +8622,7 @@ function importedAliasTarget(declaration, imports) {
|
|
|
7938
8622
|
const { name } = type.typeName;
|
|
7939
8623
|
return imports.has(name) && !declaration.typeParameters?.params.some((parameter) => parameter.name.name === name) ? name : undefined;
|
|
7940
8624
|
}
|
|
7941
|
-
var typesImportedAlias =
|
|
8625
|
+
var typesImportedAlias = defineRule78({
|
|
7942
8626
|
meta: {
|
|
7943
8627
|
type: "problem",
|
|
7944
8628
|
schema: [],
|
|
@@ -8000,7 +8684,7 @@ var typesImportedAlias = defineRule72({
|
|
|
8000
8684
|
});
|
|
8001
8685
|
|
|
8002
8686
|
// src/rules/types/types-inline.ts
|
|
8003
|
-
import { defineRule as
|
|
8687
|
+
import { defineRule as defineRule79 } from "@oxlint/plugins";
|
|
8004
8688
|
function parameterAnnotation(parameter) {
|
|
8005
8689
|
if (parameter.type === "TSParameterProperty") {
|
|
8006
8690
|
return parameterAnnotation(parameter.parameter);
|
|
@@ -8010,7 +8694,7 @@ function parameterAnnotation(parameter) {
|
|
|
8010
8694
|
}
|
|
8011
8695
|
return parameter.typeAnnotation;
|
|
8012
8696
|
}
|
|
8013
|
-
var typesInline =
|
|
8697
|
+
var typesInline = defineRule79({
|
|
8014
8698
|
meta: {
|
|
8015
8699
|
type: "problem",
|
|
8016
8700
|
schema: [
|
|
@@ -8021,6 +8705,9 @@ var typesInline = defineRule73({
|
|
|
8021
8705
|
parameters: { type: "boolean" },
|
|
8022
8706
|
returns: { type: "boolean" },
|
|
8023
8707
|
functions: { type: "boolean" },
|
|
8708
|
+
variables: { type: "boolean" },
|
|
8709
|
+
assertions: { type: "boolean" },
|
|
8710
|
+
arguments: { type: "boolean" },
|
|
8024
8711
|
min: { type: "integer", minimum: 1 }
|
|
8025
8712
|
}
|
|
8026
8713
|
}
|
|
@@ -8033,6 +8720,9 @@ var typesInline = defineRule73({
|
|
|
8033
8720
|
let checkParameters = true;
|
|
8034
8721
|
let checkReturns = true;
|
|
8035
8722
|
let checkFunctionTypes = true;
|
|
8723
|
+
let checkVariables = false;
|
|
8724
|
+
let checkAssertions = false;
|
|
8725
|
+
let checkArguments = false;
|
|
8036
8726
|
let minMembers = 1;
|
|
8037
8727
|
function isInline(node) {
|
|
8038
8728
|
if (node.type === "TSTypeLiteral") {
|
|
@@ -8068,11 +8758,44 @@ var typesInline = defineRule73({
|
|
|
8068
8758
|
checkParameters = options.parameters ?? true;
|
|
8069
8759
|
checkReturns = options.returns ?? true;
|
|
8070
8760
|
checkFunctionTypes = options.functions ?? true;
|
|
8761
|
+
checkVariables = options.variables ?? false;
|
|
8762
|
+
checkAssertions = options.assertions ?? false;
|
|
8763
|
+
checkArguments = options.arguments ?? false;
|
|
8071
8764
|
minMembers = options.min ?? 1;
|
|
8072
|
-
if (!checkParameters && !checkReturns) {
|
|
8765
|
+
if (!checkParameters && !checkReturns && !checkVariables && !checkAssertions && !checkArguments) {
|
|
8073
8766
|
return false;
|
|
8074
8767
|
}
|
|
8075
8768
|
},
|
|
8769
|
+
VariableDeclarator(node) {
|
|
8770
|
+
if (checkVariables) {
|
|
8771
|
+
check(parameterAnnotation(node.id), "variable");
|
|
8772
|
+
}
|
|
8773
|
+
},
|
|
8774
|
+
PropertyDefinition(node) {
|
|
8775
|
+
if (checkVariables) {
|
|
8776
|
+
check(node.typeAnnotation, "variable");
|
|
8777
|
+
}
|
|
8778
|
+
},
|
|
8779
|
+
TSAsExpression(node) {
|
|
8780
|
+
if (checkAssertions) {
|
|
8781
|
+
check(node.typeAnnotation, "assertion");
|
|
8782
|
+
}
|
|
8783
|
+
},
|
|
8784
|
+
TSSatisfiesExpression(node) {
|
|
8785
|
+
if (checkAssertions) {
|
|
8786
|
+
check(node.typeAnnotation, "assertion");
|
|
8787
|
+
}
|
|
8788
|
+
},
|
|
8789
|
+
CallExpression(node) {
|
|
8790
|
+
if (checkArguments) {
|
|
8791
|
+
check(node.typeArguments, "type argument");
|
|
8792
|
+
}
|
|
8793
|
+
},
|
|
8794
|
+
NewExpression(node) {
|
|
8795
|
+
if (checkArguments) {
|
|
8796
|
+
check(node.typeArguments, "type argument");
|
|
8797
|
+
}
|
|
8798
|
+
},
|
|
8076
8799
|
FunctionDeclaration: checkFunction,
|
|
8077
8800
|
FunctionExpression: checkFunction,
|
|
8078
8801
|
ArrowFunctionExpression: checkFunction,
|
|
@@ -8083,11 +8806,38 @@ var typesInline = defineRule73({
|
|
|
8083
8806
|
});
|
|
8084
8807
|
|
|
8085
8808
|
// src/rules/types/types-local-alias.ts
|
|
8086
|
-
|
|
8809
|
+
import { defineRule as defineRule80 } from "@oxlint/plugins";
|
|
8810
|
+
var typesLocalAlias = defineRule80({
|
|
8811
|
+
meta: {
|
|
8812
|
+
type: "problem",
|
|
8813
|
+
schema: [{ type: "object", additionalProperties: false, properties: { allow: optionsPatternSchema, message: { type: "string" } } }],
|
|
8814
|
+
messages: { forbidden: "{{message}}" }
|
|
8815
|
+
},
|
|
8816
|
+
createOnce(context) {
|
|
8817
|
+
let allow = [];
|
|
8818
|
+
let message = "";
|
|
8819
|
+
return {
|
|
8820
|
+
before() {
|
|
8821
|
+
const options = optionsFirst(context, {});
|
|
8822
|
+
allow = optionsPatterns(options.allow);
|
|
8823
|
+
message = options.message ?? "Local component/hook contracts use interfaces named for their owner. Derived or reusable aliases belong in domain types; do not substitute an empty interface.";
|
|
8824
|
+
},
|
|
8825
|
+
TSTypeAliasDeclaration(node) {
|
|
8826
|
+
if (!optionsPatternsTest(allow, node.id.name)) {
|
|
8827
|
+
context.report({
|
|
8828
|
+
node,
|
|
8829
|
+
messageId: "forbidden",
|
|
8830
|
+
data: { message }
|
|
8831
|
+
});
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
}
|
|
8836
|
+
});
|
|
8087
8837
|
|
|
8088
8838
|
// src/rules/types/types-namespace-import.ts
|
|
8089
|
-
import { defineRule as
|
|
8090
|
-
var typesNamespaceImport =
|
|
8839
|
+
import { defineRule as defineRule81 } from "@oxlint/plugins";
|
|
8840
|
+
var typesNamespaceImport = defineRule81({
|
|
8091
8841
|
meta: {
|
|
8092
8842
|
type: "suggestion",
|
|
8093
8843
|
schema: [
|
|
@@ -8129,8 +8879,8 @@ var typesNamespaceImport = defineRule74({
|
|
|
8129
8879
|
});
|
|
8130
8880
|
|
|
8131
8881
|
// src/rules/types/types-service.ts
|
|
8132
|
-
import { defineRule as
|
|
8133
|
-
var typesService =
|
|
8882
|
+
import { defineRule as defineRule82 } from "@oxlint/plugins";
|
|
8883
|
+
var typesService = defineRule82({
|
|
8134
8884
|
meta: {
|
|
8135
8885
|
type: "problem",
|
|
8136
8886
|
schema: [
|
|
@@ -8180,12 +8930,12 @@ var typesService = defineRule75({
|
|
|
8180
8930
|
});
|
|
8181
8931
|
|
|
8182
8932
|
// src/rules/types/types-unknown.ts
|
|
8183
|
-
import { defineRule as
|
|
8933
|
+
import { defineRule as defineRule83 } from "@oxlint/plugins";
|
|
8184
8934
|
function isCatchName(node) {
|
|
8185
8935
|
const key = "key" in node && !(("computed" in node) && node.computed) ? node.key : undefined;
|
|
8186
8936
|
return key?.type === "Identifier" && key.name === "catch";
|
|
8187
8937
|
}
|
|
8188
|
-
var typesUnknown =
|
|
8938
|
+
var typesUnknown = defineRule83({
|
|
8189
8939
|
meta: { type: "problem", schema: [], messages: { forbidden: "Use an owned domain type rather than unknown." } },
|
|
8190
8940
|
createOnce(context) {
|
|
8191
8941
|
return {
|
|
@@ -8224,6 +8974,7 @@ var src_default = eslintCompatPlugin({
|
|
|
8224
8974
|
"boundaries-token-owner": boundariesTokenOwner,
|
|
8225
8975
|
"code-branch-once": codeBranchOnce,
|
|
8226
8976
|
"code-constructor": codeConstructor,
|
|
8977
|
+
"code-delegate": codeDelegate,
|
|
8227
8978
|
"code-double-negation": codeDoubleNegation,
|
|
8228
8979
|
"code-function-nesting": codeFunctionNesting,
|
|
8229
8980
|
"code-inline": codeInline,
|
|
@@ -8268,6 +9019,7 @@ var src_default = eslintCompatPlugin({
|
|
|
8268
9019
|
"layout-padding": layoutPadding,
|
|
8269
9020
|
"layout-pipe": layoutPipe,
|
|
8270
9021
|
"layout-ternary": layoutTernary,
|
|
9022
|
+
"layout-type-arguments": layoutTypeArguments,
|
|
8271
9023
|
"naming-declarations": namingDeclarations,
|
|
8272
9024
|
"naming-exports": namingExports,
|
|
8273
9025
|
"naming-file": namingFile,
|
|
@@ -8277,6 +9029,7 @@ var src_default = eslintCompatPlugin({
|
|
|
8277
9029
|
"react-empty-effect": reactEmptyEffect,
|
|
8278
9030
|
"react-memo": reactMemo,
|
|
8279
9031
|
"react-props": reactProps,
|
|
9032
|
+
"react-query-props": reactQueryProps,
|
|
8280
9033
|
"schemas-inline": schemasInline,
|
|
8281
9034
|
"schemas-local": schemasLocal,
|
|
8282
9035
|
"schemas-rederive": schemasRederive,
|