oxlint-plugin-arch 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -1
- package/README.md +280 -9
- 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/constants/test.constants.d.ts +1 -0
- package/dist/index.js +1271 -734
- package/dist/presets/index.d.ts +2 -0
- package/dist/presets/index.js +1380 -0
- package/dist/presets/tanstack-start-react-modules-preset.d.ts +3 -0
- package/dist/presets/tanstack-start-react-modules-preset.js +1380 -0
- package/dist/rules/dillon-anti-slop/index.js +1588 -0
- package/dist/rules/module-policy/index.js +2053 -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 +127 -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
|
-
|
|
896
|
-
|
|
897
|
-
|
|
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
|
+
}
|
|
1064
|
+
}
|
|
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
|
}
|
|
@@ -1082,29 +1252,152 @@ var chainNewline = defineRule2({
|
|
|
1082
1252
|
}
|
|
1083
1253
|
});
|
|
1084
1254
|
|
|
1085
|
-
// src/rules/
|
|
1255
|
+
// src/rules/component-props.ts
|
|
1086
1256
|
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
1087
|
-
|
|
1257
|
+
function unwrapExport(statement) {
|
|
1258
|
+
return statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
|
|
1259
|
+
}
|
|
1260
|
+
function topLevelComponents(program) {
|
|
1261
|
+
return program.body.flatMap((statement, index) => {
|
|
1262
|
+
const declaration = unwrapExport(statement);
|
|
1263
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id) {
|
|
1264
|
+
return [{ candidate: { name: declaration.id.name, node: declaration, declaration }, index }];
|
|
1265
|
+
}
|
|
1266
|
+
if (declaration?.type !== "VariableDeclaration") {
|
|
1267
|
+
return [];
|
|
1268
|
+
}
|
|
1269
|
+
return declaration.declarations.flatMap((item) => item.id.type === "Identifier" ? [{ candidate: { name: item.id.name, node: item, declaration, initializer: item.init }, index }] : []);
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
function propsTarget(node) {
|
|
1273
|
+
if (node?.type === "FunctionDeclaration" || node?.type === "FunctionExpression" || node?.type === "ArrowFunctionExpression") {
|
|
1274
|
+
return { fn: node };
|
|
1275
|
+
}
|
|
1276
|
+
if (node?.type !== "CallExpression") {
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
const name = astCallName(node);
|
|
1280
|
+
const inner = name === "memo" || name === "forwardRef" ? propsTarget(node.arguments[0]) : undefined;
|
|
1281
|
+
const typeArgument = name === "forwardRef" ? node.typeArguments?.params[1] : undefined;
|
|
1282
|
+
return inner && typeArgument ? { ...inner, typeArgument } : inner;
|
|
1283
|
+
}
|
|
1284
|
+
function parameterType(parameter) {
|
|
1285
|
+
if (parameter?.type === "AssignmentPattern") {
|
|
1286
|
+
return parameterType(parameter.left);
|
|
1287
|
+
}
|
|
1288
|
+
return parameter && parameter.type !== "TSParameterProperty" ? parameter.typeAnnotation?.typeAnnotation : undefined;
|
|
1289
|
+
}
|
|
1290
|
+
function containsTypeLiteral(node) {
|
|
1291
|
+
let found = false;
|
|
1292
|
+
astVisit(node, [], (candidate) => {
|
|
1293
|
+
found ||= candidate.type === "TSTypeLiteral";
|
|
1294
|
+
});
|
|
1295
|
+
return found;
|
|
1296
|
+
}
|
|
1297
|
+
function isPassThrough(type) {
|
|
1298
|
+
if (type.type !== "TSTypeReference") {
|
|
1299
|
+
return false;
|
|
1300
|
+
}
|
|
1301
|
+
const { typeName } = type;
|
|
1302
|
+
const name = typeName.type === "TSQualifiedName" ? typeName.right.name : typeName.type === "Identifier" ? typeName.name : "";
|
|
1303
|
+
const argument = type.typeArguments?.params.length === 1 ? type.typeArguments.params[0] : undefined;
|
|
1304
|
+
return name === "ComponentProps" && (argument?.type === "TSTypeQuery" || argument?.type === "TSLiteralType" && argument.literal.type === "Literal" && typeof argument.literal.value === "string");
|
|
1305
|
+
}
|
|
1306
|
+
var componentProps = defineRule3({
|
|
1088
1307
|
meta: {
|
|
1089
1308
|
type: "problem",
|
|
1090
|
-
schema: [
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
type: "
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1309
|
+
schema: [
|
|
1310
|
+
{
|
|
1311
|
+
type: "object",
|
|
1312
|
+
additionalProperties: false,
|
|
1313
|
+
properties: {
|
|
1314
|
+
filePrefix: { type: "boolean" }
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
],
|
|
1318
|
+
messages: {
|
|
1319
|
+
inline: "'{{name}}' props are typed inline. Declare `interface {{expected}}` directly above it and use that.",
|
|
1320
|
+
name: "'{{name}}' props must use `interface {{expected}}` declared directly above it, not '{{actual}}'.",
|
|
1321
|
+
placement: "Move `interface {{expected}}` directly above '{{name}}', with only blank lines between them.",
|
|
1322
|
+
rename: "Local component '{{name}}' would need `interface {{expected}}`, which breaks the file prefix '{{prefix}}'. Rename the component to start with '{{prefix}}' (for example '{{prefix}}Item')."
|
|
1323
|
+
}
|
|
1324
|
+
},
|
|
1325
|
+
createOnce(context) {
|
|
1326
|
+
return {
|
|
1327
|
+
Program(program) {
|
|
1328
|
+
const { filePrefix = false } = optionsFirst(context, {});
|
|
1329
|
+
const stem = namingFileStem(namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, ""));
|
|
1330
|
+
const exported = new Set(exportsCollect(program).flatMap((binding) => binding.typeOnly ? [] : [binding.localName]));
|
|
1331
|
+
const interfaces = new Map(program.body.flatMap((statement, index) => {
|
|
1332
|
+
const declaration = unwrapExport(statement);
|
|
1333
|
+
return declaration?.type === "TSInterfaceDeclaration" ? [[declaration.id.name, index]] : [];
|
|
1334
|
+
}));
|
|
1335
|
+
for (const { candidate, index } of topLevelComponents(program)) {
|
|
1336
|
+
const target = propsTarget(candidate.initializer ?? candidate.declaration);
|
|
1337
|
+
const parameter = target?.fn.params[0];
|
|
1338
|
+
if (!target || !parameter || !reactComponentsIsLike(program, candidate)) {
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
const type = target.typeArgument ?? parameterType(parameter);
|
|
1342
|
+
const expected = `${candidate.name}Props`;
|
|
1343
|
+
const data = { name: candidate.name, expected };
|
|
1344
|
+
if (filePrefix && !exported.has(candidate.name) && !candidate.name.toLowerCase().startsWith(namingNormalized(stem, "remove-separators"))) {
|
|
1345
|
+
context.report({ node: candidate.node, messageId: "rename", data: { ...data, prefix: namingPascalCase(stem) } });
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
if (type && containsTypeLiteral(type)) {
|
|
1349
|
+
context.report({ node: type, messageId: "inline", data });
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
if (type && isPassThrough(type)) {
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
const declared = interfaces.get(expected);
|
|
1356
|
+
if (declared === undefined || type?.type !== "TSTypeReference" || type.typeName.type !== "Identifier" || type.typeName.name !== expected) {
|
|
1357
|
+
context.report({
|
|
1358
|
+
node: type ?? parameter,
|
|
1359
|
+
messageId: "name",
|
|
1360
|
+
data: { ...data, actual: type ? context.sourceCode.getText(type) : "untyped" }
|
|
1361
|
+
});
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
const previous = program.body[declared];
|
|
1365
|
+
const statement = program.body[index];
|
|
1366
|
+
const between = previous && statement ? context.sourceCode.text.slice(previous.range[1], statement.range[0]) : "";
|
|
1367
|
+
if (declared !== index - 1 || between.trim() !== "") {
|
|
1368
|
+
context.report({ node: type, messageId: "placement", data });
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
// src/rules/declaration-name.ts
|
|
1377
|
+
import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
1378
|
+
var declarationName = defineRule4({
|
|
1379
|
+
meta: {
|
|
1380
|
+
type: "problem",
|
|
1381
|
+
schema: [
|
|
1382
|
+
{
|
|
1383
|
+
type: "object",
|
|
1384
|
+
additionalProperties: false,
|
|
1385
|
+
properties: {
|
|
1386
|
+
kinds: {
|
|
1387
|
+
type: "array",
|
|
1388
|
+
items: { type: "string", enum: [...declarationsKinds] }
|
|
1389
|
+
},
|
|
1390
|
+
pattern: optionsPatternSchema,
|
|
1391
|
+
flags: { type: "string" },
|
|
1392
|
+
stem: { type: "string", enum: [...namingStemModes] },
|
|
1393
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1394
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1395
|
+
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1396
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1397
|
+
allowPattern: optionsPatternSchema
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
],
|
|
1108
1401
|
messages: {
|
|
1109
1402
|
prefix: "'{{name}}' must start with file prefix '{{prefix}}'.",
|
|
1110
1403
|
pattern: "'{{name}}' must match {{pattern}}."
|
|
@@ -1129,7 +1422,10 @@ var declarationName = defineRule3({
|
|
|
1129
1422
|
context.report({
|
|
1130
1423
|
node: item.node,
|
|
1131
1424
|
messageId: expected.length > 0 ? "pattern" : "prefix",
|
|
1132
|
-
data: expected.length > 0 ? {
|
|
1425
|
+
data: expected.length > 0 ? {
|
|
1426
|
+
name: item.name,
|
|
1427
|
+
pattern: optionsPatternLabel([options.pattern ?? []].flat().filter((source) => source !== ""))
|
|
1428
|
+
} : { name: item.name, prefix: prefixes.join(" or ") }
|
|
1133
1429
|
});
|
|
1134
1430
|
}
|
|
1135
1431
|
return {
|
|
@@ -1156,23 +1452,27 @@ var declarationName = defineRule3({
|
|
|
1156
1452
|
});
|
|
1157
1453
|
|
|
1158
1454
|
// src/rules/export-file-prefix.ts
|
|
1159
|
-
import { defineRule as
|
|
1160
|
-
var exportFilePrefix =
|
|
1455
|
+
import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
1456
|
+
var exportFilePrefix = defineRule5({
|
|
1161
1457
|
meta: {
|
|
1162
1458
|
type: "problem",
|
|
1163
|
-
schema: [
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1459
|
+
schema: [
|
|
1460
|
+
{
|
|
1461
|
+
type: "object",
|
|
1462
|
+
additionalProperties: false,
|
|
1463
|
+
properties: {
|
|
1464
|
+
stem: { type: "string", enum: [...namingStemModes] },
|
|
1465
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1466
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1467
|
+
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1468
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1469
|
+
serviceMethods: { type: "boolean" },
|
|
1470
|
+
allFunctions: { type: "boolean" },
|
|
1471
|
+
allDeclarations: { type: "boolean" },
|
|
1472
|
+
allowPattern: optionsPatternSchema
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
],
|
|
1176
1476
|
messages: {
|
|
1177
1477
|
prefix: "'{{name}}' must start with file prefix '{{prefix}}'."
|
|
1178
1478
|
}
|
|
@@ -1192,6 +1492,12 @@ var exportFilePrefix = defineRule4({
|
|
|
1192
1492
|
name: binding.localName ?? binding.exportedName,
|
|
1193
1493
|
node: binding.node
|
|
1194
1494
|
}));
|
|
1495
|
+
if (options.allFunctions && !options.allDeclarations) {
|
|
1496
|
+
const exportedNames = new Set(names.map((item) => item.name));
|
|
1497
|
+
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"))));
|
|
1498
|
+
}
|
|
1499
|
+
if (options.serviceMethods)
|
|
1500
|
+
names.push(...declarationsPublicServiceMethods(program));
|
|
1195
1501
|
const seen = new Set;
|
|
1196
1502
|
for (const item of names) {
|
|
1197
1503
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
@@ -1212,22 +1518,24 @@ var exportFilePrefix = defineRule4({
|
|
|
1212
1518
|
});
|
|
1213
1519
|
|
|
1214
1520
|
// src/rules/export-name-pattern.ts
|
|
1215
|
-
import { defineRule as
|
|
1216
|
-
var exportNamePattern =
|
|
1521
|
+
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
1522
|
+
var exportNamePattern = defineRule6({
|
|
1217
1523
|
meta: {
|
|
1218
1524
|
type: "problem",
|
|
1219
|
-
schema: [
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1525
|
+
schema: [
|
|
1526
|
+
{
|
|
1527
|
+
type: "object",
|
|
1528
|
+
additionalProperties: false,
|
|
1529
|
+
properties: {
|
|
1530
|
+
pattern: optionsPatternSchema,
|
|
1531
|
+
flags: { type: "string" },
|
|
1532
|
+
ignoreTypeExports: { type: "boolean" },
|
|
1533
|
+
allDeclarations: { type: "boolean" },
|
|
1534
|
+
allowPattern: optionsPatternSchema
|
|
1535
|
+
},
|
|
1536
|
+
required: ["pattern"]
|
|
1537
|
+
}
|
|
1538
|
+
],
|
|
1231
1539
|
messages: {
|
|
1232
1540
|
pattern: "'{{name}}' must match {{pattern}}."
|
|
1233
1541
|
}
|
|
@@ -1264,24 +1572,27 @@ var exportNamePattern = defineRule5({
|
|
|
1264
1572
|
});
|
|
1265
1573
|
|
|
1266
1574
|
// src/rules/filename-export-name.ts
|
|
1267
|
-
import { defineRule as
|
|
1268
|
-
var filenameExportName =
|
|
1575
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1576
|
+
var filenameExportName = defineRule7({
|
|
1269
1577
|
meta: {
|
|
1270
1578
|
type: "problem",
|
|
1271
|
-
schema: [
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1579
|
+
schema: [
|
|
1580
|
+
{
|
|
1581
|
+
type: "object",
|
|
1582
|
+
additionalProperties: false,
|
|
1583
|
+
properties: {
|
|
1584
|
+
file: { type: "string" },
|
|
1585
|
+
export: { type: "string" },
|
|
1586
|
+
mode: { type: "string", enum: ["all", "some"] },
|
|
1587
|
+
placeholderPattern: { type: "string" },
|
|
1588
|
+
camelCase: { type: "boolean" },
|
|
1589
|
+
allDeclarations: { type: "boolean" }
|
|
1590
|
+
},
|
|
1591
|
+
required: ["file", "export"]
|
|
1592
|
+
}
|
|
1593
|
+
],
|
|
1283
1594
|
messages: {
|
|
1284
|
-
mismatch: "Function '{{actual}}' must
|
|
1595
|
+
mismatch: "Function '{{actual}}' must be named '{{expected}}' for file '{{file}}'."
|
|
1285
1596
|
}
|
|
1286
1597
|
},
|
|
1287
1598
|
createOnce(context) {
|
|
@@ -1292,13 +1603,14 @@ var filenameExportName = defineRule6({
|
|
|
1292
1603
|
export: exportTemplate,
|
|
1293
1604
|
mode = "all",
|
|
1294
1605
|
placeholderPattern,
|
|
1295
|
-
allDeclarations = false
|
|
1606
|
+
allDeclarations = false,
|
|
1607
|
+
camelCase = false
|
|
1296
1608
|
} = optionsFirst(context);
|
|
1297
1609
|
const groups = namingMatchTemplate(namingFileBasename(context.filename), file, placeholderPattern);
|
|
1298
1610
|
if (!groups) {
|
|
1299
1611
|
return;
|
|
1300
1612
|
}
|
|
1301
|
-
const expected = factoriesExpandTemplate(exportTemplate, groups);
|
|
1613
|
+
const expected = factoriesExpandTemplate(exportTemplate, groups, camelCase);
|
|
1302
1614
|
const functions = allDeclarations ? declarationsCollectFunctions(program) : exportsCollectFunctions(program);
|
|
1303
1615
|
if (mode === "some") {
|
|
1304
1616
|
if (!functions.some((item) => item.name === expected)) {
|
|
@@ -1306,7 +1618,7 @@ var filenameExportName = defineRule6({
|
|
|
1306
1618
|
context.report({
|
|
1307
1619
|
node: first?.node ?? program,
|
|
1308
1620
|
messageId: "mismatch",
|
|
1309
|
-
data: { actual: first?.name ?? "<none>", expected }
|
|
1621
|
+
data: { actual: first?.name ?? "<none>", expected, file: namingFileBasename(context.filename) }
|
|
1310
1622
|
});
|
|
1311
1623
|
}
|
|
1312
1624
|
return;
|
|
@@ -1316,7 +1628,7 @@ var filenameExportName = defineRule6({
|
|
|
1316
1628
|
context.report({
|
|
1317
1629
|
node: item.node,
|
|
1318
1630
|
messageId: "mismatch",
|
|
1319
|
-
data: { actual: item.name, expected }
|
|
1631
|
+
data: { actual: item.name, expected, file: namingFileBasename(context.filename) }
|
|
1320
1632
|
});
|
|
1321
1633
|
}
|
|
1322
1634
|
}
|
|
@@ -1326,20 +1638,22 @@ var filenameExportName = defineRule6({
|
|
|
1326
1638
|
});
|
|
1327
1639
|
|
|
1328
1640
|
// src/rules/filename-match.ts
|
|
1329
|
-
import { defineRule as
|
|
1330
|
-
var filenameMatch =
|
|
1641
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
1642
|
+
var filenameMatch = defineRule8({
|
|
1331
1643
|
meta: {
|
|
1332
1644
|
type: "problem",
|
|
1333
|
-
schema: [
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1645
|
+
schema: [
|
|
1646
|
+
{
|
|
1647
|
+
type: "object",
|
|
1648
|
+
additionalProperties: false,
|
|
1649
|
+
properties: {
|
|
1650
|
+
pattern: optionsPatternSchema,
|
|
1651
|
+
message: { type: "string" },
|
|
1652
|
+
flags: { type: "string" }
|
|
1653
|
+
},
|
|
1654
|
+
required: ["pattern", "message"]
|
|
1655
|
+
}
|
|
1656
|
+
],
|
|
1343
1657
|
messages: {
|
|
1344
1658
|
mismatch: "{{message}}"
|
|
1345
1659
|
}
|
|
@@ -1362,21 +1676,24 @@ var filenameMatch = defineRule7({
|
|
|
1362
1676
|
});
|
|
1363
1677
|
|
|
1364
1678
|
// src/rules/folder-prefix.ts
|
|
1365
|
-
import { defineRule as
|
|
1366
|
-
var folderPrefix =
|
|
1679
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1680
|
+
var folderPrefix = defineRule9({
|
|
1367
1681
|
meta: {
|
|
1368
1682
|
type: "problem",
|
|
1369
|
-
schema: [
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1683
|
+
schema: [
|
|
1684
|
+
{
|
|
1685
|
+
type: "object",
|
|
1686
|
+
additionalProperties: false,
|
|
1687
|
+
properties: {
|
|
1688
|
+
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1689
|
+
separators: { type: "array", items: { type: "string" } },
|
|
1690
|
+
after: { type: "string" },
|
|
1691
|
+
stripPrefixes: { type: "array", items: { type: "string", minLength: 1 } }
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
],
|
|
1378
1695
|
messages: {
|
|
1379
|
-
prefix: "File '{{file}}' must start with
|
|
1696
|
+
prefix: "File '{{file}}' must start with '{{expected}}' to match its domain folder '{{folder}}'."
|
|
1380
1697
|
}
|
|
1381
1698
|
},
|
|
1382
1699
|
createOnce(context) {
|
|
@@ -1385,7 +1702,8 @@ var folderPrefix = defineRule8({
|
|
|
1385
1702
|
const {
|
|
1386
1703
|
singularize = "trailing-s",
|
|
1387
1704
|
separators = ["-"],
|
|
1388
|
-
after
|
|
1705
|
+
after,
|
|
1706
|
+
stripPrefixes = []
|
|
1389
1707
|
} = optionsFirst(context, {});
|
|
1390
1708
|
const filename = namingPosixPath(context.filename);
|
|
1391
1709
|
const folders = after ? namingSegmentsAfter(filename, after) : [namingDirSegments(filename).at(-1) ?? ""];
|
|
@@ -1396,13 +1714,19 @@ var folderPrefix = defineRule8({
|
|
|
1396
1714
|
const separator = separators[0] ?? "-";
|
|
1397
1715
|
const prefixes = namingFolderPrefixes(resolved, separator, singularize);
|
|
1398
1716
|
const file = namingFileBasename(filename);
|
|
1399
|
-
const
|
|
1717
|
+
const rawStem = file.replace(/\.(tsx?|jsx?)$/, "");
|
|
1718
|
+
const strip = stripPrefixes.find((prefix) => rawStem.startsWith(prefix));
|
|
1719
|
+
const stem = strip ? rawStem.slice(strip.length) : rawStem;
|
|
1400
1720
|
const valid = prefixes.some((prefix) => stem === prefix || separators.some((item) => stem.startsWith(`${prefix}${item}`)));
|
|
1401
1721
|
if (!valid) {
|
|
1402
1722
|
context.report({
|
|
1403
1723
|
node: program,
|
|
1404
1724
|
messageId: "prefix",
|
|
1405
|
-
data: {
|
|
1725
|
+
data: {
|
|
1726
|
+
file,
|
|
1727
|
+
folder: resolved.join("/"),
|
|
1728
|
+
expected: prefixes.map((prefix) => `${stripPrefixes[0] ?? ""}${prefix}`).join(" or ")
|
|
1729
|
+
}
|
|
1406
1730
|
});
|
|
1407
1731
|
}
|
|
1408
1732
|
}
|
|
@@ -1411,7 +1735,7 @@ var folderPrefix = defineRule8({
|
|
|
1411
1735
|
});
|
|
1412
1736
|
|
|
1413
1737
|
// src/rules/jsx-attributes-multiline.ts
|
|
1414
|
-
import { defineRule as
|
|
1738
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1415
1739
|
function jsxAttributesMultilineEdits(node, text, attributeIndent, baseIndent, newline) {
|
|
1416
1740
|
const first = node.attributes[0];
|
|
1417
1741
|
const last = node.attributes.at(-1);
|
|
@@ -1421,10 +1745,12 @@ function jsxAttributesMultilineEdits(node, text, attributeIndent, baseIndent, ne
|
|
|
1421
1745
|
const openingRange = [prefix.range[1], first.range[0]];
|
|
1422
1746
|
if (!/^\s*$/.test(text.slice(...openingRange)))
|
|
1423
1747
|
return null;
|
|
1424
|
-
const edits = [
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1748
|
+
const edits = [
|
|
1749
|
+
{
|
|
1750
|
+
range: openingRange,
|
|
1751
|
+
text: `${newline}${attributeIndent}`
|
|
1752
|
+
}
|
|
1753
|
+
];
|
|
1428
1754
|
for (let index = 1;index < node.attributes.length; index++) {
|
|
1429
1755
|
const previous = node.attributes[index - 1];
|
|
1430
1756
|
const current = node.attributes[index];
|
|
@@ -1440,18 +1766,20 @@ function jsxAttributesMultilineEdits(node, text, attributeIndent, baseIndent, ne
|
|
|
1440
1766
|
edits.push({ range: closingRange, text: `${newline}${baseIndent}` });
|
|
1441
1767
|
return edits;
|
|
1442
1768
|
}
|
|
1443
|
-
var jsxAttributesMultiline =
|
|
1769
|
+
var jsxAttributesMultiline = defineRule10({
|
|
1444
1770
|
meta: {
|
|
1445
1771
|
type: "layout",
|
|
1446
1772
|
fixable: "whitespace",
|
|
1447
|
-
schema: [
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1773
|
+
schema: [
|
|
1774
|
+
{
|
|
1775
|
+
type: "object",
|
|
1776
|
+
additionalProperties: false,
|
|
1777
|
+
properties: {
|
|
1778
|
+
minAttributes: { type: "integer", minimum: 1 },
|
|
1779
|
+
indent: layoutIndentSchema
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
],
|
|
1455
1783
|
messages: {
|
|
1456
1784
|
multiline: "Put every JSX attribute and the closing token on its own line."
|
|
1457
1785
|
}
|
|
@@ -1487,8 +1815,8 @@ var jsxAttributesMultiline = defineRule9({
|
|
|
1487
1815
|
});
|
|
1488
1816
|
|
|
1489
1817
|
// src/rules/key-value-same-line.ts
|
|
1490
|
-
import { defineRule as
|
|
1491
|
-
var keyValueSameLine =
|
|
1818
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
1819
|
+
var keyValueSameLine = defineRule11({
|
|
1492
1820
|
meta: {
|
|
1493
1821
|
type: "layout",
|
|
1494
1822
|
fixable: "whitespace",
|
|
@@ -1537,7 +1865,7 @@ var keyValueSameLine = defineRule10({
|
|
|
1537
1865
|
});
|
|
1538
1866
|
|
|
1539
1867
|
// src/rules/no-comments.ts
|
|
1540
|
-
import { defineRule as
|
|
1868
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
1541
1869
|
var NO_COMMENTS_LINE_GAP = /^[\t \r\n\u2028\u2029]*$/;
|
|
1542
1870
|
var NO_COMMENTS_LINE_TERMINATOR = /\r\n|[\n\r\u2028\u2029]/;
|
|
1543
1871
|
var NO_COMMENTS_TRAILING_LINES = /^[\t ]*(?:\r\n|[\n\r\u2028\u2029])(?:[\t ]*(?:\r\n|[\n\r\u2028\u2029]))*/;
|
|
@@ -1629,19 +1957,21 @@ function noCommentsJsxEmptyContainer(containers, start, end) {
|
|
|
1629
1957
|
const container = containers[low - 1];
|
|
1630
1958
|
return container?.range[1] >= end ? container : undefined;
|
|
1631
1959
|
}
|
|
1632
|
-
var noComments =
|
|
1960
|
+
var noComments = defineRule12({
|
|
1633
1961
|
meta: {
|
|
1634
1962
|
type: "suggestion",
|
|
1635
1963
|
fixable: "code",
|
|
1636
|
-
schema: [
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1964
|
+
schema: [
|
|
1965
|
+
{
|
|
1966
|
+
type: "object",
|
|
1967
|
+
additionalProperties: false,
|
|
1968
|
+
properties: {
|
|
1969
|
+
allowWhy: { type: "boolean", default: true },
|
|
1970
|
+
allowPatterns: { type: "array", items: { type: "string" } },
|
|
1971
|
+
allowJsdoc: { type: "boolean", default: false }
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
],
|
|
1645
1975
|
messages: {
|
|
1646
1976
|
comment: "Remove this comment."
|
|
1647
1977
|
}
|
|
@@ -1759,23 +2089,25 @@ var noComments = defineRule11({
|
|
|
1759
2089
|
});
|
|
1760
2090
|
|
|
1761
2091
|
// src/rules/no-extra-exports.ts
|
|
1762
|
-
import { defineRule as
|
|
1763
|
-
var noExtraExports =
|
|
2092
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
2093
|
+
var noExtraExports = defineRule13({
|
|
1764
2094
|
meta: {
|
|
1765
2095
|
type: "problem",
|
|
1766
|
-
schema: [
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
2096
|
+
schema: [
|
|
2097
|
+
{
|
|
2098
|
+
type: "object",
|
|
2099
|
+
additionalProperties: false,
|
|
2100
|
+
properties: {
|
|
2101
|
+
names: { type: "array", items: { type: "string" } },
|
|
2102
|
+
patterns: { type: "array", items: { type: "string" } },
|
|
2103
|
+
domainStem: { type: "string", enum: [...namingStemModes] },
|
|
2104
|
+
trailingRoles: { type: "array", items: { type: "string" } },
|
|
2105
|
+
roleSeparators: { type: "array", items: { type: "string" } },
|
|
2106
|
+
allowTypeExports: { type: "boolean" }
|
|
2107
|
+
},
|
|
2108
|
+
required: ["names"]
|
|
2109
|
+
}
|
|
2110
|
+
],
|
|
1779
2111
|
messages: {
|
|
1780
2112
|
extraExport: "Export '{{name}}' is not allowed; expected one of: {{allowed}}."
|
|
1781
2113
|
}
|
|
@@ -1817,7 +2149,7 @@ var noExtraExports = defineRule12({
|
|
|
1817
2149
|
});
|
|
1818
2150
|
|
|
1819
2151
|
// src/rules/no-extra-factory-keys.ts
|
|
1820
|
-
import { defineRule as
|
|
2152
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
1821
2153
|
function compileFactoryKeys(pattern, keys, requireKeys) {
|
|
1822
2154
|
const allowedList = keys.concat(requireKeys.filter((key) => !keys.includes(key)));
|
|
1823
2155
|
return {
|
|
@@ -1827,31 +2159,33 @@ function compileFactoryKeys(pattern, keys, requireKeys) {
|
|
|
1827
2159
|
requireKeys
|
|
1828
2160
|
};
|
|
1829
2161
|
}
|
|
1830
|
-
var noExtraFactoryKeys =
|
|
2162
|
+
var noExtraFactoryKeys = defineRule14({
|
|
1831
2163
|
meta: {
|
|
1832
2164
|
type: "problem",
|
|
1833
|
-
schema: [
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
2165
|
+
schema: [
|
|
2166
|
+
{
|
|
2167
|
+
type: "object",
|
|
2168
|
+
additionalProperties: false,
|
|
2169
|
+
properties: {
|
|
2170
|
+
keys: { type: "array", items: { type: "string" } },
|
|
2171
|
+
factoryPattern: optionsPatternSchema,
|
|
2172
|
+
requireKeys: { type: "array", items: { type: "string" } },
|
|
2173
|
+
keySets: {
|
|
2174
|
+
type: "array",
|
|
2175
|
+
items: {
|
|
2176
|
+
type: "object",
|
|
2177
|
+
additionalProperties: false,
|
|
2178
|
+
properties: {
|
|
2179
|
+
factoryPattern: optionsPatternSchema,
|
|
2180
|
+
keys: { type: "array", items: { type: "string" } },
|
|
2181
|
+
requireKeys: { type: "array", items: { type: "string" } }
|
|
2182
|
+
},
|
|
2183
|
+
required: ["factoryPattern", "keys"]
|
|
2184
|
+
}
|
|
1851
2185
|
}
|
|
1852
2186
|
}
|
|
1853
2187
|
}
|
|
1854
|
-
|
|
2188
|
+
],
|
|
1855
2189
|
messages: {
|
|
1856
2190
|
extraKey: "Factory '{{factory}}' must not return key '{{key}}'; allowed keys: {{allowed}}.",
|
|
1857
2191
|
missingKey: "Factory '{{factory}}' must return key '{{key}}'.",
|
|
@@ -1904,7 +2238,11 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1904
2238
|
context.report({
|
|
1905
2239
|
node: property,
|
|
1906
2240
|
messageId: "extraKey",
|
|
1907
|
-
data: {
|
|
2241
|
+
data: {
|
|
2242
|
+
factory: factory.name,
|
|
2243
|
+
key: key ?? "<computed or spread>",
|
|
2244
|
+
allowed: resolved.allowedList.join(", ")
|
|
2245
|
+
}
|
|
1908
2246
|
});
|
|
1909
2247
|
}
|
|
1910
2248
|
}
|
|
@@ -1925,21 +2263,24 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1925
2263
|
});
|
|
1926
2264
|
|
|
1927
2265
|
// src/rules/no-file-level-helpers.ts
|
|
1928
|
-
import { defineRule as
|
|
1929
|
-
var noFileLevelHelpers =
|
|
2266
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
2267
|
+
var noFileLevelHelpers = defineRule15({
|
|
1930
2268
|
meta: {
|
|
1931
2269
|
type: "problem",
|
|
1932
|
-
schema: [
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2270
|
+
schema: [
|
|
2271
|
+
{
|
|
2272
|
+
type: "object",
|
|
2273
|
+
additionalProperties: false,
|
|
2274
|
+
properties: {
|
|
2275
|
+
allowPattern: optionsPatternSchema,
|
|
2276
|
+
message: { type: "string" },
|
|
2277
|
+
detectComponents: { type: "boolean" },
|
|
2278
|
+
hookPattern: optionsPatternSchema
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
],
|
|
1941
2282
|
messages: {
|
|
1942
|
-
helper: "
|
|
2283
|
+
helper: "{{name}}: {{message}}"
|
|
1943
2284
|
}
|
|
1944
2285
|
},
|
|
1945
2286
|
createOnce(context) {
|
|
@@ -1947,6 +2288,7 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1947
2288
|
Program(program) {
|
|
1948
2289
|
const {
|
|
1949
2290
|
allowPattern,
|
|
2291
|
+
message = "Keep this helper inside its owning component or hook.",
|
|
1950
2292
|
detectComponents = true,
|
|
1951
2293
|
hookPattern = "^use[A-Z]"
|
|
1952
2294
|
} = optionsFirst(context, {});
|
|
@@ -1959,7 +2301,7 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1959
2301
|
context.report({
|
|
1960
2302
|
node: candidate.node,
|
|
1961
2303
|
messageId: "helper",
|
|
1962
|
-
data: { name: candidate.name }
|
|
2304
|
+
data: { name: candidate.name, message }
|
|
1963
2305
|
});
|
|
1964
2306
|
}
|
|
1965
2307
|
}
|
|
@@ -1968,9 +2310,9 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1968
2310
|
});
|
|
1969
2311
|
|
|
1970
2312
|
// src/rules/no-imported-type-alias.ts
|
|
1971
|
-
import { defineRule as
|
|
2313
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
1972
2314
|
function importedAliasTarget(declaration, imports) {
|
|
1973
|
-
if (declaration?.type !== "TSTypeAliasDeclaration" || declaration.typeAnnotation.type !== "TSTypeReference" || declaration.typeAnnotation.typeName.type !== "Identifier" || !imports.has(declaration.typeAnnotation.typeName.name)) {
|
|
2315
|
+
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
2316
|
return;
|
|
1975
2317
|
}
|
|
1976
2318
|
return declaration.typeAnnotation.typeName.name;
|
|
@@ -1978,18 +2320,34 @@ function importedAliasTarget(declaration, imports) {
|
|
|
1978
2320
|
function specifierLocalName(specifier) {
|
|
1979
2321
|
return specifier.local.type === "Identifier" ? specifier.local.name : specifier.local.value;
|
|
1980
2322
|
}
|
|
1981
|
-
var noImportedTypeAlias =
|
|
2323
|
+
var noImportedTypeAlias = defineRule16({
|
|
1982
2324
|
meta: {
|
|
1983
2325
|
type: "problem",
|
|
1984
2326
|
schema: [],
|
|
1985
2327
|
messages: {
|
|
1986
|
-
alias: "
|
|
2328
|
+
alias: "Import '{{name}}' from '{{source}}' at the callers instead of exporting alias '{{alias}}'. Keep genuine derivations; do not substitute an empty interface."
|
|
1987
2329
|
}
|
|
1988
2330
|
},
|
|
1989
2331
|
createOnce(context) {
|
|
1990
2332
|
return {
|
|
1991
2333
|
Program(program) {
|
|
1992
|
-
const imports = new Set
|
|
2334
|
+
const imports = new Set;
|
|
2335
|
+
const sources = new Map;
|
|
2336
|
+
const names = new Map;
|
|
2337
|
+
for (const statement of program.body) {
|
|
2338
|
+
if (statement.type !== "ImportDeclaration")
|
|
2339
|
+
continue;
|
|
2340
|
+
for (const specifier of statement.specifiers) {
|
|
2341
|
+
const local = specifier.local.name;
|
|
2342
|
+
let name = local;
|
|
2343
|
+
if (specifier.type === "ImportSpecifier") {
|
|
2344
|
+
name = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
2345
|
+
}
|
|
2346
|
+
imports.add(local);
|
|
2347
|
+
sources.set(local, statement.source.value);
|
|
2348
|
+
names.set(local, name);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
1993
2351
|
const aliases = new Map;
|
|
1994
2352
|
for (const statement of program.body) {
|
|
1995
2353
|
const declaration = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
|
|
@@ -2007,7 +2365,11 @@ var noImportedTypeAlias = defineRule15({
|
|
|
2007
2365
|
context.report({
|
|
2008
2366
|
node: statement.declaration,
|
|
2009
2367
|
messageId: "alias",
|
|
2010
|
-
data: {
|
|
2368
|
+
data: {
|
|
2369
|
+
alias: statement.declaration.id.name,
|
|
2370
|
+
name: names.get(inline) ?? inline,
|
|
2371
|
+
source: sources.get(inline) ?? "<import source>"
|
|
2372
|
+
}
|
|
2011
2373
|
});
|
|
2012
2374
|
}
|
|
2013
2375
|
for (const specifier of statement.specifiers) {
|
|
@@ -2017,7 +2379,11 @@ var noImportedTypeAlias = defineRule15({
|
|
|
2017
2379
|
context.report({
|
|
2018
2380
|
node: specifier,
|
|
2019
2381
|
messageId: "alias",
|
|
2020
|
-
data: {
|
|
2382
|
+
data: {
|
|
2383
|
+
alias: local,
|
|
2384
|
+
name: names.get(imported) ?? imported,
|
|
2385
|
+
source: sources.get(imported) ?? "<import source>"
|
|
2386
|
+
}
|
|
2021
2387
|
});
|
|
2022
2388
|
}
|
|
2023
2389
|
}
|
|
@@ -2028,26 +2394,39 @@ var noImportedTypeAlias = defineRule15({
|
|
|
2028
2394
|
});
|
|
2029
2395
|
|
|
2030
2396
|
// src/rules/no-inline-schema-elements.ts
|
|
2031
|
-
import { defineRule as
|
|
2032
|
-
var noInlineSchemaElements =
|
|
2397
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
2398
|
+
var noInlineSchemaElements = defineRule17({
|
|
2033
2399
|
meta: {
|
|
2034
2400
|
type: "problem",
|
|
2035
|
-
schema: [
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2401
|
+
schema: [
|
|
2402
|
+
{
|
|
2403
|
+
type: "object",
|
|
2404
|
+
additionalProperties: false,
|
|
2405
|
+
properties: {
|
|
2406
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
2407
|
+
methods: { type: "array", items: { type: "string" } },
|
|
2408
|
+
structuralMethods: { type: "array", items: { type: "string" } },
|
|
2409
|
+
allowZodScalars: { type: "boolean" }
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
],
|
|
2413
|
+
defaultOptions: [
|
|
2414
|
+
{
|
|
2415
|
+
namespaces: ["z"],
|
|
2416
|
+
methods: ["array", "union", "record", "tuple"],
|
|
2417
|
+
structuralMethods: [
|
|
2418
|
+
"array",
|
|
2419
|
+
"discriminatedUnion",
|
|
2420
|
+
"intersection",
|
|
2421
|
+
"lazy",
|
|
2422
|
+
"object",
|
|
2423
|
+
"record",
|
|
2424
|
+
"tuple",
|
|
2425
|
+
"union"
|
|
2426
|
+
],
|
|
2427
|
+
allowZodScalars: true
|
|
2428
|
+
}
|
|
2429
|
+
],
|
|
2051
2430
|
messages: { inline: "z.{{method}}() elements must use named schemas." }
|
|
2052
2431
|
},
|
|
2053
2432
|
createOnce(context) {
|
|
@@ -2077,7 +2456,7 @@ var noInlineSchemaElements = defineRule16({
|
|
|
2077
2456
|
});
|
|
2078
2457
|
|
|
2079
2458
|
// src/rules/no-inline-types.ts
|
|
2080
|
-
import { defineRule as
|
|
2459
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
2081
2460
|
function parameterAnnotation(parameter) {
|
|
2082
2461
|
if (parameter.type === "TSParameterProperty") {
|
|
2083
2462
|
return parameterAnnotation(parameter.parameter);
|
|
@@ -2087,19 +2466,21 @@ function parameterAnnotation(parameter) {
|
|
|
2087
2466
|
}
|
|
2088
2467
|
return parameter.typeAnnotation;
|
|
2089
2468
|
}
|
|
2090
|
-
var noInlineTypes =
|
|
2469
|
+
var noInlineTypes = defineRule18({
|
|
2091
2470
|
meta: {
|
|
2092
2471
|
type: "problem",
|
|
2093
|
-
schema: [
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2472
|
+
schema: [
|
|
2473
|
+
{
|
|
2474
|
+
type: "object",
|
|
2475
|
+
additionalProperties: false,
|
|
2476
|
+
properties: {
|
|
2477
|
+
parameters: { type: "boolean" },
|
|
2478
|
+
returns: { type: "boolean" },
|
|
2479
|
+
functionTypes: { type: "boolean" },
|
|
2480
|
+
minMembers: { type: "integer", minimum: 1 }
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
],
|
|
2103
2484
|
messages: {
|
|
2104
2485
|
inlineType: "Use a named type instead of an inline {{kind}} type in this {{position}} annotation."
|
|
2105
2486
|
}
|
|
@@ -2155,7 +2536,7 @@ var noInlineTypes = defineRule17({
|
|
|
2155
2536
|
});
|
|
2156
2537
|
|
|
2157
2538
|
// src/rules/no-literal-in.ts
|
|
2158
|
-
import { defineRule as
|
|
2539
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
2159
2540
|
function literalKey(node) {
|
|
2160
2541
|
if (node.type === "Literal" && typeof node.value === "string") {
|
|
2161
2542
|
return node.value;
|
|
@@ -2164,16 +2545,18 @@ function literalKey(node) {
|
|
|
2164
2545
|
return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw;
|
|
2165
2546
|
}
|
|
2166
2547
|
}
|
|
2167
|
-
var noLiteralIn =
|
|
2548
|
+
var noLiteralIn = defineRule19({
|
|
2168
2549
|
meta: {
|
|
2169
2550
|
type: "suggestion",
|
|
2170
|
-
schema: [
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2551
|
+
schema: [
|
|
2552
|
+
{
|
|
2553
|
+
type: "object",
|
|
2554
|
+
additionalProperties: false,
|
|
2555
|
+
properties: {
|
|
2556
|
+
allow: { type: "array", items: { type: "string" } }
|
|
2557
|
+
}
|
|
2175
2558
|
}
|
|
2176
|
-
|
|
2559
|
+
],
|
|
2177
2560
|
defaultOptions: [{ allow: [] }],
|
|
2178
2561
|
messages: {
|
|
2179
2562
|
literalIn: "Avoid '{{key}}' in value; use Object.hasOwn() or a discriminated union."
|
|
@@ -2203,32 +2586,36 @@ var noLiteralIn = defineRule18({
|
|
|
2203
2586
|
});
|
|
2204
2587
|
|
|
2205
2588
|
// src/rules/no-local-schema-construction.ts
|
|
2206
|
-
import { defineRule as
|
|
2589
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
2207
2590
|
var defaultRuntimeImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
|
|
2208
2591
|
var defaultConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
|
|
2209
2592
|
function formatMessage(template, data) {
|
|
2210
2593
|
return Object.entries(data).reduce((result, [key, value]) => result.replaceAll(`{{${key}}}`, value), template);
|
|
2211
2594
|
}
|
|
2212
|
-
var noLocalSchemaConstruction =
|
|
2595
|
+
var noLocalSchemaConstruction = defineRule20({
|
|
2213
2596
|
meta: {
|
|
2214
2597
|
type: "problem",
|
|
2215
|
-
schema: [
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2598
|
+
schema: [
|
|
2599
|
+
{
|
|
2600
|
+
type: "object",
|
|
2601
|
+
additionalProperties: false,
|
|
2602
|
+
properties: {
|
|
2603
|
+
packages: { type: "array", items: { type: "string" } },
|
|
2604
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
2605
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
2606
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
2607
|
+
message: { type: "string" },
|
|
2608
|
+
runtimeImportMessage: { type: "string" },
|
|
2609
|
+
constructionMessage: { type: "string" }
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
],
|
|
2613
|
+
defaultOptions: [
|
|
2614
|
+
{
|
|
2615
|
+
packages: ["zod"],
|
|
2616
|
+
namespaces: ["z"]
|
|
2617
|
+
}
|
|
2618
|
+
],
|
|
2232
2619
|
messages: {
|
|
2233
2620
|
runtimeImport: "{{message}}",
|
|
2234
2621
|
construction: "{{message}}"
|
|
@@ -2265,7 +2652,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2265
2652
|
node,
|
|
2266
2653
|
messageId: "runtimeImport",
|
|
2267
2654
|
data: {
|
|
2268
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2655
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2656
|
+
source: node.source.value
|
|
2657
|
+
})
|
|
2269
2658
|
}
|
|
2270
2659
|
});
|
|
2271
2660
|
},
|
|
@@ -2282,7 +2671,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2282
2671
|
node,
|
|
2283
2672
|
messageId: "runtimeImport",
|
|
2284
2673
|
data: {
|
|
2285
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2674
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2675
|
+
source: node.source.value
|
|
2676
|
+
})
|
|
2286
2677
|
}
|
|
2287
2678
|
});
|
|
2288
2679
|
},
|
|
@@ -2299,7 +2690,9 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2299
2690
|
node,
|
|
2300
2691
|
messageId: "runtimeImport",
|
|
2301
2692
|
data: {
|
|
2302
|
-
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2693
|
+
message: formatMessage(runtimeImportMessage ?? message ?? defaultRuntimeImportMessage, {
|
|
2694
|
+
source: node.source.value
|
|
2695
|
+
})
|
|
2303
2696
|
}
|
|
2304
2697
|
});
|
|
2305
2698
|
},
|
|
@@ -2321,18 +2714,20 @@ var noLocalSchemaConstruction = defineRule19({
|
|
|
2321
2714
|
});
|
|
2322
2715
|
|
|
2323
2716
|
// src/rules/no-member-comments.ts
|
|
2324
|
-
import { defineRule as
|
|
2325
|
-
var noMemberComments =
|
|
2717
|
+
import { defineRule as defineRule21 } from "@oxlint/plugins";
|
|
2718
|
+
var noMemberComments = defineRule21({
|
|
2326
2719
|
meta: {
|
|
2327
2720
|
type: "suggestion",
|
|
2328
2721
|
fixable: "code",
|
|
2329
|
-
schema: [
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2722
|
+
schema: [
|
|
2723
|
+
{
|
|
2724
|
+
type: "object",
|
|
2725
|
+
additionalProperties: false,
|
|
2726
|
+
properties: {
|
|
2727
|
+
allowWhy: { type: "boolean", default: true }
|
|
2728
|
+
}
|
|
2334
2729
|
}
|
|
2335
|
-
|
|
2730
|
+
],
|
|
2336
2731
|
messages: {
|
|
2337
2732
|
memberComment: "Remove this comment from the type member."
|
|
2338
2733
|
}
|
|
@@ -2416,7 +2811,7 @@ var noMemberComments = defineRule20({
|
|
|
2416
2811
|
});
|
|
2417
2812
|
|
|
2418
2813
|
// src/rules/no-module-mutable-state.ts
|
|
2419
|
-
import { defineRule as
|
|
2814
|
+
import { defineRule as defineRule22 } from "@oxlint/plugins";
|
|
2420
2815
|
function moduleMutableStateBindings(pattern) {
|
|
2421
2816
|
if (pattern.type === "Identifier") {
|
|
2422
2817
|
return [{ name: pattern.name, node: pattern }];
|
|
@@ -2455,20 +2850,22 @@ function moduleMutableStateInsideAmbient(node) {
|
|
|
2455
2850
|
}
|
|
2456
2851
|
return false;
|
|
2457
2852
|
}
|
|
2458
|
-
var noModuleMutableState =
|
|
2853
|
+
var noModuleMutableState = defineRule22({
|
|
2459
2854
|
meta: {
|
|
2460
2855
|
type: "problem",
|
|
2461
|
-
schema: [
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2856
|
+
schema: [
|
|
2857
|
+
{
|
|
2858
|
+
type: "object",
|
|
2859
|
+
additionalProperties: false,
|
|
2860
|
+
properties: {
|
|
2861
|
+
kinds: {
|
|
2862
|
+
type: "array",
|
|
2863
|
+
items: { type: "string", enum: ["let", "var"] }
|
|
2864
|
+
},
|
|
2865
|
+
allowNamePattern: optionsPatternSchema
|
|
2866
|
+
}
|
|
2470
2867
|
}
|
|
2471
|
-
|
|
2868
|
+
],
|
|
2472
2869
|
messages: {
|
|
2473
2870
|
moduleState: "module state is shared across requests/tests; keep it local."
|
|
2474
2871
|
}
|
|
@@ -2505,7 +2902,7 @@ var noModuleMutableState = defineRule21({
|
|
|
2505
2902
|
});
|
|
2506
2903
|
|
|
2507
2904
|
// src/rules/no-promise-all-mutation.ts
|
|
2508
|
-
import { defineRule as
|
|
2905
|
+
import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
2509
2906
|
function mutationBinding(node) {
|
|
2510
2907
|
if (node.type === "Identifier") {
|
|
2511
2908
|
return node;
|
|
@@ -2533,23 +2930,27 @@ function mutationBindings(node) {
|
|
|
2533
2930
|
}
|
|
2534
2931
|
}
|
|
2535
2932
|
}
|
|
2536
|
-
var noPromiseAllMutation =
|
|
2933
|
+
var noPromiseAllMutation = defineRule23({
|
|
2537
2934
|
meta: {
|
|
2538
2935
|
type: "problem",
|
|
2539
|
-
schema: [
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2936
|
+
schema: [
|
|
2937
|
+
{
|
|
2938
|
+
type: "object",
|
|
2939
|
+
additionalProperties: false,
|
|
2940
|
+
properties: {
|
|
2941
|
+
combinators: { type: "array", items: { type: "string" } },
|
|
2942
|
+
methods: { type: "array", items: { type: "string" } },
|
|
2943
|
+
checkAssignments: { type: "boolean" }
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
],
|
|
2947
|
+
defaultOptions: [
|
|
2948
|
+
{
|
|
2949
|
+
combinators: ["Promise.all", "Promise.allSettled", "Promise.any", "Promise.race"],
|
|
2950
|
+
methods: ["push", "unshift", "splice", "set", "add"],
|
|
2951
|
+
checkAssignments: true
|
|
2952
|
+
}
|
|
2953
|
+
],
|
|
2553
2954
|
messages: {
|
|
2554
2955
|
mutation: "Do not mutate outer binding '{{name}}' inside {{combinator}}()."
|
|
2555
2956
|
}
|
|
@@ -2629,20 +3030,22 @@ var noPromiseAllMutation = defineRule22({
|
|
|
2629
3030
|
});
|
|
2630
3031
|
|
|
2631
3032
|
// src/rules/no-rederive-schema.ts
|
|
2632
|
-
import { defineRule as
|
|
2633
|
-
var noRederiveSchema =
|
|
3033
|
+
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
3034
|
+
var noRederiveSchema = defineRule24({
|
|
2634
3035
|
meta: {
|
|
2635
3036
|
type: "problem",
|
|
2636
|
-
schema: [
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
3037
|
+
schema: [
|
|
3038
|
+
{
|
|
3039
|
+
type: "object",
|
|
3040
|
+
additionalProperties: false,
|
|
3041
|
+
properties: {
|
|
3042
|
+
from: { type: "array", items: { type: "string" } },
|
|
3043
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
3044
|
+
operators: { type: "array", items: { type: "string" } }
|
|
3045
|
+
},
|
|
3046
|
+
required: ["from"]
|
|
3047
|
+
}
|
|
3048
|
+
],
|
|
2646
3049
|
messages: {
|
|
2647
3050
|
rederive: "Do not derive {{operator}} from imported schema {{schema}}; import its DTO type."
|
|
2648
3051
|
}
|
|
@@ -2655,10 +3058,7 @@ var noRederiveSchema = defineRule23({
|
|
|
2655
3058
|
imported = new Set(program.body.flatMap((statement) => statement.type === "ImportDeclaration" && from.includes(statement.source.value) ? statement.specifiers.map((specifier) => specifier.local.name) : []));
|
|
2656
3059
|
},
|
|
2657
3060
|
TSTypeReference(node) {
|
|
2658
|
-
const {
|
|
2659
|
-
namespaces = ["z"],
|
|
2660
|
-
operators = ["infer", "input"]
|
|
2661
|
-
} = optionsFirst(context);
|
|
3061
|
+
const { namespaces = ["z"], operators = ["infer", "input"] } = optionsFirst(context);
|
|
2662
3062
|
const operator = schemasTypeOperator(node, new Set(namespaces), new Set(operators));
|
|
2663
3063
|
const parameter = node.typeArguments?.params[0];
|
|
2664
3064
|
if (!operator || parameter?.type !== "TSTypeQuery" || parameter.exprName.type !== "Identifier" || !imported.has(parameter.exprName.name)) {
|
|
@@ -2675,7 +3075,7 @@ var noRederiveSchema = defineRule23({
|
|
|
2675
3075
|
});
|
|
2676
3076
|
|
|
2677
3077
|
// src/rules/no-restricted-constructor.ts
|
|
2678
|
-
import { defineRule as
|
|
3078
|
+
import { defineRule as defineRule25 } from "@oxlint/plugins";
|
|
2679
3079
|
function restrictedConstructorEntries(constructors) {
|
|
2680
3080
|
const entries = new Map;
|
|
2681
3081
|
for (const item of constructors) {
|
|
@@ -2691,35 +3091,37 @@ function restrictedConstructorEntries(constructors) {
|
|
|
2691
3091
|
}
|
|
2692
3092
|
return entries;
|
|
2693
3093
|
}
|
|
2694
|
-
var noRestrictedConstructor =
|
|
3094
|
+
var noRestrictedConstructor = defineRule25({
|
|
2695
3095
|
meta: {
|
|
2696
3096
|
type: "problem",
|
|
2697
|
-
schema: [
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
3097
|
+
schema: [
|
|
3098
|
+
{
|
|
3099
|
+
type: "object",
|
|
3100
|
+
additionalProperties: false,
|
|
3101
|
+
properties: {
|
|
3102
|
+
constructors: {
|
|
3103
|
+
type: "array",
|
|
3104
|
+
items: {
|
|
3105
|
+
anyOf: [
|
|
3106
|
+
{ type: "string" },
|
|
3107
|
+
{
|
|
3108
|
+
type: "object",
|
|
3109
|
+
additionalProperties: false,
|
|
3110
|
+
properties: {
|
|
3111
|
+
name: { type: "string" },
|
|
3112
|
+
message: { type: "string" }
|
|
3113
|
+
},
|
|
3114
|
+
required: ["name"]
|
|
3115
|
+
}
|
|
3116
|
+
]
|
|
3117
|
+
}
|
|
3118
|
+
},
|
|
3119
|
+
checkCalls: { type: "boolean", default: false },
|
|
3120
|
+
message: { type: "string" }
|
|
2717
3121
|
},
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
required: ["constructors"]
|
|
2722
|
-
}],
|
|
3122
|
+
required: ["constructors"]
|
|
3123
|
+
}
|
|
3124
|
+
],
|
|
2723
3125
|
messages: {
|
|
2724
3126
|
construct: "Do not construct '{{name}}'.{{suffix}}",
|
|
2725
3127
|
call: "Do not call '{{name}}'.{{suffix}}"
|
|
@@ -2764,18 +3166,20 @@ var noRestrictedConstructor = defineRule24({
|
|
|
2764
3166
|
});
|
|
2765
3167
|
|
|
2766
3168
|
// src/rules/no-restricted-files.ts
|
|
2767
|
-
import { defineRule as
|
|
2768
|
-
var noRestrictedFiles =
|
|
3169
|
+
import { defineRule as defineRule26 } from "@oxlint/plugins";
|
|
3170
|
+
var noRestrictedFiles = defineRule26({
|
|
2769
3171
|
meta: {
|
|
2770
3172
|
type: "problem",
|
|
2771
|
-
schema: [
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
3173
|
+
schema: [
|
|
3174
|
+
{
|
|
3175
|
+
type: "object",
|
|
3176
|
+
additionalProperties: false,
|
|
3177
|
+
properties: {
|
|
3178
|
+
message: { type: "string" }
|
|
3179
|
+
},
|
|
3180
|
+
required: ["message"]
|
|
3181
|
+
}
|
|
3182
|
+
],
|
|
2779
3183
|
messages: {
|
|
2780
3184
|
restricted: "{{message}}"
|
|
2781
3185
|
}
|
|
@@ -2795,7 +3199,7 @@ var noRestrictedFiles = defineRule25({
|
|
|
2795
3199
|
});
|
|
2796
3200
|
|
|
2797
3201
|
// src/rules/no-restricted-token.ts
|
|
2798
|
-
import { defineRule as
|
|
3202
|
+
import { defineRule as defineRule27 } from "@oxlint/plugins";
|
|
2799
3203
|
function tokenIsTypeOnlyImport(node) {
|
|
2800
3204
|
const parent = node.parent;
|
|
2801
3205
|
if (parent?.type === "ImportSpecifier") {
|
|
@@ -2806,40 +3210,39 @@ function tokenIsTypeOnlyImport(node) {
|
|
|
2806
3210
|
function memberMatches(node, restriction) {
|
|
2807
3211
|
return restriction.startsWith("*.") ? astStaticMemberName(node) === restriction.slice(2) : astDottedName(node) === restriction;
|
|
2808
3212
|
}
|
|
2809
|
-
var noRestrictedToken =
|
|
3213
|
+
var noRestrictedToken = defineRule27({
|
|
2810
3214
|
meta: {
|
|
2811
3215
|
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
|
-
|
|
3216
|
+
schema: [
|
|
3217
|
+
{
|
|
3218
|
+
type: "object",
|
|
3219
|
+
additionalProperties: false,
|
|
3220
|
+
properties: {
|
|
3221
|
+
token: { type: "string" },
|
|
3222
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
3223
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
3224
|
+
restrictions: {
|
|
3225
|
+
type: "array",
|
|
3226
|
+
items: {
|
|
3227
|
+
type: "object",
|
|
3228
|
+
additionalProperties: false,
|
|
3229
|
+
properties: {
|
|
3230
|
+
token: { type: "string" },
|
|
3231
|
+
member: { type: "string" },
|
|
3232
|
+
allowIn: { type: "array", items: { type: "string" } },
|
|
3233
|
+
allowPathPatterns: { type: "array", items: { type: "string" } },
|
|
3234
|
+
message: { type: "string" }
|
|
3235
|
+
},
|
|
3236
|
+
oneOf: [
|
|
3237
|
+
{ required: ["token"], not: { required: ["member"] } },
|
|
3238
|
+
{ required: ["member"], not: { required: ["token"] } }
|
|
3239
|
+
]
|
|
3240
|
+
}
|
|
2835
3241
|
}
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
{ required: ["restrictions"] }
|
|
2841
|
-
]
|
|
2842
|
-
}],
|
|
3242
|
+
},
|
|
3243
|
+
anyOf: [{ required: ["token"] }, { required: ["restrictions"] }]
|
|
3244
|
+
}
|
|
3245
|
+
],
|
|
2843
3246
|
messages: {
|
|
2844
3247
|
restricted: "'{{token}}' may only appear in configured owner paths.",
|
|
2845
3248
|
restrictedWithMessage: "'{{token}}' may only appear in configured owner paths. {{custom}}"
|
|
@@ -2858,11 +3261,13 @@ var noRestrictedToken = defineRule26({
|
|
|
2858
3261
|
before() {
|
|
2859
3262
|
const options = optionsFirst(context);
|
|
2860
3263
|
const configured = [
|
|
2861
|
-
...options.token ? [
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
3264
|
+
...options.token ? [
|
|
3265
|
+
{
|
|
3266
|
+
token: options.token,
|
|
3267
|
+
allowIn: options.allowIn,
|
|
3268
|
+
allowPathPatterns: options.allowPathPatterns
|
|
3269
|
+
}
|
|
3270
|
+
] : [],
|
|
2866
3271
|
...options.restrictions ?? []
|
|
2867
3272
|
];
|
|
2868
3273
|
const filename = namingPosixPath(context.filename);
|
|
@@ -2902,7 +3307,7 @@ var noRestrictedToken = defineRule26({
|
|
|
2902
3307
|
});
|
|
2903
3308
|
|
|
2904
3309
|
// src/rules/no-runtime-in-types.ts
|
|
2905
|
-
import { defineRule as
|
|
3310
|
+
import { defineRule as defineRule28 } from "@oxlint/plugins";
|
|
2906
3311
|
function isTypeOnlyImport(statement) {
|
|
2907
3312
|
return statement.importKind === "type" || statement.specifiers.length > 0 && statement.specifiers.every((specifier) => specifier.type === "ImportSpecifier" && specifier.importKind === "type");
|
|
2908
3313
|
}
|
|
@@ -3119,22 +3524,24 @@ function isRuntimeReExport(statement, runtimeImportLocals, valueNames, isAmbient
|
|
|
3119
3524
|
}
|
|
3120
3525
|
return statement.specifiers.some((specifier) => specifier.exportKind !== "type" && runtimeImportLocals.has(exportLocalName(specifier)));
|
|
3121
3526
|
}
|
|
3122
|
-
var noRuntimeInTypes =
|
|
3527
|
+
var noRuntimeInTypes = defineRule28({
|
|
3123
3528
|
meta: {
|
|
3124
3529
|
type: "problem",
|
|
3125
|
-
schema: [
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3530
|
+
schema: [
|
|
3531
|
+
{
|
|
3532
|
+
type: "object",
|
|
3533
|
+
additionalProperties: false,
|
|
3534
|
+
properties: {
|
|
3535
|
+
allow: {
|
|
3536
|
+
type: "array",
|
|
3537
|
+
items: { type: "string", enum: ["class", "default", "enum", "function", "variable"] }
|
|
3538
|
+
},
|
|
3539
|
+
runtimeImports: { type: "string", enum: ["allow", "ban"] },
|
|
3540
|
+
allowImportSources: { type: "array", items: { type: "string" } },
|
|
3541
|
+
banReExports: { type: "boolean" }
|
|
3542
|
+
}
|
|
3136
3543
|
}
|
|
3137
|
-
|
|
3544
|
+
],
|
|
3138
3545
|
messages: {
|
|
3139
3546
|
runtimeValue: "Types files must not contain runtime value {{name}}.",
|
|
3140
3547
|
runtimeImport: "Types files must not contain runtime imports from {{source}}.",
|
|
@@ -3261,7 +3668,7 @@ var noRuntimeInTypes = defineRule27({
|
|
|
3261
3668
|
});
|
|
3262
3669
|
|
|
3263
3670
|
// src/rules/no-single-use-scalar-schema.ts
|
|
3264
|
-
import { defineRule as
|
|
3671
|
+
import { defineRule as defineRule29 } from "@oxlint/plugins";
|
|
3265
3672
|
function isScalarSchema(node, namespaces, structuralMethods) {
|
|
3266
3673
|
if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
|
|
3267
3674
|
return false;
|
|
@@ -3295,25 +3702,42 @@ function isAllowedStructuralElement(identifier, initializer, ancestors, options,
|
|
|
3295
3702
|
const method = call.callee.type === "MemberExpression" ? astStaticMemberName(call.callee) : undefined;
|
|
3296
3703
|
return Boolean(method && options.methods.includes(method) && schemasElements(call).includes(identifier));
|
|
3297
3704
|
}
|
|
3298
|
-
var noSingleUseScalarSchema =
|
|
3705
|
+
var noSingleUseScalarSchema = defineRule29({
|
|
3299
3706
|
meta: {
|
|
3300
3707
|
type: "suggestion",
|
|
3301
|
-
schema: [
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3708
|
+
schema: [
|
|
3709
|
+
{
|
|
3710
|
+
type: "object",
|
|
3711
|
+
additionalProperties: false,
|
|
3712
|
+
properties: {
|
|
3713
|
+
namespaces: { type: "array", items: { type: "string" } },
|
|
3714
|
+
methods: { type: "array", items: { type: "string" } },
|
|
3715
|
+
structuralMethods: { type: "array", items: { type: "string" } },
|
|
3716
|
+
allowZodScalars: { type: "boolean" }
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
],
|
|
3720
|
+
defaultOptions: [
|
|
3721
|
+
{
|
|
3722
|
+
namespaces: ["z"],
|
|
3723
|
+
methods: ["array", "union", "record", "tuple"],
|
|
3724
|
+
structuralMethods: [
|
|
3725
|
+
"and",
|
|
3726
|
+
"array",
|
|
3727
|
+
"discriminatedUnion",
|
|
3728
|
+
"intersection",
|
|
3729
|
+
"lazy",
|
|
3730
|
+
"object",
|
|
3731
|
+
"or",
|
|
3732
|
+
"pipe",
|
|
3733
|
+
"record",
|
|
3734
|
+
"transform",
|
|
3735
|
+
"tuple",
|
|
3736
|
+
"union"
|
|
3737
|
+
],
|
|
3738
|
+
allowZodScalars: true
|
|
3739
|
+
}
|
|
3740
|
+
],
|
|
3317
3741
|
messages: { inline: "Inline single-use scalar schema {{name}} at its only structural use." }
|
|
3318
3742
|
},
|
|
3319
3743
|
create(context) {
|
|
@@ -3363,18 +3787,20 @@ var noSingleUseScalarSchema = defineRule28({
|
|
|
3363
3787
|
});
|
|
3364
3788
|
|
|
3365
3789
|
// src/rules/no-top-level-functions.ts
|
|
3366
|
-
import { defineRule as
|
|
3367
|
-
var noTopLevelFunctions =
|
|
3790
|
+
import { defineRule as defineRule30 } from "@oxlint/plugins";
|
|
3791
|
+
var noTopLevelFunctions = defineRule30({
|
|
3368
3792
|
meta: {
|
|
3369
3793
|
type: "problem",
|
|
3370
|
-
schema: [
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3794
|
+
schema: [
|
|
3795
|
+
{
|
|
3796
|
+
type: "object",
|
|
3797
|
+
additionalProperties: false,
|
|
3798
|
+
properties: {
|
|
3799
|
+
banReExports: { type: "boolean" },
|
|
3800
|
+
allowPattern: optionsPatternSchema
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
],
|
|
3378
3804
|
defaultOptions: [{ banReExports: true }],
|
|
3379
3805
|
messages: {
|
|
3380
3806
|
noFunction: "Files in this scope must not contain top-level function {{name}}.",
|
|
@@ -3421,74 +3847,127 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3421
3847
|
});
|
|
3422
3848
|
|
|
3423
3849
|
// src/rules/no-trivial-functions.ts
|
|
3424
|
-
import { defineRule as
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
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
|
-
}
|
|
3451
|
-
var noTrivialFunctions = defineRule30({
|
|
3850
|
+
import { defineRule as defineRule31 } from "@oxlint/plugins";
|
|
3851
|
+
|
|
3852
|
+
// src/constants/trivial.constants.ts
|
|
3853
|
+
var trivialBannedNames = [
|
|
3854
|
+
"isRecord",
|
|
3855
|
+
"isPlainObject",
|
|
3856
|
+
"isObject",
|
|
3857
|
+
"isString",
|
|
3858
|
+
"isNumber",
|
|
3859
|
+
"isBoolean",
|
|
3860
|
+
"isArray",
|
|
3861
|
+
"asRecord",
|
|
3862
|
+
"asArray"
|
|
3863
|
+
];
|
|
3864
|
+
|
|
3865
|
+
// src/rules/no-trivial-functions.ts
|
|
3866
|
+
var noTrivialFunctions = defineRule31({
|
|
3452
3867
|
meta: {
|
|
3453
3868
|
type: "problem",
|
|
3454
|
-
schema: [
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3869
|
+
schema: [
|
|
3870
|
+
{
|
|
3871
|
+
type: "object",
|
|
3872
|
+
additionalProperties: false,
|
|
3873
|
+
properties: {
|
|
3874
|
+
allowPattern: optionsPatternSchema,
|
|
3875
|
+
allowCallees: { type: "array", items: { type: "string" } },
|
|
3876
|
+
allowAsync: { type: "boolean" },
|
|
3877
|
+
checkServiceMethods: { type: "boolean" },
|
|
3878
|
+
mode: { type: "string", enum: ["legacy", "precise"] },
|
|
3879
|
+
bannedNames: { type: "array", items: { type: "string" }, uniqueItems: true },
|
|
3880
|
+
checkGenericGuards: { type: "boolean" }
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
],
|
|
3463
3884
|
messages: {
|
|
3464
|
-
trivial: "Function {{name}}
|
|
3885
|
+
trivial: "Function {{name}} adds no transformation; inline it or use a value for a constant result. Keep deliberate adapters through an explicit rule exclusion.",
|
|
3886
|
+
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.",
|
|
3887
|
+
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
3888
|
}
|
|
3466
3889
|
},
|
|
3467
3890
|
createOnce(context) {
|
|
3468
3891
|
let allowed = [];
|
|
3469
3892
|
let allowedCallees = [];
|
|
3470
3893
|
let allowAsync = false;
|
|
3894
|
+
let mode = "legacy";
|
|
3895
|
+
let bannedNames = new Set;
|
|
3896
|
+
let checkGenericGuards = false;
|
|
3897
|
+
let checkServiceMethods = false;
|
|
3898
|
+
const reported = new Set;
|
|
3899
|
+
const checked = new Set;
|
|
3900
|
+
function globalArray(node) {
|
|
3901
|
+
let scope = context.sourceCode.getScope(node);
|
|
3902
|
+
while (scope) {
|
|
3903
|
+
const variable = scope.set.get("Array");
|
|
3904
|
+
if (variable)
|
|
3905
|
+
return variable.defs.length === 0;
|
|
3906
|
+
scope = scope.upper;
|
|
3907
|
+
}
|
|
3908
|
+
return true;
|
|
3909
|
+
}
|
|
3910
|
+
function checkHelper(node) {
|
|
3911
|
+
if (bannedNames.size === 0 && !checkGenericGuards || checked.has(node.start))
|
|
3912
|
+
return;
|
|
3913
|
+
checked.add(node.start);
|
|
3914
|
+
const parent = node.parent;
|
|
3915
|
+
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>";
|
|
3916
|
+
if (optionsPatternsTest(allowed, name))
|
|
3917
|
+
return;
|
|
3918
|
+
if (bannedNames.has(name)) {
|
|
3919
|
+
reported.add(node.start);
|
|
3920
|
+
context.report({ node, messageId: "bannedName", data: { name } });
|
|
3921
|
+
return;
|
|
3922
|
+
}
|
|
3923
|
+
if (checkGenericGuards && guardsIsGenericHelper(node, globalArray)) {
|
|
3924
|
+
reported.add(node.start);
|
|
3925
|
+
context.report({ node, messageId: "genericGuard", data: { name } });
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3471
3928
|
return {
|
|
3472
3929
|
before() {
|
|
3473
|
-
const
|
|
3930
|
+
const options = optionsFirst(context, {});
|
|
3931
|
+
const { allowPattern, allowCallees: calleePatterns = [], allowAsync: asyncAllowed = false } = options;
|
|
3932
|
+
mode = options.mode ?? "legacy";
|
|
3933
|
+
checkServiceMethods = options.checkServiceMethods ?? false;
|
|
3934
|
+
bannedNames = new Set(options.bannedNames ?? (mode === "precise" ? trivialBannedNames : []));
|
|
3935
|
+
checkGenericGuards = options.checkGenericGuards ?? mode === "precise";
|
|
3936
|
+
reported.clear();
|
|
3937
|
+
checked.clear();
|
|
3474
3938
|
allowed = optionsOptionalPatterns(allowPattern);
|
|
3475
3939
|
allowedCallees = calleePatterns.map((pattern) => new RegExp(pattern));
|
|
3476
3940
|
allowAsync = asyncAllowed;
|
|
3477
3941
|
},
|
|
3942
|
+
FunctionDeclaration: checkHelper,
|
|
3943
|
+
FunctionExpression: checkHelper,
|
|
3944
|
+
ArrowFunctionExpression: checkHelper,
|
|
3478
3945
|
Program(program) {
|
|
3479
3946
|
const seen = new Set;
|
|
3480
|
-
for (const item of [
|
|
3947
|
+
for (const item of [
|
|
3948
|
+
...exportsCollectFunctions(program),
|
|
3949
|
+
...declarationsTopLevelUnexportedFunctions(program),
|
|
3950
|
+
...checkServiceMethods ? declarationsPublicServiceMethods(program) : []
|
|
3951
|
+
]) {
|
|
3481
3952
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
3482
|
-
if (seen.has(key) || optionsPatternsTest(allowed, item.name)
|
|
3953
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name)) {
|
|
3483
3954
|
continue;
|
|
3484
3955
|
}
|
|
3485
|
-
|
|
3486
|
-
|
|
3956
|
+
seen.add(key);
|
|
3957
|
+
checkHelper(item.node);
|
|
3958
|
+
if (reported.has(item.node.start))
|
|
3959
|
+
continue;
|
|
3960
|
+
const expression = trivialExpression(item.node);
|
|
3961
|
+
const trivial = mode === "legacy" ? declarationsIsTrivialFunction(item.node) : expression ? trivialIsForwarder(item.node, expression) : declarationsIsTrivialFunction(item.node);
|
|
3962
|
+
if (!trivial)
|
|
3963
|
+
continue;
|
|
3964
|
+
const value = expression && trivialUnwrap(expression);
|
|
3965
|
+
const call = value?.type === "CallExpression" ? value : null;
|
|
3487
3966
|
const path = call && astDottedName(call.callee);
|
|
3488
3967
|
if (allowAsync && item.node.async && call || path && allowedCallees.some((pattern) => pattern.test(path))) {
|
|
3489
3968
|
continue;
|
|
3490
3969
|
}
|
|
3491
|
-
|
|
3970
|
+
reported.add(item.node.start);
|
|
3492
3971
|
context.report({
|
|
3493
3972
|
node: item.node,
|
|
3494
3973
|
messageId: "trivial",
|
|
@@ -3501,17 +3980,19 @@ var noTrivialFunctions = defineRule30({
|
|
|
3501
3980
|
});
|
|
3502
3981
|
|
|
3503
3982
|
// src/rules/no-type-declarations.ts
|
|
3504
|
-
import { defineRule as
|
|
3505
|
-
var noTypeDeclarations =
|
|
3983
|
+
import { defineRule as defineRule32 } from "@oxlint/plugins";
|
|
3984
|
+
var noTypeDeclarations = defineRule32({
|
|
3506
3985
|
meta: {
|
|
3507
3986
|
type: "problem",
|
|
3508
|
-
schema: [
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3987
|
+
schema: [
|
|
3988
|
+
{
|
|
3989
|
+
type: "object",
|
|
3990
|
+
additionalProperties: false,
|
|
3991
|
+
properties: {
|
|
3992
|
+
allowPattern: optionsPatternSchema
|
|
3993
|
+
}
|
|
3513
3994
|
}
|
|
3514
|
-
|
|
3995
|
+
],
|
|
3515
3996
|
messages: {
|
|
3516
3997
|
typeDeclaration: "Type '{{name}}' must not be declared in this file."
|
|
3517
3998
|
}
|
|
@@ -3545,20 +4026,23 @@ var noTypeDeclarations = defineRule31({
|
|
|
3545
4026
|
});
|
|
3546
4027
|
|
|
3547
4028
|
// src/rules/no-unescaped-like.ts
|
|
3548
|
-
import { defineRule as
|
|
3549
|
-
var noUnescapedLike =
|
|
4029
|
+
import { defineRule as defineRule33 } from "@oxlint/plugins";
|
|
4030
|
+
var noUnescapedLike = defineRule33({
|
|
3550
4031
|
meta: {
|
|
3551
4032
|
type: "problem",
|
|
3552
|
-
schema: [
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
4033
|
+
schema: [
|
|
4034
|
+
{
|
|
4035
|
+
type: "object",
|
|
4036
|
+
additionalProperties: false,
|
|
4037
|
+
properties: {
|
|
4038
|
+
methods: { type: "array", items: { type: "string" } },
|
|
4039
|
+
sanitizers: { type: "array", items: { type: "string" } },
|
|
4040
|
+
allowSanitizedBindings: { type: "boolean" },
|
|
4041
|
+
operatorMethods: { type: "array", items: { type: "string" } }
|
|
4042
|
+
},
|
|
4043
|
+
required: ["methods", "sanitizers"]
|
|
4044
|
+
}
|
|
4045
|
+
],
|
|
3562
4046
|
messages: { unescaped: ".{{method}}() values must use a configured sanitizer." }
|
|
3563
4047
|
},
|
|
3564
4048
|
createOnce(context) {
|
|
@@ -3572,9 +4056,11 @@ var noUnescapedLike = defineRule32({
|
|
|
3572
4056
|
if (node.callee.type !== "MemberExpression") {
|
|
3573
4057
|
return;
|
|
3574
4058
|
}
|
|
3575
|
-
const { methods, sanitizers } = optionsFirst(context);
|
|
4059
|
+
const { methods, sanitizers, operatorMethods = [] } = optionsFirst(context);
|
|
3576
4060
|
const method = astStaticMemberName(node.callee);
|
|
3577
|
-
|
|
4061
|
+
const operator = node.arguments[1];
|
|
4062
|
+
const operatorCall = method && operatorMethods.includes(method) && operator?.type === "Literal" && typeof operator.value === "string" && methods.includes(operator.value);
|
|
4063
|
+
if (!method || !methods.includes(method) && !operatorCall) {
|
|
3578
4064
|
return;
|
|
3579
4065
|
}
|
|
3580
4066
|
const value = node.arguments.at(-1);
|
|
@@ -3592,7 +4078,7 @@ var noUnescapedLike = defineRule32({
|
|
|
3592
4078
|
});
|
|
3593
4079
|
|
|
3594
4080
|
// src/rules/object-multiline.ts
|
|
3595
|
-
import { defineRule as
|
|
4081
|
+
import { defineRule as defineRule34 } from "@oxlint/plugins";
|
|
3596
4082
|
function objectMultilineIsCallArg(node) {
|
|
3597
4083
|
const parent = node.parent;
|
|
3598
4084
|
return (parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node);
|
|
@@ -3629,19 +4115,21 @@ function objectMultilineGaps(text, node) {
|
|
|
3629
4115
|
}
|
|
3630
4116
|
return gaps;
|
|
3631
4117
|
}
|
|
3632
|
-
var objectMultiline =
|
|
4118
|
+
var objectMultiline = defineRule34({
|
|
3633
4119
|
meta: {
|
|
3634
4120
|
type: "layout",
|
|
3635
4121
|
fixable: "whitespace",
|
|
3636
|
-
schema: [
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
4122
|
+
schema: [
|
|
4123
|
+
{
|
|
4124
|
+
type: "object",
|
|
4125
|
+
additionalProperties: false,
|
|
4126
|
+
properties: {
|
|
4127
|
+
minProperties: { type: "integer", minimum: 1, default: 3 },
|
|
4128
|
+
scope: { type: "string", enum: ["call-args", "all"], default: "call-args" },
|
|
4129
|
+
indent: { ...layoutIndentSchema, default: 2 }
|
|
4130
|
+
}
|
|
4131
|
+
}
|
|
4132
|
+
],
|
|
3645
4133
|
messages: {
|
|
3646
4134
|
callArgs: "Object with {{min}}+ properties in a call should have each property on its own line.",
|
|
3647
4135
|
always: "Object with {{min}}+ properties should have each property on its own line."
|
|
@@ -3689,19 +4177,21 @@ var objectMultiline = defineRule33({
|
|
|
3689
4177
|
});
|
|
3690
4178
|
|
|
3691
4179
|
// src/rules/only-export-components.ts
|
|
3692
|
-
import { defineRule as
|
|
3693
|
-
var onlyExportComponents =
|
|
4180
|
+
import { defineRule as defineRule35 } from "@oxlint/plugins";
|
|
4181
|
+
var onlyExportComponents = defineRule35({
|
|
3694
4182
|
meta: {
|
|
3695
4183
|
type: "problem",
|
|
3696
|
-
schema: [
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
4184
|
+
schema: [
|
|
4185
|
+
{
|
|
4186
|
+
type: "object",
|
|
4187
|
+
additionalProperties: false,
|
|
4188
|
+
properties: {
|
|
4189
|
+
matchFileName: { type: "boolean" },
|
|
4190
|
+
allowTypeExports: { type: "boolean" },
|
|
4191
|
+
denyTypePattern: optionsPatternSchema
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
],
|
|
3705
4195
|
messages: {
|
|
3706
4196
|
nonComponent: "Export '{{name}}' must be a React component or type.",
|
|
3707
4197
|
nameMismatch: "Component export '{{name}}' must match '{{expected}}' or its prefix.",
|
|
@@ -3768,7 +4258,7 @@ var onlyExportComponents = defineRule34({
|
|
|
3768
4258
|
});
|
|
3769
4259
|
|
|
3770
4260
|
// src/rules/only-export-constants.ts
|
|
3771
|
-
import { defineRule as
|
|
4261
|
+
import { defineRule as defineRule36 } from "@oxlint/plugins";
|
|
3772
4262
|
function bindingNames(pattern) {
|
|
3773
4263
|
switch (pattern.type) {
|
|
3774
4264
|
case "Identifier":
|
|
@@ -3823,18 +4313,20 @@ function collectBindings(program) {
|
|
|
3823
4313
|
}
|
|
3824
4314
|
return bindings;
|
|
3825
4315
|
}
|
|
3826
|
-
var onlyExportConstants =
|
|
4316
|
+
var onlyExportConstants = defineRule36({
|
|
3827
4317
|
meta: {
|
|
3828
4318
|
type: "problem",
|
|
3829
|
-
schema: [
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
4319
|
+
schema: [
|
|
4320
|
+
{
|
|
4321
|
+
type: "object",
|
|
4322
|
+
additionalProperties: false,
|
|
4323
|
+
properties: {
|
|
4324
|
+
allowFunctionValues: { type: "boolean" },
|
|
4325
|
+
allowTypeExports: { type: "boolean" },
|
|
4326
|
+
allowReExports: { type: "boolean" }
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
],
|
|
3838
4330
|
messages: {
|
|
3839
4331
|
nonConstant: "Export '{{name}}' must be a local const binding with an allowed value; types and re-exports require explicit options."
|
|
3840
4332
|
}
|
|
@@ -3842,7 +4334,11 @@ var onlyExportConstants = defineRule35({
|
|
|
3842
4334
|
createOnce(context) {
|
|
3843
4335
|
return {
|
|
3844
4336
|
Program(program) {
|
|
3845
|
-
const {
|
|
4337
|
+
const {
|
|
4338
|
+
allowFunctionValues = false,
|
|
4339
|
+
allowTypeExports = false,
|
|
4340
|
+
allowReExports = false
|
|
4341
|
+
} = optionsFirst(context, {});
|
|
3846
4342
|
const bindings = collectBindings(program);
|
|
3847
4343
|
function hasForbiddenValue(binding, seen = new Set) {
|
|
3848
4344
|
if (seen.has(binding) || binding.kind === "class") {
|
|
@@ -3905,7 +4401,7 @@ var onlyExportConstants = defineRule35({
|
|
|
3905
4401
|
});
|
|
3906
4402
|
|
|
3907
4403
|
// src/rules/padding-between-statements.ts
|
|
3908
|
-
import { defineRule as
|
|
4404
|
+
import { defineRule as defineRule37 } from "@oxlint/plugins";
|
|
3909
4405
|
function paddingKind(node) {
|
|
3910
4406
|
if (node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") {
|
|
3911
4407
|
return node.declaration ? paddingKind(node.declaration) : "other";
|
|
@@ -3957,17 +4453,20 @@ function paddingBlankLineFix(sourceText, comments, prev, curr, newline) {
|
|
|
3957
4453
|
}
|
|
3958
4454
|
return { newlineEnd, newline };
|
|
3959
4455
|
}
|
|
3960
|
-
var paddingBetweenStatements =
|
|
4456
|
+
var paddingBetweenStatements = defineRule37({
|
|
3961
4457
|
meta: {
|
|
3962
4458
|
type: "layout",
|
|
3963
4459
|
fixable: "whitespace",
|
|
3964
|
-
schema: [
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
4460
|
+
schema: [
|
|
4461
|
+
{
|
|
4462
|
+
type: "object",
|
|
4463
|
+
additionalProperties: false,
|
|
4464
|
+
properties: {
|
|
4465
|
+
returnMinStatements: { type: "integer", minimum: 1, default: 3 },
|
|
4466
|
+
multilineVariables: { type: "boolean" }
|
|
4467
|
+
}
|
|
3969
4468
|
}
|
|
3970
|
-
|
|
4469
|
+
],
|
|
3971
4470
|
messages: {
|
|
3972
4471
|
variableAndBlock: "Expected a blank line between a variable declaration and a function/class.",
|
|
3973
4472
|
beforeBlock: "Expected a blank line before a function/class declaration.",
|
|
@@ -3975,11 +4474,13 @@ var paddingBetweenStatements = defineRule36({
|
|
|
3975
4474
|
variableAndControl: "Expected a blank line between a variable declaration and control flow.",
|
|
3976
4475
|
controlAndVariable: "Expected a blank line between control flow and a variable declaration.",
|
|
3977
4476
|
consecutiveControl: "Expected a blank line between control flow statements.",
|
|
3978
|
-
beforeReturn: "Expected a blank line before return statement."
|
|
4477
|
+
beforeReturn: "Expected a blank line before return statement.",
|
|
4478
|
+
multilineVariable: "Expected a blank line around a multiline variable declaration."
|
|
3979
4479
|
}
|
|
3980
4480
|
},
|
|
3981
4481
|
createOnce(context) {
|
|
3982
4482
|
let returnMinStatements = 3;
|
|
4483
|
+
let multilineVariables = false;
|
|
3983
4484
|
let newline = `
|
|
3984
4485
|
`;
|
|
3985
4486
|
let source;
|
|
@@ -3993,7 +4494,8 @@ var paddingBetweenStatements = defineRule36({
|
|
|
3993
4494
|
}
|
|
3994
4495
|
const prevKind = paddingKind(prev);
|
|
3995
4496
|
const currKind = paddingKind(curr);
|
|
3996
|
-
const
|
|
4497
|
+
const multiline = multilineVariables && (prevKind === "variable" && prev.loc.start.line !== prev.loc.end.line || currKind === "variable" && curr.loc.start.line !== curr.loc.end.line);
|
|
4498
|
+
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
4499
|
if (!messageId) {
|
|
3998
4500
|
continue;
|
|
3999
4501
|
}
|
|
@@ -4010,6 +4512,7 @@ var paddingBetweenStatements = defineRule36({
|
|
|
4010
4512
|
before() {
|
|
4011
4513
|
const options = optionsFirst(context, {});
|
|
4012
4514
|
returnMinStatements = options.returnMinStatements ?? 3;
|
|
4515
|
+
multilineVariables = options.multilineVariables ?? false;
|
|
4013
4516
|
source = context.sourceCode;
|
|
4014
4517
|
newline = layoutNewline(source.text);
|
|
4015
4518
|
},
|
|
@@ -4024,7 +4527,7 @@ var paddingBetweenStatements = defineRule36({
|
|
|
4024
4527
|
});
|
|
4025
4528
|
|
|
4026
4529
|
// src/rules/prefer-namespace-type-import.ts
|
|
4027
|
-
import { defineRule as
|
|
4530
|
+
import { defineRule as defineRule38 } from "@oxlint/plugins";
|
|
4028
4531
|
var bindingName = /^[A-Za-z_$][\w$]*$/;
|
|
4029
4532
|
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(" "));
|
|
4030
4533
|
function namespaceName(source, names) {
|
|
@@ -4048,21 +4551,23 @@ function safeReference(node) {
|
|
|
4048
4551
|
}
|
|
4049
4552
|
return parent?.type === "TSTypeReference" && parent.typeName === current || parent?.type === "TSTypeQuery" && parent.exprName === current || (parent?.type === "TSInterfaceHeritage" || parent?.type === "TSClassImplements") && parent.expression === current;
|
|
4050
4553
|
}
|
|
4051
|
-
var preferNamespaceTypeImport =
|
|
4554
|
+
var preferNamespaceTypeImport = defineRule38({
|
|
4052
4555
|
meta: {
|
|
4053
4556
|
type: "suggestion",
|
|
4054
4557
|
fixable: "code",
|
|
4055
|
-
schema: [
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4558
|
+
schema: [
|
|
4559
|
+
{
|
|
4560
|
+
type: "object",
|
|
4561
|
+
additionalProperties: false,
|
|
4562
|
+
properties: {
|
|
4563
|
+
max: { type: "integer", minimum: 0 },
|
|
4564
|
+
names: { type: "object", additionalProperties: { type: "string", pattern: bindingName.source } }
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
],
|
|
4063
4568
|
defaultOptions: [{ max: 3, names: {} }],
|
|
4064
4569
|
messages: {
|
|
4065
|
-
namespace: "Use
|
|
4570
|
+
namespace: "Use `import type * as {{name}} from '{{source}}'` for {{count}} type imports (max {{max}}); keep exported domain names.{{reason}}"
|
|
4066
4571
|
}
|
|
4067
4572
|
},
|
|
4068
4573
|
createOnce(context) {
|
|
@@ -4147,7 +4652,13 @@ var preferNamespaceTypeImport = defineRule37({
|
|
|
4147
4652
|
context.report({
|
|
4148
4653
|
node,
|
|
4149
4654
|
messageId: "namespace",
|
|
4150
|
-
data: {
|
|
4655
|
+
data: {
|
|
4656
|
+
name,
|
|
4657
|
+
source: node.source.value,
|
|
4658
|
+
count: node.specifiers.length,
|
|
4659
|
+
max,
|
|
4660
|
+
reason: reason ? ` Autofix skipped: ${reason}.` : ""
|
|
4661
|
+
},
|
|
4151
4662
|
fix: reason ? undefined : (fixer) => edits.map((edit) => fixer.replaceTextRange(edit.range, edit.text))
|
|
4152
4663
|
});
|
|
4153
4664
|
}
|
|
@@ -4157,19 +4668,21 @@ var preferNamespaceTypeImport = defineRule37({
|
|
|
4157
4668
|
});
|
|
4158
4669
|
|
|
4159
4670
|
// src/rules/require-file-factory.ts
|
|
4160
|
-
import { defineRule as
|
|
4161
|
-
var requireFileFactory =
|
|
4671
|
+
import { defineRule as defineRule39 } from "@oxlint/plugins";
|
|
4672
|
+
var requireFileFactory = defineRule39({
|
|
4162
4673
|
meta: {
|
|
4163
4674
|
type: "problem",
|
|
4164
|
-
schema: [
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4675
|
+
schema: [
|
|
4676
|
+
{
|
|
4677
|
+
type: "object",
|
|
4678
|
+
additionalProperties: false,
|
|
4679
|
+
properties: {
|
|
4680
|
+
factory: { type: "string" },
|
|
4681
|
+
allDeclarations: { type: "boolean" }
|
|
4682
|
+
},
|
|
4683
|
+
required: ["factory"]
|
|
4684
|
+
}
|
|
4685
|
+
],
|
|
4173
4686
|
messages: {
|
|
4174
4687
|
factory: "Function '{{actual}}' must be named '{{expected}}'."
|
|
4175
4688
|
}
|
|
@@ -4204,19 +4717,22 @@ var requireFileFactory = defineRule38({
|
|
|
4204
4717
|
});
|
|
4205
4718
|
|
|
4206
4719
|
// src/rules/require-object-params.ts
|
|
4207
|
-
import { defineRule as
|
|
4208
|
-
var requireObjectParams =
|
|
4720
|
+
import { defineRule as defineRule40 } from "@oxlint/plugins";
|
|
4721
|
+
var requireObjectParams = defineRule40({
|
|
4209
4722
|
meta: {
|
|
4210
4723
|
type: "problem",
|
|
4211
|
-
schema: [
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4724
|
+
schema: [
|
|
4725
|
+
{
|
|
4726
|
+
type: "object",
|
|
4727
|
+
additionalProperties: false,
|
|
4728
|
+
properties: {
|
|
4729
|
+
maxParams: { type: "integer", minimum: 1 },
|
|
4730
|
+
serviceMethods: { type: "boolean" },
|
|
4731
|
+
allDeclarations: { type: "boolean" },
|
|
4732
|
+
allowPattern: optionsPatternSchema
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
],
|
|
4220
4736
|
messages: {
|
|
4221
4737
|
objectParams: "{{label}} {{name}} must accept at most {{maxParams}} object parameter{{s}}."
|
|
4222
4738
|
}
|
|
@@ -4224,10 +4740,17 @@ var requireObjectParams = defineRule39({
|
|
|
4224
4740
|
createOnce(context) {
|
|
4225
4741
|
return {
|
|
4226
4742
|
Program(program) {
|
|
4227
|
-
const {
|
|
4743
|
+
const {
|
|
4744
|
+
maxParams = 1,
|
|
4745
|
+
allDeclarations = false,
|
|
4746
|
+
serviceMethods = false,
|
|
4747
|
+
allowPattern
|
|
4748
|
+
} = optionsFirst(context, {});
|
|
4228
4749
|
const allowed = optionsOptionalPatterns(allowPattern);
|
|
4229
4750
|
const seen = new Set;
|
|
4230
4751
|
const functions = allDeclarations ? [...exportsCollectFunctions(program), ...declarationsTopLevelUnexportedFunctions(program)] : exportsCollectFunctions(program);
|
|
4752
|
+
if (serviceMethods)
|
|
4753
|
+
functions.push(...declarationsPublicServiceMethods(program));
|
|
4231
4754
|
for (const item of functions) {
|
|
4232
4755
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
4233
4756
|
if (seen.has(key) || optionsPatternsTest(allowed, item.name)) {
|
|
@@ -4253,20 +4776,22 @@ var requireObjectParams = defineRule39({
|
|
|
4253
4776
|
});
|
|
4254
4777
|
|
|
4255
4778
|
// src/rules/require-orpc-output.ts
|
|
4256
|
-
import { defineRule as
|
|
4257
|
-
var requireOrpcOutput =
|
|
4779
|
+
import { defineRule as defineRule41 } from "@oxlint/plugins";
|
|
4780
|
+
var requireOrpcOutput = defineRule41({
|
|
4258
4781
|
meta: {
|
|
4259
4782
|
type: "problem",
|
|
4260
|
-
schema: [
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4783
|
+
schema: [
|
|
4784
|
+
{
|
|
4785
|
+
type: "object",
|
|
4786
|
+
additionalProperties: false,
|
|
4787
|
+
properties: {
|
|
4788
|
+
composers: { type: "array", items: { type: "string" } },
|
|
4789
|
+
handlerMethod: { type: "string" },
|
|
4790
|
+
outputMethod: { type: "string" }
|
|
4791
|
+
},
|
|
4792
|
+
required: ["composers"]
|
|
4793
|
+
}
|
|
4794
|
+
],
|
|
4270
4795
|
messages: {
|
|
4271
4796
|
missing: "oRPC procedures must declare .output() before .handler().",
|
|
4272
4797
|
invalid: "oRPC .output() must use a named schema or configured composer with a named schema."
|
|
@@ -4278,7 +4803,11 @@ var requireOrpcOutput = defineRule40({
|
|
|
4278
4803
|
if (node.callee.type !== "MemberExpression") {
|
|
4279
4804
|
return;
|
|
4280
4805
|
}
|
|
4281
|
-
const {
|
|
4806
|
+
const {
|
|
4807
|
+
composers,
|
|
4808
|
+
handlerMethod = "handler",
|
|
4809
|
+
outputMethod = "output"
|
|
4810
|
+
} = optionsFirst(context);
|
|
4282
4811
|
if (astStaticMemberName(node.callee) !== handlerMethod) {
|
|
4283
4812
|
return;
|
|
4284
4813
|
}
|
|
@@ -4296,34 +4825,33 @@ var requireOrpcOutput = defineRule40({
|
|
|
4296
4825
|
});
|
|
4297
4826
|
|
|
4298
4827
|
// src/rules/require-paired-call.ts
|
|
4299
|
-
import { defineRule as
|
|
4300
|
-
var requirePairedCall =
|
|
4828
|
+
import { defineRule as defineRule42 } from "@oxlint/plugins";
|
|
4829
|
+
var requirePairedCall = defineRule42({
|
|
4301
4830
|
meta: {
|
|
4302
4831
|
type: "problem",
|
|
4303
|
-
schema: [
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4832
|
+
schema: [
|
|
4833
|
+
{
|
|
4834
|
+
type: "object",
|
|
4835
|
+
additionalProperties: false,
|
|
4836
|
+
properties: {
|
|
4837
|
+
when: { type: "string" },
|
|
4838
|
+
require: { type: "string" },
|
|
4839
|
+
pairs: {
|
|
4840
|
+
type: "array",
|
|
4841
|
+
items: {
|
|
4842
|
+
type: "object",
|
|
4843
|
+
additionalProperties: false,
|
|
4844
|
+
properties: {
|
|
4845
|
+
when: { type: "string" },
|
|
4846
|
+
require: { type: "string" }
|
|
4847
|
+
},
|
|
4848
|
+
required: ["when", "require"]
|
|
4849
|
+
}
|
|
4319
4850
|
}
|
|
4320
|
-
}
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
{ required: ["pairs"] }
|
|
4325
|
-
]
|
|
4326
|
-
}],
|
|
4851
|
+
},
|
|
4852
|
+
anyOf: [{ required: ["when", "require"] }, { required: ["pairs"] }]
|
|
4853
|
+
}
|
|
4854
|
+
],
|
|
4327
4855
|
messages: {
|
|
4328
4856
|
paired: "{{when}} requires a call to {{require}} in the same file."
|
|
4329
4857
|
}
|
|
@@ -4372,20 +4900,24 @@ var requirePairedCall = defineRule41({
|
|
|
4372
4900
|
});
|
|
4373
4901
|
|
|
4374
4902
|
// src/rules/route-surface.ts
|
|
4375
|
-
import { defineRule as
|
|
4376
|
-
var routeSurface =
|
|
4903
|
+
import { defineRule as defineRule43 } from "@oxlint/plugins";
|
|
4904
|
+
var routeSurface = defineRule43({
|
|
4377
4905
|
meta: {
|
|
4378
4906
|
type: "problem",
|
|
4379
|
-
schema: [
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4907
|
+
schema: [
|
|
4908
|
+
{
|
|
4909
|
+
type: "object",
|
|
4910
|
+
additionalProperties: false,
|
|
4911
|
+
properties: {
|
|
4912
|
+
exportName: { type: "string" },
|
|
4913
|
+
bannedHooks: { type: "array", items: { type: "string" } },
|
|
4914
|
+
banIntrinsicJsx: { type: "boolean" }
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
],
|
|
4918
|
+
defaultOptions: [
|
|
4919
|
+
{ exportName: "Route", bannedHooks: ["useState", "useEffect", "useMutation"], banIntrinsicJsx: true }
|
|
4920
|
+
],
|
|
4389
4921
|
messages: {
|
|
4390
4922
|
extraExport: "Route files may only export '{{expected}}'; found '{{actual}}'.",
|
|
4391
4923
|
hostJsx: "Route adapter {{name}} must not render intrinsic JSX.",
|
|
@@ -4415,8 +4947,8 @@ var routeSurface = defineRule42({
|
|
|
4415
4947
|
});
|
|
4416
4948
|
|
|
4417
4949
|
// src/rules/test-title-pattern.ts
|
|
4418
|
-
import { defineRule as
|
|
4419
|
-
var TEST_MODIFIERS = new Set(["only", "skip", "concurrent", "todo", "each"]);
|
|
4950
|
+
import { defineRule as defineRule44 } from "@oxlint/plugins";
|
|
4951
|
+
var TEST_MODIFIERS = new Set(["only", "skip", "concurrent", "sequential", "todo", "each", "for"]);
|
|
4420
4952
|
function isConfiguredName(name, callees) {
|
|
4421
4953
|
if (!name) {
|
|
4422
4954
|
return false;
|
|
@@ -4455,23 +4987,27 @@ function regexMatches(regex, value) {
|
|
|
4455
4987
|
function titlePatterns(pattern, flags) {
|
|
4456
4988
|
return pattern === undefined ? [] : [pattern].flat().map((source) => ({ regex: new RegExp(source, flags), pattern: source }));
|
|
4457
4989
|
}
|
|
4458
|
-
var testTitlePattern =
|
|
4990
|
+
var testTitlePattern = defineRule44({
|
|
4459
4991
|
meta: {
|
|
4460
4992
|
type: "suggestion",
|
|
4461
|
-
schema: [
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4993
|
+
schema: [
|
|
4994
|
+
{
|
|
4995
|
+
type: "object",
|
|
4996
|
+
additionalProperties: false,
|
|
4997
|
+
properties: {
|
|
4998
|
+
callees: { type: "array", items: { type: "string" } },
|
|
4999
|
+
forbid: optionsPatternSchema,
|
|
5000
|
+
require: optionsPatternSchema,
|
|
5001
|
+
flags: { type: "string", pattern: "^[dgimsuvy]*$" }
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
],
|
|
5005
|
+
defaultOptions: [
|
|
5006
|
+
{
|
|
5007
|
+
callees: ["describe", "it", "test"],
|
|
5008
|
+
flags: ""
|
|
5009
|
+
}
|
|
5010
|
+
],
|
|
4475
5011
|
messages: {
|
|
4476
5012
|
forbidden: "Test title matches forbidden pattern '{{pattern}}'.",
|
|
4477
5013
|
required: "Test title must match required pattern '{{pattern}}'."
|
|
@@ -4532,6 +5068,7 @@ var src_default = eslintCompatPlugin({
|
|
|
4532
5068
|
rules: {
|
|
4533
5069
|
"call-array-multiline": callArrayMultiline,
|
|
4534
5070
|
"chain-newline": chainNewline,
|
|
5071
|
+
"component-props": componentProps,
|
|
4535
5072
|
"declaration-name": declarationName,
|
|
4536
5073
|
"export-file-prefix": exportFilePrefix,
|
|
4537
5074
|
"export-name-pattern": exportNamePattern,
|