oxlint-plugin-arch 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/README.md +79 -4
- package/dist/constants/test.constants.d.ts +1 -0
- package/dist/index.js +205 -83
- package/dist/presets/index.d.ts +1 -1
- package/dist/presets/index.js +57 -31
- package/dist/presets/tanstack-start-react-modules-preset.js +57 -31
- package/dist/rules/module-policy/index.js +321 -11
- package/dist/types/preset.types.d.ts +8 -0
- package/package.json +1 -1
|
@@ -1211,7 +1211,13 @@ import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
|
1211
1211
|
var testModifiers = defineRule5({
|
|
1212
1212
|
meta: {
|
|
1213
1213
|
type: "problem",
|
|
1214
|
-
schema: [
|
|
1214
|
+
schema: [
|
|
1215
|
+
{
|
|
1216
|
+
type: "object",
|
|
1217
|
+
additionalProperties: false,
|
|
1218
|
+
properties: { additionalTestFunctions: { type: "array", items: { type: "string" } } }
|
|
1219
|
+
}
|
|
1220
|
+
],
|
|
1215
1221
|
messages: {
|
|
1216
1222
|
modifier: "Focused, skipped and placeholder tests are not allowed."
|
|
1217
1223
|
}
|
|
@@ -1220,7 +1226,13 @@ var testModifiers = defineRule5({
|
|
|
1220
1226
|
let names = new Set;
|
|
1221
1227
|
return {
|
|
1222
1228
|
before() {
|
|
1223
|
-
names = new Set([
|
|
1229
|
+
names = new Set([
|
|
1230
|
+
"test",
|
|
1231
|
+
"it",
|
|
1232
|
+
"describe",
|
|
1233
|
+
"suite",
|
|
1234
|
+
...optionsFirst(context, {}).additionalTestFunctions ?? []
|
|
1235
|
+
]);
|
|
1224
1236
|
},
|
|
1225
1237
|
ImportDeclaration(node) {
|
|
1226
1238
|
if (!["vitest", "bun:test", "@playwright/test", "@jest/globals"].includes(node.source.value)) {
|
|
@@ -1242,7 +1254,7 @@ var testModifiers = defineRule5({
|
|
|
1242
1254
|
return;
|
|
1243
1255
|
}
|
|
1244
1256
|
const parts = name.split(".");
|
|
1245
|
-
if (names.
|
|
1257
|
+
if ([...names].some((test) => name.startsWith(test + ".")) && ["only", "skip", "todo"].includes(parts.at(-1) ?? "")) {
|
|
1246
1258
|
context.report({ node, messageId: "modifier" });
|
|
1247
1259
|
}
|
|
1248
1260
|
}
|
|
@@ -1250,9 +1262,306 @@ var testModifiers = defineRule5({
|
|
|
1250
1262
|
}
|
|
1251
1263
|
});
|
|
1252
1264
|
|
|
1253
|
-
// src/rules/module-policy/
|
|
1265
|
+
// src/rules/module-policy/test-assertions.ts
|
|
1254
1266
|
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
1255
|
-
|
|
1267
|
+
|
|
1268
|
+
// src/constants/test.constants.ts
|
|
1269
|
+
var testAssertionFunctions = [
|
|
1270
|
+
"expect",
|
|
1271
|
+
"expect.poll",
|
|
1272
|
+
"expect.soft",
|
|
1273
|
+
"expect.assert",
|
|
1274
|
+
"expect.assertions",
|
|
1275
|
+
"expect.hasAssertions",
|
|
1276
|
+
"expectTypeOf",
|
|
1277
|
+
"assert",
|
|
1278
|
+
"assertType"
|
|
1279
|
+
];
|
|
1280
|
+
|
|
1281
|
+
// src/utils/helpers/test-tables.ts
|
|
1282
|
+
function testTablesRegistration(call, names, functions) {
|
|
1283
|
+
let callee = call.callee;
|
|
1284
|
+
let table;
|
|
1285
|
+
if (callee.type === "CallExpression") {
|
|
1286
|
+
const builder = astDottedName(callee.callee);
|
|
1287
|
+
if (builder?.endsWith(".for") || builder?.endsWith(".each")) {
|
|
1288
|
+
const argument = callee.arguments[0];
|
|
1289
|
+
if (argument && argument.type !== "SpreadElement")
|
|
1290
|
+
table = argument;
|
|
1291
|
+
}
|
|
1292
|
+
callee = callee.callee;
|
|
1293
|
+
}
|
|
1294
|
+
if (callee.type === "TaggedTemplateExpression")
|
|
1295
|
+
callee = callee.tag;
|
|
1296
|
+
const name = astDottedName(callee);
|
|
1297
|
+
if (!name || !names.some((test) => name === test || name.startsWith(test + ".") && name.slice(test.length + 1).split(".").every((part) => ["for", "each", "concurrent", "sequential", "only", "skip"].includes(part))))
|
|
1298
|
+
return;
|
|
1299
|
+
const argument = call.arguments.at(-1);
|
|
1300
|
+
const callback = argument?.type === "Identifier" ? functions.get(argument) : argument;
|
|
1301
|
+
if (callback?.type === "FunctionDeclaration" || callback?.type === "FunctionExpression" || callback?.type === "ArrowFunctionExpression") {
|
|
1302
|
+
return { call, callback, table };
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
function testTablesResolve(expression, values) {
|
|
1306
|
+
const seen = new Set;
|
|
1307
|
+
let value = trivialUnwrap(expression);
|
|
1308
|
+
while (values.has(value) && !seen.has(value)) {
|
|
1309
|
+
seen.add(value);
|
|
1310
|
+
value = trivialUnwrap(values.get(value));
|
|
1311
|
+
}
|
|
1312
|
+
return value;
|
|
1313
|
+
}
|
|
1314
|
+
function testTablesRows(registration, sourceCode, values, functions) {
|
|
1315
|
+
if (!registration.table)
|
|
1316
|
+
return;
|
|
1317
|
+
const table = testTablesResolve(registration.table, values);
|
|
1318
|
+
if (table.type !== "ArrayExpression")
|
|
1319
|
+
return;
|
|
1320
|
+
const parameter = registration.callback.params[0];
|
|
1321
|
+
const variables = sourceCode.getDeclaredVariables(registration.callback);
|
|
1322
|
+
return table.elements.map((element) => {
|
|
1323
|
+
const row = { bindings: new Map, callbacks: [] };
|
|
1324
|
+
if (!element || element.type === "SpreadElement")
|
|
1325
|
+
return row;
|
|
1326
|
+
const value = testTablesResolve(element, values);
|
|
1327
|
+
if (value.type !== "ObjectExpression" || value.properties.some((property) => property.type === "SpreadElement" || property.computed))
|
|
1328
|
+
return row;
|
|
1329
|
+
const properties = new Map;
|
|
1330
|
+
for (const property of value.properties) {
|
|
1331
|
+
if (property.type !== "Property" || property.kind !== "init")
|
|
1332
|
+
continue;
|
|
1333
|
+
const key = property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? String(property.key.value) : undefined;
|
|
1334
|
+
if (!key)
|
|
1335
|
+
continue;
|
|
1336
|
+
properties.delete(key);
|
|
1337
|
+
const expression = property.value;
|
|
1338
|
+
const fn = functions.get(expression) ?? expression;
|
|
1339
|
+
if (fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression" || fn.type === "ArrowFunctionExpression")
|
|
1340
|
+
properties.set(key, fn);
|
|
1341
|
+
}
|
|
1342
|
+
row.callbacks.push(...properties.values());
|
|
1343
|
+
if (parameter?.type === "ObjectPattern") {
|
|
1344
|
+
for (const property of parameter.properties) {
|
|
1345
|
+
if (property.type !== "Property" || property.computed || property.value.type !== "Identifier")
|
|
1346
|
+
continue;
|
|
1347
|
+
const key = property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? String(property.key.value) : "";
|
|
1348
|
+
const fn = properties.get(key);
|
|
1349
|
+
if (!fn)
|
|
1350
|
+
continue;
|
|
1351
|
+
const variable = variables.find((entry) => entry.identifiers.some((identifier) => identifier === property.value));
|
|
1352
|
+
for (const reference of variable?.references ?? [])
|
|
1353
|
+
row.bindings.set(reference.identifier, fn);
|
|
1354
|
+
}
|
|
1355
|
+
} else if (parameter?.type === "Identifier") {
|
|
1356
|
+
const variable = variables.find((entry) => entry.identifiers.includes(parameter));
|
|
1357
|
+
for (const reference of variable?.references ?? []) {
|
|
1358
|
+
const member = reference.identifier.parent;
|
|
1359
|
+
if (member.type !== "MemberExpression" || member.object !== reference.identifier || member.computed || member.property.type !== "Identifier")
|
|
1360
|
+
continue;
|
|
1361
|
+
const fn = properties.get(member.property.name);
|
|
1362
|
+
if (fn)
|
|
1363
|
+
row.bindings.set(member, fn);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
return row;
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
function testTablesCallName(node) {
|
|
1370
|
+
if (node.type === "CallExpression")
|
|
1371
|
+
return testTablesCallName(node.callee);
|
|
1372
|
+
if (node.type === "Identifier")
|
|
1373
|
+
return node.name;
|
|
1374
|
+
if (node.type !== "MemberExpression" || node.computed || node.property.type !== "Identifier")
|
|
1375
|
+
return;
|
|
1376
|
+
const parent = testTablesCallName(node.object);
|
|
1377
|
+
return parent ? `${parent}.${node.property.name}` : undefined;
|
|
1378
|
+
}
|
|
1379
|
+
function testTablesAssertionPattern(name) {
|
|
1380
|
+
const parts = name.split(".");
|
|
1381
|
+
const pattern = parts.map((part, index) => {
|
|
1382
|
+
if (part === "**")
|
|
1383
|
+
return "(?:\\.[^.]+)*";
|
|
1384
|
+
return (index ? "\\." : "") + part.replaceAll("$", "\\$").replaceAll("*", "[^.]*");
|
|
1385
|
+
}).join("");
|
|
1386
|
+
return new RegExp(`^${pattern}$`);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// src/rules/module-policy/test-assertions.ts
|
|
1390
|
+
var testAssertions = defineRule6({
|
|
1391
|
+
meta: {
|
|
1392
|
+
type: "problem",
|
|
1393
|
+
schema: [
|
|
1394
|
+
{
|
|
1395
|
+
type: "object",
|
|
1396
|
+
additionalProperties: false,
|
|
1397
|
+
properties: {
|
|
1398
|
+
additionalTestFunctions: { type: "array", items: { type: "string" } },
|
|
1399
|
+
additionalAssertionFunctions: { type: "array", items: { type: "string" } }
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
],
|
|
1403
|
+
messages: {
|
|
1404
|
+
missing: "This test has no recognized assertion in every case. Assert the result directly or call its assertion helper. Register imported assertion helpers only after verifying that they fail on incorrect results.",
|
|
1405
|
+
standalone: "Put this assertion inside a test or an assertion helper. Table-row assertion callbacks must belong to a registered test."
|
|
1406
|
+
}
|
|
1407
|
+
},
|
|
1408
|
+
createOnce(context) {
|
|
1409
|
+
return {
|
|
1410
|
+
"Program:exit"(program) {
|
|
1411
|
+
const options = optionsFirst(context, {});
|
|
1412
|
+
const tests = ["test", "it", ...options.additionalTestFunctions ?? []];
|
|
1413
|
+
const functions = new Map;
|
|
1414
|
+
const values = new Map;
|
|
1415
|
+
const patterns = [
|
|
1416
|
+
...testAssertionFunctions,
|
|
1417
|
+
"assert.*",
|
|
1418
|
+
...options.additionalAssertionFunctions ?? []
|
|
1419
|
+
].map(testTablesAssertionPattern);
|
|
1420
|
+
const aliases = new Map;
|
|
1421
|
+
const shadowed = new Set;
|
|
1422
|
+
const calls = [];
|
|
1423
|
+
const allowed = new Set;
|
|
1424
|
+
const assertionRoots = new Set([...testAssertionFunctions, ...options.additionalAssertionFunctions ?? []].map((name) => name.split(".")[0]));
|
|
1425
|
+
astVisit(program, [], (node) => {
|
|
1426
|
+
if (node.type === "CallExpression")
|
|
1427
|
+
calls.push(node);
|
|
1428
|
+
if (![
|
|
1429
|
+
"VariableDeclarator",
|
|
1430
|
+
"FunctionDeclaration",
|
|
1431
|
+
"FunctionExpression",
|
|
1432
|
+
"ArrowFunctionExpression",
|
|
1433
|
+
"ImportDeclaration"
|
|
1434
|
+
].includes(node.type))
|
|
1435
|
+
return;
|
|
1436
|
+
for (const variable of context.sourceCode.getDeclaredVariables(node)) {
|
|
1437
|
+
const native = node.type === "ImportDeclaration" && ["vitest", "@jest/globals", "@playwright/test"].includes(node.source.value);
|
|
1438
|
+
if (assertionRoots.has(variable.name) && node.type !== "ImportDeclaration") {
|
|
1439
|
+
for (const reference of variable.references)
|
|
1440
|
+
shadowed.add(reference.identifier);
|
|
1441
|
+
}
|
|
1442
|
+
if (native && node.type === "ImportDeclaration") {
|
|
1443
|
+
const specifier = node.specifiers.find((entry) => entry.local.name === variable.name);
|
|
1444
|
+
if (specifier?.type === "ImportSpecifier") {
|
|
1445
|
+
const imported = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
1446
|
+
if (["test", "it"].includes(imported))
|
|
1447
|
+
tests.push(variable.name);
|
|
1448
|
+
if (assertionRoots.has(imported)) {
|
|
1449
|
+
for (const reference of variable.references)
|
|
1450
|
+
aliases.set(reference.identifier, imported);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
const fn = node.type === "FunctionDeclaration" ? node : node.type === "VariableDeclarator" ? node.init : undefined;
|
|
1455
|
+
if (fn?.type === "FunctionDeclaration" || fn?.type === "FunctionExpression" || fn?.type === "ArrowFunctionExpression") {
|
|
1456
|
+
for (const reference of variable.references)
|
|
1457
|
+
functions.set(reference.identifier, fn);
|
|
1458
|
+
allowed.add(fn);
|
|
1459
|
+
}
|
|
1460
|
+
if (node.type === "VariableDeclarator" && node.init && node.parent.type === "VariableDeclaration" && node.parent.kind === "const") {
|
|
1461
|
+
for (const reference of variable.references)
|
|
1462
|
+
values.set(reference.identifier, node.init);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
function assertionName(call) {
|
|
1467
|
+
let root = call.callee;
|
|
1468
|
+
while (root.type === "MemberExpression" || root.type === "CallExpression")
|
|
1469
|
+
root = root.type === "MemberExpression" ? root.object : root.callee;
|
|
1470
|
+
if (shadowed.has(root))
|
|
1471
|
+
return;
|
|
1472
|
+
const name = testTablesCallName(call.callee);
|
|
1473
|
+
const alias = aliases.get(root);
|
|
1474
|
+
return alias && name && root.type === "Identifier" ? alias + name.slice(root.name.length) : name;
|
|
1475
|
+
}
|
|
1476
|
+
function hasAssertion(fn, bindings, seen) {
|
|
1477
|
+
if (seen.has(fn))
|
|
1478
|
+
return false;
|
|
1479
|
+
seen.add(fn);
|
|
1480
|
+
let found = false;
|
|
1481
|
+
astVisit(fn.body, [], (node, ancestors) => {
|
|
1482
|
+
if (found || node.type !== "CallExpression")
|
|
1483
|
+
return;
|
|
1484
|
+
if (ancestors.some((ancestor) => ancestor.type === "FunctionDeclaration" || (ancestor.type === "FunctionExpression" || ancestor.type === "ArrowFunctionExpression") && ancestor.parent.type !== "CallExpression"))
|
|
1485
|
+
return;
|
|
1486
|
+
const name = assertionName(node);
|
|
1487
|
+
if (name && patterns.some((pattern) => pattern.test(name)))
|
|
1488
|
+
found = true;
|
|
1489
|
+
else {
|
|
1490
|
+
const helper = bindings.get(node.callee) ?? functions.get(node.callee);
|
|
1491
|
+
if (helper)
|
|
1492
|
+
found = hasAssertion(helper, bindings, seen);
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
return found;
|
|
1496
|
+
}
|
|
1497
|
+
for (const call of calls) {
|
|
1498
|
+
const name = testTablesCallName(call.callee);
|
|
1499
|
+
const argument = call.arguments[0];
|
|
1500
|
+
if (tests.some((test) => name === test + ".extend") && argument && argument.type !== "SpreadElement") {
|
|
1501
|
+
const fixtures = testTablesResolve(argument, values);
|
|
1502
|
+
if (fixtures.type === "ObjectExpression") {
|
|
1503
|
+
for (const property of fixtures.properties) {
|
|
1504
|
+
if (property.type !== "Property")
|
|
1505
|
+
continue;
|
|
1506
|
+
let value = property.value;
|
|
1507
|
+
if (value.type === "ArrayExpression" && value.elements[0])
|
|
1508
|
+
value = value.elements[0];
|
|
1509
|
+
const fn = functions.get(value) ?? value;
|
|
1510
|
+
if (fn.type === "FunctionExpression" || fn.type === "ArrowFunctionExpression" || fn.type === "FunctionDeclaration")
|
|
1511
|
+
allowed.add(fn);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
const registration = testTablesRegistration(call, tests, functions);
|
|
1516
|
+
if (!registration)
|
|
1517
|
+
continue;
|
|
1518
|
+
allowed.add(registration.callback);
|
|
1519
|
+
const builder = call.callee.type === "CallExpression" ? testTablesCallName(call.callee.callee) : undefined;
|
|
1520
|
+
const parameter = registration.callback.params[builder?.endsWith(".for") ? 1 : 0];
|
|
1521
|
+
if (!builder?.endsWith(".each") && parameter?.type === "ObjectPattern") {
|
|
1522
|
+
const variables = context.sourceCode.getDeclaredVariables(registration.callback);
|
|
1523
|
+
for (const property of parameter.properties) {
|
|
1524
|
+
if (property.type !== "Property" || property.computed || property.key.type !== "Identifier" || property.key.name !== "expect" || property.value.type !== "Identifier")
|
|
1525
|
+
continue;
|
|
1526
|
+
const variable = variables.find((entry) => entry.identifiers.some((identifier) => identifier === property.value));
|
|
1527
|
+
for (const reference of variable?.references ?? []) {
|
|
1528
|
+
shadowed.delete(reference.identifier);
|
|
1529
|
+
aliases.set(reference.identifier, "expect");
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const rows = testTablesRows(registration, context.sourceCode, values, functions);
|
|
1534
|
+
for (const row of rows ?? [])
|
|
1535
|
+
for (const callback of row.callbacks)
|
|
1536
|
+
allowed.add(callback);
|
|
1537
|
+
const valid = rows ? rows.length > 0 && rows.every((row) => hasAssertion(registration.callback, row.bindings, new Set)) : hasAssertion(registration.callback, new Map, new Set);
|
|
1538
|
+
if (!valid)
|
|
1539
|
+
context.report({ node: call, messageId: "missing" });
|
|
1540
|
+
}
|
|
1541
|
+
for (const call of calls) {
|
|
1542
|
+
const name = assertionName(call);
|
|
1543
|
+
if (!name || !testAssertionFunctions.includes(name) || !name.startsWith("expect"))
|
|
1544
|
+
continue;
|
|
1545
|
+
let parent = call.parent;
|
|
1546
|
+
let inside = false;
|
|
1547
|
+
while (parent && parent.type !== "Program") {
|
|
1548
|
+
if ((parent.type === "FunctionDeclaration" || parent.type === "FunctionExpression" || parent.type === "ArrowFunctionExpression") && allowed.has(parent)) {
|
|
1549
|
+
inside = true;
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1552
|
+
parent = parent.parent;
|
|
1553
|
+
}
|
|
1554
|
+
if (!inside)
|
|
1555
|
+
context.report({ node: call, messageId: "standalone" });
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
// src/rules/module-policy/reasoned-directives.ts
|
|
1563
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1564
|
+
var directives = defineRule7({
|
|
1256
1565
|
meta: {
|
|
1257
1566
|
type: "problem",
|
|
1258
1567
|
schema: [],
|
|
@@ -1281,8 +1590,8 @@ var directives = defineRule6({
|
|
|
1281
1590
|
|
|
1282
1591
|
// src/rules/module-policy/tanstack-runtime.ts
|
|
1283
1592
|
import { builtinModules } from "node:module";
|
|
1284
|
-
import { defineRule as
|
|
1285
|
-
var tanstackRuntime =
|
|
1593
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
1594
|
+
var tanstackRuntime = defineRule8({
|
|
1286
1595
|
meta: {
|
|
1287
1596
|
type: "problem",
|
|
1288
1597
|
schema: [
|
|
@@ -1536,9 +1845,9 @@ var tanstackRuntime = defineRule7({
|
|
|
1536
1845
|
});
|
|
1537
1846
|
|
|
1538
1847
|
// src/rules/module-policy/import-boundaries.ts
|
|
1539
|
-
import { defineRule as
|
|
1848
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1540
1849
|
import { resolve as resolve2, basename as basename2 } from "node:path";
|
|
1541
|
-
var importBoundaries =
|
|
1850
|
+
var importBoundaries = defineRule9({
|
|
1542
1851
|
meta: {
|
|
1543
1852
|
type: "problem",
|
|
1544
1853
|
schema: [
|
|
@@ -1674,8 +1983,8 @@ var importBoundaries = defineRule8({
|
|
|
1674
1983
|
});
|
|
1675
1984
|
|
|
1676
1985
|
// src/rules/module-policy/memoization.ts
|
|
1677
|
-
import { defineRule as
|
|
1678
|
-
var memoization =
|
|
1986
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1987
|
+
var memoization = defineRule10({
|
|
1679
1988
|
meta: {
|
|
1680
1989
|
type: "problem",
|
|
1681
1990
|
schema: [],
|
|
@@ -1718,6 +2027,7 @@ var memoization = defineRule9({
|
|
|
1718
2027
|
var module_policy_default = eslintCompatPlugin({
|
|
1719
2028
|
meta: { name: "modules" },
|
|
1720
2029
|
rules: {
|
|
2030
|
+
"test-assertions": testAssertions,
|
|
1721
2031
|
"dynamic-classes": syntaxRule(':matches(JSXAttribute[name.name="className"] TemplateLiteral[expressions.length>0], JSXAttribute[name.name="className"] BinaryExpression[operator="+"])', "Write complete class names instead of constructing them dynamically."),
|
|
1722
2032
|
"backend-switch": syntaxRule("SwitchStatement", "Use ts-pattern in backend application code."),
|
|
1723
2033
|
"concurrent-db": syntaxRule('CallExpression[callee.object.name="test"][callee.property.name="concurrent"] ObjectPattern > Property[key.name="db"]', "Obtain an isolated database fixture for concurrent tests."),
|
|
@@ -28,6 +28,7 @@ export interface PresetOptions {
|
|
|
28
28
|
sql?: PresetSqlOptions;
|
|
29
29
|
forms?: PresetFormsOptions;
|
|
30
30
|
react?: PresetReactOptions;
|
|
31
|
+
tests?: PresetTestsOptions;
|
|
31
32
|
policies?: PresetPolicyOptions;
|
|
32
33
|
ignorePatterns?: string[];
|
|
33
34
|
ruleExclusions?: Record<string, string[]>;
|
|
@@ -44,6 +45,12 @@ export interface PresetLimitsOptions {
|
|
|
44
45
|
}
|
|
45
46
|
export interface PresetModulesOptions {
|
|
46
47
|
customFileRoles?: string[];
|
|
48
|
+
migrationFiles?: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface PresetTestsOptions {
|
|
51
|
+
profile?: 'standard' | 'fixtures';
|
|
52
|
+
additionalTestFunctions?: string[];
|
|
53
|
+
additionalAssertionFunctions?: string[];
|
|
47
54
|
}
|
|
48
55
|
export interface PresetImportsOptions {
|
|
49
56
|
backendEntryPoints?: string[];
|
|
@@ -63,6 +70,7 @@ export interface PresetFormsOptions {
|
|
|
63
70
|
}
|
|
64
71
|
export interface PresetReactOptions {
|
|
65
72
|
compiler?: boolean;
|
|
73
|
+
componentProps?: boolean;
|
|
66
74
|
}
|
|
67
75
|
export interface PresetTanstackStartOptions {
|
|
68
76
|
additionalServerOnlyImports?: string[];
|