oxlint-plugin-arch 0.12.4 → 0.12.6
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 +57 -0
- package/README.md +2 -2
- package/dist/index.js +1247 -280
- package/dist/preset/preset.js +79 -6
- package/dist/preset/preset.utils.d.ts +1 -0
- package/dist/rules/effect/effect-layer-file.d.ts +1 -0
- package/dist/rules/effect/effect-layers.d.ts +1 -0
- package/dist/rules/effect/effect-merge-pipe.d.ts +1 -0
- package/dist/rules/effect/effect-schema-first.d.ts +1 -0
- package/dist/rules/effect/effect-values-first.d.ts +1 -0
- package/dist/rules/types/types-duplicate.d.ts +1 -0
- package/dist/types/backend.types.d.ts +1 -0
- package/dist/types/boundaries.types.d.ts +7 -0
- package/dist/types/code.types.d.ts +3 -0
- package/dist/types/comments.types.d.ts +1 -1
- package/dist/types/effect.types.d.ts +46 -0
- package/dist/types/files.types.d.ts +6 -1
- package/dist/types/layout.types.d.ts +10 -2
- package/dist/types/preset.types.d.ts +9 -0
- package/dist/types/react.types.d.ts +1 -0
- package/dist/types/schemas.types.d.ts +2 -0
- package/dist/types/tests.types.d.ts +7 -0
- package/dist/types/types.types.d.ts +8 -0
- package/dist/utils/effect.utils.d.ts +5 -0
- package/dist/utils/source.utils.d.ts +1 -0
- package/dist/vendor/dillon-anti-slop/index.js +3 -0
- package/package.json +11 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/index.ts
|
|
2
5
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
3
6
|
|
|
@@ -510,14 +513,15 @@ var backendRegistry = defineRule3({
|
|
|
510
513
|
registry: { type: "string", minLength: 1 },
|
|
511
514
|
services: { type: "string", minLength: 1 },
|
|
512
515
|
skip: { type: "array", items: { type: "string" } },
|
|
513
|
-
object: { type: "string", minLength: 1 }
|
|
516
|
+
object: { type: "string", minLength: 1 },
|
|
517
|
+
file: { type: "string", minLength: 1, default: "{folder}.service.ts" }
|
|
514
518
|
},
|
|
515
519
|
required: ["registry", "services"]
|
|
516
520
|
}
|
|
517
521
|
],
|
|
518
522
|
messages: {
|
|
519
523
|
unregistered: "Register the {{folder}} service here under '{{key}}'.",
|
|
520
|
-
missing: "Domain folder '{{folder}}' needs {{
|
|
524
|
+
missing: "Domain folder '{{folder}}' needs {{file}}; add it, or list the folder in skip."
|
|
521
525
|
}
|
|
522
526
|
},
|
|
523
527
|
createOnce(context) {
|
|
@@ -559,11 +563,12 @@ var backendRegistry = defineRule3({
|
|
|
559
563
|
const domains = entries.filter((entry) => entry.isDirectory() && !(options.skip ?? []).includes(entry.name)).map((entry) => entry.name);
|
|
560
564
|
for (const folder of domains) {
|
|
561
565
|
const key = namingCamelCase(folder);
|
|
562
|
-
|
|
566
|
+
const file = (options.file ?? "{folder}.service.ts").replaceAll("{folder}", folder);
|
|
567
|
+
if (!existsSync(join(options.services, folder, file))) {
|
|
563
568
|
context.report({
|
|
564
569
|
node: program,
|
|
565
570
|
messageId: "missing",
|
|
566
|
-
data: { folder }
|
|
571
|
+
data: { folder, file }
|
|
567
572
|
});
|
|
568
573
|
} else if (![key, `${key}s`, key.replace(/y$/, "ies")].some((name) => keys.has(name))) {
|
|
569
574
|
context.report({
|
|
@@ -1136,11 +1141,14 @@ var boundariesDeny = defineRule6({
|
|
|
1136
1141
|
// src/rules/boundaries/boundaries-imports.ts
|
|
1137
1142
|
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1138
1143
|
import { basename, resolve as resolve2 } from "node:path";
|
|
1139
|
-
var
|
|
1144
|
+
var boundariesSurfaces = ["service", "client", "server", "rsc", "utils"];
|
|
1140
1145
|
var boundariesActionOrQuery = /\/(?:[^/]+)-(?:action|query)\./;
|
|
1141
1146
|
function boundariesContains(directory, candidate) {
|
|
1142
1147
|
return candidate === directory || candidate.startsWith(`${directory}/`);
|
|
1143
1148
|
}
|
|
1149
|
+
function boundariesIsSurface(options, stem) {
|
|
1150
|
+
return (options.surfaces ?? boundariesSurfaces).some((surface) => stem.endsWith(`.${surface}`));
|
|
1151
|
+
}
|
|
1144
1152
|
function boundariesStripExtension(path) {
|
|
1145
1153
|
return path.replace(/\.[cm]?[jt]sx?$/, "");
|
|
1146
1154
|
}
|
|
@@ -1169,12 +1177,12 @@ function boundariesPrivateDomain({ options, file, target, reExport, roots, owner
|
|
|
1169
1177
|
const targetDomain = targetOwner ? boundariesDomain(target, targetOwner, boundariesServiceFolder(options, targetOwner)) : undefined;
|
|
1170
1178
|
const sameDomain = owner && owner === targetOwner && fileDomain && fileDomain === targetDomain;
|
|
1171
1179
|
const targetStem = boundariesStripExtension(target);
|
|
1172
|
-
const publicSurface =
|
|
1180
|
+
const publicSurface = boundariesIsSurface(options, targetStem) && !boundariesActionOrQuery.test(targetStem);
|
|
1173
1181
|
const privateTarget = roles.some((role) => targetStem.endsWith(`.${role}`)) || targetDomain && !publicSurface && !/\.(?:types|constants)$/.test(targetStem);
|
|
1174
1182
|
if (!privateTarget) {
|
|
1175
1183
|
return;
|
|
1176
1184
|
}
|
|
1177
|
-
if (reExport &&
|
|
1185
|
+
if (reExport && file.endsWith(".ts") && boundariesIsSurface(options, file.slice(0, -".ts".length)) && !boundariesActionOrQuery.test(file)) {
|
|
1178
1186
|
return "public service and utility surfaces must not re-export private domain internals";
|
|
1179
1187
|
}
|
|
1180
1188
|
return sameDomain ? undefined : "private domain files stay in the same domain and application; use its service API or shared utilities";
|
|
@@ -1212,6 +1220,7 @@ var boundariesImports = defineRule7({
|
|
|
1212
1220
|
backend: { type: "array", items: { type: "string" } },
|
|
1213
1221
|
packages: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }] },
|
|
1214
1222
|
roles: { type: "array", items: { type: "string" } },
|
|
1223
|
+
surfaces: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesSurfaces },
|
|
1215
1224
|
services: { type: "array", items: { type: "string" } },
|
|
1216
1225
|
portable: { type: "boolean" },
|
|
1217
1226
|
backendPackages: { type: "array", items: { type: "string" } },
|
|
@@ -1307,11 +1316,9 @@ var boundariesNextDefaults = {
|
|
|
1307
1316
|
serverPackages: [...boundariesServerPackages, "server-only", "next/headers", "next/cache", "next/server"],
|
|
1308
1317
|
clientPackages: ["client-only", "react-dom/client"],
|
|
1309
1318
|
hookPackages: ["react"],
|
|
1310
|
-
publicEnv: "NEXT_PUBLIC_"
|
|
1319
|
+
publicEnv: "NEXT_PUBLIC_",
|
|
1320
|
+
serverHooks: ["useId", "use"]
|
|
1311
1321
|
};
|
|
1312
|
-
function boundariesIsClientHook(name) {
|
|
1313
|
-
return /^use[A-Z]/.test(name) && name !== "useId" && name !== "use";
|
|
1314
|
-
}
|
|
1315
1322
|
var boundariesNext = defineRule8({
|
|
1316
1323
|
meta: {
|
|
1317
1324
|
type: "problem",
|
|
@@ -1319,7 +1326,11 @@ var boundariesNext = defineRule8({
|
|
|
1319
1326
|
{
|
|
1320
1327
|
type: "object",
|
|
1321
1328
|
additionalProperties: false,
|
|
1322
|
-
properties: {
|
|
1329
|
+
properties: {
|
|
1330
|
+
...boundariesRuntimeProperties,
|
|
1331
|
+
publicEnv: { type: "string" },
|
|
1332
|
+
serverHooks: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesNextDefaults.serverHooks }
|
|
1333
|
+
}
|
|
1323
1334
|
}
|
|
1324
1335
|
],
|
|
1325
1336
|
messages: {
|
|
@@ -1335,6 +1346,7 @@ var boundariesNext = defineRule8({
|
|
|
1335
1346
|
let client = false;
|
|
1336
1347
|
let shared = false;
|
|
1337
1348
|
const reactNamespaces = new Set;
|
|
1349
|
+
const clientHook = (name) => /^use[A-Z]/.test(name) && !options.serverHooks.includes(name);
|
|
1338
1350
|
function check(node, source, typeOnly) {
|
|
1339
1351
|
if (typeOnly) {
|
|
1340
1352
|
return;
|
|
@@ -1398,14 +1410,14 @@ var boundariesNext = defineRule8({
|
|
|
1398
1410
|
reactNamespaces.add(specifier);
|
|
1399
1411
|
continue;
|
|
1400
1412
|
}
|
|
1401
|
-
if (specifier.importKind !== "type" && specifier.imported.type === "Identifier" &&
|
|
1413
|
+
if (specifier.importKind !== "type" && specifier.imported.type === "Identifier" && clientHook(specifier.imported.name)) {
|
|
1402
1414
|
boundariesReport(context, specifier, specifier.imported.name, boundariesClientHookReason);
|
|
1403
1415
|
}
|
|
1404
1416
|
}
|
|
1405
1417
|
},
|
|
1406
1418
|
MemberExpression(node) {
|
|
1407
1419
|
const name = boundariesMemberName(node);
|
|
1408
|
-
if (!name || !
|
|
1420
|
+
if (!name || !clientHook(name) || node.object.type !== "Identifier") {
|
|
1409
1421
|
return;
|
|
1410
1422
|
}
|
|
1411
1423
|
const binding = boundariesDeclaredVariable(context.sourceCode.getScope(node.object), node.object.name)?.defs[0]?.node;
|
|
@@ -1449,12 +1461,54 @@ var boundariesNext = defineRule8({
|
|
|
1449
1461
|
});
|
|
1450
1462
|
|
|
1451
1463
|
// src/rules/boundaries/boundaries-rpc-database.ts
|
|
1452
|
-
|
|
1453
|
-
var
|
|
1464
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1465
|
+
var boundariesRpcDatabaseMethods = ["selectFrom", "insertInto", "updateTable", "deleteFrom", "mergeInto", "executeQuery"];
|
|
1466
|
+
var boundariesRpcDatabase = defineRule9({
|
|
1467
|
+
meta: {
|
|
1468
|
+
type: "problem",
|
|
1469
|
+
schema: [
|
|
1470
|
+
{
|
|
1471
|
+
type: "object",
|
|
1472
|
+
additionalProperties: false,
|
|
1473
|
+
properties: {
|
|
1474
|
+
message: { type: "string" },
|
|
1475
|
+
methods: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesRpcDatabaseMethods }
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
],
|
|
1479
|
+
messages: { forbidden: "{{message}}" }
|
|
1480
|
+
},
|
|
1481
|
+
createOnce(context) {
|
|
1482
|
+
let message = "";
|
|
1483
|
+
let methods = new Set;
|
|
1484
|
+
return {
|
|
1485
|
+
before() {
|
|
1486
|
+
const options = optionsFirst(context, {});
|
|
1487
|
+
message = options.message ?? "RPC handlers delegate database work to services.";
|
|
1488
|
+
methods = new Set(options.methods ?? boundariesRpcDatabaseMethods);
|
|
1489
|
+
},
|
|
1490
|
+
CallExpression(node) {
|
|
1491
|
+
const callee = node.callee;
|
|
1492
|
+
if (callee.type !== "MemberExpression") {
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const property = callee.property;
|
|
1496
|
+
const literal = property.type === "Literal" && typeof property.value === "string" ? property.value : undefined;
|
|
1497
|
+
const name = callee.computed ? literal : astMemberName(callee);
|
|
1498
|
+
if (name !== undefined && methods.has(name)) {
|
|
1499
|
+
context.report({
|
|
1500
|
+
node,
|
|
1501
|
+
messageId: "forbidden",
|
|
1502
|
+
data: { message }
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1454
1509
|
|
|
1455
1510
|
// src/rules/boundaries/boundaries-tanstack.ts
|
|
1456
|
-
import { defineRule as
|
|
1457
|
-
var boundariesRenderers = ["renderServerComponent", "renderToReadableStream"];
|
|
1511
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1458
1512
|
var boundariesChainMethods = ["handler", "server", "client", "middleware", "validator", "inputValidator"];
|
|
1459
1513
|
var boundariesSplitFactories = ["createIsomorphicFn", "createMiddleware"];
|
|
1460
1514
|
var boundariesRuntimeTypeWrappers = [
|
|
@@ -1490,12 +1544,13 @@ var boundariesTanstackDefaults = {
|
|
|
1490
1544
|
clientPackages: ["react-dom/client", "@tanstack/react-start/client-only", "@tanstack/solid-start/client-only", "@tanstack/vue-start/client-only"],
|
|
1491
1545
|
hookPackages: ["react", "@tanstack/react-query", "@tanstack/react-router"],
|
|
1492
1546
|
startPackages: ["@tanstack/react-start"],
|
|
1493
|
-
rscPackages: ["@tanstack/react-start/rsc", "@tanstack/react-start-rsc"]
|
|
1547
|
+
rscPackages: ["@tanstack/react-start/rsc", "@tanstack/react-start-rsc"],
|
|
1548
|
+
renderers: ["renderServerComponent", "renderToReadableStream"]
|
|
1494
1549
|
};
|
|
1495
|
-
function
|
|
1550
|
+
function boundariesIsClientHook(name) {
|
|
1496
1551
|
return /^use[A-Z]/.test(name) && name !== "useId";
|
|
1497
1552
|
}
|
|
1498
|
-
var boundariesTanstack =
|
|
1553
|
+
var boundariesTanstack = defineRule10({
|
|
1499
1554
|
meta: {
|
|
1500
1555
|
type: "problem",
|
|
1501
1556
|
schema: [
|
|
@@ -1506,7 +1561,8 @@ var boundariesTanstack = defineRule9({
|
|
|
1506
1561
|
...boundariesRuntimeProperties,
|
|
1507
1562
|
rpc: { type: "array", items: { type: "string" } },
|
|
1508
1563
|
startPackages: { type: "array", items: { type: "string" } },
|
|
1509
|
-
rscPackages: { type: "array", items: { type: "string" } }
|
|
1564
|
+
rscPackages: { type: "array", items: { type: "string" } },
|
|
1565
|
+
renderers: { type: "array", items: { type: "string", minLength: 1 }, default: boundariesTanstackDefaults.renderers }
|
|
1510
1566
|
}
|
|
1511
1567
|
}
|
|
1512
1568
|
],
|
|
@@ -1662,7 +1718,7 @@ var boundariesTanstack = defineRule9({
|
|
|
1662
1718
|
return;
|
|
1663
1719
|
}
|
|
1664
1720
|
for (const specifier of node.specifiers) {
|
|
1665
|
-
if (options.rscPackages.includes(node.source.value) && specifier.type === "ImportSpecifier" && specifier.importKind !== "type" && specifier.imported.type === "Identifier" &&
|
|
1721
|
+
if (options.rscPackages.includes(node.source.value) && specifier.type === "ImportSpecifier" && specifier.importKind !== "type" && specifier.imported.type === "Identifier" && options.renderers.includes(specifier.imported.name)) {
|
|
1666
1722
|
check(node, node.source.value, false, false, specifier);
|
|
1667
1723
|
}
|
|
1668
1724
|
}
|
|
@@ -1670,7 +1726,7 @@ var boundariesTanstack = defineRule9({
|
|
|
1670
1726
|
return;
|
|
1671
1727
|
}
|
|
1672
1728
|
for (const specifier of node.specifiers) {
|
|
1673
|
-
if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type" || specifier.imported.type !== "Identifier" || !
|
|
1729
|
+
if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type" || specifier.imported.type !== "Identifier" || !boundariesIsClientHook(specifier.imported.name)) {
|
|
1674
1730
|
continue;
|
|
1675
1731
|
}
|
|
1676
1732
|
const references = runtimeReferences(node, specifier.local.name);
|
|
@@ -1689,10 +1745,10 @@ var boundariesTanstack = defineRule9({
|
|
|
1689
1745
|
return;
|
|
1690
1746
|
}
|
|
1691
1747
|
const kind = imported(node.object);
|
|
1692
|
-
if (kind === "rsc-renderers" &&
|
|
1748
|
+
if (kind === "rsc-renderers" && options.renderers.includes(name) && (shared || !serverPosition(node.start, true))) {
|
|
1693
1749
|
boundariesReport(context, node, name, "server renderers require a server execution boundary");
|
|
1694
1750
|
}
|
|
1695
|
-
if ((serverFile || rscFile) && kind === "client-hooks" &&
|
|
1751
|
+
if ((serverFile || rscFile) && kind === "client-hooks" && boundariesIsClientHook(name) && !clientSide(node.start)) {
|
|
1696
1752
|
boundariesReport(context, node, name, boundariesClientHookReason2);
|
|
1697
1753
|
}
|
|
1698
1754
|
},
|
|
@@ -1724,8 +1780,8 @@ var boundariesTanstack = defineRule9({
|
|
|
1724
1780
|
});
|
|
1725
1781
|
|
|
1726
1782
|
// src/rules/boundaries/boundaries-token-owner.ts
|
|
1727
|
-
import { defineRule as
|
|
1728
|
-
var boundariesTokenOwner =
|
|
1783
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
1784
|
+
var boundariesTokenOwner = defineRule11({
|
|
1729
1785
|
meta: {
|
|
1730
1786
|
type: "problem",
|
|
1731
1787
|
schema: [
|
|
@@ -1820,7 +1876,7 @@ var boundariesTokenOwner = defineRule10({
|
|
|
1820
1876
|
});
|
|
1821
1877
|
|
|
1822
1878
|
// src/rules/code/code-branch-once.ts
|
|
1823
|
-
import { defineRule as
|
|
1879
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
1824
1880
|
function codeBranchOnceSubjects(node, source) {
|
|
1825
1881
|
if (node.type === "LogicalExpression") {
|
|
1826
1882
|
return [...codeBranchOnceSubjects(node.left, source), ...codeBranchOnceSubjects(node.right, source)];
|
|
@@ -1836,18 +1892,27 @@ function codeBranchOnceSubjects(node, source) {
|
|
|
1836
1892
|
const literal = sides.some((side) => side.type === "Literal" && typeof side.value === "string");
|
|
1837
1893
|
return member && literal ? [source.getText(member)] : [];
|
|
1838
1894
|
}
|
|
1839
|
-
var codeBranchOnce =
|
|
1895
|
+
var codeBranchOnce = defineRule12({
|
|
1840
1896
|
meta: {
|
|
1841
1897
|
type: "suggestion",
|
|
1898
|
+
schema: [
|
|
1899
|
+
{
|
|
1900
|
+
type: "object",
|
|
1901
|
+
additionalProperties: false,
|
|
1902
|
+
properties: { min: { type: "integer", minimum: 2, default: 2 } }
|
|
1903
|
+
}
|
|
1904
|
+
],
|
|
1842
1905
|
messages: {
|
|
1843
1906
|
once: "{{subject}} is compared to a string in {{count}} ternaries in this file. Branch on it once and return a record."
|
|
1844
1907
|
}
|
|
1845
1908
|
},
|
|
1846
1909
|
createOnce(context) {
|
|
1847
1910
|
let groups = new Map;
|
|
1911
|
+
let min = 2;
|
|
1848
1912
|
return {
|
|
1849
1913
|
before() {
|
|
1850
1914
|
groups = new Map;
|
|
1915
|
+
min = optionsFirst(context, {}).min ?? 2;
|
|
1851
1916
|
},
|
|
1852
1917
|
ConditionalExpression(node) {
|
|
1853
1918
|
for (const subject of new Set(codeBranchOnceSubjects(node.test, context.sourceCode))) {
|
|
@@ -1856,7 +1921,7 @@ var codeBranchOnce = defineRule11({
|
|
|
1856
1921
|
},
|
|
1857
1922
|
"Program:exit"() {
|
|
1858
1923
|
for (const [subject, ternaries] of groups) {
|
|
1859
|
-
for (const node of ternaries.length
|
|
1924
|
+
for (const node of ternaries.length >= min ? ternaries : []) {
|
|
1860
1925
|
context.report({
|
|
1861
1926
|
node,
|
|
1862
1927
|
messageId: "once",
|
|
@@ -1870,8 +1935,8 @@ var codeBranchOnce = defineRule11({
|
|
|
1870
1935
|
});
|
|
1871
1936
|
|
|
1872
1937
|
// src/rules/code/code-constructor.ts
|
|
1873
|
-
import { defineRule as
|
|
1874
|
-
var codeConstructor =
|
|
1938
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
1939
|
+
var codeConstructor = defineRule13({
|
|
1875
1940
|
meta: {
|
|
1876
1941
|
type: "problem",
|
|
1877
1942
|
schema: [
|
|
@@ -1955,8 +2020,8 @@ var codeConstructor = defineRule12({
|
|
|
1955
2020
|
var codeDoubleNegation = astSelectorRule('UnaryExpression[operator="!"] > UnaryExpression[operator="!"]', "Use Boolean(value) or an explicit comparison.");
|
|
1956
2021
|
|
|
1957
2022
|
// src/rules/code/code-function-nesting.ts
|
|
1958
|
-
import { defineRule as
|
|
1959
|
-
var codeFunctionNesting =
|
|
2023
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
2024
|
+
var codeFunctionNesting = defineRule14({
|
|
1960
2025
|
meta: {
|
|
1961
2026
|
type: "suggestion",
|
|
1962
2027
|
schema: [
|
|
@@ -1997,7 +2062,7 @@ var codeFunctionNesting = defineRule13({
|
|
|
1997
2062
|
});
|
|
1998
2063
|
|
|
1999
2064
|
// src/rules/code/code-inline.ts
|
|
2000
|
-
import { defineRule as
|
|
2065
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
2001
2066
|
|
|
2002
2067
|
// src/utils/source.utils.ts
|
|
2003
2068
|
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])/;
|
|
@@ -2038,6 +2103,9 @@ function sourceLineEnd(text, offset) {
|
|
|
2038
2103
|
`, offset);
|
|
2039
2104
|
return end === -1 ? text.length : end;
|
|
2040
2105
|
}
|
|
2106
|
+
function sourceJoinedWidth(text, start, joined, end) {
|
|
2107
|
+
return start - sourceLineStart(text, start) + joined.length + text.slice(end, sourceLineEnd(text, end)).trimEnd().length;
|
|
2108
|
+
}
|
|
2041
2109
|
function sourceItemGaps(open, items, close) {
|
|
2042
2110
|
const edges = [open, ...items.flatMap((item) => item.range), close];
|
|
2043
2111
|
return Array.from({ length: items.length + 1 }, (_, index) => [edges[index * 2] ?? open, edges[index * 2 + 1] ?? close]);
|
|
@@ -2066,7 +2134,20 @@ function codeInlineEnclosingCalls(node) {
|
|
|
2066
2134
|
return outer && astIsOneLine(outer) ? 1 + codeInlineEnclosingCalls(outer) : 0;
|
|
2067
2135
|
}
|
|
2068
2136
|
var codeInlineWrapped = new Set(["ConditionalExpression", "LogicalExpression", "BinaryExpression", "ArrowFunctionExpression"]);
|
|
2069
|
-
var
|
|
2137
|
+
var codeInlineEffects = new Set([
|
|
2138
|
+
"CallExpression",
|
|
2139
|
+
"NewExpression",
|
|
2140
|
+
"AssignmentExpression",
|
|
2141
|
+
"UpdateExpression",
|
|
2142
|
+
"AwaitExpression",
|
|
2143
|
+
"YieldExpression",
|
|
2144
|
+
"TaggedTemplateExpression",
|
|
2145
|
+
"ImportExpression"
|
|
2146
|
+
]);
|
|
2147
|
+
function codeInlineEffectBetween(program, start, end) {
|
|
2148
|
+
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
|
+
}
|
|
2150
|
+
var codeInline = defineRule15({
|
|
2070
2151
|
meta: {
|
|
2071
2152
|
type: "suggestion",
|
|
2072
2153
|
schema: [
|
|
@@ -2104,6 +2185,9 @@ var codeInline = defineRule14({
|
|
|
2104
2185
|
return;
|
|
2105
2186
|
}
|
|
2106
2187
|
if (uses.length === 1) {
|
|
2188
|
+
if (init && codeInlineEffectBetween(context.sourceCode.ast, node.range[1], uses[0].identifier.range[0])) {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2107
2191
|
context.report({
|
|
2108
2192
|
node: id,
|
|
2109
2193
|
messageId: "once",
|
|
@@ -2141,7 +2225,7 @@ var codeInline = defineRule14({
|
|
|
2141
2225
|
deferred ||= current.type === "FunctionDeclaration" || astIsInlineFunction(current);
|
|
2142
2226
|
}
|
|
2143
2227
|
const wrapped = codeInlineWrapped.has(init.type) && use.parent.type === "MemberExpression" && use.parent.object === use;
|
|
2144
|
-
if (service || wrapped || deferred || codeInlineEnclosingCalls(use) + astCallDepth(init) > (options.nesting ?? 2) || line.length - id.name.length + context.sourceCode.getText(init).length > (options.max ?? 160)) {
|
|
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])) {
|
|
2145
2229
|
return;
|
|
2146
2230
|
}
|
|
2147
2231
|
context.report({
|
|
@@ -2176,8 +2260,8 @@ var codeInline = defineRule14({
|
|
|
2176
2260
|
});
|
|
2177
2261
|
|
|
2178
2262
|
// src/rules/code/code-justified-call.ts
|
|
2179
|
-
import { defineRule as
|
|
2180
|
-
var codeJustifiedCall =
|
|
2263
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
2264
|
+
var codeJustifiedCall = defineRule16({
|
|
2181
2265
|
meta: {
|
|
2182
2266
|
type: "problem",
|
|
2183
2267
|
schema: [
|
|
@@ -2231,8 +2315,8 @@ var codeJustifiedCall = defineRule15({
|
|
|
2231
2315
|
});
|
|
2232
2316
|
|
|
2233
2317
|
// src/rules/code/code-literal-in.ts
|
|
2234
|
-
import { defineRule as
|
|
2235
|
-
var codeLiteralIn =
|
|
2318
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
2319
|
+
var codeLiteralIn = defineRule17({
|
|
2236
2320
|
meta: {
|
|
2237
2321
|
type: "suggestion",
|
|
2238
2322
|
schema: [
|
|
@@ -2273,7 +2357,7 @@ var codeLiteralIn = defineRule16({
|
|
|
2273
2357
|
});
|
|
2274
2358
|
|
|
2275
2359
|
// src/rules/code/code-mutable-state.ts
|
|
2276
|
-
import { defineRule as
|
|
2360
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
2277
2361
|
var functionScopes = new Set([
|
|
2278
2362
|
"FunctionDeclaration",
|
|
2279
2363
|
"FunctionExpression",
|
|
@@ -2290,7 +2374,7 @@ function hasAncestor(node, test) {
|
|
|
2290
2374
|
}
|
|
2291
2375
|
return false;
|
|
2292
2376
|
}
|
|
2293
|
-
var codeMutableState =
|
|
2377
|
+
var codeMutableState = defineRule18({
|
|
2294
2378
|
meta: {
|
|
2295
2379
|
type: "problem",
|
|
2296
2380
|
schema: [
|
|
@@ -2348,7 +2432,7 @@ var codeMutableState = defineRule17({
|
|
|
2348
2432
|
});
|
|
2349
2433
|
|
|
2350
2434
|
// src/rules/code/code-object-params.ts
|
|
2351
|
-
import { defineRule as
|
|
2435
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
2352
2436
|
function isObjectParam(node) {
|
|
2353
2437
|
if (node.type === "ObjectPattern") {
|
|
2354
2438
|
return true;
|
|
@@ -2362,7 +2446,7 @@ function isObjectParam(node) {
|
|
|
2362
2446
|
const annotation = node.typeAnnotation?.typeAnnotation;
|
|
2363
2447
|
return !annotation || annotation.type === "TSTypeReference" || annotation.type === "TSTypeLiteral" || annotation.type === "TSIntersectionType";
|
|
2364
2448
|
}
|
|
2365
|
-
var codeObjectParams =
|
|
2449
|
+
var codeObjectParams = defineRule19({
|
|
2366
2450
|
meta: {
|
|
2367
2451
|
type: "problem",
|
|
2368
2452
|
schema: [
|
|
@@ -2411,8 +2495,8 @@ var codeObjectParams = defineRule18({
|
|
|
2411
2495
|
});
|
|
2412
2496
|
|
|
2413
2497
|
// src/rules/code/code-paired-call.ts
|
|
2414
|
-
import { defineRule as
|
|
2415
|
-
var codePairedCall =
|
|
2498
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
2499
|
+
var codePairedCall = defineRule20({
|
|
2416
2500
|
meta: {
|
|
2417
2501
|
type: "problem",
|
|
2418
2502
|
schema: [
|
|
@@ -2443,7 +2527,6 @@ var codePairedCall = defineRule19({
|
|
|
2443
2527
|
}
|
|
2444
2528
|
},
|
|
2445
2529
|
createOnce(context) {
|
|
2446
|
-
const aliases = new Map;
|
|
2447
2530
|
let pairs = [];
|
|
2448
2531
|
return {
|
|
2449
2532
|
before() {
|
|
@@ -2451,26 +2534,10 @@ var codePairedCall = defineRule19({
|
|
|
2451
2534
|
const all = when && require2 ? [{ when, require: require2 }, ...configured] : configured;
|
|
2452
2535
|
pairs = all.map((pair) => ({ ...pair, firstWhen: null, sawRequired: false }));
|
|
2453
2536
|
},
|
|
2454
|
-
Program(program) {
|
|
2455
|
-
aliases.clear();
|
|
2456
|
-
for (const statement of program.body) {
|
|
2457
|
-
if (statement.type !== "ImportDeclaration") {
|
|
2458
|
-
continue;
|
|
2459
|
-
}
|
|
2460
|
-
for (const specifier of statement.specifiers) {
|
|
2461
|
-
if (specifier.type !== "ImportSpecifier") {
|
|
2462
|
-
continue;
|
|
2463
|
-
}
|
|
2464
|
-
const imported = astModuleName(specifier.imported);
|
|
2465
|
-
if (imported !== specifier.local.name) {
|
|
2466
|
-
aliases.set(specifier.local.name, imported);
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
}
|
|
2470
|
-
},
|
|
2471
2537
|
CallExpression(node) {
|
|
2472
|
-
const
|
|
2473
|
-
const
|
|
2538
|
+
const callee = node.callee;
|
|
2539
|
+
const binding = callee.type === "Identifier" ? boundariesDeclaredVariable(context.sourceCode.getScope(node), callee.name)?.defs.at(0)?.node : undefined;
|
|
2540
|
+
const name = binding?.type === "ImportSpecifier" ? astModuleName(binding.imported) : astCallName(node);
|
|
2474
2541
|
for (const pair of pairs) {
|
|
2475
2542
|
if (name === pair.when) {
|
|
2476
2543
|
pair.firstWhen ??= node;
|
|
@@ -2496,7 +2563,7 @@ var codePairedCall = defineRule19({
|
|
|
2496
2563
|
});
|
|
2497
2564
|
|
|
2498
2565
|
// src/rules/code/code-promise-mutation.ts
|
|
2499
|
-
import { defineRule as
|
|
2566
|
+
import { defineRule as defineRule21 } from "@oxlint/plugins";
|
|
2500
2567
|
function mutationBinding(node) {
|
|
2501
2568
|
if (node.type === "Identifier") {
|
|
2502
2569
|
return node;
|
|
@@ -2525,7 +2592,7 @@ function mutationBindings(node) {
|
|
|
2525
2592
|
const binding = mutationBinding(node);
|
|
2526
2593
|
return binding ? [binding] : [];
|
|
2527
2594
|
}
|
|
2528
|
-
var codePromiseMutation =
|
|
2595
|
+
var codePromiseMutation = defineRule21({
|
|
2529
2596
|
meta: {
|
|
2530
2597
|
type: "problem",
|
|
2531
2598
|
schema: [
|
|
@@ -2618,8 +2685,8 @@ var codePromiseMutation = defineRule20({
|
|
|
2618
2685
|
var codeSwitch = astSelectorRule("SwitchStatement", "Avoid switch statements.");
|
|
2619
2686
|
|
|
2620
2687
|
// src/rules/code/code-traced.ts
|
|
2621
|
-
import { defineRule as
|
|
2622
|
-
var codeTraced =
|
|
2688
|
+
import { defineRule as defineRule22 } from "@oxlint/plugins";
|
|
2689
|
+
var codeTraced = defineRule22({
|
|
2623
2690
|
meta: {
|
|
2624
2691
|
type: "problem",
|
|
2625
2692
|
schema: [
|
|
@@ -2668,17 +2735,17 @@ var codeTraced = defineRule21({
|
|
|
2668
2735
|
message = options.message ?? `An exported function or service method gets a span: replace ${[...untraced].join(", ")} with its traced form.`;
|
|
2669
2736
|
},
|
|
2670
2737
|
ExportNamedDeclaration(node) {
|
|
2671
|
-
if (!exported
|
|
2738
|
+
if (!exported) {
|
|
2672
2739
|
return;
|
|
2673
2740
|
}
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
}
|
|
2681
|
-
}
|
|
2741
|
+
const declarators = node.declaration?.type === "VariableDeclaration" ? node.declaration.declarations.filter((declarator) => isUntraced(declarator.init)) : [];
|
|
2742
|
+
const specifiers = node.source ? [] : node.specifiers.filter((specifier) => resolves(specifier.local));
|
|
2743
|
+
for (const surface of [...declarators, ...specifiers]) {
|
|
2744
|
+
context.report({
|
|
2745
|
+
node: surface,
|
|
2746
|
+
messageId: "surface",
|
|
2747
|
+
data: { message }
|
|
2748
|
+
});
|
|
2682
2749
|
}
|
|
2683
2750
|
},
|
|
2684
2751
|
CallExpression(node) {
|
|
@@ -2706,7 +2773,7 @@ var codeTraced = defineRule21({
|
|
|
2706
2773
|
});
|
|
2707
2774
|
|
|
2708
2775
|
// src/rules/code/code-trivial-functions.ts
|
|
2709
|
-
import { defineRule as
|
|
2776
|
+
import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
2710
2777
|
var codeTrivialFunctionsBanned = [
|
|
2711
2778
|
"isRecord",
|
|
2712
2779
|
"isPlainObject",
|
|
@@ -2836,7 +2903,7 @@ function guardStatement(node, state) {
|
|
|
2836
2903
|
return guardFallback(declaration.init);
|
|
2837
2904
|
});
|
|
2838
2905
|
}
|
|
2839
|
-
var codeTrivialFunctions =
|
|
2906
|
+
var codeTrivialFunctions = defineRule23({
|
|
2840
2907
|
meta: {
|
|
2841
2908
|
type: "problem",
|
|
2842
2909
|
schema: [
|
|
@@ -2967,8 +3034,8 @@ var codeTrivialFunctions = defineRule22({
|
|
|
2967
3034
|
});
|
|
2968
3035
|
|
|
2969
3036
|
// src/rules/code/code-yield-argument.ts
|
|
2970
|
-
import { defineRule as
|
|
2971
|
-
var codeYieldArgument =
|
|
3037
|
+
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
3038
|
+
var codeYieldArgument = defineRule24({
|
|
2972
3039
|
meta: {
|
|
2973
3040
|
type: "suggestion",
|
|
2974
3041
|
messages: {
|
|
@@ -2990,7 +3057,7 @@ var codeYieldArgument = defineRule23({
|
|
|
2990
3057
|
});
|
|
2991
3058
|
|
|
2992
3059
|
// src/rules/comments/comments-code.ts
|
|
2993
|
-
import { defineRule as
|
|
3060
|
+
import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
2994
3061
|
var commentsLineGap = /^[\t \r\n\u2028\u2029]*$/;
|
|
2995
3062
|
var commentsLineTerminator = /\r\n|[\n\r\u2028\u2029]/;
|
|
2996
3063
|
var commentsUnicodeTerminator = /[\u2028\u2029]/;
|
|
@@ -3041,7 +3108,7 @@ function commentsFollowsOpeningBrace(text, offset) {
|
|
|
3041
3108
|
}
|
|
3042
3109
|
return false;
|
|
3043
3110
|
}
|
|
3044
|
-
var commentsCode =
|
|
3111
|
+
var commentsCode = defineRule25({
|
|
3045
3112
|
meta: {
|
|
3046
3113
|
type: "suggestion",
|
|
3047
3114
|
fixable: "code",
|
|
@@ -3050,7 +3117,7 @@ var commentsCode = defineRule24({
|
|
|
3050
3117
|
type: "object",
|
|
3051
3118
|
additionalProperties: false,
|
|
3052
3119
|
properties: {
|
|
3053
|
-
why: { type: "boolean", default: true },
|
|
3120
|
+
why: { anyOf: [{ type: "boolean" }, { type: "string", minLength: 1 }], default: true },
|
|
3054
3121
|
allow: { type: "array", items: { type: "string" } },
|
|
3055
3122
|
jsdoc: { type: "boolean", default: false },
|
|
3056
3123
|
members: { type: "string", enum: ["off", "also", "only"] }
|
|
@@ -3064,6 +3131,7 @@ var commentsCode = defineRule24({
|
|
|
3064
3131
|
},
|
|
3065
3132
|
createOnce(context) {
|
|
3066
3133
|
let allowWhy = true;
|
|
3134
|
+
let whyPrefix = "Why: ";
|
|
3067
3135
|
let allowJsdoc = false;
|
|
3068
3136
|
let allowed = [];
|
|
3069
3137
|
let members = "off";
|
|
@@ -3088,7 +3156,8 @@ var commentsCode = defineRule24({
|
|
|
3088
3156
|
return {
|
|
3089
3157
|
before() {
|
|
3090
3158
|
const options = optionsFirst(context, {});
|
|
3091
|
-
allowWhy = options.why
|
|
3159
|
+
allowWhy = options.why !== false;
|
|
3160
|
+
whyPrefix = `${typeof options.why === "string" ? options.why.trim() : "Why:"} `;
|
|
3092
3161
|
allowJsdoc = options.jsdoc ?? false;
|
|
3093
3162
|
allowed = (options.allow ?? []).map((pattern) => new RegExp(pattern));
|
|
3094
3163
|
members = options.members ?? "off";
|
|
@@ -3117,7 +3186,7 @@ var commentsCode = defineRule24({
|
|
|
3117
3186
|
mightContainJsxComment = true;
|
|
3118
3187
|
}
|
|
3119
3188
|
const followsPrevious = previous !== undefined && comment.loc.start.line === previous.loc.end.line + 1 && commentsLineGap.test(text.slice(previous.range[1], comment.range[0]));
|
|
3120
|
-
const isWhy = value.startsWith(
|
|
3189
|
+
const isWhy = value.startsWith(whyPrefix) || comment.type === "Line" && whyContinuation && followsPrevious;
|
|
3121
3190
|
if (/^(?:eslint|oxlint)-disable-next-line\b/.test(value)) {
|
|
3122
3191
|
protectedLines.push(comment.loc.end.line + 1);
|
|
3123
3192
|
}
|
|
@@ -3205,9 +3274,9 @@ var commentsCode = defineRule24({
|
|
|
3205
3274
|
});
|
|
3206
3275
|
|
|
3207
3276
|
// src/rules/comments/comments-directives.ts
|
|
3208
|
-
import { defineRule as
|
|
3277
|
+
import { defineRule as defineRule26 } from "@oxlint/plugins";
|
|
3209
3278
|
var directive = /^\s*(?:oxlint|eslint)-disable(?:-next-line|-line)?\b(.*)$/s;
|
|
3210
|
-
var commentsDirectives =
|
|
3279
|
+
var commentsDirectives = defineRule26({
|
|
3211
3280
|
meta: {
|
|
3212
3281
|
type: "problem",
|
|
3213
3282
|
schema: [],
|
|
@@ -3235,9 +3304,9 @@ var commentsDirectives = defineRule25({
|
|
|
3235
3304
|
});
|
|
3236
3305
|
|
|
3237
3306
|
// src/rules/copy/copy-dashes.ts
|
|
3238
|
-
import { defineRule as
|
|
3307
|
+
import { defineRule as defineRule27 } from "@oxlint/plugins";
|
|
3239
3308
|
var copyDashesMessage = "Use a comma, colon, period or parentheses instead.";
|
|
3240
|
-
var copyDashes =
|
|
3309
|
+
var copyDashes = defineRule27({
|
|
3241
3310
|
meta: {
|
|
3242
3311
|
type: "suggestion",
|
|
3243
3312
|
schema: [
|
|
@@ -3281,19 +3350,694 @@ var copyDashes = defineRule26({
|
|
|
3281
3350
|
return false;
|
|
3282
3351
|
}
|
|
3283
3352
|
},
|
|
3284
|
-
Literal(node) {
|
|
3285
|
-
if (typeof node.value === "string") {
|
|
3286
|
-
check(node);
|
|
3353
|
+
Literal(node) {
|
|
3354
|
+
if (typeof node.value === "string") {
|
|
3355
|
+
check(node);
|
|
3356
|
+
}
|
|
3357
|
+
},
|
|
3358
|
+
TemplateElement: check,
|
|
3359
|
+
JSXText: check
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3362
|
+
});
|
|
3363
|
+
|
|
3364
|
+
// src/rules/effect/effect-layer-file.ts
|
|
3365
|
+
import { defineRule as defineRule28 } from "@oxlint/plugins";
|
|
3366
|
+
|
|
3367
|
+
// src/utils/effect.utils.ts
|
|
3368
|
+
var effectBuilders = ["Effect.gen", "Effect.fn", "Effect.fnUntraced"];
|
|
3369
|
+
function effectIsBuilder(node, builders) {
|
|
3370
|
+
const value = node ? astUnwrap(node) : undefined;
|
|
3371
|
+
if (value?.type !== "CallExpression") {
|
|
3372
|
+
return false;
|
|
3373
|
+
}
|
|
3374
|
+
const callee = value.callee.type === "CallExpression" ? value.callee.callee : value.callee;
|
|
3375
|
+
return builders.has(astDottedName(callee) ?? "");
|
|
3376
|
+
}
|
|
3377
|
+
function effectGenerator(node, builders) {
|
|
3378
|
+
const value = node ? astUnwrap(node) : undefined;
|
|
3379
|
+
return effectIsBuilder(value, builders) ? value.arguments.find((argument) => argument.type === "FunctionExpression") : undefined;
|
|
3380
|
+
}
|
|
3381
|
+
function effectMatches(node, patterns) {
|
|
3382
|
+
if (!node || node.type === "Super") {
|
|
3383
|
+
return false;
|
|
3384
|
+
}
|
|
3385
|
+
const value = astUnwrap(node);
|
|
3386
|
+
const target = value.type === "CallExpression" ? value.callee : value;
|
|
3387
|
+
const name = astDottedName(target);
|
|
3388
|
+
if (name !== undefined && optionsPatternsTest(patterns, name)) {
|
|
3389
|
+
return true;
|
|
3390
|
+
}
|
|
3391
|
+
return value.type === "CallExpression" && target.type === "MemberExpression" && astMemberName(target) === "pipe" && effectMatches(target.object, patterns);
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
// src/rules/effect/effect-layer-file.ts
|
|
3395
|
+
var effectLayerFileDefaultLayers = ["^Layer\\.", "^HttpRouter\\.add(?:All)?$", "(?:^|\\.)layer[^.]*$"];
|
|
3396
|
+
var effectLayerFileDefaultServices = ["(?:^|\\.)of$", "^Context\\."];
|
|
3397
|
+
var effectLayerFileDefaultConstructors = [
|
|
3398
|
+
"Layer.effect",
|
|
3399
|
+
"Layer.effectContext",
|
|
3400
|
+
"Layer.effectDiscard",
|
|
3401
|
+
"Layer.scoped",
|
|
3402
|
+
"Layer.scopedContext",
|
|
3403
|
+
"Layer.scopedDiscard",
|
|
3404
|
+
"Layer.sync",
|
|
3405
|
+
"Layer.unwrap"
|
|
3406
|
+
];
|
|
3407
|
+
var effectLayerFile = defineRule28({
|
|
3408
|
+
meta: {
|
|
3409
|
+
type: "problem",
|
|
3410
|
+
schema: [
|
|
3411
|
+
{
|
|
3412
|
+
type: "object",
|
|
3413
|
+
additionalProperties: false,
|
|
3414
|
+
properties: {
|
|
3415
|
+
layer: { type: "string" },
|
|
3416
|
+
make: { type: "string" },
|
|
3417
|
+
prefix: { type: "string" },
|
|
3418
|
+
builders: { type: "array", items: { type: "string" } },
|
|
3419
|
+
layers: optionsPatternSchema,
|
|
3420
|
+
services: optionsPatternSchema,
|
|
3421
|
+
constructors: { type: "array", items: { type: "string" } }
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
],
|
|
3425
|
+
messages: {
|
|
3426
|
+
missing: "A layer file exports `{{layer}}`.",
|
|
3427
|
+
notLayer: "`{{layer}}` is built with Layer: a Layer call, a Layer pipe, or a function returning one.",
|
|
3428
|
+
builderName: "The Effect that builds the service is named `{{make}}`, one per layer file.",
|
|
3429
|
+
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.",
|
|
3432
|
+
makeReturn: "`{{make}}` returns the service through its tag (Tag.of({ … })), a Context, or a Layer.",
|
|
3433
|
+
inlineBuilder: "Build this layer from `{{make}}`, not an inline Effect: Layer.effect(Tag, {{make}}). One built layer per file."
|
|
3434
|
+
}
|
|
3435
|
+
},
|
|
3436
|
+
createOnce(context) {
|
|
3437
|
+
let layer = "layer";
|
|
3438
|
+
let make = "make";
|
|
3439
|
+
let prefix = "layer";
|
|
3440
|
+
let builders = new Set(effectBuilders);
|
|
3441
|
+
let layers = [];
|
|
3442
|
+
let services = [];
|
|
3443
|
+
let constructors = new Set(effectLayerFileDefaultConstructors);
|
|
3444
|
+
const returned = (node) => {
|
|
3445
|
+
const value = node ? astUnwrap(node) : node;
|
|
3446
|
+
if (!value || !astIsInlineFunction(value)) {
|
|
3447
|
+
return value;
|
|
3448
|
+
}
|
|
3449
|
+
return value.body?.type === "BlockStatement" ? returned(value.body.body.findLast((statement) => statement.type === "ReturnStatement")?.argument) : returned(value.body);
|
|
3450
|
+
};
|
|
3451
|
+
return {
|
|
3452
|
+
before() {
|
|
3453
|
+
const options = optionsFirst(context, {});
|
|
3454
|
+
layer = options.layer ?? "layer";
|
|
3455
|
+
make = options.make ?? "make";
|
|
3456
|
+
prefix = options.prefix ?? "layer";
|
|
3457
|
+
builders = new Set(options.builders ?? effectBuilders);
|
|
3458
|
+
constructors = new Set(options.constructors ?? effectLayerFileDefaultConstructors);
|
|
3459
|
+
layers = optionsPatterns(options.layers ?? effectLayerFileDefaultLayers);
|
|
3460
|
+
services = [...optionsPatterns(options.services ?? effectLayerFileDefaultServices), ...layers];
|
|
3461
|
+
},
|
|
3462
|
+
Program(program) {
|
|
3463
|
+
const data = { layer, make, prefix };
|
|
3464
|
+
const declarators = program.body.flatMap((statement) => {
|
|
3465
|
+
const declaration = astDeclaration(statement);
|
|
3466
|
+
const exported = statement.type === "ExportNamedDeclaration";
|
|
3467
|
+
return declaration?.type === "VariableDeclaration" ? declaration.declarations.map((node) => ({ exported, node, name: node.id.type === "Identifier" ? node.id.name : "" })) : [];
|
|
3468
|
+
});
|
|
3469
|
+
const exportedLayer = declarators.find(({ exported, name }) => exported && name === layer);
|
|
3470
|
+
if (!exportedLayer) {
|
|
3471
|
+
context.report({
|
|
3472
|
+
node: program,
|
|
3473
|
+
messageId: "missing",
|
|
3474
|
+
data
|
|
3475
|
+
});
|
|
3476
|
+
} else if (!effectMatches(returned(exportedLayer.node.init), layers)) {
|
|
3477
|
+
context.report({
|
|
3478
|
+
node: exportedLayer.node,
|
|
3479
|
+
messageId: "notLayer",
|
|
3480
|
+
data
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
const wired = new Set;
|
|
3484
|
+
const wiring = declarators.filter((item) => item === exportedLayer || effectMatches(item.node.init, layers));
|
|
3485
|
+
astVisit(wiring.map(({ node }) => node.init), [], (call) => {
|
|
3486
|
+
if (call.type !== "CallExpression" || !optionsPatternsTest(layers, astDottedName(call.callee) ?? "")) {
|
|
3487
|
+
return;
|
|
3488
|
+
}
|
|
3489
|
+
for (const argument of call.arguments) {
|
|
3490
|
+
const target = argument.type === "CallExpression" ? argument.callee : argument;
|
|
3491
|
+
if (target.type === "Identifier") {
|
|
3492
|
+
wired.add(target.name);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
});
|
|
3496
|
+
const locals = declarators.filter(({ exported }) => !exported);
|
|
3497
|
+
const effects = locals.filter(({ node }) => effectIsBuilder(node.init, builders));
|
|
3498
|
+
const builder = effects.find(({ name }) => name === make) ?? effects.find(({ name }) => wired.has(name));
|
|
3499
|
+
if (builder && builder.name !== make) {
|
|
3500
|
+
context.report({
|
|
3501
|
+
node: builder.node,
|
|
3502
|
+
messageId: "builderName",
|
|
3503
|
+
data
|
|
3504
|
+
});
|
|
3505
|
+
}
|
|
3506
|
+
for (const { node, name, exported } of declarators) {
|
|
3507
|
+
const isLayer = effectMatches(node.init, layers);
|
|
3508
|
+
const isEffect = effectIsBuilder(node.init, builders);
|
|
3509
|
+
if (!exported && isEffect && name !== builder?.name) {
|
|
3510
|
+
context.report({
|
|
3511
|
+
node,
|
|
3512
|
+
messageId: "moduleMethod",
|
|
3513
|
+
data
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
if (!exported && !isEffect && !isLayer && name !== make) {
|
|
3517
|
+
context.report({
|
|
3518
|
+
node,
|
|
3519
|
+
messageId: "moduleHelper",
|
|
3520
|
+
data
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
if (isLayer && name !== layer && (exported || !name.startsWith(prefix) || !/^[A-Z]\w*$/.test(name.slice(prefix.length)))) {
|
|
3524
|
+
context.report({
|
|
3525
|
+
node,
|
|
3526
|
+
messageId: "localLayer",
|
|
3527
|
+
data
|
|
3528
|
+
});
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
for (const statement of program.body) {
|
|
3532
|
+
if (statement.type === "FunctionDeclaration") {
|
|
3533
|
+
context.report({
|
|
3534
|
+
node: statement,
|
|
3535
|
+
messageId: "moduleHelper",
|
|
3536
|
+
data
|
|
3537
|
+
});
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
const generator = builder?.name === make ? effectGenerator(builder.node.init, builders) : undefined;
|
|
3541
|
+
for (const statement of generator?.body?.body ?? []) {
|
|
3542
|
+
if (statement.type === "ReturnStatement" && !effectMatches(statement.argument, services)) {
|
|
3543
|
+
context.report({
|
|
3544
|
+
node: statement,
|
|
3545
|
+
messageId: "makeReturn",
|
|
3546
|
+
data
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
},
|
|
3551
|
+
CallExpression(node) {
|
|
3552
|
+
if (!constructors.has(astDottedName(node.callee) ?? "")) {
|
|
3553
|
+
return;
|
|
3554
|
+
}
|
|
3555
|
+
for (const argument of node.arguments) {
|
|
3556
|
+
if (argument.type !== "SpreadElement" && (astIsInlineFunction(astUnwrap(argument)) || effectIsBuilder(argument, builders))) {
|
|
3557
|
+
context.report({
|
|
3558
|
+
node: argument,
|
|
3559
|
+
messageId: "inlineBuilder",
|
|
3560
|
+
data: { layer, make, prefix }
|
|
3561
|
+
});
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
};
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
|
|
3569
|
+
// src/rules/effect/effect-layers.ts
|
|
3570
|
+
import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
3571
|
+
var effectLayersDefaultMerge = ["Layer.mergeAll"];
|
|
3572
|
+
var effectLayersDefaultProvide = ["Effect.provide", "Layer.provide", "Layer.provideMerge"];
|
|
3573
|
+
var effectLayersDefaultMin = 2;
|
|
3574
|
+
var effectLayersGroupSchema = {
|
|
3575
|
+
type: "object",
|
|
3576
|
+
additionalProperties: false,
|
|
3577
|
+
properties: {
|
|
3578
|
+
callees: { type: "array", items: { type: "string" } },
|
|
3579
|
+
min: { type: "integer", minimum: 1 }
|
|
3580
|
+
}
|
|
3581
|
+
};
|
|
3582
|
+
var effectLayers = defineRule29({
|
|
3583
|
+
meta: {
|
|
3584
|
+
type: "layout",
|
|
3585
|
+
fixable: "whitespace",
|
|
3586
|
+
schema: [
|
|
3587
|
+
{
|
|
3588
|
+
type: "object",
|
|
3589
|
+
additionalProperties: false,
|
|
3590
|
+
properties: {
|
|
3591
|
+
merge: effectLayersGroupSchema,
|
|
3592
|
+
provide: effectLayersGroupSchema,
|
|
3593
|
+
indent: sourceIndentSchema
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
],
|
|
3597
|
+
messages: {
|
|
3598
|
+
merge: "Put every layer in this merge on its own line.",
|
|
3599
|
+
provide: "Put every layer in this array on its own line."
|
|
3600
|
+
}
|
|
3601
|
+
},
|
|
3602
|
+
createOnce(context) {
|
|
3603
|
+
let merge = new Set(effectLayersDefaultMerge);
|
|
3604
|
+
let provide = new Set(effectLayersDefaultProvide);
|
|
3605
|
+
let mergeMin = effectLayersDefaultMin;
|
|
3606
|
+
let provideMin = effectLayersDefaultMin;
|
|
3607
|
+
let indentUnit = sourceIndentUnit();
|
|
3608
|
+
const check = (node) => {
|
|
3609
|
+
const source = context.sourceCode;
|
|
3610
|
+
const call = node.type === "CallExpression";
|
|
3611
|
+
const items = call ? node.arguments : node.elements;
|
|
3612
|
+
const present = items.filter((item) => item !== null);
|
|
3613
|
+
const open = call ? source.getTokenAfter(node.typeArguments ?? node.callee) : source.getFirstToken(node);
|
|
3614
|
+
const close = source.getLastToken(node);
|
|
3615
|
+
if (open?.value !== (call ? "(" : "[") || close === null || present.length < (call ? mergeMin : provideMin)) {
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
const packed = [open, ...present].some((item, index) => item.loc.end.line === (present.at(index) ?? close).loc.start.line);
|
|
3619
|
+
if (!packed) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
const text = source.text;
|
|
3623
|
+
const newline = sourceNewline(text);
|
|
3624
|
+
const base = sourceLineIndent(text, open.range[0]);
|
|
3625
|
+
const gaps = sourceItemGaps(open.range[1], present, close.range[0]);
|
|
3626
|
+
context.report({
|
|
3627
|
+
node,
|
|
3628
|
+
messageId: call ? "merge" : "provide",
|
|
3629
|
+
fix: (fixer) => {
|
|
3630
|
+
if (present.length !== items.length) {
|
|
3631
|
+
return null;
|
|
3632
|
+
}
|
|
3633
|
+
return sourceRespace(fixer, text, gaps, (_, end) => `${newline}${base}${end ? "" : indentUnit}`);
|
|
3634
|
+
}
|
|
3635
|
+
});
|
|
3636
|
+
};
|
|
3637
|
+
return {
|
|
3638
|
+
before() {
|
|
3639
|
+
const options = optionsFirst(context, {});
|
|
3640
|
+
merge = new Set(options.merge?.callees ?? effectLayersDefaultMerge);
|
|
3641
|
+
provide = new Set(options.provide?.callees ?? effectLayersDefaultProvide);
|
|
3642
|
+
mergeMin = options.merge?.min ?? effectLayersDefaultMin;
|
|
3643
|
+
provideMin = options.provide?.min ?? effectLayersDefaultMin;
|
|
3644
|
+
indentUnit = sourceIndentUnit(options.indent);
|
|
3645
|
+
},
|
|
3646
|
+
CallExpression(node) {
|
|
3647
|
+
const name = astDottedName(node.callee);
|
|
3648
|
+
if (name !== undefined && merge.has(name)) {
|
|
3649
|
+
check(node);
|
|
3650
|
+
}
|
|
3651
|
+
if (name !== undefined && provide.has(name)) {
|
|
3652
|
+
for (const argument of node.arguments) {
|
|
3653
|
+
if (argument.type === "ArrayExpression") {
|
|
3654
|
+
check(argument);
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
};
|
|
3660
|
+
}
|
|
3661
|
+
});
|
|
3662
|
+
|
|
3663
|
+
// src/rules/effect/effect-merge-pipe.ts
|
|
3664
|
+
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3665
|
+
var effectMergePipeDefaultMerge = ["Layer.mergeAll"];
|
|
3666
|
+
var effectMergePipeDefaultPipe = ["pipe", "Function.pipe"];
|
|
3667
|
+
var effectMergePipeDefaultMethods = ["pipe"];
|
|
3668
|
+
var effectMergePipe = defineRule30({
|
|
3669
|
+
meta: {
|
|
3670
|
+
type: "layout",
|
|
3671
|
+
schema: [
|
|
3672
|
+
{
|
|
3673
|
+
type: "object",
|
|
3674
|
+
additionalProperties: false,
|
|
3675
|
+
properties: {
|
|
3676
|
+
merge: { type: "array", items: { type: "string" } },
|
|
3677
|
+
pipe: { type: "array", items: { type: "string" } },
|
|
3678
|
+
methods: { type: "array", items: { type: "string" } }
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
],
|
|
3682
|
+
messages: {
|
|
3683
|
+
piped: "A merge that spans lines is never piped. Name it first, then pipe the name."
|
|
3684
|
+
}
|
|
3685
|
+
},
|
|
3686
|
+
createOnce(context) {
|
|
3687
|
+
let merge = new Set(effectMergePipeDefaultMerge);
|
|
3688
|
+
let pipe = new Set(effectMergePipeDefaultPipe);
|
|
3689
|
+
let methods = new Set(effectMergePipeDefaultMethods);
|
|
3690
|
+
const isMultilineMerge = (node) => node?.type === "CallExpression" && merge.has(astDottedName(node.callee) ?? "") && !astIsOneLine(node);
|
|
3691
|
+
return {
|
|
3692
|
+
before() {
|
|
3693
|
+
const options = optionsFirst(context, {});
|
|
3694
|
+
merge = new Set(options.merge ?? effectMergePipeDefaultMerge);
|
|
3695
|
+
pipe = new Set(options.pipe ?? effectMergePipeDefaultPipe);
|
|
3696
|
+
methods = new Set(options.methods ?? effectMergePipeDefaultMethods);
|
|
3697
|
+
},
|
|
3698
|
+
CallExpression(node) {
|
|
3699
|
+
const callee = node.callee;
|
|
3700
|
+
const first = node.arguments.at(0);
|
|
3701
|
+
if (callee.type === "MemberExpression" && methods.has(astMemberName(callee) ?? "") && isMultilineMerge(callee.object)) {
|
|
3702
|
+
context.report({ node: callee.property, messageId: "piped" });
|
|
3703
|
+
}
|
|
3704
|
+
if (pipe.has(astDottedName(callee) ?? "") && first !== undefined && isMultilineMerge(first)) {
|
|
3705
|
+
context.report({ node: first, messageId: "piped" });
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
};
|
|
3709
|
+
}
|
|
3710
|
+
});
|
|
3711
|
+
|
|
3712
|
+
// src/rules/effect/effect-schema-first.ts
|
|
3713
|
+
import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
3714
|
+
var effectSchemaFirstDefaultRuntime = [
|
|
3715
|
+
"Effect",
|
|
3716
|
+
"Layer",
|
|
3717
|
+
"Stream",
|
|
3718
|
+
"Context",
|
|
3719
|
+
"Scope",
|
|
3720
|
+
"Kysely",
|
|
3721
|
+
"React",
|
|
3722
|
+
"Fiber",
|
|
3723
|
+
"Queue",
|
|
3724
|
+
"PubSub",
|
|
3725
|
+
"Ref",
|
|
3726
|
+
"Deferred",
|
|
3727
|
+
"ManagedRuntime",
|
|
3728
|
+
"Sink",
|
|
3729
|
+
"Channel",
|
|
3730
|
+
"Request",
|
|
3731
|
+
"Response",
|
|
3732
|
+
"Headers",
|
|
3733
|
+
"ReadableStream",
|
|
3734
|
+
"WritableStream",
|
|
3735
|
+
"Blob",
|
|
3736
|
+
"File",
|
|
3737
|
+
"AbortSignal",
|
|
3738
|
+
"WebSocket",
|
|
3739
|
+
"Socket",
|
|
3740
|
+
"Worker",
|
|
3741
|
+
"Uint8Array",
|
|
3742
|
+
"ArrayBuffer",
|
|
3743
|
+
"globalThis"
|
|
3744
|
+
];
|
|
3745
|
+
var effectSchemaFirstSections = {
|
|
3746
|
+
values: ["VariableDeclaration", "ClassDeclaration"],
|
|
3747
|
+
interfaces: ["TSInterfaceDeclaration"],
|
|
3748
|
+
modules: ["TSModuleDeclaration"],
|
|
3749
|
+
aliases: ["TSTypeAliasDeclaration"]
|
|
3750
|
+
};
|
|
3751
|
+
var effectSchemaFirstLabels = {
|
|
3752
|
+
values: "Schemas and values",
|
|
3753
|
+
interfaces: "interfaces",
|
|
3754
|
+
modules: "`declare module`",
|
|
3755
|
+
aliases: "type aliases"
|
|
3756
|
+
};
|
|
3757
|
+
var effectSchemaFirstDefaultOrder = ["values", ["interfaces", "modules"], "aliases"];
|
|
3758
|
+
var effectSchemaFirstSectionSchema = { type: "string", enum: ["values", "interfaces", "modules", "aliases"] };
|
|
3759
|
+
function effectSchemaFirstTypeName(node) {
|
|
3760
|
+
if (node.type === "TSQualifiedName") {
|
|
3761
|
+
const left = effectSchemaFirstTypeName(node.left);
|
|
3762
|
+
return left === undefined ? undefined : `${left}.${node.right.name}`;
|
|
3763
|
+
}
|
|
3764
|
+
return astDottedName(node);
|
|
3765
|
+
}
|
|
3766
|
+
function effectSchemaFirstReference(node) {
|
|
3767
|
+
if (node.type === "TSTypeReference") {
|
|
3768
|
+
return effectSchemaFirstTypeName(node.typeName);
|
|
3769
|
+
}
|
|
3770
|
+
if (node.type === "TSTypeQuery") {
|
|
3771
|
+
return effectSchemaFirstTypeName(node.exprName);
|
|
3772
|
+
}
|
|
3773
|
+
return node.type === "TSInterfaceHeritage" ? astDottedName(node.expression) : undefined;
|
|
3774
|
+
}
|
|
3775
|
+
var effectSchemaFirst = defineRule31({
|
|
3776
|
+
meta: {
|
|
3777
|
+
type: "suggestion",
|
|
3778
|
+
schema: [
|
|
3779
|
+
{
|
|
3780
|
+
type: "object",
|
|
3781
|
+
additionalProperties: false,
|
|
3782
|
+
properties: {
|
|
3783
|
+
member: { type: "string" },
|
|
3784
|
+
keep: optionsPatternSchema,
|
|
3785
|
+
runtime: { type: "array", items: { type: "string" } },
|
|
3786
|
+
rows: {
|
|
3787
|
+
type: "object",
|
|
3788
|
+
additionalProperties: false,
|
|
3789
|
+
properties: { types: { type: "array", items: { type: "string" } }, suffix: { type: "string" } }
|
|
3790
|
+
},
|
|
3791
|
+
order: {
|
|
3792
|
+
type: "array",
|
|
3793
|
+
items: { anyOf: [effectSchemaFirstSectionSchema, { type: "array", items: effectSchemaFirstSectionSchema, minItems: 1 }] }
|
|
3794
|
+
},
|
|
3795
|
+
derived: {
|
|
3796
|
+
type: "object",
|
|
3797
|
+
additionalProperties: false,
|
|
3798
|
+
properties: { first: { type: "boolean" }, sorted: { type: "boolean" } }
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
],
|
|
3803
|
+
messages: {
|
|
3804
|
+
order: "Order a types file as {{order}}.",
|
|
3805
|
+
schemaType: "Add `export type {{name}} = typeof {{name}}.{{member}}` to the final type block.",
|
|
3806
|
+
typeOrder: "Move {{name}}: the type block lists the `typeof` aliases first, in Schema order, then the other aliases.",
|
|
3807
|
+
dataInterface: "Every field of {{name}} fits a Schema: make it a Schema and derive its type.",
|
|
3808
|
+
rowItem: "{{name}} is built from a database row: make it a Schema; only a `…{{suffix}}` alias may read the row type."
|
|
3809
|
+
}
|
|
3810
|
+
},
|
|
3811
|
+
createOnce(context) {
|
|
3812
|
+
let member = "Type";
|
|
3813
|
+
let keep = [];
|
|
3814
|
+
let runtime = new Set(effectSchemaFirstDefaultRuntime);
|
|
3815
|
+
let rows;
|
|
3816
|
+
let suffix = "Record";
|
|
3817
|
+
let ranks = new Map;
|
|
3818
|
+
let orderText = "";
|
|
3819
|
+
let derivedFirst = true;
|
|
3820
|
+
let derivedSorted = true;
|
|
3821
|
+
const derives = (alias) => {
|
|
3822
|
+
const annotation = alias.typeAnnotation;
|
|
3823
|
+
const name = annotation.type === "TSTypeQuery" ? annotation.exprName : undefined;
|
|
3824
|
+
return name?.type === "TSQualifiedName" && name.left.type === "Identifier" && name.left.name === alias.id.name && name.right.name === member;
|
|
3825
|
+
};
|
|
3826
|
+
const refers = (node, names) => astSome(node, (child) => {
|
|
3827
|
+
if (child.type === "TSFunctionType" || child.type === "TSConstructorType" || child.type === "TSMethodSignature") {
|
|
3828
|
+
return true;
|
|
3829
|
+
}
|
|
3830
|
+
return (effectSchemaFirstReference(child)?.split(".") ?? []).some((name) => names.has(name));
|
|
3831
|
+
});
|
|
3832
|
+
const readsRow = (node) => astSome(node, (child) => Boolean(rows?.has(effectSchemaFirstReference(child) ?? "")));
|
|
3833
|
+
const checkOrder = (program) => {
|
|
3834
|
+
let highest = 0;
|
|
3835
|
+
for (const statement of program.body) {
|
|
3836
|
+
const rank = ranks.get(astDeclaration(statement)?.type ?? "") ?? 0;
|
|
3837
|
+
if (rank > 0 && rank < highest) {
|
|
3838
|
+
context.report({
|
|
3839
|
+
node: statement,
|
|
3840
|
+
messageId: "order",
|
|
3841
|
+
data: { order: orderText }
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
highest = Math.max(highest, rank);
|
|
3845
|
+
}
|
|
3846
|
+
};
|
|
3847
|
+
const keptNames = (program, aliases, interfaces) => {
|
|
3848
|
+
const kept = new Set(aliases.filter((alias) => refers(alias.typeAnnotation, runtime)).map((alias) => alias.id.name));
|
|
3849
|
+
for (const statement of program.body) {
|
|
3850
|
+
if (statement.type === "ImportDeclaration" && statement.source.value.startsWith(".")) {
|
|
3851
|
+
for (const specifier of statement.specifiers) {
|
|
3852
|
+
if (statement.importKind === "type" || specifier.type === "ImportSpecifier" && specifier.importKind === "type") {
|
|
3853
|
+
kept.add(specifier.local.name);
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
const names = new Set([...runtime, ...kept]);
|
|
3859
|
+
let grew = true;
|
|
3860
|
+
while (grew) {
|
|
3861
|
+
grew = false;
|
|
3862
|
+
for (const node of interfaces) {
|
|
3863
|
+
const stays = node.body.body.length === 0 || Boolean(node.typeParameters) || optionsPatternsTest(keep, node.id.name) || refers(node, names);
|
|
3864
|
+
if (!kept.has(node.id.name) && stays) {
|
|
3865
|
+
names.add(node.id.name);
|
|
3866
|
+
kept.add(node.id.name);
|
|
3867
|
+
grew = true;
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
return kept;
|
|
3872
|
+
};
|
|
3873
|
+
return {
|
|
3874
|
+
before() {
|
|
3875
|
+
const options = optionsFirst(context, {});
|
|
3876
|
+
member = options.member ?? "Type";
|
|
3877
|
+
keep = optionsPatterns(options.keep);
|
|
3878
|
+
runtime = new Set(options.runtime ?? effectSchemaFirstDefaultRuntime);
|
|
3879
|
+
rows = options.rows ? new Set(options.rows.types ?? ["Kysely.Selectable"]) : undefined;
|
|
3880
|
+
suffix = options.rows?.suffix ?? "Record";
|
|
3881
|
+
const order = (options.order ?? effectSchemaFirstDefaultOrder).map((group) => [group].flat());
|
|
3882
|
+
ranks = new Map(order.flatMap((group, index) => group.flatMap((section) => effectSchemaFirstSections[section].map((type) => [type, index + 1]))));
|
|
3883
|
+
orderText = order.map((group) => group.map((section) => effectSchemaFirstLabels[section]).join(" and ")).join(", then ");
|
|
3884
|
+
derivedFirst = options.derived?.first ?? true;
|
|
3885
|
+
derivedSorted = options.derived?.sorted ?? true;
|
|
3886
|
+
},
|
|
3887
|
+
Program(program) {
|
|
3888
|
+
checkOrder(program);
|
|
3889
|
+
const declarations = program.body.flatMap((statement) => astDeclaration(statement) ?? []);
|
|
3890
|
+
const aliases = declarations.filter((node) => node.type === "TSTypeAliasDeclaration");
|
|
3891
|
+
const interfaces = declarations.filter((node) => node.type === "TSInterfaceDeclaration");
|
|
3892
|
+
const schemas = declarations.flatMap((node) => node.type === "VariableDeclaration" ? node.declarations : []).map(({ id }) => id.type === "Identifier" ? id.name : "");
|
|
3893
|
+
const exported = program.body.flatMap((statement) => statement.type === "ExportNamedDeclaration" && statement.declaration ? [statement.declaration] : []);
|
|
3894
|
+
const typed = new Set(exported.flatMap((node) => node.type === "TSTypeAliasDeclaration" && derives(node) ? [node.id.name] : []));
|
|
3895
|
+
for (const node of exported.flatMap((declaration) => declaration.type === "VariableDeclaration" ? declaration.declarations : [])) {
|
|
3896
|
+
const isSchema = node.init?.type === "CallExpression" || node.init?.type === "MemberExpression";
|
|
3897
|
+
if (isSchema && node.id.type === "Identifier" && !typed.has(node.id.name)) {
|
|
3898
|
+
context.report({
|
|
3899
|
+
node,
|
|
3900
|
+
messageId: "schemaType",
|
|
3901
|
+
data: { name: node.id.name, member }
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
let order = -1;
|
|
3906
|
+
let other = false;
|
|
3907
|
+
for (const alias of aliases) {
|
|
3908
|
+
if (!derives(alias)) {
|
|
3909
|
+
other = true;
|
|
3910
|
+
continue;
|
|
3911
|
+
}
|
|
3912
|
+
const index = schemas.indexOf(alias.id.name);
|
|
3913
|
+
if (derivedFirst && other || derivedSorted && index < order) {
|
|
3914
|
+
context.report({
|
|
3915
|
+
node: alias,
|
|
3916
|
+
messageId: "typeOrder",
|
|
3917
|
+
data: { name: alias.id.name }
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
order = Math.max(order, index);
|
|
3921
|
+
}
|
|
3922
|
+
const kept = keptNames(program, aliases, interfaces);
|
|
3923
|
+
for (const node of interfaces) {
|
|
3924
|
+
if (!kept.has(node.id.name)) {
|
|
3925
|
+
context.report({
|
|
3926
|
+
node,
|
|
3927
|
+
messageId: "dataInterface",
|
|
3928
|
+
data: { name: node.id.name }
|
|
3929
|
+
});
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
for (const node of rows ? declarations : []) {
|
|
3933
|
+
const fromRow = node.type === "TSTypeAliasDeclaration" && !node.id.name.endsWith(suffix) && readsRow(node.typeAnnotation) || node.type === "TSInterfaceDeclaration" && node.extends.some(readsRow);
|
|
3934
|
+
if (fromRow) {
|
|
3935
|
+
context.report({
|
|
3936
|
+
node,
|
|
3937
|
+
messageId: "rowItem",
|
|
3938
|
+
data: { name: node.id.name, suffix }
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
});
|
|
3946
|
+
|
|
3947
|
+
// src/rules/effect/effect-values-first.ts
|
|
3948
|
+
import { defineRule as defineRule32 } from "@oxlint/plugins";
|
|
3949
|
+
var effectValuesFirstDefaultPinned = [
|
|
3950
|
+
"^Layer\\.",
|
|
3951
|
+
"^Context\\.",
|
|
3952
|
+
"^HttpRouter\\.add(?:All)?$",
|
|
3953
|
+
"(?:^|\\.)of$",
|
|
3954
|
+
"(?:^|\\.)layer[^.]*$",
|
|
3955
|
+
"^Schema\\.(?:asserts|decode\\w*|encode\\w*|is|isSchema|isSchemaError|resolveAnnotations)$"
|
|
3956
|
+
];
|
|
3957
|
+
var effectValuesFirst = defineRule32({
|
|
3958
|
+
meta: {
|
|
3959
|
+
type: "suggestion",
|
|
3960
|
+
schema: [
|
|
3961
|
+
{
|
|
3962
|
+
type: "object",
|
|
3963
|
+
additionalProperties: false,
|
|
3964
|
+
properties: {
|
|
3965
|
+
builders: { type: "array", items: { type: "string" } },
|
|
3966
|
+
pinned: optionsPatternSchema
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
],
|
|
3970
|
+
messages: {
|
|
3971
|
+
value: "`{{name}}` is a value declared after `{{after}}`: declare values first, then helpers and methods."
|
|
3972
|
+
}
|
|
3973
|
+
},
|
|
3974
|
+
createOnce(context) {
|
|
3975
|
+
let builders = new Set(effectBuilders);
|
|
3976
|
+
let pinned = [];
|
|
3977
|
+
const check = (statements) => {
|
|
3978
|
+
const tied = new Set;
|
|
3979
|
+
let first;
|
|
3980
|
+
let barrier = false;
|
|
3981
|
+
for (const statement of statements) {
|
|
3982
|
+
const declaration = astDeclaration(statement);
|
|
3983
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id) {
|
|
3984
|
+
tied.add(declaration.id.name);
|
|
3985
|
+
first ??= declaration.id.name;
|
|
3986
|
+
continue;
|
|
3987
|
+
}
|
|
3988
|
+
if (declaration?.type !== "VariableDeclaration") {
|
|
3989
|
+
barrier ||= statement.type === "ExpressionStatement" && first !== undefined;
|
|
3990
|
+
continue;
|
|
3991
|
+
}
|
|
3992
|
+
for (const declarator of declaration.declarations) {
|
|
3993
|
+
const init = declarator.init;
|
|
3994
|
+
const names = astBindings(declarator.id).map((binding) => binding.name);
|
|
3995
|
+
const helper = Boolean(init && (astIsInlineFunction(astUnwrap(init)) || effectIsBuilder(init, builders)));
|
|
3996
|
+
const kept = helper || effectMatches(init, pinned) || astSome(init, (node) => node.type === "Identifier" && tied.has(node.name));
|
|
3997
|
+
if (first !== undefined && !kept && !barrier) {
|
|
3998
|
+
context.report({
|
|
3999
|
+
node: declarator,
|
|
4000
|
+
messageId: "value",
|
|
4001
|
+
data: { name: names.join(", "), after: first }
|
|
4002
|
+
});
|
|
4003
|
+
}
|
|
4004
|
+
if (kept) {
|
|
4005
|
+
names.forEach((name) => tied.add(name));
|
|
4006
|
+
}
|
|
4007
|
+
barrier ||= kept && first !== undefined && astSome(init, (node) => node.type === "YieldExpression");
|
|
4008
|
+
first ??= helper ? names.join(", ") : undefined;
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
};
|
|
4012
|
+
const body = (init) => {
|
|
4013
|
+
const value = init ? astUnwrap(init) : null;
|
|
4014
|
+
const target = value && astIsInlineFunction(value) ? value : effectGenerator(value, builders);
|
|
4015
|
+
return target?.body?.type === "BlockStatement" ? target.body.body : [];
|
|
4016
|
+
};
|
|
4017
|
+
return {
|
|
4018
|
+
before() {
|
|
4019
|
+
const options = optionsFirst(context, {});
|
|
4020
|
+
builders = new Set(options.builders ?? effectBuilders);
|
|
4021
|
+
pinned = optionsPatterns(options.pinned ?? effectValuesFirstDefaultPinned);
|
|
4022
|
+
},
|
|
4023
|
+
Program(program) {
|
|
4024
|
+
check(program.body);
|
|
4025
|
+
for (const statement of program.body) {
|
|
4026
|
+
const declaration = astDeclaration(statement);
|
|
4027
|
+
if (declaration?.type === "FunctionDeclaration") {
|
|
4028
|
+
check(declaration.body?.body ?? []);
|
|
4029
|
+
}
|
|
4030
|
+
if (declaration?.type === "VariableDeclaration") {
|
|
4031
|
+
declaration.declarations.forEach((declarator) => check(body(declarator.init)));
|
|
4032
|
+
}
|
|
3287
4033
|
}
|
|
3288
|
-
}
|
|
3289
|
-
TemplateElement: check,
|
|
3290
|
-
JSXText: check
|
|
4034
|
+
}
|
|
3291
4035
|
};
|
|
3292
4036
|
}
|
|
3293
4037
|
});
|
|
3294
4038
|
|
|
3295
4039
|
// src/rules/files/files-components-only.ts
|
|
3296
|
-
import { defineRule as
|
|
4040
|
+
import { defineRule as defineRule33 } from "@oxlint/plugins";
|
|
3297
4041
|
|
|
3298
4042
|
// src/utils/react.utils.ts
|
|
3299
4043
|
function reactReturnsOutput(program, node) {
|
|
@@ -3365,7 +4109,7 @@ function reactIsComponent(program, candidate) {
|
|
|
3365
4109
|
function componentName(basename2) {
|
|
3366
4110
|
return basename2.replace(/\.(tsx?|jsx?)$/, "").replaceAll(/(?:^[-.]*|[-.]+)(.?)/g, (_, char) => char.toUpperCase());
|
|
3367
4111
|
}
|
|
3368
|
-
var filesComponentsOnly =
|
|
4112
|
+
var filesComponentsOnly = defineRule33({
|
|
3369
4113
|
meta: {
|
|
3370
4114
|
type: "problem",
|
|
3371
4115
|
schema: [
|
|
@@ -3373,7 +4117,7 @@ var filesComponentsOnly = defineRule27({
|
|
|
3373
4117
|
type: "object",
|
|
3374
4118
|
additionalProperties: false,
|
|
3375
4119
|
properties: {
|
|
3376
|
-
filename: { type: "boolean" },
|
|
4120
|
+
filename: { oneOf: [{ type: "boolean" }, { type: "string", enum: ["each"] }] },
|
|
3377
4121
|
roles: { type: "array", items: { type: "string" } },
|
|
3378
4122
|
types: { type: "boolean" },
|
|
3379
4123
|
deny: optionsPatternSchema
|
|
@@ -3434,10 +4178,13 @@ var filesComponentsOnly = defineRule27({
|
|
|
3434
4178
|
return;
|
|
3435
4179
|
}
|
|
3436
4180
|
const names = components.map((candidate) => candidate.name.toLowerCase());
|
|
3437
|
-
if (expectedKeys.some((key) => names.includes(key) || names.every((name) => name.startsWith(key)))) {
|
|
4181
|
+
if (matchFileName !== "each" && expectedKeys.some((key) => names.includes(key) || names.every((name) => name.startsWith(key)))) {
|
|
3438
4182
|
return;
|
|
3439
4183
|
}
|
|
3440
4184
|
for (const { name, node } of components) {
|
|
4185
|
+
if (matchFileName === "each" && expectedKeys.some((key) => name.toLowerCase().startsWith(key))) {
|
|
4186
|
+
continue;
|
|
4187
|
+
}
|
|
3441
4188
|
context.report({
|
|
3442
4189
|
node,
|
|
3443
4190
|
messageId: "nameMismatch",
|
|
@@ -3450,7 +4197,7 @@ var filesComponentsOnly = defineRule27({
|
|
|
3450
4197
|
});
|
|
3451
4198
|
|
|
3452
4199
|
// src/rules/files/files-constants-only.ts
|
|
3453
|
-
import { defineRule as
|
|
4200
|
+
import { defineRule as defineRule34 } from "@oxlint/plugins";
|
|
3454
4201
|
function unwrap(expression) {
|
|
3455
4202
|
if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "TSInstantiationExpression") {
|
|
3456
4203
|
return unwrap(expression.expression);
|
|
@@ -3505,7 +4252,7 @@ function collectBindings(program) {
|
|
|
3505
4252
|
}
|
|
3506
4253
|
return bindings;
|
|
3507
4254
|
}
|
|
3508
|
-
var filesConstantsOnly =
|
|
4255
|
+
var filesConstantsOnly = defineRule34({
|
|
3509
4256
|
meta: {
|
|
3510
4257
|
type: "problem",
|
|
3511
4258
|
schema: [
|
|
@@ -3604,7 +4351,7 @@ var filesConstantsOnly = defineRule28({
|
|
|
3604
4351
|
});
|
|
3605
4352
|
|
|
3606
4353
|
// src/rules/files/files-domain-constants.ts
|
|
3607
|
-
import { defineRule as
|
|
4354
|
+
import { defineRule as defineRule35 } from "@oxlint/plugins";
|
|
3608
4355
|
import { basename as basename2, dirname as dirname2 } from "node:path";
|
|
3609
4356
|
function isData(expression) {
|
|
3610
4357
|
const value = astUnwrap(expression);
|
|
@@ -3622,14 +4369,21 @@ function isData(expression) {
|
|
|
3622
4369
|
}
|
|
3623
4370
|
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;
|
|
3624
4371
|
}
|
|
3625
|
-
var filesDomainConstants =
|
|
4372
|
+
var filesDomainConstants = defineRule35({
|
|
3626
4373
|
meta: {
|
|
3627
4374
|
type: "problem",
|
|
3628
4375
|
schema: [
|
|
3629
4376
|
{
|
|
3630
4377
|
type: "object",
|
|
3631
4378
|
additionalProperties: false,
|
|
3632
|
-
properties: {
|
|
4379
|
+
properties: {
|
|
4380
|
+
data: { type: "boolean" },
|
|
4381
|
+
services: { type: "boolean" },
|
|
4382
|
+
pattern: { ...optionsPatternSchema, default: "^[A-Z][A-Z0-9_]+$" },
|
|
4383
|
+
folders: { type: "array", items: { type: "string", minLength: 1 }, default: ["services"] },
|
|
4384
|
+
roles: { type: "array", items: { type: "string", minLength: 1 }, default: ["action", "query"] },
|
|
4385
|
+
file: { type: "string", minLength: 1, default: "{domain}.constants.ts" }
|
|
4386
|
+
}
|
|
3633
4387
|
}
|
|
3634
4388
|
],
|
|
3635
4389
|
messages: {
|
|
@@ -3638,11 +4392,19 @@ var filesDomainConstants = defineRule29({
|
|
|
3638
4392
|
},
|
|
3639
4393
|
createOnce(context) {
|
|
3640
4394
|
let includeData = false;
|
|
4395
|
+
let names = [];
|
|
4396
|
+
let folders = [];
|
|
4397
|
+
let roles = [];
|
|
4398
|
+
let target = "";
|
|
3641
4399
|
let serviceObjects = new Set;
|
|
3642
4400
|
return {
|
|
3643
4401
|
Program(program) {
|
|
3644
4402
|
const options = optionsFirst(context, {});
|
|
3645
4403
|
includeData = Boolean(options.data);
|
|
4404
|
+
names = optionsPatterns(options.pattern ?? "^[A-Z][A-Z0-9_]+$");
|
|
4405
|
+
folders = options.folders ?? ["services"];
|
|
4406
|
+
roles = options.roles ?? ["action", "query"];
|
|
4407
|
+
target = options.file ?? "{domain}.constants.ts";
|
|
3646
4408
|
serviceObjects = new Set(options.services ? declarationsPublicServiceMethods(program).map((method) => method.binding) : []);
|
|
3647
4409
|
},
|
|
3648
4410
|
VariableDeclarator(node) {
|
|
@@ -3652,15 +4414,19 @@ var filesDomainConstants = defineRule29({
|
|
|
3652
4414
|
return;
|
|
3653
4415
|
}
|
|
3654
4416
|
const name = node.id.type === "Identifier" ? node.id.name : undefined;
|
|
3655
|
-
if ((!name ||
|
|
4417
|
+
if ((!name || !optionsPatternsTest(names, name)) && (!includeData || !node.init || !isData(node.init))) {
|
|
3656
4418
|
return;
|
|
3657
4419
|
}
|
|
3658
4420
|
const file = context.filename.replaceAll("\\", "/");
|
|
3659
|
-
const
|
|
4421
|
+
const folder = basename2(dirname2(file));
|
|
4422
|
+
const stem = basename2(file).split(".")[0];
|
|
4423
|
+
const role = roles.find((candidate) => stem.endsWith(`-${candidate}`));
|
|
4424
|
+
const domain = role ? stem.slice(0, -role.length - 1) : stem;
|
|
4425
|
+
const owner = folders.some((candidate) => file.includes(`/${candidate}/`) && folder !== candidate) ? folder : domain;
|
|
3660
4426
|
context.report({
|
|
3661
4427
|
node,
|
|
3662
4428
|
messageId: "forbidden",
|
|
3663
|
-
data: { name: name ?? "<destructured binding>", file:
|
|
4429
|
+
data: { name: name ?? "<destructured binding>", file: target.replaceAll("{domain}", owner) }
|
|
3664
4430
|
});
|
|
3665
4431
|
}
|
|
3666
4432
|
};
|
|
@@ -3668,11 +4434,11 @@ var filesDomainConstants = defineRule29({
|
|
|
3668
4434
|
});
|
|
3669
4435
|
|
|
3670
4436
|
// src/rules/files/files-exports.ts
|
|
3671
|
-
import { defineRule as
|
|
4437
|
+
import { defineRule as defineRule36 } from "@oxlint/plugins";
|
|
3672
4438
|
function escapeRegExp(value) {
|
|
3673
4439
|
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3674
4440
|
}
|
|
3675
|
-
var filesExports =
|
|
4441
|
+
var filesExports = defineRule36({
|
|
3676
4442
|
meta: {
|
|
3677
4443
|
type: "problem",
|
|
3678
4444
|
schema: [
|
|
@@ -3753,11 +4519,12 @@ var filesExports = defineRule30({
|
|
|
3753
4519
|
});
|
|
3754
4520
|
|
|
3755
4521
|
// src/rules/files/files-externals.ts
|
|
3756
|
-
import { defineRule as
|
|
4522
|
+
import { defineRule as defineRule37 } from "@oxlint/plugins";
|
|
3757
4523
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
3758
4524
|
import { builtinModules as builtinModules2 } from "node:module";
|
|
3759
4525
|
import { dirname as dirname3, join as join2 } from "node:path";
|
|
3760
|
-
var
|
|
4526
|
+
var filesExternalsConfigs = "^(?:vite|next)\\.config\\.[cm]?[jt]s$";
|
|
4527
|
+
var filesExternals = defineRule37({
|
|
3761
4528
|
meta: {
|
|
3762
4529
|
type: "problem",
|
|
3763
4530
|
schema: [
|
|
@@ -3765,7 +4532,8 @@ var filesExternals = defineRule31({
|
|
|
3765
4532
|
type: "object",
|
|
3766
4533
|
additionalProperties: false,
|
|
3767
4534
|
properties: {
|
|
3768
|
-
packages: { type: "array", items: { type: "string", minLength: 1 } }
|
|
4535
|
+
packages: { type: "array", items: { type: "string", minLength: 1 } },
|
|
4536
|
+
files: { ...optionsPatternSchema, default: filesExternalsConfigs }
|
|
3769
4537
|
}
|
|
3770
4538
|
}
|
|
3771
4539
|
],
|
|
@@ -3821,7 +4589,8 @@ var filesExternals = defineRule31({
|
|
|
3821
4589
|
}
|
|
3822
4590
|
return {
|
|
3823
4591
|
before() {
|
|
3824
|
-
|
|
4592
|
+
const files = optionsPatterns(optionsFirst(context, {}).files ?? filesExternalsConfigs);
|
|
4593
|
+
if (!optionsPatternsTest(files, namingBasename(context.filename))) {
|
|
3825
4594
|
return false;
|
|
3826
4595
|
}
|
|
3827
4596
|
},
|
|
@@ -3848,7 +4617,7 @@ var filesExternals = defineRule31({
|
|
|
3848
4617
|
});
|
|
3849
4618
|
|
|
3850
4619
|
// src/rules/files/files-factory-keys.ts
|
|
3851
|
-
import { defineRule as
|
|
4620
|
+
import { defineRule as defineRule38 } from "@oxlint/plugins";
|
|
3852
4621
|
function returnedObject(expression) {
|
|
3853
4622
|
if (expression?.type === "TSAsExpression" || expression?.type === "TSSatisfiesExpression" || expression?.type === "TSTypeAssertion" || expression?.type === "TSNonNullExpression") {
|
|
3854
4623
|
return returnedObject(expression.expression);
|
|
@@ -3859,7 +4628,7 @@ function compileKeys(pattern, keys, requireKeys) {
|
|
|
3859
4628
|
const allowedList = keys.concat(requireKeys.filter((key) => !keys.includes(key)));
|
|
3860
4629
|
return { patterns: optionsPatternsWithEmpty(pattern), allowed: new Set(allowedList), allowedList, required: requireKeys };
|
|
3861
4630
|
}
|
|
3862
|
-
var filesFactoryKeys =
|
|
4631
|
+
var filesFactoryKeys = defineRule38({
|
|
3863
4632
|
meta: {
|
|
3864
4633
|
type: "problem",
|
|
3865
4634
|
schema: [
|
|
@@ -3977,8 +4746,8 @@ var filesFactoryKeys = defineRule32({
|
|
|
3977
4746
|
});
|
|
3978
4747
|
|
|
3979
4748
|
// src/rules/files/files-helpers.ts
|
|
3980
|
-
import { defineRule as
|
|
3981
|
-
var filesHelpers =
|
|
4749
|
+
import { defineRule as defineRule39 } from "@oxlint/plugins";
|
|
4750
|
+
var filesHelpers = defineRule39({
|
|
3982
4751
|
meta: {
|
|
3983
4752
|
type: "problem",
|
|
3984
4753
|
schema: [
|
|
@@ -4026,8 +4795,8 @@ var filesHelpers = defineRule33({
|
|
|
4026
4795
|
});
|
|
4027
4796
|
|
|
4028
4797
|
// src/rules/files/files-no-functions.ts
|
|
4029
|
-
import { defineRule as
|
|
4030
|
-
var filesNoFunctions =
|
|
4798
|
+
import { defineRule as defineRule40 } from "@oxlint/plugins";
|
|
4799
|
+
var filesNoFunctions = defineRule40({
|
|
4031
4800
|
meta: {
|
|
4032
4801
|
type: "problem",
|
|
4033
4802
|
schema: [
|
|
@@ -4081,8 +4850,8 @@ var filesNoFunctions = defineRule34({
|
|
|
4081
4850
|
});
|
|
4082
4851
|
|
|
4083
4852
|
// src/rules/files/files-restricted.ts
|
|
4084
|
-
import { defineRule as
|
|
4085
|
-
var filesRestricted =
|
|
4853
|
+
import { defineRule as defineRule41 } from "@oxlint/plugins";
|
|
4854
|
+
var filesRestricted = defineRule41({
|
|
4086
4855
|
meta: {
|
|
4087
4856
|
type: "problem",
|
|
4088
4857
|
schema: [
|
|
@@ -4114,7 +4883,7 @@ var filesRestricted = defineRule35({
|
|
|
4114
4883
|
});
|
|
4115
4884
|
|
|
4116
4885
|
// src/rules/files/files-route.ts
|
|
4117
|
-
import { defineRule as
|
|
4886
|
+
import { defineRule as defineRule42 } from "@oxlint/plugins";
|
|
4118
4887
|
function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
|
|
4119
4888
|
astVisit(item.node.body, [item.node], (node) => {
|
|
4120
4889
|
if (banIntrinsicJsx && node.type === "JSXOpeningElement" && node.name.type === "JSXIdentifier" && /^[a-z]/.test(node.name.name)) {
|
|
@@ -4134,7 +4903,7 @@ function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
|
|
|
4134
4903
|
}
|
|
4135
4904
|
});
|
|
4136
4905
|
}
|
|
4137
|
-
var filesRoute =
|
|
4906
|
+
var filesRoute = defineRule42({
|
|
4138
4907
|
meta: {
|
|
4139
4908
|
type: "problem",
|
|
4140
4909
|
schema: [
|
|
@@ -4204,7 +4973,7 @@ var filesRoute = defineRule36({
|
|
|
4204
4973
|
});
|
|
4205
4974
|
|
|
4206
4975
|
// src/rules/files/files-types-only.ts
|
|
4207
|
-
import { defineRule as
|
|
4976
|
+
import { defineRule as defineRule43 } from "@oxlint/plugins";
|
|
4208
4977
|
function runtimeImportLocalNames(statement) {
|
|
4209
4978
|
return statement.specifiers.flatMap((specifier) => specifier.type !== "ImportSpecifier" || specifier.importKind !== "type" ? [specifier.local.name] : []);
|
|
4210
4979
|
}
|
|
@@ -4373,7 +5142,7 @@ function runtimeKind(node) {
|
|
|
4373
5142
|
}
|
|
4374
5143
|
return node.type === "FunctionDeclaration" ? "function" : "variable";
|
|
4375
5144
|
}
|
|
4376
|
-
var filesTypesOnly =
|
|
5145
|
+
var filesTypesOnly = defineRule43({
|
|
4377
5146
|
meta: {
|
|
4378
5147
|
type: "problem",
|
|
4379
5148
|
schema: [
|
|
@@ -4481,8 +5250,8 @@ var filesTypesOnly = defineRule37({
|
|
|
4481
5250
|
});
|
|
4482
5251
|
|
|
4483
5252
|
// src/rules/layout/layout-arrow-body.ts
|
|
4484
|
-
import { defineRule as
|
|
4485
|
-
var layoutArrowBody =
|
|
5253
|
+
import { defineRule as defineRule44 } from "@oxlint/plugins";
|
|
5254
|
+
var layoutArrowBody = defineRule44({
|
|
4486
5255
|
meta: {
|
|
4487
5256
|
type: "layout",
|
|
4488
5257
|
fixable: "whitespace",
|
|
@@ -4534,12 +5303,12 @@ var layoutArrowBody = defineRule38({
|
|
|
4534
5303
|
});
|
|
4535
5304
|
|
|
4536
5305
|
// src/rules/layout/layout-call-arguments.ts
|
|
4537
|
-
import { defineRule as
|
|
5306
|
+
import { defineRule as defineRule45 } from "@oxlint/plugins";
|
|
4538
5307
|
function layoutCallArgumentsHuggable(node) {
|
|
4539
5308
|
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);
|
|
4540
5309
|
}
|
|
4541
5310
|
var layoutCallArgumentsMax = { type: "integer", minimum: 1 };
|
|
4542
|
-
var layoutCallArguments =
|
|
5311
|
+
var layoutCallArguments = defineRule45({
|
|
4543
5312
|
meta: {
|
|
4544
5313
|
type: "layout",
|
|
4545
5314
|
fixable: "whitespace",
|
|
@@ -4553,11 +5322,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4553
5322
|
minimum: 2,
|
|
4554
5323
|
default: 3
|
|
4555
5324
|
},
|
|
4556
|
-
indent: {
|
|
4557
|
-
type: "integer",
|
|
4558
|
-
minimum: 1,
|
|
4559
|
-
default: 2
|
|
4560
|
-
},
|
|
5325
|
+
indent: { ...sourceIndentSchema, default: 2 },
|
|
4561
5326
|
split: {
|
|
4562
5327
|
type: "boolean",
|
|
4563
5328
|
default: true
|
|
@@ -4575,6 +5340,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4575
5340
|
properties: {
|
|
4576
5341
|
max: layoutCallArgumentsMax,
|
|
4577
5342
|
nesting: layoutCallArgumentsMax,
|
|
5343
|
+
items: layoutCallArgumentsMax,
|
|
4578
5344
|
keep: { type: "array", items: { type: "string" } }
|
|
4579
5345
|
}
|
|
4580
5346
|
}
|
|
@@ -4591,7 +5357,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4591
5357
|
createOnce(context) {
|
|
4592
5358
|
let options = {};
|
|
4593
5359
|
let minArguments = 3;
|
|
4594
|
-
let
|
|
5360
|
+
let indentUnit = sourceIndentUnit();
|
|
4595
5361
|
const split = (node) => {
|
|
4596
5362
|
const args = node.arguments;
|
|
4597
5363
|
const last = args.at(-1);
|
|
@@ -4615,7 +5381,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4615
5381
|
const unsafe = source.getCommentsInside(node).length > 0 || text[open] !== "(" || text[close] !== ")" || !/^\s*$/.test(between[0]) || between.slice(1, -1).some((gap) => !/^\s*,\s*$/.test(gap)) || !/^\s*,?\s*$/.test(between.at(-1) ?? "");
|
|
4616
5382
|
const baseIndent = sourceLineIndent(text, open);
|
|
4617
5383
|
const newline = sourceNewline(text);
|
|
4618
|
-
const argumentIndent = `${baseIndent}${
|
|
5384
|
+
const argumentIndent = `${baseIndent}${indentUnit}`;
|
|
4619
5385
|
context.report({
|
|
4620
5386
|
node,
|
|
4621
5387
|
messageId: "multiline",
|
|
@@ -4660,7 +5426,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4660
5426
|
}
|
|
4661
5427
|
const newline = sourceNewline(text);
|
|
4662
5428
|
const base = sourceLineIndent(text, open.range[0]);
|
|
4663
|
-
const inner = `${base}${
|
|
5429
|
+
const inner = `${base}${indentUnit}`;
|
|
4664
5430
|
context.report({
|
|
4665
5431
|
node,
|
|
4666
5432
|
messageId: "hug",
|
|
@@ -4671,16 +5437,14 @@ var layoutCallArguments = defineRule39({
|
|
|
4671
5437
|
const source = context.sourceCode;
|
|
4672
5438
|
const text = source.text;
|
|
4673
5439
|
const first = items.at(0);
|
|
4674
|
-
if (!first || !open || !close || items.length > 2 || first.loc.start.line === open.loc.end.line || !items.every(astIsOneLine) || source.commentsExistBetween(open, close)) {
|
|
5440
|
+
if (!first || !open || !close || items.length > Math.min(options.join?.items ?? 2, options.split === false ? Number.POSITIVE_INFINITY : minArguments - 1) || first.loc.start.line === open.loc.end.line || !items.every(astIsOneLine) || source.commentsExistBetween(open, close)) {
|
|
4675
5441
|
return;
|
|
4676
5442
|
}
|
|
4677
|
-
const
|
|
4678
|
-
const
|
|
4679
|
-
|
|
4680
|
-
if (`${before}${inside}${after}`.length > (options.join?.max ?? 0)) {
|
|
5443
|
+
const gaps = sourceItemGaps(open.range[1], items, close.range[0]);
|
|
5444
|
+
const comma = text.slice(...gaps.at(-1) ?? [0, 0]).includes(",") ? "," : "";
|
|
5445
|
+
if (sourceJoinedWidth(text, open.range[1], `${items.map((item) => source.getText(item)).join(", ")}${comma}`, close.range[0]) > (options.join?.max ?? 0)) {
|
|
4681
5446
|
return;
|
|
4682
5447
|
}
|
|
4683
|
-
const gaps = sourceItemGaps(open.range[1], items, close.range[0]);
|
|
4684
5448
|
context.report({
|
|
4685
5449
|
node,
|
|
4686
5450
|
messageId: "join",
|
|
@@ -4712,7 +5476,7 @@ var layoutCallArguments = defineRule39({
|
|
|
4712
5476
|
before() {
|
|
4713
5477
|
options = optionsFirst(context, {});
|
|
4714
5478
|
minArguments = options.min ?? 3;
|
|
4715
|
-
|
|
5479
|
+
indentUnit = sourceIndentUnit(options.indent);
|
|
4716
5480
|
},
|
|
4717
5481
|
CallExpression: call,
|
|
4718
5482
|
NewExpression: call,
|
|
@@ -4726,12 +5490,12 @@ var layoutCallArguments = defineRule39({
|
|
|
4726
5490
|
});
|
|
4727
5491
|
|
|
4728
5492
|
// src/rules/layout/layout-call-array.ts
|
|
4729
|
-
import { defineRule as
|
|
5493
|
+
import { defineRule as defineRule46 } from "@oxlint/plugins";
|
|
4730
5494
|
var layoutCallArrayDefaultCallees = ["Promise.all", "Promise.allSettled"];
|
|
4731
5495
|
function layoutCallArrayRoot(node) {
|
|
4732
5496
|
return node.type === "MemberExpression" ? layoutCallArrayRoot(node.object) : node;
|
|
4733
5497
|
}
|
|
4734
|
-
var layoutCallArray =
|
|
5498
|
+
var layoutCallArray = defineRule46({
|
|
4735
5499
|
meta: {
|
|
4736
5500
|
type: "layout",
|
|
4737
5501
|
fixable: "whitespace",
|
|
@@ -4847,7 +5611,7 @@ var layoutCallArray = defineRule40({
|
|
|
4847
5611
|
});
|
|
4848
5612
|
|
|
4849
5613
|
// src/rules/layout/layout-call-depth.ts
|
|
4850
|
-
import { defineRule as
|
|
5614
|
+
import { defineRule as defineRule47 } from "@oxlint/plugins";
|
|
4851
5615
|
function layoutCallDepthOuter(node) {
|
|
4852
5616
|
const parent = node.parent;
|
|
4853
5617
|
if (!parent || parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression" || parent.type.endsWith("Statement")) {
|
|
@@ -4855,7 +5619,7 @@ function layoutCallDepthOuter(node) {
|
|
|
4855
5619
|
}
|
|
4856
5620
|
return astIsCall(parent) && parent.arguments.some((argument) => argument === node) ? parent : layoutCallDepthOuter(parent);
|
|
4857
5621
|
}
|
|
4858
|
-
var layoutCallDepth =
|
|
5622
|
+
var layoutCallDepth = defineRule47({
|
|
4859
5623
|
meta: {
|
|
4860
5624
|
type: "layout",
|
|
4861
5625
|
schema: [
|
|
@@ -4894,8 +5658,8 @@ var layoutCallDepth = defineRule41({
|
|
|
4894
5658
|
});
|
|
4895
5659
|
|
|
4896
5660
|
// src/rules/layout/layout-chain.ts
|
|
4897
|
-
import { defineRule as
|
|
4898
|
-
var layoutChain =
|
|
5661
|
+
import { defineRule as defineRule48 } from "@oxlint/plugins";
|
|
5662
|
+
var layoutChain = defineRule48({
|
|
4899
5663
|
meta: {
|
|
4900
5664
|
type: "layout",
|
|
4901
5665
|
fixable: "whitespace",
|
|
@@ -5014,8 +5778,8 @@ var layoutChain = defineRule42({
|
|
|
5014
5778
|
});
|
|
5015
5779
|
|
|
5016
5780
|
// src/rules/layout/layout-items.ts
|
|
5017
|
-
import { defineRule as
|
|
5018
|
-
var layoutItems =
|
|
5781
|
+
import { defineRule as defineRule49 } from "@oxlint/plugins";
|
|
5782
|
+
var layoutItems = defineRule49({
|
|
5019
5783
|
meta: {
|
|
5020
5784
|
type: "layout",
|
|
5021
5785
|
fixable: "whitespace",
|
|
@@ -5070,8 +5834,8 @@ var layoutItems = defineRule43({
|
|
|
5070
5834
|
});
|
|
5071
5835
|
|
|
5072
5836
|
// src/rules/layout/layout-jsx-attributes.ts
|
|
5073
|
-
import { defineRule as
|
|
5074
|
-
var layoutJsxAttributes =
|
|
5837
|
+
import { defineRule as defineRule50 } from "@oxlint/plugins";
|
|
5838
|
+
var layoutJsxAttributes = defineRule50({
|
|
5075
5839
|
meta: {
|
|
5076
5840
|
type: "layout",
|
|
5077
5841
|
fixable: "whitespace",
|
|
@@ -5081,12 +5845,19 @@ var layoutJsxAttributes = defineRule44({
|
|
|
5081
5845
|
additionalProperties: false,
|
|
5082
5846
|
properties: {
|
|
5083
5847
|
min: { type: "integer", minimum: 1 },
|
|
5084
|
-
indent: sourceIndentSchema
|
|
5848
|
+
indent: sourceIndentSchema,
|
|
5849
|
+
join: {
|
|
5850
|
+
type: "object",
|
|
5851
|
+
additionalProperties: false,
|
|
5852
|
+
required: ["max"],
|
|
5853
|
+
properties: { max: { type: "integer", minimum: 1 } }
|
|
5854
|
+
}
|
|
5085
5855
|
}
|
|
5086
5856
|
}
|
|
5087
5857
|
],
|
|
5088
5858
|
messages: {
|
|
5089
|
-
multiline: "Put every JSX attribute and the closing token on its own line."
|
|
5859
|
+
multiline: "Put every JSX attribute and the closing token on its own line.",
|
|
5860
|
+
join: "This tag fits on one line, so keep it on one line."
|
|
5090
5861
|
}
|
|
5091
5862
|
},
|
|
5092
5863
|
createOnce(context) {
|
|
@@ -5094,35 +5865,52 @@ var layoutJsxAttributes = defineRule44({
|
|
|
5094
5865
|
let indentUnit = sourceIndentUnit();
|
|
5095
5866
|
let newline = `
|
|
5096
5867
|
`;
|
|
5868
|
+
let joinMax;
|
|
5097
5869
|
return {
|
|
5098
5870
|
before() {
|
|
5099
5871
|
const options = optionsFirst(context, {});
|
|
5100
5872
|
minAttributes = options.min ?? 3;
|
|
5101
5873
|
indentUnit = sourceIndentUnit(options.indent);
|
|
5102
5874
|
newline = sourceNewline(context.sourceCode.text);
|
|
5875
|
+
joinMax = options.join?.max;
|
|
5103
5876
|
},
|
|
5104
5877
|
JSXOpeningElement(node) {
|
|
5105
|
-
if (node.attributes.length < minAttributes || node.loc.start.line !== node.loc.end.line) {
|
|
5106
|
-
return;
|
|
5107
|
-
}
|
|
5108
5878
|
const source = context.sourceCode;
|
|
5109
5879
|
const text = source.text;
|
|
5880
|
+
const attributes = node.attributes;
|
|
5881
|
+
const split = attributes.length >= minAttributes;
|
|
5882
|
+
if (split ? !astIsOneLine(node) : joinMax === undefined || astIsOneLine(node)) {
|
|
5883
|
+
return;
|
|
5884
|
+
}
|
|
5885
|
+
if (!split) {
|
|
5886
|
+
const start = (node.typeArguments ?? node.name).range[1];
|
|
5887
|
+
if (attributes.length === 0 || !attributes.every(astIsOneLine) || text.slice(node.range[0], start).includes(`
|
|
5888
|
+
`) || source.getCommentsInside(node).length > 0) {
|
|
5889
|
+
return;
|
|
5890
|
+
}
|
|
5891
|
+
const end = node.range[1] - (node.selfClosing ? 2 : 1);
|
|
5892
|
+
const ranges = sourceItemGaps(start, attributes, end);
|
|
5893
|
+
const closing = node.selfClosing ? " " : "";
|
|
5894
|
+
if (sourceJoinedWidth(text, start, ` ${attributes.map((attribute) => source.getText(attribute)).join(" ")}${closing}`, end) > (joinMax ?? 0)) {
|
|
5895
|
+
return;
|
|
5896
|
+
}
|
|
5897
|
+
context.report({
|
|
5898
|
+
node,
|
|
5899
|
+
messageId: "join",
|
|
5900
|
+
fix: (fixer) => ranges.some((range) => !/^\s*$/.test(text.slice(...range))) ? null : ranges.map((range, index) => fixer.replaceTextRange(range, index === ranges.length - 1 ? closing : " "))
|
|
5901
|
+
});
|
|
5902
|
+
return;
|
|
5903
|
+
}
|
|
5110
5904
|
const baseIndent = sourceLineIndent(text, node.range[0]);
|
|
5111
5905
|
const attributeIndent = baseIndent + indentUnit;
|
|
5112
|
-
const attributes = node.attributes;
|
|
5113
5906
|
context.report({
|
|
5114
5907
|
node,
|
|
5115
5908
|
messageId: "multiline",
|
|
5116
5909
|
fix: (fixer) => {
|
|
5117
|
-
|
|
5118
|
-
if (source.getCommentsInside(node).length > 0 || !last) {
|
|
5910
|
+
if (source.getCommentsInside(node).length > 0) {
|
|
5119
5911
|
return null;
|
|
5120
5912
|
}
|
|
5121
|
-
const ranges = [
|
|
5122
|
-
[(node.typeArguments ?? node.name).range[1], attributes[0].range[0]],
|
|
5123
|
-
...attributes.slice(1).map((attribute, index) => [attributes[index].range[1], attribute.range[0]]),
|
|
5124
|
-
[last.range[1], node.range[1] - (node.selfClosing ? 2 : 1)]
|
|
5125
|
-
];
|
|
5913
|
+
const ranges = sourceItemGaps((node.typeArguments ?? node.name).range[1], attributes, node.range[1] - (node.selfClosing ? 2 : 1));
|
|
5126
5914
|
if (ranges.some((range) => !/^\s*$/.test(text.slice(...range)))) {
|
|
5127
5915
|
return null;
|
|
5128
5916
|
}
|
|
@@ -5135,8 +5923,8 @@ var layoutJsxAttributes = defineRule44({
|
|
|
5135
5923
|
});
|
|
5136
5924
|
|
|
5137
5925
|
// src/rules/layout/layout-key-value.ts
|
|
5138
|
-
import { defineRule as
|
|
5139
|
-
var layoutKeyValue =
|
|
5926
|
+
import { defineRule as defineRule51 } from "@oxlint/plugins";
|
|
5927
|
+
var layoutKeyValue = defineRule51({
|
|
5140
5928
|
meta: {
|
|
5141
5929
|
type: "layout",
|
|
5142
5930
|
fixable: "whitespace",
|
|
@@ -5172,11 +5960,15 @@ var layoutKeyValue = defineRule45({
|
|
|
5172
5960
|
});
|
|
5173
5961
|
|
|
5174
5962
|
// src/rules/layout/layout-object.ts
|
|
5175
|
-
import { defineRule as
|
|
5963
|
+
import { defineRule as defineRule52 } from "@oxlint/plugins";
|
|
5176
5964
|
function layoutObjectIsWhitespace(text) {
|
|
5177
5965
|
return /^[\t\n\r\f ]*$/.test(text);
|
|
5178
5966
|
}
|
|
5179
|
-
|
|
5967
|
+
function layoutObjectIsFlat(property) {
|
|
5968
|
+
const value = property.type === "SpreadElement" ? property.argument : property.value;
|
|
5969
|
+
return astIsOneLine(property) && (property.type === "SpreadElement" || !property.method && property.kind === "init") && value.type !== "ObjectExpression" && value.type !== "ArrayExpression" && !astIsInlineFunction(value);
|
|
5970
|
+
}
|
|
5971
|
+
var layoutObject = defineRule52({
|
|
5180
5972
|
meta: {
|
|
5181
5973
|
type: "layout",
|
|
5182
5974
|
fixable: "whitespace",
|
|
@@ -5187,13 +5979,23 @@ var layoutObject = defineRule46({
|
|
|
5187
5979
|
properties: {
|
|
5188
5980
|
min: { type: "integer", minimum: 1, default: 3 },
|
|
5189
5981
|
scope: { type: "string", enum: ["call-args", "all"], default: "call-args" },
|
|
5190
|
-
indent: { ...sourceIndentSchema, default: 2 }
|
|
5982
|
+
indent: { ...sourceIndentSchema, default: 2 },
|
|
5983
|
+
join: {
|
|
5984
|
+
type: "object",
|
|
5985
|
+
additionalProperties: false,
|
|
5986
|
+
required: ["max"],
|
|
5987
|
+
properties: {
|
|
5988
|
+
max: { type: "integer", minimum: 1 },
|
|
5989
|
+
keep: { type: "array", items: { type: "string" } }
|
|
5990
|
+
}
|
|
5991
|
+
}
|
|
5191
5992
|
}
|
|
5192
5993
|
}
|
|
5193
5994
|
],
|
|
5194
5995
|
messages: {
|
|
5195
5996
|
callArgs: "Object with {{min}}+ properties in a call should have each property on its own line.",
|
|
5196
|
-
always: "Object with {{min}}+ properties should have each property on its own line."
|
|
5997
|
+
always: "Object with {{min}}+ properties should have each property on its own line.",
|
|
5998
|
+
join: "This object fits on one line, so keep it on one line."
|
|
5197
5999
|
}
|
|
5198
6000
|
},
|
|
5199
6001
|
createOnce(context) {
|
|
@@ -5202,6 +6004,7 @@ var layoutObject = defineRule46({
|
|
|
5202
6004
|
let indentUnit = sourceIndentUnit();
|
|
5203
6005
|
let newline = `
|
|
5204
6006
|
`;
|
|
6007
|
+
let join3;
|
|
5205
6008
|
return {
|
|
5206
6009
|
before() {
|
|
5207
6010
|
const options = optionsFirst(context, {});
|
|
@@ -5209,21 +6012,43 @@ var layoutObject = defineRule46({
|
|
|
5209
6012
|
scope = options.scope ?? "call-args";
|
|
5210
6013
|
indentUnit = sourceIndentUnit(options.indent);
|
|
5211
6014
|
newline = sourceNewline(context.sourceCode.text);
|
|
6015
|
+
join3 = options.join;
|
|
5212
6016
|
},
|
|
5213
6017
|
ObjectExpression(node) {
|
|
5214
|
-
|
|
6018
|
+
const source = context.sourceCode;
|
|
6019
|
+
const text = source.text;
|
|
6020
|
+
const properties = node.properties;
|
|
6021
|
+
const split = properties.length >= minProperties;
|
|
6022
|
+
if (split ? !astIsOneLine(node) : !join3 || astIsOneLine(node)) {
|
|
5215
6023
|
return;
|
|
5216
6024
|
}
|
|
5217
6025
|
const parent = node.parent;
|
|
5218
|
-
|
|
6026
|
+
const call = (parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node) ? parent : undefined;
|
|
6027
|
+
if (scope === "call-args" && !call) {
|
|
6028
|
+
return;
|
|
6029
|
+
}
|
|
6030
|
+
if (!split) {
|
|
6031
|
+
const callee = call ? astDottedName(call.callee) : undefined;
|
|
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) {
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
const gaps = sourceItemGaps(node.range[0] + 1, properties, node.range[1] - 1);
|
|
6037
|
+
const comma = text.slice(...gaps.at(-1) ?? [0, 0]).includes(",") ? "," : "";
|
|
6038
|
+
const joined = ` ${properties.map((property) => source.getText(property)).join(", ")}${comma} `;
|
|
6039
|
+
if (sourceJoinedWidth(text, node.range[0] + 1, joined, node.range[1] - 1) > (join3?.max ?? 0)) {
|
|
6040
|
+
return;
|
|
6041
|
+
}
|
|
6042
|
+
context.report({
|
|
6043
|
+
node,
|
|
6044
|
+
messageId: "join",
|
|
6045
|
+
fix: (fixer) => sourceRespace(fixer, text, gaps, () => " ")
|
|
6046
|
+
});
|
|
5219
6047
|
return;
|
|
5220
6048
|
}
|
|
5221
|
-
const source = context.sourceCode;
|
|
5222
|
-
const text = source.text;
|
|
5223
6049
|
const baseIndent = sourceLineIndent(text, node.range[0]);
|
|
5224
6050
|
const propertyIndent = `${baseIndent}${indentUnit}`;
|
|
5225
6051
|
const close = node.range[1] - 1;
|
|
5226
|
-
const properties = node.properties;
|
|
5227
6052
|
context.report({
|
|
5228
6053
|
node,
|
|
5229
6054
|
messageId: scope === "all" ? "always" : "callArgs",
|
|
@@ -5260,7 +6085,7 @@ var layoutObject = defineRule46({
|
|
|
5260
6085
|
});
|
|
5261
6086
|
|
|
5262
6087
|
// src/rules/layout/layout-padding.ts
|
|
5263
|
-
import { defineRule as
|
|
6088
|
+
import { defineRule as defineRule53 } from "@oxlint/plugins";
|
|
5264
6089
|
var layoutPaddingControl = new Set([
|
|
5265
6090
|
"IfStatement",
|
|
5266
6091
|
"ForStatement",
|
|
@@ -5289,7 +6114,7 @@ function layoutPaddingKind(node) {
|
|
|
5289
6114
|
function layoutPaddingIsMultilineVariable(node, kind) {
|
|
5290
6115
|
return kind === "variable" && node.loc.start.line !== node.loc.end.line;
|
|
5291
6116
|
}
|
|
5292
|
-
var layoutPadding =
|
|
6117
|
+
var layoutPadding = defineRule53({
|
|
5293
6118
|
meta: {
|
|
5294
6119
|
type: "layout",
|
|
5295
6120
|
fixable: "whitespace",
|
|
@@ -5378,8 +6203,8 @@ var layoutPadding = defineRule47({
|
|
|
5378
6203
|
});
|
|
5379
6204
|
|
|
5380
6205
|
// src/rules/layout/layout-pipe.ts
|
|
5381
|
-
import { defineRule as
|
|
5382
|
-
var layoutPipe =
|
|
6206
|
+
import { defineRule as defineRule54 } from "@oxlint/plugins";
|
|
6207
|
+
var layoutPipe = defineRule54({
|
|
5383
6208
|
meta: {
|
|
5384
6209
|
type: "layout",
|
|
5385
6210
|
messages: {
|
|
@@ -5410,7 +6235,7 @@ var layoutPipe = defineRule48({
|
|
|
5410
6235
|
});
|
|
5411
6236
|
|
|
5412
6237
|
// src/rules/layout/layout-ternary.ts
|
|
5413
|
-
import { defineRule as
|
|
6238
|
+
import { defineRule as defineRule55 } from "@oxlint/plugins";
|
|
5414
6239
|
function layoutTernaryLines(node) {
|
|
5415
6240
|
return node.loc.end.line - node.loc.start.line + 1;
|
|
5416
6241
|
}
|
|
@@ -5418,7 +6243,7 @@ function layoutTernaryBreak(between, operator, newline) {
|
|
|
5418
6243
|
const at = between.indexOf(operator);
|
|
5419
6244
|
return `${between.slice(0, at).trimEnd()}${newline}${operator} ${between.slice(at + 1).trimStart()}`;
|
|
5420
6245
|
}
|
|
5421
|
-
var layoutTernary =
|
|
6246
|
+
var layoutTernary = defineRule55({
|
|
5422
6247
|
meta: {
|
|
5423
6248
|
type: "layout",
|
|
5424
6249
|
fixable: "whitespace",
|
|
@@ -5432,11 +6257,7 @@ var layoutTernary = defineRule49({
|
|
|
5432
6257
|
minimum: 1,
|
|
5433
6258
|
default: 160
|
|
5434
6259
|
},
|
|
5435
|
-
indent: {
|
|
5436
|
-
type: "integer",
|
|
5437
|
-
minimum: 1,
|
|
5438
|
-
default: 2
|
|
5439
|
-
},
|
|
6260
|
+
indent: { ...sourceIndentSchema, default: 2 },
|
|
5440
6261
|
fit: {
|
|
5441
6262
|
type: "boolean",
|
|
5442
6263
|
default: true
|
|
@@ -5459,7 +6280,7 @@ var layoutTernary = defineRule49({
|
|
|
5459
6280
|
},
|
|
5460
6281
|
createOnce(context) {
|
|
5461
6282
|
let maxLength = 160;
|
|
5462
|
-
let
|
|
6283
|
+
let indentUnit = sourceIndentUnit();
|
|
5463
6284
|
let fit = true;
|
|
5464
6285
|
let branchMax;
|
|
5465
6286
|
const branch = (node, max) => {
|
|
@@ -5480,7 +6301,7 @@ var layoutTernary = defineRule49({
|
|
|
5480
6301
|
before() {
|
|
5481
6302
|
const options = optionsFirst(context, {});
|
|
5482
6303
|
maxLength = options.max ?? 160;
|
|
5483
|
-
|
|
6304
|
+
indentUnit = sourceIndentUnit(options.indent);
|
|
5484
6305
|
fit = options.fit ?? true;
|
|
5485
6306
|
branchMax = options.branch?.max;
|
|
5486
6307
|
},
|
|
@@ -5520,7 +6341,7 @@ var layoutTernary = defineRule49({
|
|
|
5520
6341
|
if (!onOneLine || interpolated || length <= maxLength) {
|
|
5521
6342
|
return;
|
|
5522
6343
|
}
|
|
5523
|
-
const newline = `${sourceNewline(text)}${sourceLineIndent(text, node.range[0])}${
|
|
6344
|
+
const newline = `${sourceNewline(text)}${sourceLineIndent(text, node.range[0])}${indentUnit}`;
|
|
5524
6345
|
const question = [node.test.range[1], node.consequent.range[0]];
|
|
5525
6346
|
const colon = [node.consequent.range[1], node.alternate.range[0]];
|
|
5526
6347
|
context.report({
|
|
@@ -5538,9 +6359,9 @@ var layoutTernary = defineRule49({
|
|
|
5538
6359
|
});
|
|
5539
6360
|
|
|
5540
6361
|
// src/rules/naming/naming-declarations.ts
|
|
5541
|
-
import { defineRule as
|
|
6362
|
+
import { defineRule as defineRule56 } from "@oxlint/plugins";
|
|
5542
6363
|
var namingDeclarationsKinds = ["function", "const", "let", "var", "class", "type", "interface", "enum"];
|
|
5543
|
-
var namingDeclarations =
|
|
6364
|
+
var namingDeclarations = defineRule56({
|
|
5544
6365
|
meta: {
|
|
5545
6366
|
type: "problem",
|
|
5546
6367
|
schema: [
|
|
@@ -5572,11 +6393,9 @@ var namingDeclarations = defineRule50({
|
|
|
5572
6393
|
const declarator = node.type === "VariableDeclarator";
|
|
5573
6394
|
const kind = declarationsKindOf(node, declarator ? [node.parent] : []);
|
|
5574
6395
|
const name = declarationsIdName(node);
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
}
|
|
5579
|
-
if (!kind || !name || insideLoop || kinds && !kinds.has(kind) || optionsPatternsTest(allowed, name)) {
|
|
6396
|
+
const loop = declarator ? node.parent.parent : null;
|
|
6397
|
+
const loopHeader = loop?.type === "ForStatement" ? loop.init === node.parent : (loop?.type === "ForInStatement" || loop?.type === "ForOfStatement") && loop.left === node.parent;
|
|
6398
|
+
if (!kind || !name || loopHeader || kinds && !kinds.has(kind) || optionsPatternsTest(allowed, name)) {
|
|
5580
6399
|
return;
|
|
5581
6400
|
}
|
|
5582
6401
|
if (expected.length > 0) {
|
|
@@ -5619,7 +6438,7 @@ var namingDeclarations = defineRule50({
|
|
|
5619
6438
|
});
|
|
5620
6439
|
|
|
5621
6440
|
// src/rules/naming/naming-exports.ts
|
|
5622
|
-
import { defineRule as
|
|
6441
|
+
import { defineRule as defineRule57 } from "@oxlint/plugins";
|
|
5623
6442
|
var namingExportsScopeProperties = {
|
|
5624
6443
|
scope: { type: "string", enum: ["exports", "functions", "declarations"] },
|
|
5625
6444
|
types: { type: "boolean" },
|
|
@@ -5645,7 +6464,7 @@ function matchTemplate(basename3, template, placeholder = "[a-z0-9-]+") {
|
|
|
5645
6464
|
}
|
|
5646
6465
|
return new RegExp(`^${pattern}$`).exec(basename3)?.groups ?? null;
|
|
5647
6466
|
}
|
|
5648
|
-
var namingExports =
|
|
6467
|
+
var namingExports = defineRule57({
|
|
5649
6468
|
meta: {
|
|
5650
6469
|
type: "problem",
|
|
5651
6470
|
schema: {
|
|
@@ -5740,9 +6559,12 @@ var namingExports = defineRule51({
|
|
|
5740
6559
|
}
|
|
5741
6560
|
continue;
|
|
5742
6561
|
}
|
|
5743
|
-
const names = scope === "declarations" ? [...declarations ??= declarationsNamed(program)] : (bindings ??= exportsCollect(program)).flatMap((binding) =>
|
|
6562
|
+
const names = scope === "declarations" ? [...declarations ??= declarationsNamed(program)] : (bindings ??= exportsCollect(program)).flatMap((binding) => {
|
|
6563
|
+
const name = binding.default ? binding.localName ?? binding.exportedName : binding.exportedName;
|
|
6564
|
+
return options.types && binding.typeOnly ? [] : [{ name, node: binding.node }];
|
|
6565
|
+
});
|
|
5744
6566
|
if (scope === "functions") {
|
|
5745
|
-
const exported = new Set(names.map((item) => item.name));
|
|
6567
|
+
const exported = new Set([...names.map((item) => item.name), ...(bindings ?? []).flatMap((binding) => binding.localName ?? [])]);
|
|
5746
6568
|
names.push(...(declarations ??= declarationsNamed(program)).filter(({ name, node }) => !exported.has(name) && (node.type === "FunctionDeclaration" || node.type === "VariableDeclarator" && declarationsIsFunctionValue(node.init))));
|
|
5747
6569
|
}
|
|
5748
6570
|
if (options.services) {
|
|
@@ -5779,10 +6601,10 @@ var namingExports = defineRule51({
|
|
|
5779
6601
|
});
|
|
5780
6602
|
|
|
5781
6603
|
// src/rules/naming/naming-file.ts
|
|
5782
|
-
import { defineRule as
|
|
6604
|
+
import { defineRule as defineRule58 } from "@oxlint/plugins";
|
|
5783
6605
|
import { readdirSync as readdirSync2 } from "node:fs";
|
|
5784
6606
|
import { dirname as dirname4 } from "node:path";
|
|
5785
|
-
var namingFile =
|
|
6607
|
+
var namingFile = defineRule58({
|
|
5786
6608
|
meta: {
|
|
5787
6609
|
type: "problem",
|
|
5788
6610
|
schema: {
|
|
@@ -5852,9 +6674,9 @@ var namingFile = defineRule52({
|
|
|
5852
6674
|
});
|
|
5853
6675
|
|
|
5854
6676
|
// src/rules/naming/naming-folder.ts
|
|
5855
|
-
import { defineRule as
|
|
6677
|
+
import { defineRule as defineRule59 } from "@oxlint/plugins";
|
|
5856
6678
|
import { posix as posix2 } from "node:path";
|
|
5857
|
-
var namingFolder =
|
|
6679
|
+
var namingFolder = defineRule59({
|
|
5858
6680
|
meta: {
|
|
5859
6681
|
type: "problem",
|
|
5860
6682
|
schema: [
|
|
@@ -5928,9 +6750,9 @@ var reactDynamicClasses = astSelectorRule(':matches(JSXAttribute[name.name="clas
|
|
|
5928
6750
|
var reactEmptyEffect = astSelectorRule(':matches(CallExpression[callee.name=/^use(Layout)?Effect$/], CallExpression[callee.object.name="React"][callee.property.name=/^use(Layout)?Effect$/]) > :matches(ArrowFunctionExpression, FunctionExpression) > BlockStatement[body.length=0]', "Remove the empty effect.");
|
|
5929
6751
|
|
|
5930
6752
|
// src/rules/react/react-memo.ts
|
|
5931
|
-
import { defineRule as
|
|
6753
|
+
import { defineRule as defineRule60 } from "@oxlint/plugins";
|
|
5932
6754
|
var reactMemoNames = ["memo", "useMemo", "useCallback"];
|
|
5933
|
-
var reactMemo =
|
|
6755
|
+
var reactMemo = defineRule60({
|
|
5934
6756
|
meta: {
|
|
5935
6757
|
type: "problem",
|
|
5936
6758
|
schema: [],
|
|
@@ -5965,7 +6787,7 @@ var reactMemo = defineRule54({
|
|
|
5965
6787
|
});
|
|
5966
6788
|
|
|
5967
6789
|
// src/rules/react/react-props.ts
|
|
5968
|
-
import { defineRule as
|
|
6790
|
+
import { defineRule as defineRule61 } from "@oxlint/plugins";
|
|
5969
6791
|
function reactPropsTarget(node) {
|
|
5970
6792
|
if (node?.type === "FunctionDeclaration" || node?.type === "FunctionExpression" || node?.type === "ArrowFunctionExpression") {
|
|
5971
6793
|
return { fn: node };
|
|
@@ -5992,7 +6814,7 @@ function reactIsPassThrough(type) {
|
|
|
5992
6814
|
const argument = type.typeArguments?.params.length === 1 ? type.typeArguments.params[0] : undefined;
|
|
5993
6815
|
return name.type === "Identifier" && name.name === "ComponentProps" && (argument?.type === "TSTypeQuery" || argument?.type === "TSLiteralType" && argument.literal.type === "Literal" && typeof argument.literal.value === "string");
|
|
5994
6816
|
}
|
|
5995
|
-
var reactProps =
|
|
6817
|
+
var reactProps = defineRule61({
|
|
5996
6818
|
meta: {
|
|
5997
6819
|
type: "problem",
|
|
5998
6820
|
schema: [
|
|
@@ -6000,7 +6822,8 @@ var reactProps = defineRule55({
|
|
|
6000
6822
|
type: "object",
|
|
6001
6823
|
additionalProperties: false,
|
|
6002
6824
|
properties: {
|
|
6003
|
-
prefix: { type: "boolean" }
|
|
6825
|
+
prefix: { type: "boolean" },
|
|
6826
|
+
suffix: { type: "string", minLength: 1, default: "Props" }
|
|
6004
6827
|
}
|
|
6005
6828
|
}
|
|
6006
6829
|
],
|
|
@@ -6014,7 +6837,7 @@ var reactProps = defineRule55({
|
|
|
6014
6837
|
createOnce(context) {
|
|
6015
6838
|
return {
|
|
6016
6839
|
Program(program) {
|
|
6017
|
-
const { prefix: filePrefix = false } = optionsFirst(context, {});
|
|
6840
|
+
const { prefix: filePrefix = false, suffix = "Props" } = optionsFirst(context, {});
|
|
6018
6841
|
const stem = namingFileStem(namingBasename(context.filename).replace(/\.(tsx?|jsx?)$/, ""));
|
|
6019
6842
|
const prefix = namingNormalized(stem, "remove-separators");
|
|
6020
6843
|
const exported = new Set(exportsCollect(program).flatMap((binding) => binding.typeOnly ? [] : [binding.localName]));
|
|
@@ -6039,7 +6862,7 @@ var reactProps = defineRule55({
|
|
|
6039
6862
|
continue;
|
|
6040
6863
|
}
|
|
6041
6864
|
const type = target.typeArgument ?? reactParameterType(parameter);
|
|
6042
|
-
const expected = `${candidate.name}
|
|
6865
|
+
const expected = `${candidate.name}${suffix}`;
|
|
6043
6866
|
const data = { name: candidate.name, expected };
|
|
6044
6867
|
if (filePrefix && !exported.has(candidate.name) && !candidate.name.toLowerCase().startsWith(prefix)) {
|
|
6045
6868
|
context.report({
|
|
@@ -6090,7 +6913,7 @@ var reactProps = defineRule55({
|
|
|
6090
6913
|
});
|
|
6091
6914
|
|
|
6092
6915
|
// src/rules/schemas/schemas-inline.ts
|
|
6093
|
-
import { defineRule as
|
|
6916
|
+
import { defineRule as defineRule62 } from "@oxlint/plugins";
|
|
6094
6917
|
|
|
6095
6918
|
// src/utils/schemas.utils.ts
|
|
6096
6919
|
var schemasElementOptionsSchema = {
|
|
@@ -6126,7 +6949,7 @@ function schemasIsAllowedElement(node, allowScalars, namespaces, structuralMetho
|
|
|
6126
6949
|
}
|
|
6127
6950
|
|
|
6128
6951
|
// src/rules/schemas/schemas-inline.ts
|
|
6129
|
-
var schemasInline =
|
|
6952
|
+
var schemasInline = defineRule62({
|
|
6130
6953
|
meta: {
|
|
6131
6954
|
type: "problem",
|
|
6132
6955
|
schema: [schemasElementOptionsSchema],
|
|
@@ -6175,11 +6998,11 @@ var schemasInline = defineRule56({
|
|
|
6175
6998
|
});
|
|
6176
6999
|
|
|
6177
7000
|
// src/rules/schemas/schemas-local.ts
|
|
6178
|
-
import { defineRule as
|
|
7001
|
+
import { defineRule as defineRule63 } from "@oxlint/plugins";
|
|
6179
7002
|
var schemasLocalImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
|
|
6180
7003
|
var schemasLocalConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
|
|
6181
7004
|
var schemasLocalCalls = ["config", "prettifyError", "treeifyError", "flattenError", "formatError"];
|
|
6182
|
-
var schemasLocal =
|
|
7005
|
+
var schemasLocal = defineRule63({
|
|
6183
7006
|
meta: {
|
|
6184
7007
|
type: "problem",
|
|
6185
7008
|
schema: [
|
|
@@ -6192,6 +7015,8 @@ var schemasLocal = defineRule57({
|
|
|
6192
7015
|
calls: { type: "array", items: { type: "string" } },
|
|
6193
7016
|
allow: { type: "array", items: { type: "string" } },
|
|
6194
7017
|
patterns: { type: "array", items: { type: "string" } },
|
|
7018
|
+
imports: { type: "boolean" },
|
|
7019
|
+
values: { type: "boolean" },
|
|
6195
7020
|
message: { type: "string" },
|
|
6196
7021
|
importMessage: { type: "string" },
|
|
6197
7022
|
constructionMessage: { type: "string" }
|
|
@@ -6209,10 +7034,34 @@ var schemasLocal = defineRule57({
|
|
|
6209
7034
|
let packages = new Set;
|
|
6210
7035
|
let calls = new Set;
|
|
6211
7036
|
let pending = [];
|
|
6212
|
-
let schemaUses = new Set;
|
|
6213
|
-
let callUses = new Set;
|
|
6214
7037
|
let importMessage = schemasLocalImportMessage;
|
|
6215
7038
|
let constructionMessage = schemasLocalConstructionMessage;
|
|
7039
|
+
let imports = true;
|
|
7040
|
+
let values = false;
|
|
7041
|
+
let inline = new Set;
|
|
7042
|
+
function isInline(node) {
|
|
7043
|
+
if (inline.size === 0) {
|
|
7044
|
+
return false;
|
|
7045
|
+
}
|
|
7046
|
+
for (let parent = node.parent;parent; parent = parent.parent) {
|
|
7047
|
+
if (inline.has(parent)) {
|
|
7048
|
+
return true;
|
|
7049
|
+
}
|
|
7050
|
+
}
|
|
7051
|
+
return false;
|
|
7052
|
+
}
|
|
7053
|
+
function readsLocal(node) {
|
|
7054
|
+
const scope = context.sourceCode.getScope(node);
|
|
7055
|
+
return astSome(node, (child) => {
|
|
7056
|
+
if (child.type !== "Identifier") {
|
|
7057
|
+
return false;
|
|
7058
|
+
}
|
|
7059
|
+
const parent = child.parent;
|
|
7060
|
+
const named = parent.type === "MemberExpression" && parent.property === child && !parent.computed || parent.type === "Property" && parent.key === child && !parent.computed && !parent.shorthand;
|
|
7061
|
+
const type = named ? undefined : boundariesDeclaredVariable(scope, child.name)?.scope.type;
|
|
7062
|
+
return type !== undefined && type !== "module" && type !== "global";
|
|
7063
|
+
});
|
|
7064
|
+
}
|
|
6216
7065
|
function isAllowedCall(node, member) {
|
|
6217
7066
|
return member?.type === "MemberExpression" && member.object === node && !member.computed && member.property.type === "Identifier" && calls.has(member.property.name) && member.parent.type === "CallExpression" && member.parent.callee === member;
|
|
6218
7067
|
}
|
|
@@ -6220,6 +7069,9 @@ var schemasLocal = defineRule57({
|
|
|
6220
7069
|
return packages.has(source) || [...packages].some((name) => source.startsWith(`${name}/`));
|
|
6221
7070
|
}
|
|
6222
7071
|
function reportRuntimeImport(node, source) {
|
|
7072
|
+
if (!imports) {
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
6223
7075
|
context.report({
|
|
6224
7076
|
node,
|
|
6225
7077
|
messageId: "runtimeImport",
|
|
@@ -6242,10 +7094,11 @@ var schemasLocal = defineRule57({
|
|
|
6242
7094
|
packages = new Set(options.packages);
|
|
6243
7095
|
calls = new Set(options.calls ?? schemasLocalCalls);
|
|
6244
7096
|
pending = [];
|
|
6245
|
-
schemaUses = new Set;
|
|
6246
|
-
callUses = new Set;
|
|
6247
7097
|
importMessage = options.importMessage ?? options.message ?? schemasLocalImportMessage;
|
|
6248
7098
|
constructionMessage = options.constructionMessage ?? options.message ?? schemasLocalConstructionMessage;
|
|
7099
|
+
imports = options.imports ?? true;
|
|
7100
|
+
values = options.values ?? false;
|
|
7101
|
+
inline = new Set;
|
|
6249
7102
|
if ((options.allow ?? []).some((suffix) => filename.endsWith(suffix)) || (options.patterns ?? []).some((pattern) => new RegExp(pattern).test(filename))) {
|
|
6250
7103
|
return false;
|
|
6251
7104
|
}
|
|
@@ -6267,18 +7120,8 @@ var schemasLocal = defineRule57({
|
|
|
6267
7120
|
}
|
|
6268
7121
|
pending.push({ node, locals });
|
|
6269
7122
|
},
|
|
6270
|
-
Identifier(node) {
|
|
6271
|
-
if (!constructors.has(node.name) || node.parent.type.startsWith("Import")) {
|
|
6272
|
-
return;
|
|
6273
|
-
}
|
|
6274
|
-
if (isAllowedCall(node, node.parent)) {
|
|
6275
|
-
callUses.add(node.name);
|
|
6276
|
-
return;
|
|
6277
|
-
}
|
|
6278
|
-
schemaUses.add(node.name);
|
|
6279
|
-
},
|
|
6280
7123
|
"Program:exit"() {
|
|
6281
|
-
const runtime = pending.filter(({ locals }) =>
|
|
7124
|
+
const runtime = pending.filter(({ node, locals }) => context.sourceCode.getDeclaredVariables(node).filter((variable) => locals.includes(variable.name)).some((variable) => variable.references.length === 0 || variable.references.some((reference) => !isAllowedCall(reference.identifier, reference.identifier.parent) && !isInline(reference.identifier))));
|
|
6282
7125
|
for (const { node } of runtime) {
|
|
6283
7126
|
reportRuntimeImport(node, node.source.value);
|
|
6284
7127
|
}
|
|
@@ -6293,6 +7136,10 @@ var schemasLocal = defineRule57({
|
|
|
6293
7136
|
if (root.type !== "Identifier" || !constructors.has(root.name) || node.callee.type === "MemberExpression" && node.callee.object === root && isAllowedCall(root, root.parent)) {
|
|
6294
7137
|
return;
|
|
6295
7138
|
}
|
|
7139
|
+
if (values && (isInline(node) || readsLocal(node))) {
|
|
7140
|
+
inline.add(node);
|
|
7141
|
+
return;
|
|
7142
|
+
}
|
|
6296
7143
|
context.report({
|
|
6297
7144
|
node,
|
|
6298
7145
|
messageId: "construction",
|
|
@@ -6304,8 +7151,8 @@ var schemasLocal = defineRule57({
|
|
|
6304
7151
|
});
|
|
6305
7152
|
|
|
6306
7153
|
// src/rules/schemas/schemas-rederive.ts
|
|
6307
|
-
import { defineRule as
|
|
6308
|
-
var schemasRederive =
|
|
7154
|
+
import { defineRule as defineRule64 } from "@oxlint/plugins";
|
|
7155
|
+
var schemasRederive = defineRule64({
|
|
6309
7156
|
meta: {
|
|
6310
7157
|
type: "problem",
|
|
6311
7158
|
schema: [
|
|
@@ -6351,7 +7198,7 @@ var schemasRederive = defineRule58({
|
|
|
6351
7198
|
});
|
|
6352
7199
|
|
|
6353
7200
|
// src/rules/schemas/schemas-single-use.ts
|
|
6354
|
-
import { defineRule as
|
|
7201
|
+
import { defineRule as defineRule65 } from "@oxlint/plugins";
|
|
6355
7202
|
function isScalarSchema(node, namespaces, structuralMethods) {
|
|
6356
7203
|
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
|
|
6357
7204
|
return false;
|
|
@@ -6365,7 +7212,7 @@ function isScalarSchema(node, namespaces, structuralMethods) {
|
|
|
6365
7212
|
}
|
|
6366
7213
|
return node.callee.object.type === "CallExpression" && isScalarSchema(node.callee.object, namespaces, structuralMethods);
|
|
6367
7214
|
}
|
|
6368
|
-
var schemasSingleUse =
|
|
7215
|
+
var schemasSingleUse = defineRule65({
|
|
6369
7216
|
meta: {
|
|
6370
7217
|
type: "suggestion",
|
|
6371
7218
|
schema: [schemasElementOptionsSchema],
|
|
@@ -6441,7 +7288,7 @@ var schemasSingleUse = defineRule59({
|
|
|
6441
7288
|
});
|
|
6442
7289
|
|
|
6443
7290
|
// src/rules/tests/tests-assertions.ts
|
|
6444
|
-
import { defineRule as
|
|
7291
|
+
import { defineRule as defineRule66 } from "@oxlint/plugins";
|
|
6445
7292
|
var testsAssertionsModifiers = new Set(["for", "each", "concurrent", "sequential", "only", "skip"]);
|
|
6446
7293
|
var testsAssertionsFunctions = [
|
|
6447
7294
|
"expect",
|
|
@@ -6631,7 +7478,7 @@ function isAssertedTest(registration, sourceCode, state) {
|
|
|
6631
7478
|
}
|
|
6632
7479
|
return rows.length > 0 && rows.every((row) => hasAssertion(callback, row.bindings, new Set, state));
|
|
6633
7480
|
}
|
|
6634
|
-
var testsAssertions =
|
|
7481
|
+
var testsAssertions = defineRule66({
|
|
6635
7482
|
meta: {
|
|
6636
7483
|
type: "problem",
|
|
6637
7484
|
schema: [
|
|
@@ -6757,17 +7604,36 @@ var testsAssertions = defineRule60({
|
|
|
6757
7604
|
});
|
|
6758
7605
|
|
|
6759
7606
|
// src/rules/tests/tests-concurrent-db.ts
|
|
6760
|
-
import { defineRule as
|
|
6761
|
-
var testsConcurrentDb =
|
|
7607
|
+
import { defineRule as defineRule67 } from "@oxlint/plugins";
|
|
7608
|
+
var testsConcurrentDb = defineRule67({
|
|
6762
7609
|
meta: {
|
|
6763
7610
|
type: "problem",
|
|
6764
|
-
schema: [
|
|
7611
|
+
schema: [
|
|
7612
|
+
{
|
|
7613
|
+
type: "object",
|
|
7614
|
+
additionalProperties: false,
|
|
7615
|
+
properties: {
|
|
7616
|
+
message: { type: "string" },
|
|
7617
|
+
fixtures: { type: "array", items: { type: "string", minLength: 1 }, default: ["db"] },
|
|
7618
|
+
callees: { type: "array", items: { type: "string", minLength: 1 }, default: ["test.concurrent"] }
|
|
7619
|
+
}
|
|
7620
|
+
}
|
|
7621
|
+
],
|
|
6765
7622
|
messages: { forbidden: "{{message}}" }
|
|
6766
7623
|
},
|
|
6767
7624
|
createOnce(context) {
|
|
7625
|
+
let message = "";
|
|
7626
|
+
let fixtures = new Set;
|
|
7627
|
+
let callees = new Set;
|
|
6768
7628
|
return {
|
|
7629
|
+
before() {
|
|
7630
|
+
const options = optionsFirst(context, {});
|
|
7631
|
+
message = options.message ?? "Obtain an isolated database fixture for concurrent tests.";
|
|
7632
|
+
fixtures = new Set(options.fixtures ?? ["db"]);
|
|
7633
|
+
callees = new Set(options.callees ?? ["test.concurrent"]);
|
|
7634
|
+
},
|
|
6769
7635
|
CallExpression(node) {
|
|
6770
|
-
const callback = astDottedName(node.callee)
|
|
7636
|
+
const callback = callees.has(astDottedName(node.callee) ?? "") ? node.arguments.findLast(declarationsIsFunctionValue) : undefined;
|
|
6771
7637
|
const parameter = callback?.params.at(0);
|
|
6772
7638
|
const patterns = parameter?.type === "ObjectPattern" ? [parameter] : [];
|
|
6773
7639
|
if (callback && parameter?.type === "Identifier") {
|
|
@@ -6780,8 +7646,8 @@ var testsConcurrentDb = defineRule61({
|
|
|
6780
7646
|
}
|
|
6781
7647
|
}
|
|
6782
7648
|
for (const property of patterns.flatMap((pattern) => pattern.properties)) {
|
|
6783
|
-
|
|
6784
|
-
|
|
7649
|
+
const key = property.type === "Property" && !property.computed ? property.key : undefined;
|
|
7650
|
+
if (fixtures.has((key?.type === "Identifier" ? key.name : key && astStaticString(key)) ?? "")) {
|
|
6785
7651
|
context.report({
|
|
6786
7652
|
node: property,
|
|
6787
7653
|
messageId: "forbidden",
|
|
@@ -6795,10 +7661,10 @@ var testsConcurrentDb = defineRule61({
|
|
|
6795
7661
|
});
|
|
6796
7662
|
|
|
6797
7663
|
// src/rules/tests/tests-modifiers.ts
|
|
6798
|
-
import { defineRule as
|
|
7664
|
+
import { defineRule as defineRule68 } from "@oxlint/plugins";
|
|
6799
7665
|
var testsModifiersNames = ["test", "it", "describe", "suite"];
|
|
6800
7666
|
var testsModifiersPackages = new Set(["vitest", "bun:test", "@playwright/test", "@jest/globals"]);
|
|
6801
|
-
var testsModifiersBanned =
|
|
7667
|
+
var testsModifiersBanned = ["only", "skip", "todo"];
|
|
6802
7668
|
var testsModifiersBuilders = new Set(["if", "runIf", "skipIf"]);
|
|
6803
7669
|
function modifierName(node) {
|
|
6804
7670
|
if (node.type === "Identifier") {
|
|
@@ -6814,14 +7680,17 @@ function modifierName(node) {
|
|
|
6814
7680
|
const property = astMemberName(node);
|
|
6815
7681
|
return object && property ? `${object}.${property}` : undefined;
|
|
6816
7682
|
}
|
|
6817
|
-
var testsModifiers =
|
|
7683
|
+
var testsModifiers = defineRule68({
|
|
6818
7684
|
meta: {
|
|
6819
7685
|
type: "problem",
|
|
6820
7686
|
schema: [
|
|
6821
7687
|
{
|
|
6822
7688
|
type: "object",
|
|
6823
7689
|
additionalProperties: false,
|
|
6824
|
-
properties: {
|
|
7690
|
+
properties: {
|
|
7691
|
+
functions: { type: "array", items: { type: "string" } },
|
|
7692
|
+
modifiers: { type: "array", items: { type: "string", minLength: 1 }, default: testsModifiersBanned }
|
|
7693
|
+
}
|
|
6825
7694
|
}
|
|
6826
7695
|
],
|
|
6827
7696
|
messages: {
|
|
@@ -6830,12 +7699,12 @@ var testsModifiers = defineRule62({
|
|
|
6830
7699
|
},
|
|
6831
7700
|
createOnce(context) {
|
|
6832
7701
|
let names = new Set;
|
|
7702
|
+
let banned = new Set;
|
|
6833
7703
|
return {
|
|
6834
7704
|
before() {
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
]);
|
|
7705
|
+
const options = optionsFirst(context, {});
|
|
7706
|
+
names = new Set([...testsModifiersNames, ...options.functions ?? []]);
|
|
7707
|
+
banned = new Set(options.modifiers ?? testsModifiersBanned);
|
|
6839
7708
|
},
|
|
6840
7709
|
ImportDeclaration(node) {
|
|
6841
7710
|
if (!testsModifiersPackages.has(node.source.value)) {
|
|
@@ -6853,7 +7722,7 @@ var testsModifiers = defineRule62({
|
|
|
6853
7722
|
},
|
|
6854
7723
|
MemberExpression(node) {
|
|
6855
7724
|
const name = modifierName(node);
|
|
6856
|
-
if (!name || !
|
|
7725
|
+
if (!name || !banned.has(name.split(".").at(-1) ?? "")) {
|
|
6857
7726
|
return;
|
|
6858
7727
|
}
|
|
6859
7728
|
if ([...names].some((test) => name.startsWith(`${test}.`))) {
|
|
@@ -6865,9 +7734,9 @@ var testsModifiers = defineRule62({
|
|
|
6865
7734
|
});
|
|
6866
7735
|
|
|
6867
7736
|
// src/rules/tests/tests-titles.ts
|
|
6868
|
-
import { defineRule as
|
|
6869
|
-
var testsTitlesModifiers =
|
|
6870
|
-
var testsTitles =
|
|
7737
|
+
import { defineRule as defineRule69 } from "@oxlint/plugins";
|
|
7738
|
+
var testsTitlesModifiers = ["only", "skip", "concurrent", "sequential", "todo", "each", "for"];
|
|
7739
|
+
var testsTitles = defineRule69({
|
|
6871
7740
|
meta: {
|
|
6872
7741
|
type: "suggestion",
|
|
6873
7742
|
schema: [
|
|
@@ -6876,6 +7745,7 @@ var testsTitles = defineRule63({
|
|
|
6876
7745
|
additionalProperties: false,
|
|
6877
7746
|
properties: {
|
|
6878
7747
|
callees: { type: "array", items: { type: "string" } },
|
|
7748
|
+
modifiers: { type: "array", items: { type: "string", minLength: 1 }, default: testsTitlesModifiers },
|
|
6879
7749
|
deny: optionsPatternSchema,
|
|
6880
7750
|
require: optionsPatternSchema,
|
|
6881
7751
|
flags: { type: "string", pattern: "^[dgimsuvy]*$" }
|
|
@@ -6895,6 +7765,7 @@ var testsTitles = defineRule63({
|
|
|
6895
7765
|
},
|
|
6896
7766
|
createOnce(context) {
|
|
6897
7767
|
let callees = [];
|
|
7768
|
+
let modifiers = new Set;
|
|
6898
7769
|
let forbid = [];
|
|
6899
7770
|
let required = [];
|
|
6900
7771
|
let requiredLabel = "";
|
|
@@ -6903,6 +7774,7 @@ var testsTitles = defineRule63({
|
|
|
6903
7774
|
const options = optionsFirst(context);
|
|
6904
7775
|
const flags = options.flags ?? "";
|
|
6905
7776
|
callees = options.callees;
|
|
7777
|
+
modifiers = new Set(options.modifiers ?? testsTitlesModifiers);
|
|
6906
7778
|
forbid = options.deny === undefined ? [] : [options.deny].flat().map((source) => ({ regex: new RegExp(source, flags), pattern: source }));
|
|
6907
7779
|
required = optionsPatternsWithEmpty(options.require, flags);
|
|
6908
7780
|
requiredLabel = optionsPatternLabel(options.require);
|
|
@@ -6913,7 +7785,7 @@ var testsTitles = defineRule63({
|
|
|
6913
7785
|
CallExpression(node) {
|
|
6914
7786
|
const title = node.arguments.at(0);
|
|
6915
7787
|
const callee = node.callee;
|
|
6916
|
-
const configured = astMatchesCallee(astDottedName(callee), callees,
|
|
7788
|
+
const configured = astMatchesCallee(astDottedName(callee), callees, modifiers) || callee.type === "CallExpression" && astMatchesCallee(astDottedName(callee.callee), callees, modifiers) || callee.type === "TaggedTemplateExpression" && astMatchesCallee(astDottedName(callee.tag), callees, modifiers);
|
|
6917
7789
|
if (!title || !configured) {
|
|
6918
7790
|
return;
|
|
6919
7791
|
}
|
|
@@ -6942,11 +7814,11 @@ var testsTitles = defineRule63({
|
|
|
6942
7814
|
});
|
|
6943
7815
|
|
|
6944
7816
|
// src/rules/types/types-declarations.ts
|
|
6945
|
-
import { defineRule as
|
|
7817
|
+
import { defineRule as defineRule70 } from "@oxlint/plugins";
|
|
6946
7818
|
function isValuePattern(source) {
|
|
6947
7819
|
return /^\^?=/.test(source);
|
|
6948
7820
|
}
|
|
6949
|
-
var typesDeclarations =
|
|
7821
|
+
var typesDeclarations = defineRule70({
|
|
6950
7822
|
meta: {
|
|
6951
7823
|
type: "problem",
|
|
6952
7824
|
schema: [
|
|
@@ -6988,8 +7860,73 @@ var typesDeclarations = defineRule64({
|
|
|
6988
7860
|
}
|
|
6989
7861
|
});
|
|
6990
7862
|
|
|
7863
|
+
// src/rules/types/types-duplicate.ts
|
|
7864
|
+
import { defineRule as defineRule71 } from "@oxlint/plugins";
|
|
7865
|
+
var typesDuplicate = defineRule71({
|
|
7866
|
+
meta: {
|
|
7867
|
+
type: "suggestion",
|
|
7868
|
+
schema: [
|
|
7869
|
+
{
|
|
7870
|
+
type: "object",
|
|
7871
|
+
additionalProperties: false,
|
|
7872
|
+
properties: {
|
|
7873
|
+
structs: { type: "array", items: { type: "string" } },
|
|
7874
|
+
min: { type: "integer", minimum: 1 }
|
|
7875
|
+
}
|
|
7876
|
+
}
|
|
7877
|
+
],
|
|
7878
|
+
messages: { duplicate: "{{name}} has the same members as {{first}}; use {{first}}, or derive one from the other." }
|
|
7879
|
+
},
|
|
7880
|
+
createOnce(context) {
|
|
7881
|
+
let structs = new Set(["Schema.Struct"]);
|
|
7882
|
+
let min = 2;
|
|
7883
|
+
let seen = new Map;
|
|
7884
|
+
const check = (node, name, kind, members) => {
|
|
7885
|
+
if (members.length < min) {
|
|
7886
|
+
return;
|
|
7887
|
+
}
|
|
7888
|
+
const signature = members.map((item) => context.sourceCode.getText(item).replaceAll(/\breadonly\s+/g, "").replaceAll(/\s+/g, "").replace(/[;,]$/, "")).sort().join(";");
|
|
7889
|
+
const key = `${kind}:${signature}`;
|
|
7890
|
+
const first = seen.get(key);
|
|
7891
|
+
if (first === undefined) {
|
|
7892
|
+
seen.set(key, name);
|
|
7893
|
+
return;
|
|
7894
|
+
}
|
|
7895
|
+
context.report({
|
|
7896
|
+
node,
|
|
7897
|
+
messageId: "duplicate",
|
|
7898
|
+
data: { name, first }
|
|
7899
|
+
});
|
|
7900
|
+
};
|
|
7901
|
+
return {
|
|
7902
|
+
before() {
|
|
7903
|
+
const options = optionsFirst(context, {});
|
|
7904
|
+
structs = new Set(options.structs ?? ["Schema.Struct"]);
|
|
7905
|
+
min = options.min ?? 2;
|
|
7906
|
+
seen = new Map;
|
|
7907
|
+
},
|
|
7908
|
+
TSInterfaceDeclaration(node) {
|
|
7909
|
+
const heritage = node.extends.map((item) => context.sourceCode.getText(item)).join(",");
|
|
7910
|
+
check(node, node.id.name, `type:${heritage}`, node.body.body);
|
|
7911
|
+
},
|
|
7912
|
+
TSTypeAliasDeclaration(node) {
|
|
7913
|
+
if (node.typeAnnotation.type === "TSTypeLiteral") {
|
|
7914
|
+
check(node, node.id.name, "type:", node.typeAnnotation.members);
|
|
7915
|
+
}
|
|
7916
|
+
},
|
|
7917
|
+
VariableDeclarator(node) {
|
|
7918
|
+
const init = node.init ? astUnwrap(node.init) : undefined;
|
|
7919
|
+
const fields = init?.type === "CallExpression" && structs.has(astDottedName(init.callee) ?? "") ? init.arguments[0] : undefined;
|
|
7920
|
+
if (fields?.type === "ObjectExpression" && node.id.type === "Identifier") {
|
|
7921
|
+
check(node, node.id.name, "struct", fields.properties);
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
};
|
|
7925
|
+
}
|
|
7926
|
+
});
|
|
7927
|
+
|
|
6991
7928
|
// src/rules/types/types-imported-alias.ts
|
|
6992
|
-
import { defineRule as
|
|
7929
|
+
import { defineRule as defineRule72 } from "@oxlint/plugins";
|
|
6993
7930
|
function importedAliasTarget(declaration, imports) {
|
|
6994
7931
|
if (declaration?.type !== "TSTypeAliasDeclaration") {
|
|
6995
7932
|
return;
|
|
@@ -7001,7 +7938,7 @@ function importedAliasTarget(declaration, imports) {
|
|
|
7001
7938
|
const { name } = type.typeName;
|
|
7002
7939
|
return imports.has(name) && !declaration.typeParameters?.params.some((parameter) => parameter.name.name === name) ? name : undefined;
|
|
7003
7940
|
}
|
|
7004
|
-
var typesImportedAlias =
|
|
7941
|
+
var typesImportedAlias = defineRule72({
|
|
7005
7942
|
meta: {
|
|
7006
7943
|
type: "problem",
|
|
7007
7944
|
schema: [],
|
|
@@ -7063,7 +8000,7 @@ var typesImportedAlias = defineRule65({
|
|
|
7063
8000
|
});
|
|
7064
8001
|
|
|
7065
8002
|
// src/rules/types/types-inline.ts
|
|
7066
|
-
import { defineRule as
|
|
8003
|
+
import { defineRule as defineRule73 } from "@oxlint/plugins";
|
|
7067
8004
|
function parameterAnnotation(parameter) {
|
|
7068
8005
|
if (parameter.type === "TSParameterProperty") {
|
|
7069
8006
|
return parameterAnnotation(parameter.parameter);
|
|
@@ -7073,7 +8010,7 @@ function parameterAnnotation(parameter) {
|
|
|
7073
8010
|
}
|
|
7074
8011
|
return parameter.typeAnnotation;
|
|
7075
8012
|
}
|
|
7076
|
-
var typesInline =
|
|
8013
|
+
var typesInline = defineRule73({
|
|
7077
8014
|
meta: {
|
|
7078
8015
|
type: "problem",
|
|
7079
8016
|
schema: [
|
|
@@ -7149,8 +8086,8 @@ var typesInline = defineRule66({
|
|
|
7149
8086
|
var typesLocalAlias = astSelectorRule("TSTypeAliasDeclaration", "Local component/hook contracts use interfaces named for their owner. Derived or reusable aliases belong in domain types; do not substitute an empty interface.");
|
|
7150
8087
|
|
|
7151
8088
|
// src/rules/types/types-namespace-import.ts
|
|
7152
|
-
import { defineRule as
|
|
7153
|
-
var typesNamespaceImport =
|
|
8089
|
+
import { defineRule as defineRule74 } from "@oxlint/plugins";
|
|
8090
|
+
var typesNamespaceImport = defineRule74({
|
|
7154
8091
|
meta: {
|
|
7155
8092
|
type: "suggestion",
|
|
7156
8093
|
schema: [
|
|
@@ -7192,26 +8129,50 @@ var typesNamespaceImport = defineRule67({
|
|
|
7192
8129
|
});
|
|
7193
8130
|
|
|
7194
8131
|
// src/rules/types/types-service.ts
|
|
7195
|
-
import { defineRule as
|
|
7196
|
-
var typesService =
|
|
8132
|
+
import { defineRule as defineRule75 } from "@oxlint/plugins";
|
|
8133
|
+
var typesService = defineRule75({
|
|
7197
8134
|
meta: {
|
|
7198
8135
|
type: "problem",
|
|
7199
|
-
schema: [
|
|
8136
|
+
schema: [
|
|
8137
|
+
{
|
|
8138
|
+
type: "object",
|
|
8139
|
+
additionalProperties: false,
|
|
8140
|
+
properties: {
|
|
8141
|
+
suffix: { type: "string", minLength: 1, default: "Service" },
|
|
8142
|
+
factory: { type: "string", minLength: 1, default: "make" }
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
],
|
|
7200
8146
|
messages: {
|
|
7201
|
-
domain: "Move this type to its domain types file; only the matching factory-derived
|
|
8147
|
+
domain: "Move this type to its domain types file; only the matching factory-derived {{suffix}} alias belongs here."
|
|
7202
8148
|
}
|
|
7203
8149
|
},
|
|
7204
8150
|
createOnce(context) {
|
|
8151
|
+
let suffix = "Service";
|
|
8152
|
+
let factory = "make";
|
|
7205
8153
|
return {
|
|
8154
|
+
before() {
|
|
8155
|
+
const options = optionsFirst(context, {});
|
|
8156
|
+
suffix = options.suffix ?? "Service";
|
|
8157
|
+
factory = options.factory ?? "make";
|
|
8158
|
+
},
|
|
7206
8159
|
TSInterfaceDeclaration(node) {
|
|
7207
|
-
context.report({
|
|
8160
|
+
context.report({
|
|
8161
|
+
node,
|
|
8162
|
+
messageId: "domain",
|
|
8163
|
+
data: { suffix }
|
|
8164
|
+
});
|
|
7208
8165
|
},
|
|
7209
8166
|
TSTypeAliasDeclaration(node) {
|
|
7210
8167
|
const type = node.typeAnnotation;
|
|
7211
8168
|
const argument = type.type === "TSTypeReference" && type.typeArguments?.params.length === 1 ? type.typeArguments.params[0] : undefined;
|
|
7212
|
-
const isFactoryService = node.id.name.endsWith(
|
|
8169
|
+
const isFactoryService = node.id.name.endsWith(suffix) && type.type === "TSTypeReference" && type.typeName.type === "Identifier" && type.typeName.name === "ReturnType" && argument?.type === "TSTypeQuery" && argument.exprName.type === "Identifier" && argument.exprName.name === `${factory}${node.id.name}`;
|
|
7213
8170
|
if (!isFactoryService) {
|
|
7214
|
-
context.report({
|
|
8171
|
+
context.report({
|
|
8172
|
+
node,
|
|
8173
|
+
messageId: "domain",
|
|
8174
|
+
data: { suffix }
|
|
8175
|
+
});
|
|
7215
8176
|
}
|
|
7216
8177
|
}
|
|
7217
8178
|
};
|
|
@@ -7219,12 +8180,12 @@ var typesService = defineRule68({
|
|
|
7219
8180
|
});
|
|
7220
8181
|
|
|
7221
8182
|
// src/rules/types/types-unknown.ts
|
|
7222
|
-
import { defineRule as
|
|
8183
|
+
import { defineRule as defineRule76 } from "@oxlint/plugins";
|
|
7223
8184
|
function isCatchName(node) {
|
|
7224
8185
|
const key = "key" in node && !(("computed" in node) && node.computed) ? node.key : undefined;
|
|
7225
8186
|
return key?.type === "Identifier" && key.name === "catch";
|
|
7226
8187
|
}
|
|
7227
|
-
var typesUnknown =
|
|
8188
|
+
var typesUnknown = defineRule76({
|
|
7228
8189
|
meta: { type: "problem", schema: [], messages: { forbidden: "Use an owned domain type rather than unknown." } },
|
|
7229
8190
|
createOnce(context) {
|
|
7230
8191
|
return {
|
|
@@ -7279,6 +8240,11 @@ var src_default = eslintCompatPlugin({
|
|
|
7279
8240
|
"comments-code": commentsCode,
|
|
7280
8241
|
"comments-directives": commentsDirectives,
|
|
7281
8242
|
"copy-dashes": copyDashes,
|
|
8243
|
+
"effect-layer-file": effectLayerFile,
|
|
8244
|
+
"effect-layers": effectLayers,
|
|
8245
|
+
"effect-merge-pipe": effectMergePipe,
|
|
8246
|
+
"effect-schema-first": effectSchemaFirst,
|
|
8247
|
+
"effect-values-first": effectValuesFirst,
|
|
7282
8248
|
"files-components-only": filesComponentsOnly,
|
|
7283
8249
|
"files-constants-only": filesConstantsOnly,
|
|
7284
8250
|
"files-domain-constants": filesDomainConstants,
|
|
@@ -7320,6 +8286,7 @@ var src_default = eslintCompatPlugin({
|
|
|
7320
8286
|
"tests-modifiers": testsModifiers,
|
|
7321
8287
|
"tests-titles": testsTitles,
|
|
7322
8288
|
"types-declarations": typesDeclarations,
|
|
8289
|
+
"types-duplicate": typesDuplicate,
|
|
7323
8290
|
"types-imported-alias": typesImportedAlias,
|
|
7324
8291
|
"types-inline": typesInline,
|
|
7325
8292
|
"types-local-alias": typesLocalAlias,
|