oxlint-plugin-arch 0.3.4 → 0.5.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 +48 -0
- package/README.md +232 -10
- package/dist/configs/boundaries.d.ts +2 -0
- package/dist/configs/modules.d.ts +2 -0
- package/dist/configs/plugins.d.ts +3 -0
- package/dist/configs/react.d.ts +2 -0
- package/dist/configs/source.d.ts +2 -0
- package/dist/configs/tests.d.ts +2 -0
- package/dist/configs/types.d.ts +2 -0
- package/dist/constants/preset.constants.d.ts +28 -0
- package/dist/index.js +1182 -633
- package/dist/presets/index.d.ts +2 -0
- package/dist/presets/index.js +1354 -0
- package/dist/presets/tanstack-start-react-modules-preset.d.ts +3 -0
- package/dist/presets/tanstack-start-react-modules-preset.js +1354 -0
- package/dist/rules/dillon-anti-slop/index.js +1588 -0
- package/dist/rules/module-policy/index.js +1743 -0
- package/dist/services/preset-compose.d.ts +3 -0
- package/dist/services/preset-context.d.ts +2 -0
- package/dist/types/preset.types.d.ts +119 -0
- package/dist/utils/helpers/preset.d.ts +6 -0
- package/package.json +45 -10
- package/src/rules/dillon-anti-slop/LICENSE +21 -0
- package/src/rules/dillon-anti-slop/UPSTREAM.md +19 -0
package/dist/index.js
CHANGED
|
@@ -5,16 +5,7 @@ import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
|
5
5
|
import { defineRule } from "@oxlint/plugins";
|
|
6
6
|
|
|
7
7
|
// src/utils/helpers/ast.ts
|
|
8
|
-
var astVisitSkip = new Set([
|
|
9
|
-
"parent",
|
|
10
|
-
"type",
|
|
11
|
-
"start",
|
|
12
|
-
"end",
|
|
13
|
-
"range",
|
|
14
|
-
"loc",
|
|
15
|
-
"tokens",
|
|
16
|
-
"comments"
|
|
17
|
-
]);
|
|
8
|
+
var astVisitSkip = new Set(["parent", "type", "start", "end", "range", "loc", "tokens", "comments"]);
|
|
18
9
|
function astIsNode(value) {
|
|
19
10
|
return value !== null && typeof value === "object" && typeof Reflect.get(value, "type") === "string";
|
|
20
11
|
}
|
|
@@ -103,6 +94,75 @@ function astResolvedCallName(node, aliases) {
|
|
|
103
94
|
const name = astCallName(node);
|
|
104
95
|
return name ? aliases.get(name) ?? name : undefined;
|
|
105
96
|
}
|
|
97
|
+
// src/utils/helpers/comments.ts
|
|
98
|
+
var COMMENTS_DIRECTIVE = /^\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])/;
|
|
99
|
+
var COMMENTS_DISABLE_NEXT_LINE = /^(?:eslint|oxlint)-disable-next-line\b/;
|
|
100
|
+
var COMMENTS_LEGAL_BLOCK = "\x00legal-block\x00";
|
|
101
|
+
function commentsNormalizedValue(comment) {
|
|
102
|
+
const value = (comment.type === "Block" ? comment.value.replace(/^\s*\* ?/gm, "") : comment.value).trimStart();
|
|
103
|
+
return comment.type === "Block" && comment.value.startsWith("!") ? COMMENTS_LEGAL_BLOCK + value : value;
|
|
104
|
+
}
|
|
105
|
+
function commentsIsDirective(value) {
|
|
106
|
+
return value.startsWith(COMMENTS_LEGAL_BLOCK) || COMMENTS_DIRECTIVE.test(value);
|
|
107
|
+
}
|
|
108
|
+
function commentsIsDisableNextLine(value) {
|
|
109
|
+
return COMMENTS_DISABLE_NEXT_LINE.test(value);
|
|
110
|
+
}
|
|
111
|
+
function commentsIsWhy(value) {
|
|
112
|
+
return value.startsWith("Why: ");
|
|
113
|
+
}
|
|
114
|
+
function commentsIsJsdoc(source, comment) {
|
|
115
|
+
return comment.type === "Block" && source.startsWith("/**", comment.range[0]);
|
|
116
|
+
}
|
|
117
|
+
// src/utils/helpers/trivial.ts
|
|
118
|
+
function trivialExpression(node) {
|
|
119
|
+
if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
|
|
120
|
+
return node.body;
|
|
121
|
+
}
|
|
122
|
+
if (!node.body || node.body.type !== "BlockStatement")
|
|
123
|
+
return null;
|
|
124
|
+
const statements = node.body.body.filter((statement) => statement.type !== "EmptyStatement" && !(statement.type === "ExpressionStatement" && statement.directive));
|
|
125
|
+
if (statements.length !== 1)
|
|
126
|
+
return null;
|
|
127
|
+
const statement = statements[0];
|
|
128
|
+
if (statement.type === "ReturnStatement")
|
|
129
|
+
return statement.argument;
|
|
130
|
+
return statement.type === "ExpressionStatement" ? statement.expression : null;
|
|
131
|
+
}
|
|
132
|
+
function trivialUnwrap(expression) {
|
|
133
|
+
if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "ChainExpression") {
|
|
134
|
+
return trivialUnwrap(expression.expression);
|
|
135
|
+
}
|
|
136
|
+
return expression.type === "AwaitExpression" ? trivialUnwrap(expression.argument) : expression;
|
|
137
|
+
}
|
|
138
|
+
function trivialCallRoot(expression) {
|
|
139
|
+
if (expression.type === "Identifier")
|
|
140
|
+
return expression.name;
|
|
141
|
+
if (expression.type === "MemberExpression" && !expression.computed && !expression.optional) {
|
|
142
|
+
return trivialCallRoot(expression.object);
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
function trivialIsForwarder(node, expression) {
|
|
147
|
+
const value = trivialUnwrap(expression);
|
|
148
|
+
if (value.type === "Literal")
|
|
149
|
+
return !("regex" in value);
|
|
150
|
+
if (value.type === "TemplateLiteral")
|
|
151
|
+
return value.expressions.length === 0;
|
|
152
|
+
if (value.type === "Identifier")
|
|
153
|
+
return true;
|
|
154
|
+
if (value.type !== "CallExpression" || value.optional)
|
|
155
|
+
return false;
|
|
156
|
+
const root = trivialCallRoot(value.callee);
|
|
157
|
+
if (!root || node.params.some((param) => param.type !== "Identifier"))
|
|
158
|
+
return false;
|
|
159
|
+
const parameters = node.params.flatMap((param) => param.type === "Identifier" ? [param.name] : []);
|
|
160
|
+
const arguments_ = value.arguments;
|
|
161
|
+
const receiver = value.callee.type === "MemberExpression" ? root : undefined;
|
|
162
|
+
const forwarded = parameters.filter((name) => name !== receiver);
|
|
163
|
+
return arguments_.length === forwarded.length && arguments_.every((argument, index) => argument.type === "Identifier" && argument.name === forwarded[index]);
|
|
164
|
+
}
|
|
165
|
+
|
|
106
166
|
// src/utils/helpers/declarations.ts
|
|
107
167
|
function declarationsTopLevelUnexportedFunctions(program) {
|
|
108
168
|
return program.body.flatMap((statement) => {
|
|
@@ -284,6 +344,21 @@ function declarationsCollectFunctions(root) {
|
|
|
284
344
|
return [];
|
|
285
345
|
});
|
|
286
346
|
}
|
|
347
|
+
function declarationsPublicServiceMethods(program) {
|
|
348
|
+
return program.body.flatMap((statement) => {
|
|
349
|
+
if (statement.type !== "ExportNamedDeclaration" || statement.declaration?.type !== "VariableDeclaration" || statement.declaration.kind !== "const")
|
|
350
|
+
return [];
|
|
351
|
+
return statement.declaration.declarations.flatMap((binding) => {
|
|
352
|
+
if (binding.id.type !== "Identifier" || !binding.init)
|
|
353
|
+
return [];
|
|
354
|
+
const value = trivialUnwrap(binding.init);
|
|
355
|
+
if (value.type !== "ObjectExpression" || value.properties.length === 0)
|
|
356
|
+
return [];
|
|
357
|
+
const methods = value.properties.flatMap((property) => property.type === "Property" && property.method && property.kind === "init" && !property.computed && property.key.type === "Identifier" && property.value.type === "FunctionExpression" ? [{ name: property.key.name, node: property.value, binding }] : []);
|
|
358
|
+
return methods.length === value.properties.length ? methods : [];
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
}
|
|
287
362
|
// src/utils/helpers/exports.ts
|
|
288
363
|
function moduleExportName(node) {
|
|
289
364
|
return node.type === "Identifier" ? node.name : node.value;
|
|
@@ -305,15 +380,17 @@ function declarationBindings(declaration) {
|
|
|
305
380
|
}));
|
|
306
381
|
}
|
|
307
382
|
const name = declaration.id?.name ?? "<anonymous>";
|
|
308
|
-
return [
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
383
|
+
return [
|
|
384
|
+
{
|
|
385
|
+
exportedName: name,
|
|
386
|
+
localName: declaration.id?.name,
|
|
387
|
+
node: declaration,
|
|
388
|
+
declaration,
|
|
389
|
+
typeOnly: declaration.type === "TSInterfaceDeclaration" || declaration.type === "TSTypeAliasDeclaration" || declaration.type === "TSDeclareFunction",
|
|
390
|
+
default: false,
|
|
391
|
+
reExport: false
|
|
392
|
+
}
|
|
393
|
+
];
|
|
317
394
|
}
|
|
318
395
|
function localBindings(program) {
|
|
319
396
|
const result = new Map;
|
|
@@ -335,29 +412,33 @@ function exportsCollect(program) {
|
|
|
335
412
|
const locals = localBindings(program);
|
|
336
413
|
return program.body.flatMap((statement) => {
|
|
337
414
|
if (statement.type === "ExportAllDeclaration") {
|
|
338
|
-
return [
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
415
|
+
return [
|
|
416
|
+
{
|
|
417
|
+
exportedName: "*",
|
|
418
|
+
node: statement,
|
|
419
|
+
typeOnly: statement.exportKind === "type",
|
|
420
|
+
default: false,
|
|
421
|
+
reExport: true
|
|
422
|
+
}
|
|
423
|
+
];
|
|
345
424
|
}
|
|
346
425
|
if (statement.type === "ExportDefaultDeclaration") {
|
|
347
426
|
if (statement.declaration.type === "Identifier") {
|
|
348
427
|
const local = locals.get(statement.declaration.name);
|
|
349
|
-
return [
|
|
350
|
-
|
|
428
|
+
return [
|
|
429
|
+
{
|
|
430
|
+
...local ?? {
|
|
431
|
+
exportedName: "default",
|
|
432
|
+
node: statement,
|
|
433
|
+
typeOnly: false,
|
|
434
|
+
default: true,
|
|
435
|
+
reExport: false
|
|
436
|
+
},
|
|
351
437
|
exportedName: "default",
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
},
|
|
357
|
-
exportedName: "default",
|
|
358
|
-
localName: local?.localName ?? statement.declaration.name,
|
|
359
|
-
default: true
|
|
360
|
-
}];
|
|
438
|
+
localName: local?.localName ?? statement.declaration.name,
|
|
439
|
+
default: true
|
|
440
|
+
}
|
|
441
|
+
];
|
|
361
442
|
}
|
|
362
443
|
if (statement.declaration.type.endsWith("Declaration")) {
|
|
363
444
|
const bindings = declarationBindings(statement.declaration);
|
|
@@ -464,7 +545,7 @@ function namingMatchTemplate(basename, template, placeholderPattern = "[a-z0-9-]
|
|
|
464
545
|
}
|
|
465
546
|
var namingStemModes = ["before-first-dot", "full-basename"];
|
|
466
547
|
function namingNormalized(value, normalize) {
|
|
467
|
-
return normalize === "none" ? value : value.replaceAll(/[-_]/g, "").toLowerCase();
|
|
548
|
+
return normalize === "none" ? value : value.replaceAll(/[-_.]/g, "").toLowerCase();
|
|
468
549
|
}
|
|
469
550
|
function namingFileStem(basename, mode = "before-first-dot", trailingRoles = [], roleSeparators = [".", "-"]) {
|
|
470
551
|
const stem = mode === "full-basename" ? basename : basename.split(".")[0] ?? "";
|
|
@@ -504,13 +585,16 @@ function namingFilePrefixes(stem, normalize = "remove-separators", singularize =
|
|
|
504
585
|
}
|
|
505
586
|
|
|
506
587
|
// src/utils/helpers/factories.ts
|
|
507
|
-
function factoriesExpandTemplate(template, groups) {
|
|
588
|
+
function factoriesExpandTemplate(template, groups, camelCase = false) {
|
|
508
589
|
return template.replaceAll(/\{([^}]+)\}/g, (placeholder, key) => {
|
|
509
590
|
const group = groups[key.toLowerCase()];
|
|
510
591
|
if (!group) {
|
|
511
592
|
return placeholder;
|
|
512
593
|
}
|
|
513
|
-
|
|
594
|
+
if (/^[A-Z]/.test(key)) {
|
|
595
|
+
return namingPascalCase(group);
|
|
596
|
+
}
|
|
597
|
+
return camelCase ? namingCamelCase(group) : group;
|
|
514
598
|
});
|
|
515
599
|
}
|
|
516
600
|
function factoriesCollectTopLevel(program, pattern) {
|
|
@@ -547,15 +631,130 @@ function factoriesObjectPropertyName(property) {
|
|
|
547
631
|
}
|
|
548
632
|
return property.key.type === "Literal" && typeof property.key.value === "string" ? property.key.value : undefined;
|
|
549
633
|
}
|
|
634
|
+
// src/utils/helpers/guards.ts
|
|
635
|
+
var guardsPrimitiveNames = new Set([
|
|
636
|
+
"string",
|
|
637
|
+
"number",
|
|
638
|
+
"boolean",
|
|
639
|
+
"object",
|
|
640
|
+
"undefined",
|
|
641
|
+
"bigint",
|
|
642
|
+
"symbol",
|
|
643
|
+
"function"
|
|
644
|
+
]);
|
|
645
|
+
function guardsValue(node, state) {
|
|
646
|
+
const value = trivialUnwrap(node);
|
|
647
|
+
if (value.type === "Identifier")
|
|
648
|
+
return state.values.has(value.name);
|
|
649
|
+
return value.type === "MemberExpression" && value.computed && value.object.type === "Identifier" && state.values.has(value.object.name) && value.property.type === "Identifier" && state.values.has(value.property.name);
|
|
650
|
+
}
|
|
651
|
+
function guardsFallback(node) {
|
|
652
|
+
return node.type === "Literal" && !("regex" in node) || node.type === "Identifier" && node.name === "undefined" || node.type === "ArrayExpression" && node.elements.length === 0 || node.type === "ObjectExpression" && node.properties.length === 0;
|
|
653
|
+
}
|
|
654
|
+
function guardsPredicate(expression, state) {
|
|
655
|
+
const node = trivialUnwrap(expression);
|
|
656
|
+
if (node.type === "Identifier")
|
|
657
|
+
return state.predicates.has(node.name);
|
|
658
|
+
if (node.type === "UnaryExpression" && node.operator === "!")
|
|
659
|
+
return guardsPredicate(node.argument, state);
|
|
660
|
+
if (node.type === "LogicalExpression" && (node.operator === "&&" || node.operator === "||")) {
|
|
661
|
+
return guardsPredicate(node.left, state) && guardsPredicate(node.right, state);
|
|
662
|
+
}
|
|
663
|
+
if (node.type === "BinaryExpression" && ["===", "!==", "==", "!="].includes(node.operator)) {
|
|
664
|
+
for (const [left, right] of [
|
|
665
|
+
[node.left, node.right],
|
|
666
|
+
[node.right, node.left]
|
|
667
|
+
]) {
|
|
668
|
+
if (left.type === "UnaryExpression" && left.operator === "typeof" && right.type === "Literal" && typeof right.value === "string" && guardsPrimitiveNames.has(right.value) && guardsValue(left.argument, state)) {
|
|
669
|
+
state.primitive = true;
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
if (left.type !== "PrivateIdentifier" && guardsValue(left, state) && (right.type === "Literal" && right.value === null || right.type === "Identifier" && right.name === "undefined"))
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (node.type === "CallExpression" && !node.optional && node.arguments.length === 1 && node.arguments[0].type !== "SpreadElement" && guardsValue(node.arguments[0], state) && node.callee.type === "MemberExpression" && !node.callee.computed && !node.callee.optional && node.callee.object.type === "Identifier" && node.callee.object.name === "Array" && node.callee.property.type === "Identifier" && node.callee.property.name === "isArray" && state.globalArray(node.callee.object)) {
|
|
677
|
+
state.primitive = true;
|
|
678
|
+
return true;
|
|
679
|
+
}
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
function guardsResult(node, state) {
|
|
683
|
+
const value = trivialUnwrap(node);
|
|
684
|
+
if (guardsValue(value, state) || guardsFallback(value) || guardsPredicate(value, state))
|
|
685
|
+
return true;
|
|
686
|
+
return value.type === "ConditionalExpression" && guardsPredicate(value.test, state) && guardsResult(value.consequent, state) && guardsResult(value.alternate, state);
|
|
687
|
+
}
|
|
688
|
+
function guardsStatement(node, state) {
|
|
689
|
+
if (node.type === "EmptyStatement" || node.type === "ExpressionStatement" && Boolean(node.directive))
|
|
690
|
+
return true;
|
|
691
|
+
if (node.type === "ReturnStatement" && node.argument) {
|
|
692
|
+
state.returned = true;
|
|
693
|
+
return guardsResult(node.argument, state);
|
|
694
|
+
}
|
|
695
|
+
if (node.type === "BlockStatement")
|
|
696
|
+
return node.body.every((statement) => guardsStatement(statement, state));
|
|
697
|
+
if (node.type === "IfStatement") {
|
|
698
|
+
return guardsPredicate(node.test, state) && guardsStatement(node.consequent, state) && (!node.alternate || guardsStatement(node.alternate, state));
|
|
699
|
+
}
|
|
700
|
+
if (node.type === "VariableDeclaration" && node.kind === "const") {
|
|
701
|
+
return node.declarations.every((declaration) => {
|
|
702
|
+
if (declaration.id.type !== "Identifier" || !declaration.init)
|
|
703
|
+
return false;
|
|
704
|
+
if (guardsValue(declaration.init, state)) {
|
|
705
|
+
state.values.add(declaration.id.name);
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
if (guardsPredicate(declaration.init, state)) {
|
|
709
|
+
state.predicates.add(declaration.id.name);
|
|
710
|
+
return true;
|
|
711
|
+
}
|
|
712
|
+
return guardsFallback(declaration.init);
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
function guardsIsGenericHelper(node, globalArray) {
|
|
718
|
+
if (!node.body || node.params.length === 0 || node.params.some((param) => param.type !== "Identifier"))
|
|
719
|
+
return false;
|
|
720
|
+
const state = {
|
|
721
|
+
values: new Set(node.params.flatMap((param) => param.type === "Identifier" ? [param.name] : [])),
|
|
722
|
+
predicates: new Set,
|
|
723
|
+
primitive: false,
|
|
724
|
+
returned: false,
|
|
725
|
+
globalArray
|
|
726
|
+
};
|
|
727
|
+
if (node.body.type !== "BlockStatement")
|
|
728
|
+
return guardsResult(node.body, state) && state.primitive;
|
|
729
|
+
return node.body.body.every((statement) => guardsStatement(statement, state)) && state.primitive && state.returned;
|
|
730
|
+
}
|
|
731
|
+
// src/utils/helpers/layout.ts
|
|
732
|
+
var layoutIndentSchema = {
|
|
733
|
+
anyOf: [
|
|
734
|
+
{ type: "integer", minimum: 0 },
|
|
735
|
+
{ type: "string", enum: ["tab"] }
|
|
736
|
+
]
|
|
737
|
+
};
|
|
738
|
+
function layoutLineIndent(text, offset) {
|
|
739
|
+
const lineStart = text.lastIndexOf(`
|
|
740
|
+
`, offset - 1) + 1;
|
|
741
|
+
return /^[\t ]*/.exec(text.slice(lineStart, offset))?.[0] ?? "";
|
|
742
|
+
}
|
|
743
|
+
function layoutIndentUnit(indent = 2) {
|
|
744
|
+
return indent === "tab" ? "\t" : " ".repeat(indent);
|
|
745
|
+
}
|
|
746
|
+
function layoutNewline(text) {
|
|
747
|
+
return text.includes(`\r
|
|
748
|
+
`) ? `\r
|
|
749
|
+
` : `
|
|
750
|
+
`;
|
|
751
|
+
}
|
|
550
752
|
// src/utils/helpers/options.ts
|
|
551
753
|
function optionsFirst(context, fallback) {
|
|
552
754
|
return context.options[0] ?? fallback;
|
|
553
755
|
}
|
|
554
756
|
var optionsPatternSchema = {
|
|
555
|
-
anyOf: [
|
|
556
|
-
{ type: "string" },
|
|
557
|
-
{ type: "array", items: { type: "string" }, minItems: 1 }
|
|
558
|
-
]
|
|
757
|
+
anyOf: [{ type: "string" }, { type: "array", items: { type: "string" }, minItems: 1 }]
|
|
559
758
|
};
|
|
560
759
|
function optionsPatterns(pattern, flags) {
|
|
561
760
|
return pattern === undefined ? [] : [pattern].flat().map((source) => new RegExp(source, flags));
|
|
@@ -774,46 +973,13 @@ function schemasIsAllowedElement(node, allowScalars, namespaces, structuralMetho
|
|
|
774
973
|
function schemasTypeOperator(node, namespaces, operators) {
|
|
775
974
|
return node.typeName.type === "TSQualifiedName" && node.typeName.left.type === "Identifier" && namespaces.has(node.typeName.left.name) && operators.has(node.typeName.right.name) ? node.typeName.right.name : undefined;
|
|
776
975
|
}
|
|
777
|
-
// src/utils/helpers/
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const
|
|
783
|
-
return
|
|
784
|
-
}
|
|
785
|
-
function commentsIsDirective(value) {
|
|
786
|
-
return value.startsWith(COMMENTS_LEGAL_BLOCK) || COMMENTS_DIRECTIVE.test(value);
|
|
787
|
-
}
|
|
788
|
-
function commentsIsDisableNextLine(value) {
|
|
789
|
-
return COMMENTS_DISABLE_NEXT_LINE.test(value);
|
|
790
|
-
}
|
|
791
|
-
function commentsIsWhy(value) {
|
|
792
|
-
return value.startsWith("Why: ");
|
|
793
|
-
}
|
|
794
|
-
function commentsIsJsdoc(source, comment) {
|
|
795
|
-
return comment.type === "Block" && source.startsWith("/**", comment.range[0]);
|
|
796
|
-
}
|
|
797
|
-
// src/utils/helpers/layout.ts
|
|
798
|
-
var layoutIndentSchema = {
|
|
799
|
-
anyOf: [
|
|
800
|
-
{ type: "integer", minimum: 0 },
|
|
801
|
-
{ type: "string", enum: ["tab"] }
|
|
802
|
-
]
|
|
803
|
-
};
|
|
804
|
-
function layoutLineIndent(text, offset) {
|
|
805
|
-
const lineStart = text.lastIndexOf(`
|
|
806
|
-
`, offset - 1) + 1;
|
|
807
|
-
return /^[\t ]*/.exec(text.slice(lineStart, offset))?.[0] ?? "";
|
|
808
|
-
}
|
|
809
|
-
function layoutIndentUnit(indent = 2) {
|
|
810
|
-
return indent === "tab" ? "\t" : " ".repeat(indent);
|
|
811
|
-
}
|
|
812
|
-
function layoutNewline(text) {
|
|
813
|
-
return text.includes(`\r
|
|
814
|
-
`) ? `\r
|
|
815
|
-
` : `
|
|
816
|
-
`;
|
|
976
|
+
// src/utils/helpers/boundaries.ts
|
|
977
|
+
import { resolve, dirname } from "node:path";
|
|
978
|
+
function boundaryResolveTarget(options, file, source) {
|
|
979
|
+
const owner = [...options.web, ...options.backend].sort((a, b) => b.length - a.length).find((root) => file.startsWith(root + "/"));
|
|
980
|
+
const web = owner && options.web.includes(owner) ? owner : undefined;
|
|
981
|
+
const alias = Object.entries(options.aliases).sort(([a], [b]) => b.length - a.length).find(([prefix]) => source === prefix || source.startsWith(`${prefix}/`));
|
|
982
|
+
return alias ? resolve(alias[1], source.slice(alias[0].length).replace(/^\//, "")).replaceAll("\\", "/") : source.startsWith(".") ? resolve(dirname(file), source).replaceAll("\\", "/") : source.startsWith("@/") && web ? `${web}/${source.slice(2)}` : source.startsWith("#/") && owner ? `${owner}/${source.slice(2)}` : source.startsWith("#services/") && owner ? `${owner}/services/${source.slice(10)}` : source;
|
|
817
983
|
}
|
|
818
984
|
// src/rules/call-array-multiline.ts
|
|
819
985
|
function callArrayMultilineCallee(node) {
|
|
@@ -886,15 +1052,17 @@ var callArrayMultiline = defineRule({
|
|
|
886
1052
|
meta: {
|
|
887
1053
|
type: "layout",
|
|
888
1054
|
fixable: "whitespace",
|
|
889
|
-
schema: [
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1055
|
+
schema: [
|
|
1056
|
+
{
|
|
1057
|
+
type: "object",
|
|
1058
|
+
additionalProperties: false,
|
|
1059
|
+
properties: {
|
|
1060
|
+
callees: { type: "array", items: { type: "string" } },
|
|
1061
|
+
minElements: { type: "integer", minimum: 1 },
|
|
1062
|
+
indent: layoutIndentSchema
|
|
1063
|
+
}
|
|
896
1064
|
}
|
|
897
|
-
|
|
1065
|
+
],
|
|
898
1066
|
messages: {
|
|
899
1067
|
multiline: "Put every array element in this call on its own line."
|
|
900
1068
|
}
|
|
@@ -983,28 +1151,30 @@ var chainNewline = defineRule2({
|
|
|
983
1151
|
meta: {
|
|
984
1152
|
type: "layout",
|
|
985
1153
|
fixable: "whitespace",
|
|
986
|
-
schema: [
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1154
|
+
schema: [
|
|
1155
|
+
{
|
|
1156
|
+
type: "object",
|
|
1157
|
+
additionalProperties: false,
|
|
1158
|
+
properties: {
|
|
1159
|
+
groups: {
|
|
1160
|
+
type: "array",
|
|
1161
|
+
items: {
|
|
1162
|
+
type: "object",
|
|
1163
|
+
additionalProperties: false,
|
|
1164
|
+
properties: {
|
|
1165
|
+
minDepth: { type: "integer", minimum: 1 },
|
|
1166
|
+
methods: { type: "array", items: { type: "string" } },
|
|
1167
|
+
onlyMethods: { type: "array", items: { type: "string" } },
|
|
1168
|
+
rootPattern: optionsPatternSchema
|
|
1169
|
+
},
|
|
1170
|
+
required: ["minDepth"]
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
indent: layoutIndentSchema
|
|
1003
1174
|
},
|
|
1004
|
-
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
}],
|
|
1175
|
+
required: ["groups"]
|
|
1176
|
+
}
|
|
1177
|
+
],
|
|
1008
1178
|
messages: {
|
|
1009
1179
|
newline: "Put every method in this call chain on its own line."
|
|
1010
1180
|
}
|
|
@@ -1087,24 +1257,26 @@ import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
|
1087
1257
|
var declarationName = defineRule3({
|
|
1088
1258
|
meta: {
|
|
1089
1259
|
type: "problem",
|
|
1090
|
-
schema: [
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1260
|
+
schema: [
|
|
1261
|
+
{
|
|
1262
|
+
type: "object",
|
|
1263
|
+
additionalProperties: false,
|
|
1264
|
+
properties: {
|
|
1265
|
+
kinds: {
|
|
1266
|
+
type: "array",
|
|
1267
|
+
items: { type: "string", enum: [...declarationsKinds] }
|
|
1268
|
+
},
|
|
1269
|
+
pattern: optionsPatternSchema,
|
|
1270
|
+
flags: { type: "string" },
|
|
1271
|
+
stem: { type: "string", enum: [...namingStemModes] },
|
|
1272
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1273
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1274
|
+
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1275
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1276
|
+
allowPattern: optionsPatternSchema
|
|
1277
|
+
}
|
|
1106
1278
|
}
|
|
1107
|
-
|
|
1279
|
+
],
|
|
1108
1280
|
messages: {
|
|
1109
1281
|
prefix: "'{{name}}' must start with file prefix '{{prefix}}'.",
|
|
1110
1282
|
pattern: "'{{name}}' must match {{pattern}}."
|
|
@@ -1129,7 +1301,10 @@ var declarationName = defineRule3({
|
|
|
1129
1301
|
context.report({
|
|
1130
1302
|
node: item.node,
|
|
1131
1303
|
messageId: expected.length > 0 ? "pattern" : "prefix",
|
|
1132
|
-
data: expected.length > 0 ? {
|
|
1304
|
+
data: expected.length > 0 ? {
|
|
1305
|
+
name: item.name,
|
|
1306
|
+
pattern: optionsPatternLabel([options.pattern ?? []].flat().filter((source) => source !== ""))
|
|
1307
|
+
} : { name: item.name, prefix: prefixes.join(" or ") }
|
|
1133
1308
|
});
|
|
1134
1309
|
}
|
|
1135
1310
|
return {
|
|
@@ -1160,19 +1335,23 @@ import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
|
1160
1335
|
var exportFilePrefix = defineRule4({
|
|
1161
1336
|
meta: {
|
|
1162
1337
|
type: "problem",
|
|
1163
|
-
schema: [
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1338
|
+
schema: [
|
|
1339
|
+
{
|
|
1340
|
+
type: "object",
|
|
1341
|
+
additionalProperties: false,
|
|
1342
|
+
properties: {
|
|
1343
|
+
stem: { type: "string", enum: [...namingStemModes] },
|
|
1344
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1345
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1346
|
+
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1347
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1348
|
+
serviceMethods: { type: "boolean" },
|
|
1349
|
+
allFunctions: { type: "boolean" },
|
|
1350
|
+
allDeclarations: { type: "boolean" },
|
|
1351
|
+
allowPattern: optionsPatternSchema
|
|
1352
|
+
}
|
|
1174
1353
|
}
|
|
1175
|
-
|
|
1354
|
+
],
|
|
1176
1355
|
messages: {
|
|
1177
1356
|
prefix: "'{{name}}' must start with file prefix '{{prefix}}'."
|
|
1178
1357
|
}
|
|
@@ -1192,6 +1371,12 @@ var exportFilePrefix = defineRule4({
|
|
|
1192
1371
|
name: binding.localName ?? binding.exportedName,
|
|
1193
1372
|
node: binding.node
|
|
1194
1373
|
}));
|
|
1374
|
+
if (options.allFunctions && !options.allDeclarations) {
|
|
1375
|
+
const exportedNames = new Set(names.map((item) => item.name));
|
|
1376
|
+
names.push(...declarationsCollectNamed(program).filter((item) => !exportedNames.has(item.name) && (item.node.type === "FunctionDeclaration" || item.node.type === "VariableDeclarator" && (item.node.init?.type === "ArrowFunctionExpression" || item.node.init?.type === "FunctionExpression"))));
|
|
1377
|
+
}
|
|
1378
|
+
if (options.serviceMethods)
|
|
1379
|
+
names.push(...declarationsPublicServiceMethods(program));
|
|
1195
1380
|
const seen = new Set;
|
|
1196
1381
|
for (const item of names) {
|
|
1197
1382
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
@@ -1216,18 +1401,20 @@ import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
|
1216
1401
|
var exportNamePattern = defineRule5({
|
|
1217
1402
|
meta: {
|
|
1218
1403
|
type: "problem",
|
|
1219
|
-
schema: [
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1404
|
+
schema: [
|
|
1405
|
+
{
|
|
1406
|
+
type: "object",
|
|
1407
|
+
additionalProperties: false,
|
|
1408
|
+
properties: {
|
|
1409
|
+
pattern: optionsPatternSchema,
|
|
1410
|
+
flags: { type: "string" },
|
|
1411
|
+
ignoreTypeExports: { type: "boolean" },
|
|
1412
|
+
allDeclarations: { type: "boolean" },
|
|
1413
|
+
allowPattern: optionsPatternSchema
|
|
1414
|
+
},
|
|
1415
|
+
required: ["pattern"]
|
|
1416
|
+
}
|
|
1417
|
+
],
|
|
1231
1418
|
messages: {
|
|
1232
1419
|
pattern: "'{{name}}' must match {{pattern}}."
|
|
1233
1420
|
}
|
|
@@ -1268,20 +1455,23 @@ import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
|
1268
1455
|
var filenameExportName = defineRule6({
|
|
1269
1456
|
meta: {
|
|
1270
1457
|
type: "problem",
|
|
1271
|
-
schema: [
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1458
|
+
schema: [
|
|
1459
|
+
{
|
|
1460
|
+
type: "object",
|
|
1461
|
+
additionalProperties: false,
|
|
1462
|
+
properties: {
|
|
1463
|
+
file: { type: "string" },
|
|
1464
|
+
export: { type: "string" },
|
|
1465
|
+
mode: { type: "string", enum: ["all", "some"] },
|
|
1466
|
+
placeholderPattern: { type: "string" },
|
|
1467
|
+
camelCase: { type: "boolean" },
|
|
1468
|
+
allDeclarations: { type: "boolean" }
|
|
1469
|
+
},
|
|
1470
|
+
required: ["file", "export"]
|
|
1471
|
+
}
|
|
1472
|
+
],
|
|
1283
1473
|
messages: {
|
|
1284
|
-
mismatch: "Function '{{actual}}' must
|
|
1474
|
+
mismatch: "Function '{{actual}}' must be named '{{expected}}' for file '{{file}}'."
|
|
1285
1475
|
}
|
|
1286
1476
|
},
|
|
1287
1477
|
createOnce(context) {
|
|
@@ -1292,13 +1482,14 @@ var filenameExportName = defineRule6({
|
|
|
1292
1482
|
export: exportTemplate,
|
|
1293
1483
|
mode = "all",
|
|
1294
1484
|
placeholderPattern,
|
|
1295
|
-
allDeclarations = false
|
|
1485
|
+
allDeclarations = false,
|
|
1486
|
+
camelCase = false
|
|
1296
1487
|
} = optionsFirst(context);
|
|
1297
1488
|
const groups = namingMatchTemplate(namingFileBasename(context.filename), file, placeholderPattern);
|
|
1298
1489
|
if (!groups) {
|
|
1299
1490
|
return;
|
|
1300
1491
|
}
|
|
1301
|
-
const expected = factoriesExpandTemplate(exportTemplate, groups);
|
|
1492
|
+
const expected = factoriesExpandTemplate(exportTemplate, groups, camelCase);
|
|
1302
1493
|
const functions = allDeclarations ? declarationsCollectFunctions(program) : exportsCollectFunctions(program);
|
|
1303
1494
|
if (mode === "some") {
|
|
1304
1495
|
if (!functions.some((item) => item.name === expected)) {
|
|
@@ -1306,7 +1497,7 @@ var filenameExportName = defineRule6({
|
|
|
1306
1497
|
context.report({
|
|
1307
1498
|
node: first?.node ?? program,
|
|
1308
1499
|
messageId: "mismatch",
|
|
1309
|
-
data: { actual: first?.name ?? "<none>", expected }
|
|
1500
|
+
data: { actual: first?.name ?? "<none>", expected, file: namingFileBasename(context.filename) }
|
|
1310
1501
|
});
|
|
1311
1502
|
}
|
|
1312
1503
|
return;
|
|
@@ -1316,7 +1507,7 @@ var filenameExportName = defineRule6({
|
|
|
1316
1507
|
context.report({
|
|
1317
1508
|
node: item.node,
|
|
1318
1509
|
messageId: "mismatch",
|
|
1319
|
-
data: { actual: item.name, expected }
|
|
1510
|
+
data: { actual: item.name, expected, file: namingFileBasename(context.filename) }
|
|
1320
1511
|
});
|
|
1321
1512
|
}
|
|
1322
1513
|
}
|
|
@@ -1330,16 +1521,18 @@ import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
|
1330
1521
|
var filenameMatch = defineRule7({
|
|
1331
1522
|
meta: {
|
|
1332
1523
|
type: "problem",
|
|
1333
|
-
schema: [
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1524
|
+
schema: [
|
|
1525
|
+
{
|
|
1526
|
+
type: "object",
|
|
1527
|
+
additionalProperties: false,
|
|
1528
|
+
properties: {
|
|
1529
|
+
pattern: optionsPatternSchema,
|
|
1530
|
+
message: { type: "string" },
|
|
1531
|
+
flags: { type: "string" }
|
|
1532
|
+
},
|
|
1533
|
+
required: ["pattern", "message"]
|
|
1534
|
+
}
|
|
1535
|
+
],
|
|
1343
1536
|
messages: {
|
|
1344
1537
|
mismatch: "{{message}}"
|
|
1345
1538
|
}
|
|
@@ -1366,17 +1559,20 @@ import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
|
1366
1559
|
var folderPrefix = defineRule8({
|
|
1367
1560
|
meta: {
|
|
1368
1561
|
type: "problem",
|
|
1369
|
-
schema: [
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1562
|
+
schema: [
|
|
1563
|
+
{
|
|
1564
|
+
type: "object",
|
|
1565
|
+
additionalProperties: false,
|
|
1566
|
+
properties: {
|
|
1567
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1568
|
+
separators: { type: "array", items: { type: "string" } },
|
|
1569
|
+
after: { type: "string" },
|
|
1570
|
+
stripPrefixes: { type: "array", items: { type: "string", minLength: 1 } }
|
|
1571
|
+
}
|
|
1376
1572
|
}
|
|
1377
|
-
|
|
1573
|
+
],
|
|
1378
1574
|
messages: {
|
|
1379
|
-
prefix: "File '{{file}}' must start with
|
|
1575
|
+
prefix: "File '{{file}}' must start with '{{expected}}' to match its domain folder '{{folder}}'."
|
|
1380
1576
|
}
|
|
1381
1577
|
},
|
|
1382
1578
|
createOnce(context) {
|
|
@@ -1385,7 +1581,8 @@ var folderPrefix = defineRule8({
|
|
|
1385
1581
|
const {
|
|
1386
1582
|
singularize = "trailing-s",
|
|
1387
1583
|
separators = ["-"],
|
|
1388
|
-
after
|
|
1584
|
+
after,
|
|
1585
|
+
stripPrefixes = []
|
|
1389
1586
|
} = optionsFirst(context, {});
|
|
1390
1587
|
const filename = namingPosixPath(context.filename);
|
|
1391
1588
|
const folders = after ? namingSegmentsAfter(filename, after) : [namingDirSegments(filename).at(-1) ?? ""];
|
|
@@ -1396,13 +1593,19 @@ var folderPrefix = defineRule8({
|
|
|
1396
1593
|
const separator = separators[0] ?? "-";
|
|
1397
1594
|
const prefixes = namingFolderPrefixes(resolved, separator, singularize);
|
|
1398
1595
|
const file = namingFileBasename(filename);
|
|
1399
|
-
const
|
|
1596
|
+
const rawStem = file.replace(/\.(tsx?|jsx?)$/, "");
|
|
1597
|
+
const strip = stripPrefixes.find((prefix) => rawStem.startsWith(prefix));
|
|
1598
|
+
const stem = strip ? rawStem.slice(strip.length) : rawStem;
|
|
1400
1599
|
const valid = prefixes.some((prefix) => stem === prefix || separators.some((item) => stem.startsWith(`${prefix}${item}`)));
|
|
1401
1600
|
if (!valid) {
|
|
1402
1601
|
context.report({
|
|
1403
1602
|
node: program,
|
|
1404
1603
|
messageId: "prefix",
|
|
1405
|
-
data: {
|
|
1604
|
+
data: {
|
|
1605
|
+
file,
|
|
1606
|
+
folder: resolved.join("/"),
|
|
1607
|
+
expected: prefixes.map((prefix) => `${stripPrefixes[0] ?? ""}${prefix}`).join(" or ")
|
|
1608
|
+
}
|
|
1406
1609
|
});
|
|
1407
1610
|
}
|
|
1408
1611
|
}
|
|
@@ -1421,10 +1624,12 @@ function jsxAttributesMultilineEdits(node, text, attributeIndent, baseIndent, ne
|
|
|
1421
1624
|
const openingRange = [prefix.range[1], first.range[0]];
|
|
1422
1625
|
if (!/^\s*$/.test(text.slice(...openingRange)))
|
|
1423
1626
|
return null;
|
|
1424
|
-
const edits = [
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1627
|
+
const edits = [
|
|
1628
|
+
{
|
|
1629
|
+
range: openingRange,
|
|
1630
|
+
text: `${newline}${attributeIndent}`
|
|
1631
|
+
}
|
|
1632
|
+
];
|
|
1428
1633
|
for (let index = 1;index < node.attributes.length; index++) {
|
|
1429
1634
|
const previous = node.attributes[index - 1];
|
|
1430
1635
|
const current = node.attributes[index];
|
|
@@ -1444,14 +1649,16 @@ var jsxAttributesMultiline = defineRule9({
|
|
|
1444
1649
|
meta: {
|
|
1445
1650
|
type: "layout",
|
|
1446
1651
|
fixable: "whitespace",
|
|
1447
|
-
schema: [
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1652
|
+
schema: [
|
|
1653
|
+
{
|
|
1654
|
+
type: "object",
|
|
1655
|
+
additionalProperties: false,
|
|
1656
|
+
properties: {
|
|
1657
|
+
minAttributes: { type: "integer", minimum: 1 },
|
|
1658
|
+
indent: layoutIndentSchema
|
|
1659
|
+
}
|
|
1453
1660
|
}
|
|
1454
|
-
|
|
1661
|
+
],
|
|
1455
1662
|
messages: {
|
|
1456
1663
|
multiline: "Put every JSX attribute and the closing token on its own line."
|
|
1457
1664
|
}
|
|
@@ -1633,15 +1840,17 @@ var noComments = defineRule11({
|
|
|
1633
1840
|
meta: {
|
|
1634
1841
|
type: "suggestion",
|
|
1635
1842
|
fixable: "code",
|
|
1636
|
-
schema: [
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1843
|
+
schema: [
|
|
1844
|
+
{
|
|
1845
|
+
type: "object",
|
|
1846
|
+
additionalProperties: false,
|
|
1847
|
+
properties: {
|
|
1848
|
+
allowWhy: { type: "boolean", default: true },
|
|
1849
|
+
allowPatterns: { type: "array", items: { type: "string" } },
|
|
1850
|
+
allowJsdoc: { type: "boolean", default: false }
|
|
1851
|
+
}
|
|
1643
1852
|
}
|
|
1644
|
-
|
|
1853
|
+
],
|
|
1645
1854
|
messages: {
|
|
1646
1855
|
comment: "Remove this comment."
|
|
1647
1856
|
}
|
|
@@ -1763,19 +1972,21 @@ import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
|
1763
1972
|
var noExtraExports = defineRule12({
|
|
1764
1973
|
meta: {
|
|
1765
1974
|
type: "problem",
|
|
1766
|
-
schema: [
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1975
|
+
schema: [
|
|
1976
|
+
{
|
|
1977
|
+
type: "object",
|
|
1978
|
+
additionalProperties: false,
|
|
1979
|
+
properties: {
|
|
1980
|
+
names: { type: "array", items: { type: "string" } },
|
|
1981
|
+
patterns: { type: "array", items: { type: "string" } },
|
|
1982
|
+
domainStem: { type: "string", enum: [...namingStemModes] },
|
|
1983
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1984
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1985
|
+
allowTypeExports: { type: "boolean" }
|
|
1986
|
+
},
|
|
1987
|
+
required: ["names"]
|
|
1988
|
+
}
|
|
1989
|
+
],
|
|
1779
1990
|
messages: {
|
|
1780
1991
|
extraExport: "Export '{{name}}' is not allowed; expected one of: {{allowed}}."
|
|
1781
1992
|
}
|
|
@@ -1830,28 +2041,30 @@ function compileFactoryKeys(pattern, keys, requireKeys) {
|
|
|
1830
2041
|
var noExtraFactoryKeys = defineRule13({
|
|
1831
2042
|
meta: {
|
|
1832
2043
|
type: "problem",
|
|
1833
|
-
schema: [
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
2044
|
+
schema: [
|
|
2045
|
+
{
|
|
2046
|
+
type: "object",
|
|
2047
|
+
additionalProperties: false,
|
|
2048
|
+
properties: {
|
|
2049
|
+
keys: { type: "array", items: { type: "string" } },
|
|
2050
|
+
factoryPattern: optionsPatternSchema,
|
|
2051
|
+
requireKeys: { type: "array", items: { type: "string" } },
|
|
2052
|
+
keySets: {
|
|
2053
|
+
type: "array",
|
|
2054
|
+
items: {
|
|
2055
|
+
type: "object",
|
|
2056
|
+
additionalProperties: false,
|
|
2057
|
+
properties: {
|
|
2058
|
+
factoryPattern: optionsPatternSchema,
|
|
2059
|
+
keys: { type: "array", items: { type: "string" } },
|
|
2060
|
+
requireKeys: { type: "array", items: { type: "string" } }
|
|
2061
|
+
},
|
|
2062
|
+
required: ["factoryPattern", "keys"]
|
|
2063
|
+
}
|
|
1851
2064
|
}
|
|
1852
2065
|
}
|
|
1853
2066
|
}
|
|
1854
|
-
|
|
2067
|
+
],
|
|
1855
2068
|
messages: {
|
|
1856
2069
|
extraKey: "Factory '{{factory}}' must not return key '{{key}}'; allowed keys: {{allowed}}.",
|
|
1857
2070
|
missingKey: "Factory '{{factory}}' must return key '{{key}}'.",
|
|
@@ -1904,7 +2117,11 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1904
2117
|
context.report({
|
|
1905
2118
|
node: property,
|
|
1906
2119
|
messageId: "extraKey",
|
|
1907
|
-
data: {
|
|
2120
|
+
data: {
|
|
2121
|
+
factory: factory.name,
|
|
2122
|
+
key: key ?? "<computed or spread>",
|
|
2123
|
+
allowed: resolved.allowedList.join(", ")
|
|
2124
|
+
}
|
|
1908
2125
|
});
|
|
1909
2126
|
}
|
|
1910
2127
|
}
|
|
@@ -1929,17 +2146,20 @@ import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
|
1929
2146
|
var noFileLevelHelpers = defineRule14({
|
|
1930
2147
|
meta: {
|
|
1931
2148
|
type: "problem",
|
|
1932
|
-
schema: [
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2149
|
+
schema: [
|
|
2150
|
+
{
|
|
2151
|
+
type: "object",
|
|
2152
|
+
additionalProperties: false,
|
|
2153
|
+
properties: {
|
|
2154
|
+
allowPattern: optionsPatternSchema,
|
|
2155
|
+
message: { type: "string" },
|
|
2156
|
+
detectComponents: { type: "boolean" },
|
|
2157
|
+
hookPattern: optionsPatternSchema
|
|
2158
|
+
}
|
|
1939
2159
|
}
|
|
1940
|
-
|
|
2160
|
+
],
|
|
1941
2161
|
messages: {
|
|
1942
|
-
helper: "
|
|
2162
|
+
helper: "{{name}}: {{message}}"
|
|
1943
2163
|
}
|
|
1944
2164
|
},
|
|
1945
2165
|
createOnce(context) {
|
|
@@ -1947,6 +2167,7 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1947
2167
|
Program(program) {
|
|
1948
2168
|
const {
|
|
1949
2169
|
allowPattern,
|
|
2170
|
+
message = "Keep this helper inside its owning component or hook.",
|
|
1950
2171
|
detectComponents = true,
|
|
1951
2172
|
hookPattern = "^use[A-Z]"
|
|
1952
2173
|
} = optionsFirst(context, {});
|
|
@@ -1959,7 +2180,7 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1959
2180
|
context.report({
|
|
1960
2181
|
node: candidate.node,
|
|
1961
2182
|
messageId: "helper",
|
|
1962
|
-
data: { name: candidate.name }
|
|
2183
|
+
data: { name: candidate.name, message }
|
|
1963
2184
|
});
|
|
1964
2185
|
}
|
|
1965
2186
|
}
|
|
@@ -1970,7 +2191,7 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1970
2191
|
// src/rules/no-imported-type-alias.ts
|
|
1971
2192
|
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
1972
2193
|
function importedAliasTarget(declaration, imports) {
|
|
1973
|
-
if (declaration?.type !== "TSTypeAliasDeclaration" || declaration.typeAnnotation.type !== "TSTypeReference" || declaration.typeAnnotation.typeName.type !== "Identifier" || !imports.has(declaration.typeAnnotation.typeName.name)) {
|
|
2194
|
+
if (declaration?.type !== "TSTypeAliasDeclaration" || declaration.typeAnnotation.type !== "TSTypeReference" || declaration.typeAnnotation.typeName.type !== "Identifier" || Boolean(declaration.typeAnnotation.typeArguments?.params.length) || !imports.has(declaration.typeAnnotation.typeName.name)) {
|
|
1974
2195
|
return;
|
|
1975
2196
|
}
|
|
1976
2197
|
return declaration.typeAnnotation.typeName.name;
|
|
@@ -1983,13 +2204,29 @@ var noImportedTypeAlias = defineRule15({
|
|
|
1983
2204
|
type: "problem",
|
|
1984
2205
|
schema: [],
|
|
1985
2206
|
messages: {
|
|
1986
|
-
alias: "
|
|
2207
|
+
alias: "Import '{{name}}' from '{{source}}' at the callers instead of exporting alias '{{alias}}'. Keep genuine derivations; do not substitute an empty interface."
|
|
1987
2208
|
}
|
|
1988
2209
|
},
|
|
1989
2210
|
createOnce(context) {
|
|
1990
2211
|
return {
|
|
1991
2212
|
Program(program) {
|
|
1992
|
-
const imports = new Set
|
|
2213
|
+
const imports = new Set;
|
|
2214
|
+
const sources = new Map;
|
|
2215
|
+
const names = new Map;
|
|
2216
|
+
for (const statement of program.body) {
|
|
2217
|
+
if (statement.type !== "ImportDeclaration")
|
|
2218
|
+
continue;
|
|
2219
|
+
for (const specifier of statement.specifiers) {
|
|
2220
|
+
const local = specifier.local.name;
|
|
2221
|
+
let name = local;
|
|
2222
|
+
if (specifier.type === "ImportSpecifier") {
|
|
2223
|
+
name = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
2224
|
+
}
|
|
2225
|
+
imports.add(local);
|
|
2226
|
+
sources.set(local, statement.source.value);
|
|
2227
|
+
names.set(local, name);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
1993
2230
|
const aliases = new Map;
|
|
1994
2231
|
for (const statement of program.body) {
|
|
1995
2232
|
const declaration = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
|
|
@@ -2007,7 +2244,11 @@ var noImportedTypeAlias = defineRule15({
|
|
|
2007
2244
|
context.report({
|
|
2008
2245
|
node: statement.declaration,
|
|
2009
2246
|
messageId: "alias",
|
|
2010
|
-
data: {
|
|
2247
|
+
data: {
|
|
2248
|
+
alias: statement.declaration.id.name,
|
|
2249
|
+
name: names.get(inline) ?? inline,
|
|
2250
|
+
source: sources.get(inline) ?? "<import source>"
|
|
2251
|
+
}
|
|
2011
2252
|
});
|
|
2012
2253
|
}
|
|
2013
2254
|
for (const specifier of statement.specifiers) {
|
|
@@ -2017,7 +2258,11 @@ var noImportedTypeAlias = defineRule15({
|
|
|
2017
2258
|
context.report({
|
|
2018
2259
|
node: specifier,
|
|
2019
2260
|
messageId: "alias",
|
|
2020
|
-
data: {
|
|
2261
|
+
data: {
|
|
2262
|
+
alias: local,
|
|
2263
|
+
name: names.get(imported) ?? imported,
|
|
2264
|
+
source: sources.get(imported) ?? "<import source>"
|
|
2265
|
+
}
|
|
2021
2266
|
});
|
|
2022
2267
|
}
|
|
2023
2268
|
}
|
|
@@ -2032,22 +2277,35 @@ import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
|
2032
2277
|
var noInlineSchemaElements = defineRule16({
|
|
2033
2278
|
meta: {
|
|
2034
2279
|
type: "problem",
|
|
2035
|
-
schema: [
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2280
|
+
schema: [
|
|
2281
|
+
{
|
|
2282
|
+
type: "object",
|
|
2283
|
+
additionalProperties: false,
|
|
2284
|
+
properties: {
|
|
2285
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
2286
|
+
methods: { type: "array", items: { type: "string" } },
|
|
2287
|
+
structuralMethods: { type: "array", items: { type: "string" } },
|
|
2288
|
+
allowZodScalars: { type: "boolean" }
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
],
|
|
2292
|
+
defaultOptions: [
|
|
2293
|
+
{
|
|
2294
|
+
namespaces: ["z"],
|
|
2295
|
+
methods: ["array", "union", "record", "tuple"],
|
|
2296
|
+
structuralMethods: [
|
|
2297
|
+
"array",
|
|
2298
|
+
"discriminatedUnion",
|
|
2299
|
+
"intersection",
|
|
2300
|
+
"lazy",
|
|
2301
|
+
"object",
|
|
2302
|
+
"record",
|
|
2303
|
+
"tuple",
|
|
2304
|
+
"union"
|
|
2305
|
+
],
|
|
2306
|
+
allowZodScalars: true
|
|
2043
2307
|
}
|
|
2044
|
-
|
|
2045
|
-
defaultOptions: [{
|
|
2046
|
-
namespaces: ["z"],
|
|
2047
|
-
methods: ["array", "union", "record", "tuple"],
|
|
2048
|
-
structuralMethods: ["array", "discriminatedUnion", "intersection", "lazy", "object", "record", "tuple", "union"],
|
|
2049
|
-
allowZodScalars: true
|
|
2050
|
-
}],
|
|
2308
|
+
],
|
|
2051
2309
|
messages: { inline: "z.{{method}}() elements must use named schemas." }
|
|
2052
2310
|
},
|
|
2053
2311
|
createOnce(context) {
|
|
@@ -2090,16 +2348,18 @@ function parameterAnnotation(parameter) {
|
|
|
2090
2348
|
var noInlineTypes = defineRule17({
|
|
2091
2349
|
meta: {
|
|
2092
2350
|
type: "problem",
|
|
2093
|
-
schema: [
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2351
|
+
schema: [
|
|
2352
|
+
{
|
|
2353
|
+
type: "object",
|
|
2354
|
+
additionalProperties: false,
|
|
2355
|
+
properties: {
|
|
2356
|
+
parameters: { type: "boolean" },
|
|
2357
|
+
returns: { type: "boolean" },
|
|
2358
|
+
functionTypes: { type: "boolean" },
|
|
2359
|
+
minMembers: { type: "integer", minimum: 1 }
|
|
2360
|
+
}
|
|
2101
2361
|
}
|
|
2102
|
-
|
|
2362
|
+
],
|
|
2103
2363
|
messages: {
|
|
2104
2364
|
inlineType: "Use a named type instead of an inline {{kind}} type in this {{position}} annotation."
|
|
2105
2365
|
}
|
|
@@ -2167,13 +2427,15 @@ function literalKey(node) {
|
|
|
2167
2427
|
var noLiteralIn = defineRule18({
|
|
2168
2428
|
meta: {
|
|
2169
2429
|
type: "suggestion",
|
|
2170
|
-
schema: [
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2430
|
+
schema: [
|
|
2431
|
+
{
|
|
2432
|
+
type: "object",
|
|
2433
|
+
additionalProperties: false,
|
|
2434
|
+
properties: {
|
|
2435
|
+
allow: { type: "array", items: { type: "string" } }
|
|
2436
|
+
}
|
|
2175
2437
|
}
|
|
2176
|
-
|
|
2438
|
+
],
|
|
2177
2439
|
defaultOptions: [{ allow: [] }],
|
|
2178
2440
|
messages: {
|
|
2179
2441
|
literalIn: "Avoid '{{key}}' in value; use Object.hasOwn() or a discriminated union."
|
|
@@ -2212,23 +2474,27 @@ function formatMessage(template, data) {
|
|
|
2212
2474
|
var noLocalSchemaConstruction = defineRule19({
|
|
2213
2475
|
meta: {
|
|
2214
2476
|
type: "problem",
|
|
2215
|
-
schema: [
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2477
|
+
schema: [
|
|
2478
|
+
{
|
|
2479
|
+
type: "object",
|
|
2480
|
+
additionalProperties: false,
|
|
2481
|
+
properties: {
|
|
2482
|
+
packages: { type: "array", items: { type: "string" } },
|
|
2483
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
2484
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
2485
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
2486
|
+
message: { type: "string" },
|
|
2487
|
+
runtimeImportMessage: { type: "string" },
|
|
2488
|
+
constructionMessage: { type: "string" }
|
|
2489
|
+
}
|
|
2226
2490
|
}
|
|
2227
|
-
|
|
2228
|
-
defaultOptions: [
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2491
|
+
],
|
|
2492
|
+
defaultOptions: [
|
|
2493
|
+
{
|
|
2494
|
+
packages: ["zod"],
|
|
2495
|
+
namespaces: ["z"]
|
|
2496
|
+
}
|
|
2497
|
+
],
|
|
2232
2498
|
messages: {
|
|
2233
2499
|
runtimeImport: "{{message}}",
|
|
2234
2500
|
construction: "{{message}}"
|
|
@@ -2265,7 +2531,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2265
2531
|
node,
|
|
2266
2532
|
messageId: "runtimeImport",
|
|
2267
2533
|
data: {
|
|
2268
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2534
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2535
|
+
source: node.source.value
|
|
2536
|
+
})
|
|
2269
2537
|
}
|
|
2270
2538
|
});
|
|
2271
2539
|
},
|
|
@@ -2282,7 +2550,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2282
2550
|
node,
|
|
2283
2551
|
messageId: "runtimeImport",
|
|
2284
2552
|
data: {
|
|
2285
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2553
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2554
|
+
source: node.source.value
|
|
2555
|
+
})
|
|
2286
2556
|
}
|
|
2287
2557
|
});
|
|
2288
2558
|
},
|
|
@@ -2299,7 +2569,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2299
2569
|
node,
|
|
2300
2570
|
messageId: "runtimeImport",
|
|
2301
2571
|
data: {
|
|
2302
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2572
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2573
|
+
source: node.source.value
|
|
2574
|
+
})
|
|
2303
2575
|
}
|
|
2304
2576
|
});
|
|
2305
2577
|
},
|
|
@@ -2326,13 +2598,15 @@ var noMemberComments = defineRule20({
|
|
|
2326
2598
|
meta: {
|
|
2327
2599
|
type: "suggestion",
|
|
2328
2600
|
fixable: "code",
|
|
2329
|
-
schema: [
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2601
|
+
schema: [
|
|
2602
|
+
{
|
|
2603
|
+
type: "object",
|
|
2604
|
+
additionalProperties: false,
|
|
2605
|
+
properties: {
|
|
2606
|
+
allowWhy: { type: "boolean", default: true }
|
|
2607
|
+
}
|
|
2334
2608
|
}
|
|
2335
|
-
|
|
2609
|
+
],
|
|
2336
2610
|
messages: {
|
|
2337
2611
|
memberComment: "Remove this comment from the type member."
|
|
2338
2612
|
}
|
|
@@ -2458,17 +2732,19 @@ function moduleMutableStateInsideAmbient(node) {
|
|
|
2458
2732
|
var noModuleMutableState = defineRule21({
|
|
2459
2733
|
meta: {
|
|
2460
2734
|
type: "problem",
|
|
2461
|
-
schema: [
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2735
|
+
schema: [
|
|
2736
|
+
{
|
|
2737
|
+
type: "object",
|
|
2738
|
+
additionalProperties: false,
|
|
2739
|
+
properties: {
|
|
2740
|
+
kinds: {
|
|
2741
|
+
type: "array",
|
|
2742
|
+
items: { type: "string", enum: ["let", "var"] }
|
|
2743
|
+
},
|
|
2744
|
+
allowNamePattern: optionsPatternSchema
|
|
2745
|
+
}
|
|
2470
2746
|
}
|
|
2471
|
-
|
|
2747
|
+
],
|
|
2472
2748
|
messages: {
|
|
2473
2749
|
moduleState: "module state is shared across requests/tests; keep it local."
|
|
2474
2750
|
}
|
|
@@ -2536,20 +2812,24 @@ function mutationBindings(node) {
|
|
|
2536
2812
|
var noPromiseAllMutation = defineRule22({
|
|
2537
2813
|
meta: {
|
|
2538
2814
|
type: "problem",
|
|
2539
|
-
schema: [
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2815
|
+
schema: [
|
|
2816
|
+
{
|
|
2817
|
+
type: "object",
|
|
2818
|
+
additionalProperties: false,
|
|
2819
|
+
properties: {
|
|
2820
|
+
combinators: { type: "array", items: { type: "string" } },
|
|
2821
|
+
methods: { type: "array", items: { type: "string" } },
|
|
2822
|
+
checkAssignments: { type: "boolean" }
|
|
2823
|
+
}
|
|
2546
2824
|
}
|
|
2547
|
-
|
|
2548
|
-
defaultOptions: [
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2825
|
+
],
|
|
2826
|
+
defaultOptions: [
|
|
2827
|
+
{
|
|
2828
|
+
combinators: ["Promise.all", "Promise.allSettled", "Promise.any", "Promise.race"],
|
|
2829
|
+
methods: ["push", "unshift", "splice", "set", "add"],
|
|
2830
|
+
checkAssignments: true
|
|
2831
|
+
}
|
|
2832
|
+
],
|
|
2553
2833
|
messages: {
|
|
2554
2834
|
mutation: "Do not mutate outer binding '{{name}}' inside {{combinator}}()."
|
|
2555
2835
|
}
|
|
@@ -2633,16 +2913,18 @@ import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
|
2633
2913
|
var noRederiveSchema = defineRule23({
|
|
2634
2914
|
meta: {
|
|
2635
2915
|
type: "problem",
|
|
2636
|
-
schema: [
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2916
|
+
schema: [
|
|
2917
|
+
{
|
|
2918
|
+
type: "object",
|
|
2919
|
+
additionalProperties: false,
|
|
2920
|
+
properties: {
|
|
2921
|
+
from: { type: "array", items: { type: "string" } },
|
|
2922
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
2923
|
+
operators: { type: "array", items: { type: "string" } }
|
|
2924
|
+
},
|
|
2925
|
+
required: ["from"]
|
|
2926
|
+
}
|
|
2927
|
+
],
|
|
2646
2928
|
messages: {
|
|
2647
2929
|
rederive: "Do not derive {{operator}} from imported schema {{schema}}; import its DTO type."
|
|
2648
2930
|
}
|
|
@@ -2655,10 +2937,7 @@ var noRederiveSchema = defineRule23({
|
|
|
2655
2937
|
imported = new Set(program.body.flatMap((statement) => statement.type === "ImportDeclaration" && from.includes(statement.source.value) ? statement.specifiers.map((specifier) => specifier.local.name) : []));
|
|
2656
2938
|
},
|
|
2657
2939
|
TSTypeReference(node) {
|
|
2658
|
-
const {
|
|
2659
|
-
namespaces = ["z"],
|
|
2660
|
-
operators = ["infer", "input"]
|
|
2661
|
-
} = optionsFirst(context);
|
|
2940
|
+
const { namespaces = ["z"], operators = ["infer", "input"] } = optionsFirst(context);
|
|
2662
2941
|
const operator = schemasTypeOperator(node, new Set(namespaces), new Set(operators));
|
|
2663
2942
|
const parameter = node.typeArguments?.params[0];
|
|
2664
2943
|
if (!operator || parameter?.type !== "TSTypeQuery" || parameter.exprName.type !== "Identifier" || !imported.has(parameter.exprName.name)) {
|
|
@@ -2694,32 +2973,34 @@ function restrictedConstructorEntries(constructors) {
|
|
|
2694
2973
|
var noRestrictedConstructor = defineRule24({
|
|
2695
2974
|
meta: {
|
|
2696
2975
|
type: "problem",
|
|
2697
|
-
schema: [
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2976
|
+
schema: [
|
|
2977
|
+
{
|
|
2978
|
+
type: "object",
|
|
2979
|
+
additionalProperties: false,
|
|
2980
|
+
properties: {
|
|
2981
|
+
constructors: {
|
|
2982
|
+
type: "array",
|
|
2983
|
+
items: {
|
|
2984
|
+
anyOf: [
|
|
2985
|
+
{ type: "string" },
|
|
2986
|
+
{
|
|
2987
|
+
type: "object",
|
|
2988
|
+
additionalProperties: false,
|
|
2989
|
+
properties: {
|
|
2990
|
+
name: { type: "string" },
|
|
2991
|
+
message: { type: "string" }
|
|
2992
|
+
},
|
|
2993
|
+
required: ["name"]
|
|
2994
|
+
}
|
|
2995
|
+
]
|
|
2996
|
+
}
|
|
2997
|
+
},
|
|
2998
|
+
checkCalls: { type: "boolean", default: false },
|
|
2999
|
+
message: { type: "string" }
|
|
2717
3000
|
},
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
required: ["constructors"]
|
|
2722
|
-
}],
|
|
3001
|
+
required: ["constructors"]
|
|
3002
|
+
}
|
|
3003
|
+
],
|
|
2723
3004
|
messages: {
|
|
2724
3005
|
construct: "Do not construct '{{name}}'.{{suffix}}",
|
|
2725
3006
|
call: "Do not call '{{name}}'.{{suffix}}"
|
|
@@ -2768,14 +3049,16 @@ import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
|
2768
3049
|
var noRestrictedFiles = defineRule25({
|
|
2769
3050
|
meta: {
|
|
2770
3051
|
type: "problem",
|
|
2771
|
-
schema: [
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
3052
|
+
schema: [
|
|
3053
|
+
{
|
|
3054
|
+
type: "object",
|
|
3055
|
+
additionalProperties: false,
|
|
3056
|
+
properties: {
|
|
3057
|
+
message: { type: "string" }
|
|
3058
|
+
},
|
|
3059
|
+
required: ["message"]
|
|
3060
|
+
}
|
|
3061
|
+
],
|
|
2779
3062
|
messages: {
|
|
2780
3063
|
restricted: "{{message}}"
|
|
2781
3064
|
}
|
|
@@ -2809,37 +3092,36 @@ function memberMatches(node, restriction) {
|
|
|
2809
3092
|
var noRestrictedToken = defineRule26({
|
|
2810
3093
|
meta: {
|
|
2811
3094
|
type: "problem",
|
|
2812
|
-
schema: [
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
3095
|
+
schema: [
|
|
3096
|
+
{
|
|
3097
|
+
type: "object",
|
|
3098
|
+
additionalProperties: false,
|
|
3099
|
+
properties: {
|
|
3100
|
+
token: { type: "string" },
|
|
3101
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
3102
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
3103
|
+
restrictions: {
|
|
3104
|
+
type: "array",
|
|
3105
|
+
items: {
|
|
3106
|
+
type: "object",
|
|
3107
|
+
additionalProperties: false,
|
|
3108
|
+
properties: {
|
|
3109
|
+
token: { type: "string" },
|
|
3110
|
+
member: { type: "string" },
|
|
3111
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
3112
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
3113
|
+
message: { type: "string" }
|
|
3114
|
+
},
|
|
3115
|
+
oneOf: [
|
|
3116
|
+
{ required: ["token"], not: { required: ["member"] } },
|
|
3117
|
+
{ required: ["member"], not: { required: ["token"] } }
|
|
3118
|
+
]
|
|
3119
|
+
}
|
|
2835
3120
|
}
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
{ required: ["restrictions"] }
|
|
2841
|
-
]
|
|
2842
|
-
}],
|
|
3121
|
+
},
|
|
3122
|
+
anyOf: [{ required: ["token"] }, { required: ["restrictions"] }]
|
|
3123
|
+
}
|
|
3124
|
+
],
|
|
2843
3125
|
messages: {
|
|
2844
3126
|
restricted: "'{{token}}' may only appear in configured owner paths.",
|
|
2845
3127
|
restrictedWithMessage: "'{{token}}' may only appear in configured owner paths. {{custom}}"
|
|
@@ -2858,11 +3140,13 @@ var noRestrictedToken = defineRule26({
|
|
|
2858
3140
|
before() {
|
|
2859
3141
|
const options = optionsFirst(context);
|
|
2860
3142
|
const configured = [
|
|
2861
|
-
...options.token ? [
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
3143
|
+
...options.token ? [
|
|
3144
|
+
{
|
|
3145
|
+
token: options.token,
|
|
3146
|
+
allowIn: options.allowIn,
|
|
3147
|
+
allowPathPatterns: options.allowPathPatterns
|
|
3148
|
+
}
|
|
3149
|
+
] : [],
|
|
2866
3150
|
...options.restrictions ?? []
|
|
2867
3151
|
];
|
|
2868
3152
|
const filename = namingPosixPath(context.filename);
|
|
@@ -3122,19 +3406,21 @@ function isRuntimeReExport(statement, runtimeImportLocals, valueNames, isAmbient
|
|
|
3122
3406
|
var noRuntimeInTypes = defineRule27({
|
|
3123
3407
|
meta: {
|
|
3124
3408
|
type: "problem",
|
|
3125
|
-
schema: [
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3409
|
+
schema: [
|
|
3410
|
+
{
|
|
3411
|
+
type: "object",
|
|
3412
|
+
additionalProperties: false,
|
|
3413
|
+
properties: {
|
|
3414
|
+
allow: {
|
|
3415
|
+
type: "array",
|
|
3416
|
+
items: { type: "string", enum: ["class", "default", "enum", "function", "variable"] }
|
|
3417
|
+
},
|
|
3418
|
+
runtimeImports: { type: "string", enum: ["allow", "ban"] },
|
|
3419
|
+
allowImportSources: { type: "array", items: { type: "string" } },
|
|
3420
|
+
banReExports: { type: "boolean" }
|
|
3421
|
+
}
|
|
3136
3422
|
}
|
|
3137
|
-
|
|
3423
|
+
],
|
|
3138
3424
|
messages: {
|
|
3139
3425
|
runtimeValue: "Types files must not contain runtime value {{name}}.",
|
|
3140
3426
|
runtimeImport: "Types files must not contain runtime imports from {{source}}.",
|
|
@@ -3298,22 +3584,39 @@ function isAllowedStructuralElement(identifier, initializer, ancestors, options,
|
|
|
3298
3584
|
var noSingleUseScalarSchema = defineRule28({
|
|
3299
3585
|
meta: {
|
|
3300
3586
|
type: "suggestion",
|
|
3301
|
-
schema: [
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3587
|
+
schema: [
|
|
3588
|
+
{
|
|
3589
|
+
type: "object",
|
|
3590
|
+
additionalProperties: false,
|
|
3591
|
+
properties: {
|
|
3592
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
3593
|
+
methods: { type: "array", items: { type: "string" } },
|
|
3594
|
+
structuralMethods: { type: "array", items: { type: "string" } },
|
|
3595
|
+
allowZodScalars: { type: "boolean" }
|
|
3596
|
+
}
|
|
3309
3597
|
}
|
|
3310
|
-
|
|
3311
|
-
defaultOptions: [
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3598
|
+
],
|
|
3599
|
+
defaultOptions: [
|
|
3600
|
+
{
|
|
3601
|
+
namespaces: ["z"],
|
|
3602
|
+
methods: ["array", "union", "record", "tuple"],
|
|
3603
|
+
structuralMethods: [
|
|
3604
|
+
"and",
|
|
3605
|
+
"array",
|
|
3606
|
+
"discriminatedUnion",
|
|
3607
|
+
"intersection",
|
|
3608
|
+
"lazy",
|
|
3609
|
+
"object",
|
|
3610
|
+
"or",
|
|
3611
|
+
"pipe",
|
|
3612
|
+
"record",
|
|
3613
|
+
"transform",
|
|
3614
|
+
"tuple",
|
|
3615
|
+
"union"
|
|
3616
|
+
],
|
|
3617
|
+
allowZodScalars: true
|
|
3618
|
+
}
|
|
3619
|
+
],
|
|
3317
3620
|
messages: { inline: "Inline single-use scalar schema {{name}} at its only structural use." }
|
|
3318
3621
|
},
|
|
3319
3622
|
create(context) {
|
|
@@ -3367,14 +3670,16 @@ import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
|
3367
3670
|
var noTopLevelFunctions = defineRule29({
|
|
3368
3671
|
meta: {
|
|
3369
3672
|
type: "problem",
|
|
3370
|
-
schema: [
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3673
|
+
schema: [
|
|
3674
|
+
{
|
|
3675
|
+
type: "object",
|
|
3676
|
+
additionalProperties: false,
|
|
3677
|
+
properties: {
|
|
3678
|
+
banReExports: { type: "boolean" },
|
|
3679
|
+
allowPattern: optionsPatternSchema
|
|
3680
|
+
}
|
|
3376
3681
|
}
|
|
3377
|
-
|
|
3682
|
+
],
|
|
3378
3683
|
defaultOptions: [{ banReExports: true }],
|
|
3379
3684
|
messages: {
|
|
3380
3685
|
noFunction: "Files in this scope must not contain top-level function {{name}}.",
|
|
@@ -3422,73 +3727,126 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3422
3727
|
|
|
3423
3728
|
// src/rules/no-trivial-functions.ts
|
|
3424
3729
|
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
return statement.type === "ExpressionStatement" ? statement.expression : null;
|
|
3441
|
-
}
|
|
3442
|
-
function forwardedCall(expression) {
|
|
3443
|
-
if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "ChainExpression") {
|
|
3444
|
-
return forwardedCall(expression.expression);
|
|
3445
|
-
}
|
|
3446
|
-
if (expression.type === "AwaitExpression") {
|
|
3447
|
-
return forwardedCall(expression.argument);
|
|
3448
|
-
}
|
|
3449
|
-
return expression.type === "CallExpression" ? expression : null;
|
|
3450
|
-
}
|
|
3730
|
+
|
|
3731
|
+
// src/constants/trivial.constants.ts
|
|
3732
|
+
var trivialBannedNames = [
|
|
3733
|
+
"isRecord",
|
|
3734
|
+
"isPlainObject",
|
|
3735
|
+
"isObject",
|
|
3736
|
+
"isString",
|
|
3737
|
+
"isNumber",
|
|
3738
|
+
"isBoolean",
|
|
3739
|
+
"isArray",
|
|
3740
|
+
"asRecord",
|
|
3741
|
+
"asArray"
|
|
3742
|
+
];
|
|
3743
|
+
|
|
3744
|
+
// src/rules/no-trivial-functions.ts
|
|
3451
3745
|
var noTrivialFunctions = defineRule30({
|
|
3452
3746
|
meta: {
|
|
3453
3747
|
type: "problem",
|
|
3454
|
-
schema: [
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3748
|
+
schema: [
|
|
3749
|
+
{
|
|
3750
|
+
type: "object",
|
|
3751
|
+
additionalProperties: false,
|
|
3752
|
+
properties: {
|
|
3753
|
+
allowPattern: optionsPatternSchema,
|
|
3754
|
+
allowCallees: { type: "array", items: { type: "string" } },
|
|
3755
|
+
allowAsync: { type: "boolean" },
|
|
3756
|
+
checkServiceMethods: { type: "boolean" },
|
|
3757
|
+
mode: { type: "string", enum: ["legacy", "precise"] },
|
|
3758
|
+
bannedNames: { type: "array", items: { type: "string" }, uniqueItems: true },
|
|
3759
|
+
checkGenericGuards: { type: "boolean" }
|
|
3760
|
+
}
|
|
3461
3761
|
}
|
|
3462
|
-
|
|
3762
|
+
],
|
|
3463
3763
|
messages: {
|
|
3464
|
-
trivial: "Function {{name}}
|
|
3764
|
+
trivial: "Function {{name}} adds no transformation; inline it or use a value for a constant result. Keep deliberate adapters through an explicit rule exclusion.",
|
|
3765
|
+
bannedName: "Helper {{name}} is forbidden by this policy. Inline the local check, or validate external input at its boundary; renaming the guard does not fix it.",
|
|
3766
|
+
genericGuard: "Helper {{name}} only performs generic runtime type checks or fallback reads. Inline the local check, or validate external input at its boundary; do not add a schema merely to retain this helper."
|
|
3465
3767
|
}
|
|
3466
3768
|
},
|
|
3467
3769
|
createOnce(context) {
|
|
3468
3770
|
let allowed = [];
|
|
3469
3771
|
let allowedCallees = [];
|
|
3470
3772
|
let allowAsync = false;
|
|
3773
|
+
let mode = "legacy";
|
|
3774
|
+
let bannedNames = new Set;
|
|
3775
|
+
let checkGenericGuards = false;
|
|
3776
|
+
let checkServiceMethods = false;
|
|
3777
|
+
const reported = new Set;
|
|
3778
|
+
const checked = new Set;
|
|
3779
|
+
function globalArray(node) {
|
|
3780
|
+
let scope = context.sourceCode.getScope(node);
|
|
3781
|
+
while (scope) {
|
|
3782
|
+
const variable = scope.set.get("Array");
|
|
3783
|
+
if (variable)
|
|
3784
|
+
return variable.defs.length === 0;
|
|
3785
|
+
scope = scope.upper;
|
|
3786
|
+
}
|
|
3787
|
+
return true;
|
|
3788
|
+
}
|
|
3789
|
+
function checkHelper(node) {
|
|
3790
|
+
if (bannedNames.size === 0 && !checkGenericGuards || checked.has(node.start))
|
|
3791
|
+
return;
|
|
3792
|
+
checked.add(node.start);
|
|
3793
|
+
const parent = node.parent;
|
|
3794
|
+
const name = node.type !== "ArrowFunctionExpression" && node.id ? node.id.name : parent.type === "VariableDeclarator" && parent.id.type === "Identifier" ? parent.id.name : parent.type === "Property" && !parent.computed && parent.key.type === "Identifier" ? parent.key.name : "<anonymous>";
|
|
3795
|
+
if (optionsPatternsTest(allowed, name))
|
|
3796
|
+
return;
|
|
3797
|
+
if (bannedNames.has(name)) {
|
|
3798
|
+
reported.add(node.start);
|
|
3799
|
+
context.report({ node, messageId: "bannedName", data: { name } });
|
|
3800
|
+
return;
|
|
3801
|
+
}
|
|
3802
|
+
if (checkGenericGuards && guardsIsGenericHelper(node, globalArray)) {
|
|
3803
|
+
reported.add(node.start);
|
|
3804
|
+
context.report({ node, messageId: "genericGuard", data: { name } });
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3471
3807
|
return {
|
|
3472
3808
|
before() {
|
|
3473
|
-
const
|
|
3809
|
+
const options = optionsFirst(context, {});
|
|
3810
|
+
const { allowPattern, allowCallees: calleePatterns = [], allowAsync: asyncAllowed = false } = options;
|
|
3811
|
+
mode = options.mode ?? "legacy";
|
|
3812
|
+
checkServiceMethods = options.checkServiceMethods ?? false;
|
|
3813
|
+
bannedNames = new Set(options.bannedNames ?? (mode === "precise" ? trivialBannedNames : []));
|
|
3814
|
+
checkGenericGuards = options.checkGenericGuards ?? mode === "precise";
|
|
3815
|
+
reported.clear();
|
|
3816
|
+
checked.clear();
|
|
3474
3817
|
allowed = optionsOptionalPatterns(allowPattern);
|
|
3475
3818
|
allowedCallees = calleePatterns.map((pattern) => new RegExp(pattern));
|
|
3476
3819
|
allowAsync = asyncAllowed;
|
|
3477
3820
|
},
|
|
3821
|
+
FunctionDeclaration: checkHelper,
|
|
3822
|
+
FunctionExpression: checkHelper,
|
|
3823
|
+
ArrowFunctionExpression: checkHelper,
|
|
3478
3824
|
Program(program) {
|
|
3479
3825
|
const seen = new Set;
|
|
3480
|
-
for (const item of [
|
|
3826
|
+
for (const item of [
|
|
3827
|
+
...exportsCollectFunctions(program),
|
|
3828
|
+
...declarationsTopLevelUnexportedFunctions(program),
|
|
3829
|
+
...checkServiceMethods ? declarationsPublicServiceMethods(program) : []
|
|
3830
|
+
]) {
|
|
3481
3831
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
3482
|
-
if (seen.has(key) || optionsPatternsTest(allowed, item.name)
|
|
3832
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name)) {
|
|
3483
3833
|
continue;
|
|
3484
3834
|
}
|
|
3485
|
-
|
|
3486
|
-
|
|
3835
|
+
seen.add(key);
|
|
3836
|
+
checkHelper(item.node);
|
|
3837
|
+
if (reported.has(item.node.start))
|
|
3838
|
+
continue;
|
|
3839
|
+
const expression = trivialExpression(item.node);
|
|
3840
|
+
const trivial = mode === "legacy" ? declarationsIsTrivialFunction(item.node) : expression ? trivialIsForwarder(item.node, expression) : declarationsIsTrivialFunction(item.node);
|
|
3841
|
+
if (!trivial)
|
|
3842
|
+
continue;
|
|
3843
|
+
const value = expression && trivialUnwrap(expression);
|
|
3844
|
+
const call = value?.type === "CallExpression" ? value : null;
|
|
3487
3845
|
const path = call && astDottedName(call.callee);
|
|
3488
3846
|
if (allowAsync && item.node.async && call || path && allowedCallees.some((pattern) => pattern.test(path))) {
|
|
3489
3847
|
continue;
|
|
3490
3848
|
}
|
|
3491
|
-
|
|
3849
|
+
reported.add(item.node.start);
|
|
3492
3850
|
context.report({
|
|
3493
3851
|
node: item.node,
|
|
3494
3852
|
messageId: "trivial",
|
|
@@ -3505,13 +3863,15 @@ import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
|
3505
3863
|
var noTypeDeclarations = defineRule31({
|
|
3506
3864
|
meta: {
|
|
3507
3865
|
type: "problem",
|
|
3508
|
-
schema: [
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3866
|
+
schema: [
|
|
3867
|
+
{
|
|
3868
|
+
type: "object",
|
|
3869
|
+
additionalProperties: false,
|
|
3870
|
+
properties: {
|
|
3871
|
+
allowPattern: optionsPatternSchema
|
|
3872
|
+
}
|
|
3513
3873
|
}
|
|
3514
|
-
|
|
3874
|
+
],
|
|
3515
3875
|
messages: {
|
|
3516
3876
|
typeDeclaration: "Type '{{name}}' must not be declared in this file."
|
|
3517
3877
|
}
|
|
@@ -3549,16 +3909,19 @@ import { defineRule as defineRule32 } from "@oxlint/plugins";
|
|
|
3549
3909
|
var noUnescapedLike = defineRule32({
|
|
3550
3910
|
meta: {
|
|
3551
3911
|
type: "problem",
|
|
3552
|
-
schema: [
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3912
|
+
schema: [
|
|
3913
|
+
{
|
|
3914
|
+
type: "object",
|
|
3915
|
+
additionalProperties: false,
|
|
3916
|
+
properties: {
|
|
3917
|
+
methods: { type: "array", items: { type: "string" } },
|
|
3918
|
+
sanitizers: { type: "array", items: { type: "string" } },
|
|
3919
|
+
allowSanitizedBindings: { type: "boolean" },
|
|
3920
|
+
operatorMethods: { type: "array", items: { type: "string" } }
|
|
3921
|
+
},
|
|
3922
|
+
required: ["methods", "sanitizers"]
|
|
3923
|
+
}
|
|
3924
|
+
],
|
|
3562
3925
|
messages: { unescaped: ".{{method}}() values must use a configured sanitizer." }
|
|
3563
3926
|
},
|
|
3564
3927
|
createOnce(context) {
|
|
@@ -3572,9 +3935,11 @@ var noUnescapedLike = defineRule32({
|
|
|
3572
3935
|
if (node.callee.type !== "MemberExpression") {
|
|
3573
3936
|
return;
|
|
3574
3937
|
}
|
|
3575
|
-
const { methods, sanitizers } = optionsFirst(context);
|
|
3938
|
+
const { methods, sanitizers, operatorMethods = [] } = optionsFirst(context);
|
|
3576
3939
|
const method = astStaticMemberName(node.callee);
|
|
3577
|
-
|
|
3940
|
+
const operator = node.arguments[1];
|
|
3941
|
+
const operatorCall = method && operatorMethods.includes(method) && operator?.type === "Literal" && typeof operator.value === "string" && methods.includes(operator.value);
|
|
3942
|
+
if (!method || !methods.includes(method) && !operatorCall) {
|
|
3578
3943
|
return;
|
|
3579
3944
|
}
|
|
3580
3945
|
const value = node.arguments.at(-1);
|
|
@@ -3633,15 +3998,17 @@ var objectMultiline = defineRule33({
|
|
|
3633
3998
|
meta: {
|
|
3634
3999
|
type: "layout",
|
|
3635
4000
|
fixable: "whitespace",
|
|
3636
|
-
schema: [
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
4001
|
+
schema: [
|
|
4002
|
+
{
|
|
4003
|
+
type: "object",
|
|
4004
|
+
additionalProperties: false,
|
|
4005
|
+
properties: {
|
|
4006
|
+
minProperties: { type: "integer", minimum: 1, default: 3 },
|
|
4007
|
+
scope: { type: "string", enum: ["call-args", "all"], default: "call-args" },
|
|
4008
|
+
indent: { ...layoutIndentSchema, default: 2 }
|
|
4009
|
+
}
|
|
3643
4010
|
}
|
|
3644
|
-
|
|
4011
|
+
],
|
|
3645
4012
|
messages: {
|
|
3646
4013
|
callArgs: "Object with {{min}}+ properties in a call should have each property on its own line.",
|
|
3647
4014
|
always: "Object with {{min}}+ properties should have each property on its own line."
|
|
@@ -3693,15 +4060,17 @@ import { defineRule as defineRule34 } from "@oxlint/plugins";
|
|
|
3693
4060
|
var onlyExportComponents = defineRule34({
|
|
3694
4061
|
meta: {
|
|
3695
4062
|
type: "problem",
|
|
3696
|
-
schema: [
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
4063
|
+
schema: [
|
|
4064
|
+
{
|
|
4065
|
+
type: "object",
|
|
4066
|
+
additionalProperties: false,
|
|
4067
|
+
properties: {
|
|
4068
|
+
matchFileName: { type: "boolean" },
|
|
4069
|
+
allowTypeExports: { type: "boolean" },
|
|
4070
|
+
denyTypePattern: optionsPatternSchema
|
|
4071
|
+
}
|
|
3703
4072
|
}
|
|
3704
|
-
|
|
4073
|
+
],
|
|
3705
4074
|
messages: {
|
|
3706
4075
|
nonComponent: "Export '{{name}}' must be a React component or type.",
|
|
3707
4076
|
nameMismatch: "Component export '{{name}}' must match '{{expected}}' or its prefix.",
|
|
@@ -3826,15 +4195,17 @@ function collectBindings(program) {
|
|
|
3826
4195
|
var onlyExportConstants = defineRule35({
|
|
3827
4196
|
meta: {
|
|
3828
4197
|
type: "problem",
|
|
3829
|
-
schema: [
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
4198
|
+
schema: [
|
|
4199
|
+
{
|
|
4200
|
+
type: "object",
|
|
4201
|
+
additionalProperties: false,
|
|
4202
|
+
properties: {
|
|
4203
|
+
allowFunctionValues: { type: "boolean" },
|
|
4204
|
+
allowTypeExports: { type: "boolean" },
|
|
4205
|
+
allowReExports: { type: "boolean" }
|
|
4206
|
+
}
|
|
3836
4207
|
}
|
|
3837
|
-
|
|
4208
|
+
],
|
|
3838
4209
|
messages: {
|
|
3839
4210
|
nonConstant: "Export '{{name}}' must be a local const binding with an allowed value; types and re-exports require explicit options."
|
|
3840
4211
|
}
|
|
@@ -3842,7 +4213,11 @@ var onlyExportConstants = defineRule35({
|
|
|
3842
4213
|
createOnce(context) {
|
|
3843
4214
|
return {
|
|
3844
4215
|
Program(program) {
|
|
3845
|
-
const {
|
|
4216
|
+
const {
|
|
4217
|
+
allowFunctionValues = false,
|
|
4218
|
+
allowTypeExports = false,
|
|
4219
|
+
allowReExports = false
|
|
4220
|
+
} = optionsFirst(context, {});
|
|
3846
4221
|
const bindings = collectBindings(program);
|
|
3847
4222
|
function hasForbiddenValue(binding, seen = new Set) {
|
|
3848
4223
|
if (seen.has(binding) || binding.kind === "class") {
|
|
@@ -3961,13 +4336,16 @@ var paddingBetweenStatements = defineRule36({
|
|
|
3961
4336
|
meta: {
|
|
3962
4337
|
type: "layout",
|
|
3963
4338
|
fixable: "whitespace",
|
|
3964
|
-
schema: [
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
4339
|
+
schema: [
|
|
4340
|
+
{
|
|
4341
|
+
type: "object",
|
|
4342
|
+
additionalProperties: false,
|
|
4343
|
+
properties: {
|
|
4344
|
+
returnMinStatements: { type: "integer", minimum: 1, default: 3 },
|
|
4345
|
+
multilineVariables: { type: "boolean" }
|
|
4346
|
+
}
|
|
3969
4347
|
}
|
|
3970
|
-
|
|
4348
|
+
],
|
|
3971
4349
|
messages: {
|
|
3972
4350
|
variableAndBlock: "Expected a blank line between a variable declaration and a function/class.",
|
|
3973
4351
|
beforeBlock: "Expected a blank line before a function/class declaration.",
|
|
@@ -3975,11 +4353,13 @@ var paddingBetweenStatements = defineRule36({
|
|
|
3975
4353
|
variableAndControl: "Expected a blank line between a variable declaration and control flow.",
|
|
3976
4354
|
controlAndVariable: "Expected a blank line between control flow and a variable declaration.",
|
|
3977
4355
|
consecutiveControl: "Expected a blank line between control flow statements.",
|
|
3978
|
-
beforeReturn: "Expected a blank line before return statement."
|
|
4356
|
+
beforeReturn: "Expected a blank line before return statement.",
|
|
4357
|
+
multilineVariable: "Expected a blank line around a multiline variable declaration."
|
|
3979
4358
|
}
|
|
3980
4359
|
},
|
|
3981
4360
|
createOnce(context) {
|
|
3982
4361
|
let returnMinStatements = 3;
|
|
4362
|
+
let multilineVariables = false;
|
|
3983
4363
|
let newline = `
|
|
3984
4364
|
`;
|
|
3985
4365
|
let source;
|
|
@@ -3993,7 +4373,8 @@ var paddingBetweenStatements = defineRule36({
|
|
|
3993
4373
|
}
|
|
3994
4374
|
const prevKind = paddingKind(prev);
|
|
3995
4375
|
const currKind = paddingKind(curr);
|
|
3996
|
-
const
|
|
4376
|
+
const multiline = multilineVariables && (prevKind === "variable" && prev.loc.start.line !== prev.loc.end.line || currKind === "variable" && curr.loc.start.line !== curr.loc.end.line);
|
|
4377
|
+
const messageId = multiline ? "multilineVariable" : prevKind === "variable" && currKind === "block" || prevKind === "block" && currKind === "variable" ? "variableAndBlock" : currKind === "block" ? "beforeBlock" : prevKind === "block" ? "afterBlock" : prevKind === "variable" && currKind === "control" ? "variableAndControl" : prevKind === "control" && currKind === "variable" ? "controlAndVariable" : prevKind === "control" && currKind === "control" ? "consecutiveControl" : currKind === "return" && prevKind !== "variable" && statements.length >= returnMinStatements ? "beforeReturn" : null;
|
|
3997
4378
|
if (!messageId) {
|
|
3998
4379
|
continue;
|
|
3999
4380
|
}
|
|
@@ -4010,6 +4391,7 @@ var paddingBetweenStatements = defineRule36({
|
|
|
4010
4391
|
before() {
|
|
4011
4392
|
const options = optionsFirst(context, {});
|
|
4012
4393
|
returnMinStatements = options.returnMinStatements ?? 3;
|
|
4394
|
+
multilineVariables = options.multilineVariables ?? false;
|
|
4013
4395
|
source = context.sourceCode;
|
|
4014
4396
|
newline = layoutNewline(source.text);
|
|
4015
4397
|
},
|
|
@@ -4023,20 +4405,163 @@ var paddingBetweenStatements = defineRule36({
|
|
|
4023
4405
|
}
|
|
4024
4406
|
});
|
|
4025
4407
|
|
|
4026
|
-
// src/rules/
|
|
4408
|
+
// src/rules/prefer-namespace-type-import.ts
|
|
4027
4409
|
import { defineRule as defineRule37 } from "@oxlint/plugins";
|
|
4028
|
-
var
|
|
4410
|
+
var bindingName = /^[A-Za-z_$][\w$]*$/;
|
|
4411
|
+
var reservedNames = new Set("await break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield implements interface let package private protected public static arguments eval".split(" "));
|
|
4412
|
+
function namespaceName(source, names) {
|
|
4413
|
+
if (Object.hasOwn(names, source)) {
|
|
4414
|
+
return names[source];
|
|
4415
|
+
}
|
|
4416
|
+
const stem = namingFileBasename(source).replace(/(?:\.d)?\.[cm]?[jt]sx?$/i, "");
|
|
4417
|
+
const name = namingPascalCase(stem.replace(/[^A-Za-z0-9_$.-]/g, "-")) || "Module";
|
|
4418
|
+
const prefixed = /^\d/.test(name) ? `Module${name}` : name;
|
|
4419
|
+
return prefixed.endsWith("Types") ? prefixed : `${prefixed}Types`;
|
|
4420
|
+
}
|
|
4421
|
+
function isTypeOnlyNamedImport(node) {
|
|
4422
|
+
return node.specifiers.length > 0 && node.specifiers.every((specifier) => specifier.type === "ImportSpecifier" && (node.importKind === "type" || specifier.importKind === "type"));
|
|
4423
|
+
}
|
|
4424
|
+
function safeReference(node) {
|
|
4425
|
+
let current = node;
|
|
4426
|
+
let parent = current.parent;
|
|
4427
|
+
while (parent?.type === "TSQualifiedName" && parent.left === current || parent?.type === "MemberExpression" && !parent.computed && parent.object === current) {
|
|
4428
|
+
current = parent;
|
|
4429
|
+
parent = current.parent;
|
|
4430
|
+
}
|
|
4431
|
+
return parent?.type === "TSTypeReference" && parent.typeName === current || parent?.type === "TSTypeQuery" && parent.exprName === current || (parent?.type === "TSInterfaceHeritage" || parent?.type === "TSClassImplements") && parent.expression === current;
|
|
4432
|
+
}
|
|
4433
|
+
var preferNamespaceTypeImport = defineRule37({
|
|
4029
4434
|
meta: {
|
|
4030
|
-
type: "
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4435
|
+
type: "suggestion",
|
|
4436
|
+
fixable: "code",
|
|
4437
|
+
schema: [
|
|
4438
|
+
{
|
|
4439
|
+
type: "object",
|
|
4440
|
+
additionalProperties: false,
|
|
4441
|
+
properties: {
|
|
4442
|
+
max: { type: "integer", minimum: 0 },
|
|
4443
|
+
names: { type: "object", additionalProperties: { type: "string", pattern: bindingName.source } }
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
],
|
|
4447
|
+
defaultOptions: [{ max: 3, names: {} }],
|
|
4448
|
+
messages: {
|
|
4449
|
+
namespace: "Use `import type * as {{name}} from '{{source}}'` for {{count}} type imports (max {{max}}); keep exported domain names.{{reason}}"
|
|
4450
|
+
}
|
|
4451
|
+
},
|
|
4452
|
+
createOnce(context) {
|
|
4453
|
+
const imports = [];
|
|
4454
|
+
return {
|
|
4455
|
+
before() {
|
|
4456
|
+
imports.length = 0;
|
|
4037
4457
|
},
|
|
4038
|
-
|
|
4039
|
-
|
|
4458
|
+
ImportDeclaration(node) {
|
|
4459
|
+
imports.push(node);
|
|
4460
|
+
},
|
|
4461
|
+
"Program:exit"() {
|
|
4462
|
+
const { max, names } = optionsFirst(context);
|
|
4463
|
+
const candidates = imports.filter((node) => isTypeOnlyNamedImport(node) && node.specifiers.length > max);
|
|
4464
|
+
if (candidates.length === 0) {
|
|
4465
|
+
return;
|
|
4466
|
+
}
|
|
4467
|
+
const sourceCode = context.sourceCode;
|
|
4468
|
+
const occupied = new Set;
|
|
4469
|
+
for (const scope of sourceCode.scopeManager.scopes) {
|
|
4470
|
+
for (const variable of scope.variables) {
|
|
4471
|
+
occupied.add(variable.name);
|
|
4472
|
+
}
|
|
4473
|
+
for (const reference of scope.references) {
|
|
4474
|
+
occupied.add(reference.identifier.name);
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
const proposed = candidates.map((node) => namespaceName(node.source.value, names));
|
|
4478
|
+
const comments = sourceCode.getAllComments();
|
|
4479
|
+
const reports = [];
|
|
4480
|
+
const edits = [];
|
|
4481
|
+
for (const [index, node] of candidates.entries()) {
|
|
4482
|
+
const name = proposed[index];
|
|
4483
|
+
let reason = "";
|
|
4484
|
+
const replacements = new Map;
|
|
4485
|
+
if (!bindingName.test(name) || reservedNames.has(name)) {
|
|
4486
|
+
reason = "invalid namespace binding";
|
|
4487
|
+
} else if (imports.some((other) => other.source.value === node.source.value && other.specifiers.some((specifier) => specifier.type === "ImportNamespaceSpecifier"))) {
|
|
4488
|
+
reason = "existing namespace import from this module";
|
|
4489
|
+
} else if (occupied.has(name) || proposed.some((other, otherIndex) => otherIndex !== index && other === name)) {
|
|
4490
|
+
reason = "namespace name collides with a binding, reference, or another proposed namespace";
|
|
4491
|
+
} else if (comments.some((comment) => comment.range[0] >= node.range[0] && comment.range[1] <= node.range[1])) {
|
|
4492
|
+
reason = "comment inside import";
|
|
4493
|
+
} else {
|
|
4494
|
+
const variables = sourceCode.getDeclaredVariables(node);
|
|
4495
|
+
for (const specifier of node.specifiers) {
|
|
4496
|
+
if (specifier.type !== "ImportSpecifier") {
|
|
4497
|
+
continue;
|
|
4498
|
+
}
|
|
4499
|
+
const imported = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
4500
|
+
const variable = variables.find((binding) => binding.identifiers.some((id) => id.range[0] === specifier.local.range[0]));
|
|
4501
|
+
if (!bindingName.test(imported) || !variable || variable.defs.length !== 1) {
|
|
4502
|
+
reason = "unsupported imported name or binding";
|
|
4503
|
+
break;
|
|
4504
|
+
}
|
|
4505
|
+
for (const reference of variable.references) {
|
|
4506
|
+
const identifier = reference.identifier;
|
|
4507
|
+
if (identifier.parent.type === "ExportSpecifier") {
|
|
4508
|
+
reason = "local re-export";
|
|
4509
|
+
break;
|
|
4510
|
+
}
|
|
4511
|
+
if (!safeReference(identifier)) {
|
|
4512
|
+
reason = "unsupported reference syntax";
|
|
4513
|
+
break;
|
|
4514
|
+
}
|
|
4515
|
+
replacements.set(identifier, `${name}.${imported}`);
|
|
4516
|
+
}
|
|
4517
|
+
if (reason) {
|
|
4518
|
+
break;
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
reports.push({ node, name, reason });
|
|
4523
|
+
if (!reason) {
|
|
4524
|
+
edits.push({ range: [node.range[0], node.source.range[0]], text: `import type * as ${name} from ` });
|
|
4525
|
+
for (const [identifier, text] of replacements) {
|
|
4526
|
+
edits.push({ range: identifier.range, text });
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
for (const { node, name, reason } of reports) {
|
|
4531
|
+
context.report({
|
|
4532
|
+
node,
|
|
4533
|
+
messageId: "namespace",
|
|
4534
|
+
data: {
|
|
4535
|
+
name,
|
|
4536
|
+
source: node.source.value,
|
|
4537
|
+
count: node.specifiers.length,
|
|
4538
|
+
max,
|
|
4539
|
+
reason: reason ? ` Autofix skipped: ${reason}.` : ""
|
|
4540
|
+
},
|
|
4541
|
+
fix: reason ? undefined : (fixer) => edits.map((edit) => fixer.replaceTextRange(edit.range, edit.text))
|
|
4542
|
+
});
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
};
|
|
4546
|
+
}
|
|
4547
|
+
});
|
|
4548
|
+
|
|
4549
|
+
// src/rules/require-file-factory.ts
|
|
4550
|
+
import { defineRule as defineRule38 } from "@oxlint/plugins";
|
|
4551
|
+
var requireFileFactory = defineRule38({
|
|
4552
|
+
meta: {
|
|
4553
|
+
type: "problem",
|
|
4554
|
+
schema: [
|
|
4555
|
+
{
|
|
4556
|
+
type: "object",
|
|
4557
|
+
additionalProperties: false,
|
|
4558
|
+
properties: {
|
|
4559
|
+
factory: { type: "string" },
|
|
4560
|
+
allDeclarations: { type: "boolean" }
|
|
4561
|
+
},
|
|
4562
|
+
required: ["factory"]
|
|
4563
|
+
}
|
|
4564
|
+
],
|
|
4040
4565
|
messages: {
|
|
4041
4566
|
factory: "Function '{{actual}}' must be named '{{expected}}'."
|
|
4042
4567
|
}
|
|
@@ -4071,19 +4596,22 @@ var requireFileFactory = defineRule37({
|
|
|
4071
4596
|
});
|
|
4072
4597
|
|
|
4073
4598
|
// src/rules/require-object-params.ts
|
|
4074
|
-
import { defineRule as
|
|
4075
|
-
var requireObjectParams =
|
|
4599
|
+
import { defineRule as defineRule39 } from "@oxlint/plugins";
|
|
4600
|
+
var requireObjectParams = defineRule39({
|
|
4076
4601
|
meta: {
|
|
4077
4602
|
type: "problem",
|
|
4078
|
-
schema: [
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4603
|
+
schema: [
|
|
4604
|
+
{
|
|
4605
|
+
type: "object",
|
|
4606
|
+
additionalProperties: false,
|
|
4607
|
+
properties: {
|
|
4608
|
+
maxParams: { type: "integer", minimum: 1 },
|
|
4609
|
+
serviceMethods: { type: "boolean" },
|
|
4610
|
+
allDeclarations: { type: "boolean" },
|
|
4611
|
+
allowPattern: optionsPatternSchema
|
|
4612
|
+
}
|
|
4085
4613
|
}
|
|
4086
|
-
|
|
4614
|
+
],
|
|
4087
4615
|
messages: {
|
|
4088
4616
|
objectParams: "{{label}} {{name}} must accept at most {{maxParams}} object parameter{{s}}."
|
|
4089
4617
|
}
|
|
@@ -4091,10 +4619,17 @@ var requireObjectParams = defineRule38({
|
|
|
4091
4619
|
createOnce(context) {
|
|
4092
4620
|
return {
|
|
4093
4621
|
Program(program) {
|
|
4094
|
-
const {
|
|
4622
|
+
const {
|
|
4623
|
+
maxParams = 1,
|
|
4624
|
+
allDeclarations = false,
|
|
4625
|
+
serviceMethods = false,
|
|
4626
|
+
allowPattern
|
|
4627
|
+
} = optionsFirst(context, {});
|
|
4095
4628
|
const allowed = optionsOptionalPatterns(allowPattern);
|
|
4096
4629
|
const seen = new Set;
|
|
4097
4630
|
const functions = allDeclarations ? [...exportsCollectFunctions(program), ...declarationsTopLevelUnexportedFunctions(program)] : exportsCollectFunctions(program);
|
|
4631
|
+
if (serviceMethods)
|
|
4632
|
+
functions.push(...declarationsPublicServiceMethods(program));
|
|
4098
4633
|
for (const item of functions) {
|
|
4099
4634
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
4100
4635
|
if (seen.has(key) || optionsPatternsTest(allowed, item.name)) {
|
|
@@ -4120,20 +4655,22 @@ var requireObjectParams = defineRule38({
|
|
|
4120
4655
|
});
|
|
4121
4656
|
|
|
4122
4657
|
// src/rules/require-orpc-output.ts
|
|
4123
|
-
import { defineRule as
|
|
4124
|
-
var requireOrpcOutput =
|
|
4658
|
+
import { defineRule as defineRule40 } from "@oxlint/plugins";
|
|
4659
|
+
var requireOrpcOutput = defineRule40({
|
|
4125
4660
|
meta: {
|
|
4126
4661
|
type: "problem",
|
|
4127
|
-
schema: [
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4662
|
+
schema: [
|
|
4663
|
+
{
|
|
4664
|
+
type: "object",
|
|
4665
|
+
additionalProperties: false,
|
|
4666
|
+
properties: {
|
|
4667
|
+
composers: { type: "array", items: { type: "string" } },
|
|
4668
|
+
handlerMethod: { type: "string" },
|
|
4669
|
+
outputMethod: { type: "string" }
|
|
4670
|
+
},
|
|
4671
|
+
required: ["composers"]
|
|
4672
|
+
}
|
|
4673
|
+
],
|
|
4137
4674
|
messages: {
|
|
4138
4675
|
missing: "oRPC procedures must declare .output() before .handler().",
|
|
4139
4676
|
invalid: "oRPC .output() must use a named schema or configured composer with a named schema."
|
|
@@ -4145,7 +4682,11 @@ var requireOrpcOutput = defineRule39({
|
|
|
4145
4682
|
if (node.callee.type !== "MemberExpression") {
|
|
4146
4683
|
return;
|
|
4147
4684
|
}
|
|
4148
|
-
const {
|
|
4685
|
+
const {
|
|
4686
|
+
composers,
|
|
4687
|
+
handlerMethod = "handler",
|
|
4688
|
+
outputMethod = "output"
|
|
4689
|
+
} = optionsFirst(context);
|
|
4149
4690
|
if (astStaticMemberName(node.callee) !== handlerMethod) {
|
|
4150
4691
|
return;
|
|
4151
4692
|
}
|
|
@@ -4163,34 +4704,33 @@ var requireOrpcOutput = defineRule39({
|
|
|
4163
4704
|
});
|
|
4164
4705
|
|
|
4165
4706
|
// src/rules/require-paired-call.ts
|
|
4166
|
-
import { defineRule as
|
|
4167
|
-
var requirePairedCall =
|
|
4707
|
+
import { defineRule as defineRule41 } from "@oxlint/plugins";
|
|
4708
|
+
var requirePairedCall = defineRule41({
|
|
4168
4709
|
meta: {
|
|
4169
4710
|
type: "problem",
|
|
4170
|
-
schema: [
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4711
|
+
schema: [
|
|
4712
|
+
{
|
|
4713
|
+
type: "object",
|
|
4714
|
+
additionalProperties: false,
|
|
4715
|
+
properties: {
|
|
4716
|
+
when: { type: "string" },
|
|
4717
|
+
require: { type: "string" },
|
|
4718
|
+
pairs: {
|
|
4719
|
+
type: "array",
|
|
4720
|
+
items: {
|
|
4721
|
+
type: "object",
|
|
4722
|
+
additionalProperties: false,
|
|
4723
|
+
properties: {
|
|
4724
|
+
when: { type: "string" },
|
|
4725
|
+
require: { type: "string" }
|
|
4726
|
+
},
|
|
4727
|
+
required: ["when", "require"]
|
|
4728
|
+
}
|
|
4186
4729
|
}
|
|
4187
|
-
}
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
{ required: ["pairs"] }
|
|
4192
|
-
]
|
|
4193
|
-
}],
|
|
4730
|
+
},
|
|
4731
|
+
anyOf: [{ required: ["when", "require"] }, { required: ["pairs"] }]
|
|
4732
|
+
}
|
|
4733
|
+
],
|
|
4194
4734
|
messages: {
|
|
4195
4735
|
paired: "{{when}} requires a call to {{require}} in the same file."
|
|
4196
4736
|
}
|
|
@@ -4239,20 +4779,24 @@ var requirePairedCall = defineRule40({
|
|
|
4239
4779
|
});
|
|
4240
4780
|
|
|
4241
4781
|
// src/rules/route-surface.ts
|
|
4242
|
-
import { defineRule as
|
|
4243
|
-
var routeSurface =
|
|
4782
|
+
import { defineRule as defineRule42 } from "@oxlint/plugins";
|
|
4783
|
+
var routeSurface = defineRule42({
|
|
4244
4784
|
meta: {
|
|
4245
4785
|
type: "problem",
|
|
4246
|
-
schema: [
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4786
|
+
schema: [
|
|
4787
|
+
{
|
|
4788
|
+
type: "object",
|
|
4789
|
+
additionalProperties: false,
|
|
4790
|
+
properties: {
|
|
4791
|
+
exportName: { type: "string" },
|
|
4792
|
+
bannedHooks: { type: "array", items: { type: "string" } },
|
|
4793
|
+
banIntrinsicJsx: { type: "boolean" }
|
|
4794
|
+
}
|
|
4253
4795
|
}
|
|
4254
|
-
|
|
4255
|
-
defaultOptions: [
|
|
4796
|
+
],
|
|
4797
|
+
defaultOptions: [
|
|
4798
|
+
{ exportName: "Route", bannedHooks: ["useState", "useEffect", "useMutation"], banIntrinsicJsx: true }
|
|
4799
|
+
],
|
|
4256
4800
|
messages: {
|
|
4257
4801
|
extraExport: "Route files may only export '{{expected}}'; found '{{actual}}'.",
|
|
4258
4802
|
hostJsx: "Route adapter {{name}} must not render intrinsic JSX.",
|
|
@@ -4282,7 +4826,7 @@ var routeSurface = defineRule41({
|
|
|
4282
4826
|
});
|
|
4283
4827
|
|
|
4284
4828
|
// src/rules/test-title-pattern.ts
|
|
4285
|
-
import { defineRule as
|
|
4829
|
+
import { defineRule as defineRule43 } from "@oxlint/plugins";
|
|
4286
4830
|
var TEST_MODIFIERS = new Set(["only", "skip", "concurrent", "todo", "each"]);
|
|
4287
4831
|
function isConfiguredName(name, callees) {
|
|
4288
4832
|
if (!name) {
|
|
@@ -4322,23 +4866,27 @@ function regexMatches(regex, value) {
|
|
|
4322
4866
|
function titlePatterns(pattern, flags) {
|
|
4323
4867
|
return pattern === undefined ? [] : [pattern].flat().map((source) => ({ regex: new RegExp(source, flags), pattern: source }));
|
|
4324
4868
|
}
|
|
4325
|
-
var testTitlePattern =
|
|
4869
|
+
var testTitlePattern = defineRule43({
|
|
4326
4870
|
meta: {
|
|
4327
4871
|
type: "suggestion",
|
|
4328
|
-
schema: [
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4872
|
+
schema: [
|
|
4873
|
+
{
|
|
4874
|
+
type: "object",
|
|
4875
|
+
additionalProperties: false,
|
|
4876
|
+
properties: {
|
|
4877
|
+
callees: { type: "array", items: { type: "string" } },
|
|
4878
|
+
forbid: optionsPatternSchema,
|
|
4879
|
+
require: optionsPatternSchema,
|
|
4880
|
+
flags: { type: "string", pattern: "^[dgimsuvy]*$" }
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
],
|
|
4884
|
+
defaultOptions: [
|
|
4885
|
+
{
|
|
4886
|
+
callees: ["describe", "it", "test"],
|
|
4887
|
+
flags: ""
|
|
4336
4888
|
}
|
|
4337
|
-
|
|
4338
|
-
defaultOptions: [{
|
|
4339
|
-
callees: ["describe", "it", "test"],
|
|
4340
|
-
flags: ""
|
|
4341
|
-
}],
|
|
4889
|
+
],
|
|
4342
4890
|
messages: {
|
|
4343
4891
|
forbidden: "Test title matches forbidden pattern '{{pattern}}'.",
|
|
4344
4892
|
required: "Test title must match required pattern '{{pattern}}'."
|
|
@@ -4433,6 +4981,7 @@ var src_default = eslintCompatPlugin({
|
|
|
4433
4981
|
"only-export-components": onlyExportComponents,
|
|
4434
4982
|
"only-export-constants": onlyExportConstants,
|
|
4435
4983
|
"padding-between-statements": paddingBetweenStatements,
|
|
4984
|
+
"prefer-namespace-type-import": preferNamespaceTypeImport,
|
|
4436
4985
|
"require-file-factory": requireFileFactory,
|
|
4437
4986
|
"require-object-params": requireObjectParams,
|
|
4438
4987
|
"require-orpc-output": requireOrpcOutput,
|