oxlint-plugin-arch 0.3.1 → 0.3.4
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 +13 -0
- package/README.md +17 -0
- package/dist/index.js +129 -79
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- Options that took one regex string now also take a non-empty list, where any pattern may match: `pattern`, `allowPattern`, `allowNamePattern`, `denyTypePattern`, `hookPattern`, `rootPattern`, `factoryPattern`, `forbid`, and `require`. Single strings keep their behavior.
|
|
6
|
+
- `no-type-declarations` `allowPattern` entries starting with `=` or `^=` match a type alias's value (`= ` plus its source text) instead of its name, so `'^= ReturnType<typeof '` keeps factory return types next to their factory. A name pattern that starts with `=` or `^=` is now read as a value pattern.
|
|
7
|
+
- Fix `declaration-name` `pattern` with `g` or `y` flags rejecting every name after the first match.
|
|
8
|
+
|
|
9
|
+
## 0.3.3
|
|
10
|
+
|
|
11
|
+
Version 0.3.2 was tagged but never published to npm; 0.3.3 contains its fixes.
|
|
12
|
+
|
|
13
|
+
- Fix `chain-newline` reporting chains that already have one call per line when the root is parenthesized (`(db as TestDb)\n .insertInto()`), the root spans several lines, or a comment sits between two links.
|
|
14
|
+
- Autofix `call-array-multiline` arrays with parenthesized elements, like `Promise.all([(a), (b)])`.
|
|
15
|
+
|
|
3
16
|
## 0.3.1
|
|
4
17
|
|
|
5
18
|
- Fix `key-value-same-line` reporting `key: (` values whose parenthesized expression starts on the next line.
|
package/README.md
CHANGED
|
@@ -76,6 +76,8 @@ export default defineConfig({
|
|
|
76
76
|
|
|
77
77
|
42 rules in 9 groups. 🔧 means the rule can autofix. Each rule file in [`src/rules/`](src/rules) explains its behavior in plain English, and the tests in [`src/tests/`](src/tests) show every option shape.
|
|
78
78
|
|
|
79
|
+
Options that take one regex string (`pattern`, `allowPattern`, `forbid`, `require`, and the other `*Pattern` options) also take a non-empty list; any pattern in the list may match. Options that were already lists, such as `allowPatterns` and `allowCallees`, are unchanged.
|
|
80
|
+
|
|
79
81
|
### 📁 Files & folders
|
|
80
82
|
|
|
81
83
|
| Rule | What it enforces |
|
|
@@ -198,6 +200,21 @@ Use `no-type-declarations` separately to control where named types may live. Wit
|
|
|
198
200
|
|
|
199
201
|
</details>
|
|
200
202
|
|
|
203
|
+
### `no-type-declarations`
|
|
204
|
+
|
|
205
|
+
Rejects type aliases and interfaces in matched files, so types live in one place.
|
|
206
|
+
|
|
207
|
+
| Option | Default | What it does |
|
|
208
|
+
| --- | --- | --- |
|
|
209
|
+
| `allowPattern` | none | Keep a declaration whose **name** matches. A pattern that starts with `=` or `^=` matches a type alias's **value** instead: `= ` followed by the value's source text, without surrounding parentheses or comments. Interfaces have no value, so only name patterns apply to them. |
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// allowPattern: ['(Service|Deps)$', '^= ReturnType<typeof ']
|
|
213
|
+
export type AiRetry = ReturnType<typeof makeAiRetry> // ✅ value matches
|
|
214
|
+
export interface OrderDeps { db: Database } // ✅ name matches
|
|
215
|
+
export type OrderCreateParams = { id: string } // ❌ move it to your types file
|
|
216
|
+
```
|
|
217
|
+
|
|
201
218
|
### `only-export-constants`
|
|
202
219
|
|
|
203
220
|
Every runtime export must point to a local `const`. Direct, destructured, renamed, and default exports of local constants all work.
|
package/dist/index.js
CHANGED
|
@@ -551,6 +551,27 @@ function factoriesObjectPropertyName(property) {
|
|
|
551
551
|
function optionsFirst(context, fallback) {
|
|
552
552
|
return context.options[0] ?? fallback;
|
|
553
553
|
}
|
|
554
|
+
var optionsPatternSchema = {
|
|
555
|
+
anyOf: [
|
|
556
|
+
{ type: "string" },
|
|
557
|
+
{ type: "array", items: { type: "string" }, minItems: 1 }
|
|
558
|
+
]
|
|
559
|
+
};
|
|
560
|
+
function optionsPatterns(pattern, flags) {
|
|
561
|
+
return pattern === undefined ? [] : [pattern].flat().map((source) => new RegExp(source, flags));
|
|
562
|
+
}
|
|
563
|
+
function optionsOptionalPatterns(pattern, flags) {
|
|
564
|
+
return optionsPatterns(pattern === undefined ? undefined : [pattern].flat().filter((source) => source !== ""), flags);
|
|
565
|
+
}
|
|
566
|
+
function optionsPatternLabel(pattern) {
|
|
567
|
+
return pattern === undefined ? "" : [pattern].flat().join(" | ");
|
|
568
|
+
}
|
|
569
|
+
function optionsPatternsTest(patterns, value) {
|
|
570
|
+
return patterns.some((pattern) => {
|
|
571
|
+
pattern.lastIndex = 0;
|
|
572
|
+
return pattern.test(value);
|
|
573
|
+
});
|
|
574
|
+
}
|
|
554
575
|
// src/utils/helpers/orpc.ts
|
|
555
576
|
function orpcFindChainCall(expression, method) {
|
|
556
577
|
if (expression.type === "CallExpression") {
|
|
@@ -815,32 +836,43 @@ function callArrayMultilineIsShadowed(context, root) {
|
|
|
815
836
|
}
|
|
816
837
|
return false;
|
|
817
838
|
}
|
|
818
|
-
function
|
|
839
|
+
function callArrayMultilineOuterRange(source, node) {
|
|
840
|
+
let range = [node.range[0], node.range[1]];
|
|
841
|
+
let before = source.getTokenBefore(node);
|
|
842
|
+
let after = source.getTokenAfter(node);
|
|
843
|
+
while (before?.value === "(" && after?.value === ")") {
|
|
844
|
+
range = [before.range[0], after.range[1]];
|
|
845
|
+
before = source.getTokenBefore(before);
|
|
846
|
+
after = source.getTokenAfter(after);
|
|
847
|
+
}
|
|
848
|
+
return range;
|
|
849
|
+
}
|
|
850
|
+
function callArrayMultilineEdits(array, source, text, elementIndent, baseIndent, newline) {
|
|
819
851
|
const elements = array.elements;
|
|
820
852
|
if (elements.some((element) => element === null))
|
|
821
853
|
return null;
|
|
822
|
-
const present = elements.filter((element) => element !== null);
|
|
854
|
+
const present = elements.filter((element) => element !== null).map((element) => callArrayMultilineOuterRange(source, element));
|
|
823
855
|
const first = present[0];
|
|
824
856
|
const last = present.at(-1);
|
|
825
857
|
if (!first || !last)
|
|
826
858
|
return null;
|
|
827
859
|
const edits = [];
|
|
828
|
-
const openingRange = [array.range[0] + 1, first
|
|
860
|
+
const openingRange = [array.range[0] + 1, first[0]];
|
|
829
861
|
if (!/^\s*$/.test(text.slice(...openingRange)))
|
|
830
862
|
return null;
|
|
831
863
|
edits.push({ range: openingRange, text: `${newline}${elementIndent}` });
|
|
832
864
|
for (let index = 1;index < present.length; index++) {
|
|
833
865
|
const previous = present[index - 1];
|
|
834
866
|
const current = present[index];
|
|
835
|
-
const gap = text.slice(previous
|
|
867
|
+
const gap = text.slice(previous[1], current[0]);
|
|
836
868
|
if (!/^,\s*$/.test(gap))
|
|
837
869
|
return null;
|
|
838
870
|
edits.push({
|
|
839
|
-
range: [previous
|
|
871
|
+
range: [previous[1] + 1, current[0]],
|
|
840
872
|
text: `${newline}${elementIndent}`
|
|
841
873
|
});
|
|
842
874
|
}
|
|
843
|
-
const closingRange = [last
|
|
875
|
+
const closingRange = [last[1], array.range[1] - 1];
|
|
844
876
|
const closingGap = text.slice(...closingRange);
|
|
845
877
|
if (!/^,?\s*$/.test(closingGap))
|
|
846
878
|
return null;
|
|
@@ -898,7 +930,7 @@ var callArrayMultiline = defineRule({
|
|
|
898
930
|
const text = source.text;
|
|
899
931
|
const baseIndent = layoutLineIndent(text, array.range[0]);
|
|
900
932
|
const hasComments = source.getCommentsInside(array).length > 0;
|
|
901
|
-
const edits = hasComments ? null : callArrayMultilineEdits(array, text, baseIndent + indentUnit, baseIndent, newline);
|
|
933
|
+
const edits = hasComments ? null : callArrayMultilineEdits(array, source, text, baseIndent + indentUnit, baseIndent, newline);
|
|
902
934
|
context.report({
|
|
903
935
|
node: array,
|
|
904
936
|
messageId: "multiline",
|
|
@@ -936,7 +968,7 @@ function chainNewlineRootIdentifier(node) {
|
|
|
936
968
|
function chainNewlineMatches(root, links, group) {
|
|
937
969
|
if (links.length < group.minDepth)
|
|
938
970
|
return false;
|
|
939
|
-
const hasCriteria = group.methods !== undefined || group.onlyMethods !== undefined || group.
|
|
971
|
+
const hasCriteria = group.methods !== undefined || group.onlyMethods !== undefined || group.rootPatterns.length > 0;
|
|
940
972
|
if (!hasCriteria)
|
|
941
973
|
return true;
|
|
942
974
|
if (group.methods && links.some((link) => link.methodName !== null && group.methods?.has(link.methodName))) {
|
|
@@ -945,7 +977,7 @@ function chainNewlineMatches(root, links, group) {
|
|
|
945
977
|
if (group.onlyMethods && links.every((link) => link.methodName !== null && group.onlyMethods?.has(link.methodName)))
|
|
946
978
|
return true;
|
|
947
979
|
const rootName = chainNewlineRootIdentifier(root);
|
|
948
|
-
return rootName !== null && group.
|
|
980
|
+
return rootName !== null && optionsPatternsTest(group.rootPatterns, rootName);
|
|
949
981
|
}
|
|
950
982
|
var chainNewline = defineRule2({
|
|
951
983
|
meta: {
|
|
@@ -964,7 +996,7 @@ var chainNewline = defineRule2({
|
|
|
964
996
|
minDepth: { type: "integer", minimum: 1 },
|
|
965
997
|
methods: { type: "array", items: { type: "string" } },
|
|
966
998
|
onlyMethods: { type: "array", items: { type: "string" } },
|
|
967
|
-
rootPattern:
|
|
999
|
+
rootPattern: optionsPatternSchema
|
|
968
1000
|
},
|
|
969
1001
|
required: ["minDepth"]
|
|
970
1002
|
}
|
|
@@ -990,7 +1022,7 @@ var chainNewline = defineRule2({
|
|
|
990
1022
|
minDepth: group.minDepth,
|
|
991
1023
|
methods: group.methods ? new Set(group.methods) : undefined,
|
|
992
1024
|
onlyMethods: group.onlyMethods ? new Set(group.onlyMethods) : undefined,
|
|
993
|
-
|
|
1025
|
+
rootPatterns: optionsPatterns(group.rootPattern)
|
|
994
1026
|
}));
|
|
995
1027
|
indentUnit = layoutIndentUnit(options.indent);
|
|
996
1028
|
newline = layoutNewline(context.sourceCode.text);
|
|
@@ -1011,7 +1043,7 @@ var chainNewline = defineRule2({
|
|
|
1011
1043
|
return;
|
|
1012
1044
|
const source = context.sourceCode;
|
|
1013
1045
|
const text = source.text;
|
|
1014
|
-
const chainIndent = layoutLineIndent(text,
|
|
1046
|
+
const chainIndent = layoutLineIndent(text, node.range[0]) + indentUnit;
|
|
1015
1047
|
const replacements = [];
|
|
1016
1048
|
let fixable = true;
|
|
1017
1049
|
let needsFix = false;
|
|
@@ -1021,14 +1053,19 @@ var chainNewline = defineRule2({
|
|
|
1021
1053
|
needsFix = true;
|
|
1022
1054
|
continue;
|
|
1023
1055
|
}
|
|
1024
|
-
const
|
|
1056
|
+
const operatorToken = source.getTokenBefore(link.member.property);
|
|
1057
|
+
const objectEnd = (operatorToken && source.getTokenBefore(operatorToken)) ?? link.member.object;
|
|
1058
|
+
const range = [objectEnd.range[1], link.member.property.range[0]];
|
|
1025
1059
|
const gap = text.slice(...range);
|
|
1026
1060
|
const operator = link.member.optional ? "?." : ".";
|
|
1027
1061
|
const expected = `${newline}${chainIndent}${operator}`;
|
|
1028
|
-
|
|
1062
|
+
const hasComments = source.commentsExistBetween(objectEnd, link.member.property);
|
|
1063
|
+
if (hasComments || gap.trim() !== operator) {
|
|
1029
1064
|
fixable = false;
|
|
1030
1065
|
}
|
|
1031
|
-
|
|
1066
|
+
const lastComment = hasComments && operatorToken ? source.getTokenBefore(operatorToken, { includeComments: true }) : null;
|
|
1067
|
+
const alignedAfterComment = lastComment !== null && text.slice(lastComment.range[1], link.member.property.range[0]) === expected;
|
|
1068
|
+
if (gap !== expected && !alignedAfterComment) {
|
|
1032
1069
|
needsFix = true;
|
|
1033
1070
|
replacements.push({ range, text: expected });
|
|
1034
1071
|
}
|
|
@@ -1058,14 +1095,14 @@ var declarationName = defineRule3({
|
|
|
1058
1095
|
type: "array",
|
|
1059
1096
|
items: { type: "string", enum: [...declarationsKinds] }
|
|
1060
1097
|
},
|
|
1061
|
-
pattern:
|
|
1098
|
+
pattern: optionsPatternSchema,
|
|
1062
1099
|
flags: { type: "string" },
|
|
1063
1100
|
stem: { type: "string", enum: [...namingStemModes] },
|
|
1064
1101
|
trailingRoles: { type: "array", items: { type: "string" } },
|
|
1065
1102
|
roleSeparators: { type: "array", items: { type: "string" } },
|
|
1066
1103
|
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1067
1104
|
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1068
|
-
allowPattern:
|
|
1105
|
+
allowPattern: optionsPatternSchema
|
|
1069
1106
|
}
|
|
1070
1107
|
}],
|
|
1071
1108
|
messages: {
|
|
@@ -1076,23 +1113,23 @@ var declarationName = defineRule3({
|
|
|
1076
1113
|
createOnce(context) {
|
|
1077
1114
|
let options = {};
|
|
1078
1115
|
let kinds = null;
|
|
1079
|
-
let allowed =
|
|
1080
|
-
let expected =
|
|
1116
|
+
let allowed = [];
|
|
1117
|
+
let expected = [];
|
|
1081
1118
|
let prefixes = [];
|
|
1082
1119
|
function check(node) {
|
|
1083
1120
|
const item = declarationsNamedFromNode(node);
|
|
1084
|
-
if (!item || kinds && !kinds.has(item.kind) || allowed
|
|
1121
|
+
if (!item || kinds && !kinds.has(item.kind) || optionsPatternsTest(allowed, item.name)) {
|
|
1085
1122
|
return;
|
|
1086
1123
|
}
|
|
1087
1124
|
const comparableName = options.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
|
|
1088
|
-
const matches = expected ? expected
|
|
1125
|
+
const matches = expected.length > 0 ? optionsPatternsTest(expected, item.name) : prefixes.some((prefix) => comparableName.startsWith(prefix));
|
|
1089
1126
|
if (matches) {
|
|
1090
1127
|
return;
|
|
1091
1128
|
}
|
|
1092
1129
|
context.report({
|
|
1093
1130
|
node: item.node,
|
|
1094
|
-
messageId: expected ? "pattern" : "prefix",
|
|
1095
|
-
data: expected ? { name: item.name, pattern: options.pattern ?? "" } : { name: item.name, prefix: prefixes.join(" or ") }
|
|
1131
|
+
messageId: expected.length > 0 ? "pattern" : "prefix",
|
|
1132
|
+
data: expected.length > 0 ? { name: item.name, pattern: optionsPatternLabel([options.pattern ?? []].flat().filter((source) => source !== "")) } : { name: item.name, prefix: prefixes.join(" or ") }
|
|
1096
1133
|
});
|
|
1097
1134
|
}
|
|
1098
1135
|
return {
|
|
@@ -1102,8 +1139,8 @@ var declarationName = defineRule3({
|
|
|
1102
1139
|
normalize: "remove-separators"
|
|
1103
1140
|
});
|
|
1104
1141
|
kinds = options.kinds && options.kinds.length > 0 ? new Set(options.kinds) : null;
|
|
1105
|
-
allowed =
|
|
1106
|
-
expected =
|
|
1142
|
+
allowed = optionsOptionalPatterns(options.allowPattern);
|
|
1143
|
+
expected = optionsOptionalPatterns(options.pattern, options.flags);
|
|
1107
1144
|
const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
|
|
1108
1145
|
const stem = namingFileStem(basename, options.stem, options.trailingRoles, options.roleSeparators);
|
|
1109
1146
|
prefixes = namingFilePrefixes(stem, options.normalize ?? "remove-separators", options.singularize ?? "none");
|
|
@@ -1133,7 +1170,7 @@ var exportFilePrefix = defineRule4({
|
|
|
1133
1170
|
normalize: { type: "string", enum: ["remove-separators", "none"] },
|
|
1134
1171
|
singularize: { type: "string", enum: ["none", "trailing-s"] },
|
|
1135
1172
|
allDeclarations: { type: "boolean" },
|
|
1136
|
-
allowPattern:
|
|
1173
|
+
allowPattern: optionsPatternSchema
|
|
1137
1174
|
}
|
|
1138
1175
|
}],
|
|
1139
1176
|
messages: {
|
|
@@ -1150,7 +1187,7 @@ var exportFilePrefix = defineRule4({
|
|
|
1150
1187
|
const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
|
|
1151
1188
|
const stem = namingFileStem(basename, options.stem, options.trailingRoles, options.roleSeparators);
|
|
1152
1189
|
const prefixes = namingFilePrefixes(stem, options.normalize ?? "remove-separators", options.singularize ?? "none");
|
|
1153
|
-
const allowed =
|
|
1190
|
+
const allowed = optionsOptionalPatterns(options.allowPattern);
|
|
1154
1191
|
const names = options.allDeclarations ? declarationsCollectNamed(program) : exportsCollect(program).map((binding) => ({
|
|
1155
1192
|
name: binding.localName ?? binding.exportedName,
|
|
1156
1193
|
node: binding.node
|
|
@@ -1159,7 +1196,7 @@ var exportFilePrefix = defineRule4({
|
|
|
1159
1196
|
for (const item of names) {
|
|
1160
1197
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
1161
1198
|
const comparableName = options.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
|
|
1162
|
-
if (seen.has(key) || allowed
|
|
1199
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name) || prefixes.some((prefix) => comparableName.startsWith(prefix))) {
|
|
1163
1200
|
continue;
|
|
1164
1201
|
}
|
|
1165
1202
|
seen.add(key);
|
|
@@ -1183,11 +1220,11 @@ var exportNamePattern = defineRule5({
|
|
|
1183
1220
|
type: "object",
|
|
1184
1221
|
additionalProperties: false,
|
|
1185
1222
|
properties: {
|
|
1186
|
-
pattern:
|
|
1223
|
+
pattern: optionsPatternSchema,
|
|
1187
1224
|
flags: { type: "string" },
|
|
1188
1225
|
ignoreTypeExports: { type: "boolean" },
|
|
1189
1226
|
allDeclarations: { type: "boolean" },
|
|
1190
|
-
allowPattern:
|
|
1227
|
+
allowPattern: optionsPatternSchema
|
|
1191
1228
|
},
|
|
1192
1229
|
required: ["pattern"]
|
|
1193
1230
|
}],
|
|
@@ -1205,19 +1242,20 @@ var exportNamePattern = defineRule5({
|
|
|
1205
1242
|
allDeclarations = false,
|
|
1206
1243
|
allowPattern
|
|
1207
1244
|
} = optionsFirst(context);
|
|
1208
|
-
const allowed =
|
|
1245
|
+
const allowed = optionsOptionalPatterns(allowPattern);
|
|
1246
|
+
const expected = optionsPatterns(pattern, flags);
|
|
1209
1247
|
const names = allDeclarations ? declarationsCollectNamed(program) : exportsCollect(program).flatMap((binding) => ignoreTypeExports && binding.typeOnly ? [] : [{ name: binding.localName ?? binding.exportedName, node: binding.node }]);
|
|
1210
1248
|
const seen = new Set;
|
|
1211
1249
|
for (const item of names) {
|
|
1212
1250
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
1213
|
-
if (seen.has(key) || allowed
|
|
1251
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name) || optionsPatternsTest(expected, item.name)) {
|
|
1214
1252
|
continue;
|
|
1215
1253
|
}
|
|
1216
1254
|
seen.add(key);
|
|
1217
1255
|
context.report({
|
|
1218
1256
|
node: item.node,
|
|
1219
1257
|
messageId: "pattern",
|
|
1220
|
-
data: { name: item.name, pattern }
|
|
1258
|
+
data: { name: item.name, pattern: optionsPatternLabel(pattern) }
|
|
1221
1259
|
});
|
|
1222
1260
|
}
|
|
1223
1261
|
}
|
|
@@ -1296,7 +1334,7 @@ var filenameMatch = defineRule7({
|
|
|
1296
1334
|
type: "object",
|
|
1297
1335
|
additionalProperties: false,
|
|
1298
1336
|
properties: {
|
|
1299
|
-
pattern:
|
|
1337
|
+
pattern: optionsPatternSchema,
|
|
1300
1338
|
message: { type: "string" },
|
|
1301
1339
|
flags: { type: "string" }
|
|
1302
1340
|
},
|
|
@@ -1310,7 +1348,8 @@ var filenameMatch = defineRule7({
|
|
|
1310
1348
|
return {
|
|
1311
1349
|
Program(program) {
|
|
1312
1350
|
const { pattern, message, flags } = optionsFirst(context);
|
|
1313
|
-
|
|
1351
|
+
const patterns = optionsPatterns(pattern, flags);
|
|
1352
|
+
if (!optionsPatternsTest(patterns, namingFileBasename(context.filename))) {
|
|
1314
1353
|
context.report({
|
|
1315
1354
|
node: program,
|
|
1316
1355
|
messageId: "mismatch",
|
|
@@ -1782,7 +1821,7 @@ import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
|
1782
1821
|
function compileFactoryKeys(pattern, keys, requireKeys) {
|
|
1783
1822
|
const allowedList = keys.concat(requireKeys.filter((key) => !keys.includes(key)));
|
|
1784
1823
|
return {
|
|
1785
|
-
|
|
1824
|
+
patterns: optionsPatterns(pattern),
|
|
1786
1825
|
allowed: new Set(allowedList),
|
|
1787
1826
|
allowedList,
|
|
1788
1827
|
requireKeys
|
|
@@ -1796,7 +1835,7 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1796
1835
|
additionalProperties: false,
|
|
1797
1836
|
properties: {
|
|
1798
1837
|
keys: { type: "array", items: { type: "string" } },
|
|
1799
|
-
factoryPattern:
|
|
1838
|
+
factoryPattern: optionsPatternSchema,
|
|
1800
1839
|
requireKeys: { type: "array", items: { type: "string" } },
|
|
1801
1840
|
keySets: {
|
|
1802
1841
|
type: "array",
|
|
@@ -1804,7 +1843,7 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1804
1843
|
type: "object",
|
|
1805
1844
|
additionalProperties: false,
|
|
1806
1845
|
properties: {
|
|
1807
|
-
factoryPattern:
|
|
1846
|
+
factoryPattern: optionsPatternSchema,
|
|
1808
1847
|
keys: { type: "array", items: { type: "string" } },
|
|
1809
1848
|
requireKeys: { type: "array", items: { type: "string" } }
|
|
1810
1849
|
},
|
|
@@ -1823,11 +1862,11 @@ var noExtraFactoryKeys = defineRule13({
|
|
|
1823
1862
|
let keySets = [];
|
|
1824
1863
|
let fallback;
|
|
1825
1864
|
function resolveFactoryKeys(name) {
|
|
1826
|
-
const matched = keySets.find((item) => item.
|
|
1865
|
+
const matched = keySets.find((item) => optionsPatternsTest(item.patterns, name));
|
|
1827
1866
|
if (matched) {
|
|
1828
1867
|
return matched;
|
|
1829
1868
|
}
|
|
1830
|
-
if (fallback
|
|
1869
|
+
if (fallback && optionsPatternsTest(fallback.patterns, name)) {
|
|
1831
1870
|
return fallback;
|
|
1832
1871
|
}
|
|
1833
1872
|
}
|
|
@@ -1894,9 +1933,9 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1894
1933
|
type: "object",
|
|
1895
1934
|
additionalProperties: false,
|
|
1896
1935
|
properties: {
|
|
1897
|
-
allowPattern:
|
|
1936
|
+
allowPattern: optionsPatternSchema,
|
|
1898
1937
|
detectComponents: { type: "boolean" },
|
|
1899
|
-
hookPattern:
|
|
1938
|
+
hookPattern: optionsPatternSchema
|
|
1900
1939
|
}
|
|
1901
1940
|
}],
|
|
1902
1941
|
messages: {
|
|
@@ -1911,10 +1950,10 @@ var noFileLevelHelpers = defineRule14({
|
|
|
1911
1950
|
detectComponents = true,
|
|
1912
1951
|
hookPattern = "^use[A-Z]"
|
|
1913
1952
|
} = optionsFirst(context, {});
|
|
1914
|
-
const allowed =
|
|
1915
|
-
const hooks =
|
|
1953
|
+
const allowed = optionsOptionalPatterns(allowPattern);
|
|
1954
|
+
const hooks = optionsPatterns(hookPattern);
|
|
1916
1955
|
for (const candidate of declarationsFileLevelFunctionCandidates(program)) {
|
|
1917
|
-
if (detectComponents && reactComponentsIsLike(program, candidate) || hooks
|
|
1956
|
+
if (detectComponents && reactComponentsIsLike(program, candidate) || optionsPatternsTest(hooks, candidate.name) || optionsPatternsTest(allowed, candidate.name)) {
|
|
1918
1957
|
continue;
|
|
1919
1958
|
}
|
|
1920
1959
|
context.report({
|
|
@@ -2427,7 +2466,7 @@ var noModuleMutableState = defineRule21({
|
|
|
2427
2466
|
type: "array",
|
|
2428
2467
|
items: { type: "string", enum: ["let", "var"] }
|
|
2429
2468
|
},
|
|
2430
|
-
allowNamePattern:
|
|
2469
|
+
allowNamePattern: optionsPatternSchema
|
|
2431
2470
|
}
|
|
2432
2471
|
}],
|
|
2433
2472
|
messages: {
|
|
@@ -2436,12 +2475,12 @@ var noModuleMutableState = defineRule21({
|
|
|
2436
2475
|
},
|
|
2437
2476
|
createOnce(context) {
|
|
2438
2477
|
let kindSet = new Set(["let", "var"]);
|
|
2439
|
-
let allowed =
|
|
2478
|
+
let allowed = [];
|
|
2440
2479
|
return {
|
|
2441
2480
|
before() {
|
|
2442
2481
|
const { kinds = ["let", "var"], allowNamePattern } = optionsFirst(context, {});
|
|
2443
2482
|
kindSet = new Set(kinds);
|
|
2444
|
-
allowed =
|
|
2483
|
+
allowed = optionsOptionalPatterns(allowNamePattern);
|
|
2445
2484
|
},
|
|
2446
2485
|
VariableDeclaration(node) {
|
|
2447
2486
|
if (node.declare || !kindSet.has(node.kind)) {
|
|
@@ -2452,7 +2491,7 @@ var noModuleMutableState = defineRule21({
|
|
|
2452
2491
|
}
|
|
2453
2492
|
for (const declarator of node.declarations) {
|
|
2454
2493
|
for (const binding of moduleMutableStateBindings(declarator.id)) {
|
|
2455
|
-
if (!allowed
|
|
2494
|
+
if (!optionsPatternsTest(allowed, binding.name)) {
|
|
2456
2495
|
context.report({
|
|
2457
2496
|
node: binding.node,
|
|
2458
2497
|
messageId: "moduleState"
|
|
@@ -3333,7 +3372,7 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3333
3372
|
additionalProperties: false,
|
|
3334
3373
|
properties: {
|
|
3335
3374
|
banReExports: { type: "boolean" },
|
|
3336
|
-
allowPattern:
|
|
3375
|
+
allowPattern: optionsPatternSchema
|
|
3337
3376
|
}
|
|
3338
3377
|
}],
|
|
3339
3378
|
defaultOptions: [{ banReExports: true }],
|
|
@@ -3346,7 +3385,7 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3346
3385
|
return {
|
|
3347
3386
|
Program(program) {
|
|
3348
3387
|
const { banReExports, allowPattern } = optionsFirst(context);
|
|
3349
|
-
const allowed =
|
|
3388
|
+
const allowed = optionsOptionalPatterns(allowPattern);
|
|
3350
3389
|
for (const statement of program.body) {
|
|
3351
3390
|
if (banReExports && (statement.type === "ExportAllDeclaration" || statement.type === "ExportNamedDeclaration" && statement.source)) {
|
|
3352
3391
|
context.report({ node: statement, messageId: "noReExport" });
|
|
@@ -3354,7 +3393,7 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3354
3393
|
}
|
|
3355
3394
|
const declaration = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
|
|
3356
3395
|
if (declaration?.type === "FunctionDeclaration") {
|
|
3357
|
-
if (!allowed
|
|
3396
|
+
if (!optionsPatternsTest(allowed, declarationsFunctionName(declaration))) {
|
|
3358
3397
|
context.report({
|
|
3359
3398
|
node: declaration,
|
|
3360
3399
|
messageId: "noFunction",
|
|
@@ -3367,7 +3406,7 @@ var noTopLevelFunctions = defineRule29({
|
|
|
3367
3406
|
continue;
|
|
3368
3407
|
}
|
|
3369
3408
|
for (const item of declaration.declarations) {
|
|
3370
|
-
if ((item.init?.type === "FunctionExpression" || item.init?.type === "ArrowFunctionExpression") && !allowed
|
|
3409
|
+
if ((item.init?.type === "FunctionExpression" || item.init?.type === "ArrowFunctionExpression") && !optionsPatternsTest(allowed, declarationsFunctionName(item))) {
|
|
3371
3410
|
context.report({
|
|
3372
3411
|
node: item,
|
|
3373
3412
|
messageId: "noFunction",
|
|
@@ -3416,7 +3455,7 @@ var noTrivialFunctions = defineRule30({
|
|
|
3416
3455
|
type: "object",
|
|
3417
3456
|
additionalProperties: false,
|
|
3418
3457
|
properties: {
|
|
3419
|
-
allowPattern:
|
|
3458
|
+
allowPattern: optionsPatternSchema,
|
|
3420
3459
|
allowCallees: { type: "array", items: { type: "string" } },
|
|
3421
3460
|
allowAsync: { type: "boolean" }
|
|
3422
3461
|
}
|
|
@@ -3426,13 +3465,13 @@ var noTrivialFunctions = defineRule30({
|
|
|
3426
3465
|
}
|
|
3427
3466
|
},
|
|
3428
3467
|
createOnce(context) {
|
|
3429
|
-
let allowed =
|
|
3468
|
+
let allowed = [];
|
|
3430
3469
|
let allowedCallees = [];
|
|
3431
3470
|
let allowAsync = false;
|
|
3432
3471
|
return {
|
|
3433
3472
|
before() {
|
|
3434
3473
|
const { allowPattern, allowCallees: calleePatterns = [], allowAsync: asyncAllowed = false } = optionsFirst(context, {});
|
|
3435
|
-
allowed =
|
|
3474
|
+
allowed = optionsOptionalPatterns(allowPattern);
|
|
3436
3475
|
allowedCallees = calleePatterns.map((pattern) => new RegExp(pattern));
|
|
3437
3476
|
allowAsync = asyncAllowed;
|
|
3438
3477
|
},
|
|
@@ -3440,7 +3479,7 @@ var noTrivialFunctions = defineRule30({
|
|
|
3440
3479
|
const seen = new Set;
|
|
3441
3480
|
for (const item of [...exportsCollectFunctions(program), ...declarationsTopLevelUnexportedFunctions(program)]) {
|
|
3442
3481
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
3443
|
-
if (seen.has(key) || allowed
|
|
3482
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name) || !declarationsIsTrivialFunction(item.node)) {
|
|
3444
3483
|
continue;
|
|
3445
3484
|
}
|
|
3446
3485
|
const expression = forwardedExpression(item.node);
|
|
@@ -3470,7 +3509,7 @@ var noTypeDeclarations = defineRule31({
|
|
|
3470
3509
|
type: "object",
|
|
3471
3510
|
additionalProperties: false,
|
|
3472
3511
|
properties: {
|
|
3473
|
-
allowPattern:
|
|
3512
|
+
allowPattern: optionsPatternSchema
|
|
3474
3513
|
}
|
|
3475
3514
|
}],
|
|
3476
3515
|
messages: {
|
|
@@ -3478,11 +3517,13 @@ var noTypeDeclarations = defineRule31({
|
|
|
3478
3517
|
}
|
|
3479
3518
|
},
|
|
3480
3519
|
createOnce(context) {
|
|
3481
|
-
let
|
|
3520
|
+
let allowedNames = [];
|
|
3521
|
+
let allowedValues = [];
|
|
3482
3522
|
function check(node) {
|
|
3483
|
-
if (
|
|
3523
|
+
if (optionsPatternsTest(allowedNames, node.id.name))
|
|
3524
|
+
return;
|
|
3525
|
+
if (node.type === "TSTypeAliasDeclaration" && allowedValues.length > 0 && optionsPatternsTest(allowedValues, `= ${context.sourceCode.getText(node.typeAnnotation)}`))
|
|
3484
3526
|
return;
|
|
3485
|
-
}
|
|
3486
3527
|
context.report({
|
|
3487
3528
|
node,
|
|
3488
3529
|
messageId: "typeDeclaration",
|
|
@@ -3492,7 +3533,10 @@ var noTypeDeclarations = defineRule31({
|
|
|
3492
3533
|
return {
|
|
3493
3534
|
before() {
|
|
3494
3535
|
const { allowPattern } = optionsFirst(context, {});
|
|
3495
|
-
|
|
3536
|
+
const sources = allowPattern === undefined ? [] : [allowPattern].flat();
|
|
3537
|
+
const isValuePattern = (source) => /^\^?=/.test(source);
|
|
3538
|
+
allowedNames = optionsOptionalPatterns(sources.filter((source) => !isValuePattern(source)));
|
|
3539
|
+
allowedValues = optionsOptionalPatterns(sources.filter(isValuePattern));
|
|
3496
3540
|
},
|
|
3497
3541
|
TSTypeAliasDeclaration: check,
|
|
3498
3542
|
TSInterfaceDeclaration: check
|
|
@@ -3655,7 +3699,7 @@ var onlyExportComponents = defineRule34({
|
|
|
3655
3699
|
properties: {
|
|
3656
3700
|
matchFileName: { type: "boolean" },
|
|
3657
3701
|
allowTypeExports: { type: "boolean" },
|
|
3658
|
-
denyTypePattern:
|
|
3702
|
+
denyTypePattern: optionsPatternSchema
|
|
3659
3703
|
}
|
|
3660
3704
|
}],
|
|
3661
3705
|
messages: {
|
|
@@ -3674,7 +3718,7 @@ var onlyExportComponents = defineRule34({
|
|
|
3674
3718
|
denyTypePattern
|
|
3675
3719
|
} = optionsFirst(context, {});
|
|
3676
3720
|
const expected = reactComponentsPascalFromBasename(namingFileBasename(context.filename));
|
|
3677
|
-
const denied =
|
|
3721
|
+
const denied = optionsOptionalPatterns(denyTypePattern);
|
|
3678
3722
|
const components = [];
|
|
3679
3723
|
for (const candidate of reactComponentsExportCandidates(program)) {
|
|
3680
3724
|
if (candidate.typeOnly) {
|
|
@@ -3684,7 +3728,7 @@ var onlyExportComponents = defineRule34({
|
|
|
3684
3728
|
messageId: "typeExport",
|
|
3685
3729
|
data: { name: candidate.name, expected }
|
|
3686
3730
|
});
|
|
3687
|
-
} else if (denied
|
|
3731
|
+
} else if (optionsPatternsTest(denied, candidate.name)) {
|
|
3688
3732
|
context.report({
|
|
3689
3733
|
node: candidate.node,
|
|
3690
3734
|
messageId: "deniedType",
|
|
@@ -4037,7 +4081,7 @@ var requireObjectParams = defineRule38({
|
|
|
4037
4081
|
properties: {
|
|
4038
4082
|
maxParams: { type: "integer", minimum: 1 },
|
|
4039
4083
|
allDeclarations: { type: "boolean" },
|
|
4040
|
-
allowPattern:
|
|
4084
|
+
allowPattern: optionsPatternSchema
|
|
4041
4085
|
}
|
|
4042
4086
|
}],
|
|
4043
4087
|
messages: {
|
|
@@ -4048,12 +4092,12 @@ var requireObjectParams = defineRule38({
|
|
|
4048
4092
|
return {
|
|
4049
4093
|
Program(program) {
|
|
4050
4094
|
const { maxParams = 1, allDeclarations = false, allowPattern } = optionsFirst(context, {});
|
|
4051
|
-
const allowed =
|
|
4095
|
+
const allowed = optionsOptionalPatterns(allowPattern);
|
|
4052
4096
|
const seen = new Set;
|
|
4053
4097
|
const functions = allDeclarations ? [...exportsCollectFunctions(program), ...declarationsTopLevelUnexportedFunctions(program)] : exportsCollectFunctions(program);
|
|
4054
4098
|
for (const item of functions) {
|
|
4055
4099
|
const key = `${item.name}:${item.node.start}:${item.node.end}`;
|
|
4056
|
-
if (seen.has(key) || allowed
|
|
4100
|
+
if (seen.has(key) || optionsPatternsTest(allowed, item.name)) {
|
|
4057
4101
|
continue;
|
|
4058
4102
|
}
|
|
4059
4103
|
seen.add(key);
|
|
@@ -4275,6 +4319,9 @@ function regexMatches(regex, value) {
|
|
|
4275
4319
|
regex.lastIndex = 0;
|
|
4276
4320
|
return regex.test(value);
|
|
4277
4321
|
}
|
|
4322
|
+
function titlePatterns(pattern, flags) {
|
|
4323
|
+
return pattern === undefined ? [] : [pattern].flat().map((source) => ({ regex: new RegExp(source, flags), pattern: source }));
|
|
4324
|
+
}
|
|
4278
4325
|
var testTitlePattern = defineRule42({
|
|
4279
4326
|
meta: {
|
|
4280
4327
|
type: "suggestion",
|
|
@@ -4283,8 +4330,8 @@ var testTitlePattern = defineRule42({
|
|
|
4283
4330
|
additionalProperties: false,
|
|
4284
4331
|
properties: {
|
|
4285
4332
|
callees: { type: "array", items: { type: "string" } },
|
|
4286
|
-
forbid:
|
|
4287
|
-
require:
|
|
4333
|
+
forbid: optionsPatternSchema,
|
|
4334
|
+
require: optionsPatternSchema,
|
|
4288
4335
|
flags: { type: "string", pattern: "^[dgimsuvy]*$" }
|
|
4289
4336
|
}
|
|
4290
4337
|
}],
|
|
@@ -4299,16 +4346,18 @@ var testTitlePattern = defineRule42({
|
|
|
4299
4346
|
},
|
|
4300
4347
|
createOnce(context) {
|
|
4301
4348
|
let callees = [];
|
|
4302
|
-
let forbid;
|
|
4303
|
-
let required;
|
|
4349
|
+
let forbid = [];
|
|
4350
|
+
let required = [];
|
|
4351
|
+
let requiredLabel = "";
|
|
4304
4352
|
return {
|
|
4305
4353
|
before() {
|
|
4306
4354
|
const options = optionsFirst(context);
|
|
4307
4355
|
callees = options.callees;
|
|
4308
4356
|
const flags = options.flags ?? "";
|
|
4309
|
-
forbid =
|
|
4310
|
-
required =
|
|
4311
|
-
|
|
4357
|
+
forbid = titlePatterns(options.forbid, flags);
|
|
4358
|
+
required = titlePatterns(options.require, flags);
|
|
4359
|
+
requiredLabel = optionsPatternLabel(options.require);
|
|
4360
|
+
if (forbid.length === 0 && required.length === 0) {
|
|
4312
4361
|
return false;
|
|
4313
4362
|
}
|
|
4314
4363
|
},
|
|
@@ -4324,18 +4373,19 @@ var testTitlePattern = defineRule42({
|
|
|
4324
4373
|
if (text === undefined) {
|
|
4325
4374
|
return;
|
|
4326
4375
|
}
|
|
4327
|
-
|
|
4376
|
+
const forbidden = forbid.find((item) => regexMatches(item.regex, text));
|
|
4377
|
+
if (forbidden) {
|
|
4328
4378
|
context.report({
|
|
4329
4379
|
node: title,
|
|
4330
4380
|
messageId: "forbidden",
|
|
4331
|
-
data: { pattern:
|
|
4381
|
+
data: { pattern: forbidden.pattern }
|
|
4332
4382
|
});
|
|
4333
4383
|
}
|
|
4334
|
-
if (required && !regexMatches(
|
|
4384
|
+
if (required.length > 0 && !required.some((item) => regexMatches(item.regex, text))) {
|
|
4335
4385
|
context.report({
|
|
4336
4386
|
node: title,
|
|
4337
4387
|
messageId: "required",
|
|
4338
|
-
data: { pattern:
|
|
4388
|
+
data: { pattern: requiredLabel }
|
|
4339
4389
|
});
|
|
4340
4390
|
}
|
|
4341
4391
|
}
|