@sarj/eslint-plugin 11.1.0 → 11.2.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/dist/index.cjs +66 -7
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +66 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -869,6 +869,7 @@ var BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\*{4,}|~{4,}|[\u2500-\u257f]{4,}/;
|
|
|
869
869
|
var REGION_MARKER_RE = /^#?(?:end)?region\b(.*)$/i;
|
|
870
870
|
var REGION_TITLE_RE = /^[\s:\-\u2013\u2014]*\w[\w \-/&+]*$/;
|
|
871
871
|
var REGION_TITLE_MAX_WORDS = 5;
|
|
872
|
+
var REGION_PROSE_VERB_RE = /^(?:is|are|was|were|comes?|defaults?|derives?|inherits?|depends?|uses?|maps?|resolves?)\b/i;
|
|
872
873
|
function stripCommentMarker(line) {
|
|
873
874
|
return line.replace(/^\s*\/{1,2}/, "").replace(/^\s*\*+/, "").trim();
|
|
874
875
|
}
|
|
@@ -930,7 +931,9 @@ var CALL_RE = /^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
|
|
|
930
931
|
var ASSERTION_CODE_RE = /^(?:await\s+)?(?:expect(?:TypeOf)?|assert(?:\.\w+)?)\s*\(/;
|
|
931
932
|
var HTTP_CONTRACT_RE = /\b(?:GET|HEAD|OPTIONS|PATCH|POST|PUT|DELETE)\s+(?:https?:\/\/|\/|\{[A-Za-z_$])/;
|
|
932
933
|
var PROSE_ASSIGNMENT_RE = /^[A-Za-z_$][\w.$[\]]*\s*=\s*[A-Za-z][A-Za-z '-]{2,}\s+\((?:how|what|when|where|which|who|why)\b[^)]*\)[.!]?$/i;
|
|
933
|
-
var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w
|
|
934
|
+
var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|\b[A-Za-z_$][\w$]*\s+x\d+\b|…|\.\.\./;
|
|
935
|
+
var CALL_LABEL_RE = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\([^;{}]*\)$/;
|
|
936
|
+
var MULTIPLIER_PSEUDOCODE_RE = /\b[A-Za-z_$][\w$]*\s+x\d+\b/;
|
|
934
937
|
function isBanner(text) {
|
|
935
938
|
const t = text.trim();
|
|
936
939
|
if (!t) return false;
|
|
@@ -942,6 +945,7 @@ function isRegionMarker(text) {
|
|
|
942
945
|
if (match === null) return false;
|
|
943
946
|
const title = (match[1] ?? "").trim();
|
|
944
947
|
if (title.length === 0) return true;
|
|
948
|
+
if (REGION_PROSE_VERB_RE.test(title)) return false;
|
|
945
949
|
if (!REGION_TITLE_RE.test(title)) return false;
|
|
946
950
|
return title.split(/\s+/).length <= REGION_TITLE_MAX_WORDS;
|
|
947
951
|
}
|
|
@@ -957,6 +961,15 @@ function looksLikeCode(text, allowCall = true) {
|
|
|
957
961
|
function hasPseudocode(text) {
|
|
958
962
|
return PSEUDOCODE_RE.test(text);
|
|
959
963
|
}
|
|
964
|
+
function testCallMatrixStems(comments) {
|
|
965
|
+
const stems = /* @__PURE__ */ new Set();
|
|
966
|
+
for (const comment of comments) {
|
|
967
|
+
const body2 = stripCommentMarker(comment.value);
|
|
968
|
+
const stem3 = CALL_LABEL_RE.exec(body2)?.[1];
|
|
969
|
+
if (stem3 !== void 0 && MULTIPLIER_PSEUDOCODE_RE.test(body2)) stems.add(stem3);
|
|
970
|
+
}
|
|
971
|
+
return stems;
|
|
972
|
+
}
|
|
960
973
|
function isEnumeratedProseItem(text) {
|
|
961
974
|
const t = text.trim();
|
|
962
975
|
return ENUMERATED_ITEM_RE.test(t) && t.split(/\s+/).length >= ENUMERATED_ITEM_MIN_WORDS;
|
|
@@ -1245,6 +1258,7 @@ var no_comment_cruft_default = createRule({
|
|
|
1245
1258
|
return {
|
|
1246
1259
|
Program() {
|
|
1247
1260
|
const comments = sourceCode.getAllComments();
|
|
1261
|
+
const callMatrixStems = isTestFile(context.filename) ? testCallMatrixStems(comments) : /* @__PURE__ */ new Set();
|
|
1248
1262
|
const walls = findCommentWalls(comments);
|
|
1249
1263
|
const wallByLeader = new Map(walls.map((wall) => [wall.leader, wall]));
|
|
1250
1264
|
const wallMembers = new Set(walls.flatMap((wall) => [...wall.members]));
|
|
@@ -1282,6 +1296,8 @@ var no_comment_cruft_default = createRule({
|
|
|
1282
1296
|
continue;
|
|
1283
1297
|
}
|
|
1284
1298
|
const firstText = texts[0];
|
|
1299
|
+
const firstTextStem = firstText === void 0 ? void 0 : CALL_LABEL_RE.exec(firstText)?.[1];
|
|
1300
|
+
if (firstTextStem !== void 0 && texts.length === 1 && callMatrixStems.has(firstTextStem)) continue;
|
|
1285
1301
|
if (firstText !== void 0 && /^(?:todo|fixme)\b/i.test(firstText)) {
|
|
1286
1302
|
if (!runCitesAReference(comments, i)) {
|
|
1287
1303
|
context.report({
|
|
@@ -2211,6 +2227,20 @@ var PURE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2211
2227
|
"startsWith",
|
|
2212
2228
|
"endsWith"
|
|
2213
2229
|
]);
|
|
2230
|
+
var SYNC_CALLBACK_METHODS = /* @__PURE__ */ new Set([
|
|
2231
|
+
"every",
|
|
2232
|
+
"filter",
|
|
2233
|
+
"findIndex",
|
|
2234
|
+
"findLast",
|
|
2235
|
+
"findLastIndex",
|
|
2236
|
+
"flatMap",
|
|
2237
|
+
"forEach",
|
|
2238
|
+
"map",
|
|
2239
|
+
"reduce",
|
|
2240
|
+
"reduceRight",
|
|
2241
|
+
"some",
|
|
2242
|
+
"sort"
|
|
2243
|
+
]);
|
|
2214
2244
|
var PURE_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2215
2245
|
"Object",
|
|
2216
2246
|
"Array",
|
|
@@ -2260,7 +2290,17 @@ function isPureCall(node) {
|
|
|
2260
2290
|
if (callee.object.type === import_utils13.AST_NODE_TYPES.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
|
|
2261
2291
|
return !IMPURE_NAMESPACE_METHODS.has(`${callee.object.name}.${property.name}`);
|
|
2262
2292
|
}
|
|
2263
|
-
return PURE_METHODS.has(property.name);
|
|
2293
|
+
return PURE_METHODS.has(property.name) && (!SYNC_CALLBACK_METHODS.has(property.name) || !synchronousCallbackCanThrow(node));
|
|
2294
|
+
}
|
|
2295
|
+
function synchronousCallbackCanThrow(node) {
|
|
2296
|
+
return node.arguments.some((argument) => {
|
|
2297
|
+
if (argument.type !== import_utils13.AST_NODE_TYPES.ArrowFunctionExpression && argument.type !== import_utils13.AST_NODE_TYPES.FunctionExpression) return false;
|
|
2298
|
+
if (argument.async) return false;
|
|
2299
|
+
return subtreeMatches2(
|
|
2300
|
+
argument.body,
|
|
2301
|
+
(current) => current.type === import_utils13.AST_NODE_TYPES.ThrowStatement || current.type === import_utils13.AST_NODE_TYPES.CallExpression && current.callee.type === import_utils13.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.object.type === import_utils13.AST_NODE_TYPES.Identifier && current.callee.object.name === "JSON" && current.callee.property.type === import_utils13.AST_NODE_TYPES.Identifier && current.callee.property.name === "parse"
|
|
2302
|
+
);
|
|
2303
|
+
});
|
|
2264
2304
|
}
|
|
2265
2305
|
function isPureNew(node) {
|
|
2266
2306
|
return node.callee.type === import_utils13.AST_NODE_TYPES.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
|
|
@@ -3522,6 +3562,8 @@ function typedFunction(node) {
|
|
|
3522
3562
|
|
|
3523
3563
|
// src/rules/no-long-comment.ts
|
|
3524
3564
|
var EXCESSIVE_SENTENCE_COUNT = 8;
|
|
3565
|
+
var EXCESSIVE_WORD_COUNT = 120;
|
|
3566
|
+
var PROSE_WORD_RE = /[\p{L}\p{N}][\p{L}\p{N}'’-]*/gu;
|
|
3525
3567
|
var VERSIONED_DEPENDENCY_TREE_RE = /(?:^|\/)lib\/[^/]*-?v?\d+\.\d+(?:\.\d+)?[^/]*\//iu;
|
|
3526
3568
|
function documentsTypeOrMember(sourceCode, comment) {
|
|
3527
3569
|
const token = sourceCode.getTokenAfter(comment, { includeComments: false });
|
|
@@ -3533,6 +3575,9 @@ function documentsTypeOrMember(sourceCode, comment) {
|
|
|
3533
3575
|
}
|
|
3534
3576
|
return false;
|
|
3535
3577
|
}
|
|
3578
|
+
function wordUnits(text) {
|
|
3579
|
+
return text.match(PROSE_WORD_RE)?.length ?? 0;
|
|
3580
|
+
}
|
|
3536
3581
|
var no_long_comment_default = createRule({
|
|
3537
3582
|
name: "no-long-comment",
|
|
3538
3583
|
meta: {
|
|
@@ -3550,7 +3595,7 @@ var no_long_comment_default = createRule({
|
|
|
3550
3595
|
return {
|
|
3551
3596
|
Program() {
|
|
3552
3597
|
for (const group of proseGroups(context.filename, context.sourceCode)) {
|
|
3553
|
-
if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT) continue;
|
|
3598
|
+
if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT && wordUnits(group.text) < EXCESSIVE_WORD_COUNT) continue;
|
|
3554
3599
|
context.report({ node: group.comment, messageId: "tooLong" });
|
|
3555
3600
|
}
|
|
3556
3601
|
}
|
|
@@ -8554,6 +8599,11 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8554
8599
|
type: "boolean",
|
|
8555
8600
|
description: "Skip test files, where a fixture schema belongs next to its assertion."
|
|
8556
8601
|
},
|
|
8602
|
+
memoCallees: {
|
|
8603
|
+
type: "array",
|
|
8604
|
+
items: { type: "string" },
|
|
8605
|
+
description: "Wrappers that construct their callback at most once. Defaults to lazy, memo, once, and useMemo."
|
|
8606
|
+
},
|
|
8557
8607
|
minProperties: {
|
|
8558
8608
|
type: "number",
|
|
8559
8609
|
minimum: 0,
|
|
@@ -8571,6 +8621,7 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8571
8621
|
create(context, [options]) {
|
|
8572
8622
|
const factories = new Set(options?.factories ?? DEFAULT_FACTORIES);
|
|
8573
8623
|
const ignoreTestFiles = options?.ignoreTestFiles ?? true;
|
|
8624
|
+
const memoCallees = new Set(options?.memoCallees ?? MEMO_CALLEES);
|
|
8574
8625
|
const minProperties = options?.minProperties ?? DEFAULT_MIN_PROPERTIES;
|
|
8575
8626
|
const sourceCode = context.sourceCode;
|
|
8576
8627
|
const filename = context.filename;
|
|
@@ -8590,7 +8641,7 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8590
8641
|
if (current !== node && isZodCall(current) && current.callee.type === import_utils56.AST_NODE_TYPES.MemberExpression && current.callee.property.type === import_utils56.AST_NODE_TYPES.Identifier && factories.has(current.callee.property.name)) {
|
|
8591
8642
|
return true;
|
|
8592
8643
|
}
|
|
8593
|
-
if (current.type === import_utils56.AST_NODE_TYPES.CallExpression && (current.callee.type === import_utils56.AST_NODE_TYPES.Identifier &&
|
|
8644
|
+
if (current.type === import_utils56.AST_NODE_TYPES.CallExpression && (current.callee.type === import_utils56.AST_NODE_TYPES.Identifier && memoCallees.has(current.callee.name) || current.callee.type === import_utils56.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.property.type === import_utils56.AST_NODE_TYPES.Identifier && memoCallees.has(current.callee.property.name))) {
|
|
8594
8645
|
return true;
|
|
8595
8646
|
}
|
|
8596
8647
|
current = current.parent ?? void 0;
|
|
@@ -8640,6 +8691,9 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8640
8691
|
if (definition.type === "ImportBinding") {
|
|
8641
8692
|
continue;
|
|
8642
8693
|
}
|
|
8694
|
+
if (definition.node.type === import_utils56.AST_NODE_TYPES.VariableDeclarator && definition.node.parent.type === import_utils56.AST_NODE_TYPES.VariableDeclaration && definition.node.parent.kind !== "const") {
|
|
8695
|
+
return false;
|
|
8696
|
+
}
|
|
8643
8697
|
const [defStart, defEnd] = definition.node.range;
|
|
8644
8698
|
if (defStart >= schemaStart && defEnd <= schemaEnd) {
|
|
8645
8699
|
continue;
|
|
@@ -8874,7 +8928,7 @@ function sameAccess(node, access) {
|
|
|
8874
8928
|
return node.type === import_utils58.AST_NODE_TYPES.MemberExpression && !node.computed && node.object.type === import_utils58.AST_NODE_TYPES.Identifier && node.object.name === access.object && node.property.type === import_utils58.AST_NODE_TYPES.Identifier && node.property.name === access.property;
|
|
8875
8929
|
}
|
|
8876
8930
|
function isNullGuard(node, access) {
|
|
8877
|
-
if (node.type === import_utils58.AST_NODE_TYPES.UnaryExpression && node.operator === "!" && sameAccess(node.argument, access)) return true;
|
|
8931
|
+
if (node.type === import_utils58.AST_NODE_TYPES.UnaryExpression && node.operator === "!" && (sameAccess(node.argument, access) || optionalMemberLengthOf(node.argument, access))) return true;
|
|
8878
8932
|
if (node.type !== import_utils58.AST_NODE_TYPES.BinaryExpression || !["==", "==="].includes(node.operator)) {
|
|
8879
8933
|
return false;
|
|
8880
8934
|
}
|
|
@@ -8890,7 +8944,11 @@ function isEmptyGuard(node, access) {
|
|
|
8890
8944
|
return memberLengthOf(node.left, access) && zero(node.right) || memberLengthOf(node.right, access) && zero(node.left);
|
|
8891
8945
|
}
|
|
8892
8946
|
function memberLengthOf(node, access) {
|
|
8893
|
-
|
|
8947
|
+
const target = node.type === import_utils58.AST_NODE_TYPES.ChainExpression ? node.expression : node;
|
|
8948
|
+
return target.type === import_utils58.AST_NODE_TYPES.MemberExpression && !target.computed && target.property.type === import_utils58.AST_NODE_TYPES.Identifier && target.property.name === "length" && sameAccess(target.object, access);
|
|
8949
|
+
}
|
|
8950
|
+
function optionalMemberLengthOf(node, access) {
|
|
8951
|
+
return node.type === import_utils58.AST_NODE_TYPES.ChainExpression && node.expression.type === import_utils58.AST_NODE_TYPES.MemberExpression && node.expression.optional && memberLengthOf(node, access);
|
|
8894
8952
|
}
|
|
8895
8953
|
function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
|
|
8896
8954
|
if (fn.body.type !== import_utils58.AST_NODE_TYPES.BlockStatement) return false;
|
|
@@ -8898,6 +8956,7 @@ function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
|
|
|
8898
8956
|
if (first?.type !== import_utils58.AST_NODE_TYPES.IfStatement) return false;
|
|
8899
8957
|
const terminating = first.consequent.type === import_utils58.AST_NODE_TYPES.ReturnStatement || first.consequent.type === import_utils58.AST_NODE_TYPES.ThrowStatement || first.consequent.type === import_utils58.AST_NODE_TYPES.BlockStatement && first.consequent.body.length === 1 && (first.consequent.body[0]?.type === import_utils58.AST_NODE_TYPES.ReturnStatement || first.consequent.body[0]?.type === import_utils58.AST_NODE_TYPES.ThrowStatement);
|
|
8900
8958
|
if (!terminating) return false;
|
|
8959
|
+
if (contains(first.consequent, visitorKeys, (node) => sameAccess(node, access))) return false;
|
|
8901
8960
|
return contains(first.test, visitorKeys, (node) => isNullGuard(node, access)) && contains(first.test, visitorKeys, (node) => isEmptyGuard(node, access));
|
|
8902
8961
|
}
|
|
8903
8962
|
function contains(node, visitorKeys, predicate) {
|
|
@@ -12641,7 +12700,7 @@ var rules = {
|
|
|
12641
12700
|
};
|
|
12642
12701
|
var meta = {
|
|
12643
12702
|
name: "@sarj/eslint-plugin",
|
|
12644
|
-
version: "11.
|
|
12703
|
+
version: "11.2.0"
|
|
12645
12704
|
};
|
|
12646
12705
|
var applicationOnlyRules = [
|
|
12647
12706
|
"no-restricted-library-load",
|
package/dist/index.d.cts
CHANGED
|
@@ -246,6 +246,7 @@ declare const rules: {
|
|
|
246
246
|
readonly "prefer-module-level-schema": _typescript_eslint_utils_ts_eslint.RuleModule<"hoistSchema", readonly [{
|
|
247
247
|
factories?: readonly string[];
|
|
248
248
|
ignoreTestFiles?: boolean;
|
|
249
|
+
memoCallees?: readonly string[];
|
|
249
250
|
minProperties?: number;
|
|
250
251
|
}?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
251
252
|
name: string;
|
|
@@ -453,7 +454,7 @@ type FlatPreset = {
|
|
|
453
454
|
declare const plugin: {
|
|
454
455
|
readonly meta: {
|
|
455
456
|
readonly name: "@sarj/eslint-plugin";
|
|
456
|
-
readonly version: "11.
|
|
457
|
+
readonly version: "11.2.0";
|
|
457
458
|
};
|
|
458
459
|
readonly rules: {
|
|
459
460
|
readonly "duplicate-test-body": _typescript_eslint_utils_ts_eslint.RuleModule<"duplicateTestBody", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
@@ -614,6 +615,7 @@ declare const plugin: {
|
|
|
614
615
|
readonly "prefer-module-level-schema": _typescript_eslint_utils_ts_eslint.RuleModule<"hoistSchema", readonly [{
|
|
615
616
|
factories?: readonly string[];
|
|
616
617
|
ignoreTestFiles?: boolean;
|
|
618
|
+
memoCallees?: readonly string[];
|
|
617
619
|
minProperties?: number;
|
|
618
620
|
}?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
619
621
|
name: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -246,6 +246,7 @@ declare const rules: {
|
|
|
246
246
|
readonly "prefer-module-level-schema": _typescript_eslint_utils_ts_eslint.RuleModule<"hoistSchema", readonly [{
|
|
247
247
|
factories?: readonly string[];
|
|
248
248
|
ignoreTestFiles?: boolean;
|
|
249
|
+
memoCallees?: readonly string[];
|
|
249
250
|
minProperties?: number;
|
|
250
251
|
}?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
251
252
|
name: string;
|
|
@@ -453,7 +454,7 @@ type FlatPreset = {
|
|
|
453
454
|
declare const plugin: {
|
|
454
455
|
readonly meta: {
|
|
455
456
|
readonly name: "@sarj/eslint-plugin";
|
|
456
|
-
readonly version: "11.
|
|
457
|
+
readonly version: "11.2.0";
|
|
457
458
|
};
|
|
458
459
|
readonly rules: {
|
|
459
460
|
readonly "duplicate-test-body": _typescript_eslint_utils_ts_eslint.RuleModule<"duplicateTestBody", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
@@ -614,6 +615,7 @@ declare const plugin: {
|
|
|
614
615
|
readonly "prefer-module-level-schema": _typescript_eslint_utils_ts_eslint.RuleModule<"hoistSchema", readonly [{
|
|
615
616
|
factories?: readonly string[];
|
|
616
617
|
ignoreTestFiles?: boolean;
|
|
618
|
+
memoCallees?: readonly string[];
|
|
617
619
|
minProperties?: number;
|
|
618
620
|
}?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
619
621
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -827,6 +827,7 @@ var BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\*{4,}|~{4,}|[\u2500-\u257f]{4,}/;
|
|
|
827
827
|
var REGION_MARKER_RE = /^#?(?:end)?region\b(.*)$/i;
|
|
828
828
|
var REGION_TITLE_RE = /^[\s:\-\u2013\u2014]*\w[\w \-/&+]*$/;
|
|
829
829
|
var REGION_TITLE_MAX_WORDS = 5;
|
|
830
|
+
var REGION_PROSE_VERB_RE = /^(?:is|are|was|were|comes?|defaults?|derives?|inherits?|depends?|uses?|maps?|resolves?)\b/i;
|
|
830
831
|
function stripCommentMarker(line) {
|
|
831
832
|
return line.replace(/^\s*\/{1,2}/, "").replace(/^\s*\*+/, "").trim();
|
|
832
833
|
}
|
|
@@ -888,7 +889,9 @@ var CALL_RE = /^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
|
|
|
888
889
|
var ASSERTION_CODE_RE = /^(?:await\s+)?(?:expect(?:TypeOf)?|assert(?:\.\w+)?)\s*\(/;
|
|
889
890
|
var HTTP_CONTRACT_RE = /\b(?:GET|HEAD|OPTIONS|PATCH|POST|PUT|DELETE)\s+(?:https?:\/\/|\/|\{[A-Za-z_$])/;
|
|
890
891
|
var PROSE_ASSIGNMENT_RE = /^[A-Za-z_$][\w.$[\]]*\s*=\s*[A-Za-z][A-Za-z '-]{2,}\s+\((?:how|what|when|where|which|who|why)\b[^)]*\)[.!]?$/i;
|
|
891
|
-
var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w
|
|
892
|
+
var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|\b[A-Za-z_$][\w$]*\s+x\d+\b|…|\.\.\./;
|
|
893
|
+
var CALL_LABEL_RE = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\([^;{}]*\)$/;
|
|
894
|
+
var MULTIPLIER_PSEUDOCODE_RE = /\b[A-Za-z_$][\w$]*\s+x\d+\b/;
|
|
892
895
|
function isBanner(text) {
|
|
893
896
|
const t = text.trim();
|
|
894
897
|
if (!t) return false;
|
|
@@ -900,6 +903,7 @@ function isRegionMarker(text) {
|
|
|
900
903
|
if (match === null) return false;
|
|
901
904
|
const title = (match[1] ?? "").trim();
|
|
902
905
|
if (title.length === 0) return true;
|
|
906
|
+
if (REGION_PROSE_VERB_RE.test(title)) return false;
|
|
903
907
|
if (!REGION_TITLE_RE.test(title)) return false;
|
|
904
908
|
return title.split(/\s+/).length <= REGION_TITLE_MAX_WORDS;
|
|
905
909
|
}
|
|
@@ -915,6 +919,15 @@ function looksLikeCode(text, allowCall = true) {
|
|
|
915
919
|
function hasPseudocode(text) {
|
|
916
920
|
return PSEUDOCODE_RE.test(text);
|
|
917
921
|
}
|
|
922
|
+
function testCallMatrixStems(comments) {
|
|
923
|
+
const stems = /* @__PURE__ */ new Set();
|
|
924
|
+
for (const comment of comments) {
|
|
925
|
+
const body2 = stripCommentMarker(comment.value);
|
|
926
|
+
const stem3 = CALL_LABEL_RE.exec(body2)?.[1];
|
|
927
|
+
if (stem3 !== void 0 && MULTIPLIER_PSEUDOCODE_RE.test(body2)) stems.add(stem3);
|
|
928
|
+
}
|
|
929
|
+
return stems;
|
|
930
|
+
}
|
|
918
931
|
function isEnumeratedProseItem(text) {
|
|
919
932
|
const t = text.trim();
|
|
920
933
|
return ENUMERATED_ITEM_RE.test(t) && t.split(/\s+/).length >= ENUMERATED_ITEM_MIN_WORDS;
|
|
@@ -1203,6 +1216,7 @@ var no_comment_cruft_default = createRule({
|
|
|
1203
1216
|
return {
|
|
1204
1217
|
Program() {
|
|
1205
1218
|
const comments = sourceCode.getAllComments();
|
|
1219
|
+
const callMatrixStems = isTestFile(context.filename) ? testCallMatrixStems(comments) : /* @__PURE__ */ new Set();
|
|
1206
1220
|
const walls = findCommentWalls(comments);
|
|
1207
1221
|
const wallByLeader = new Map(walls.map((wall) => [wall.leader, wall]));
|
|
1208
1222
|
const wallMembers = new Set(walls.flatMap((wall) => [...wall.members]));
|
|
@@ -1240,6 +1254,8 @@ var no_comment_cruft_default = createRule({
|
|
|
1240
1254
|
continue;
|
|
1241
1255
|
}
|
|
1242
1256
|
const firstText = texts[0];
|
|
1257
|
+
const firstTextStem = firstText === void 0 ? void 0 : CALL_LABEL_RE.exec(firstText)?.[1];
|
|
1258
|
+
if (firstTextStem !== void 0 && texts.length === 1 && callMatrixStems.has(firstTextStem)) continue;
|
|
1243
1259
|
if (firstText !== void 0 && /^(?:todo|fixme)\b/i.test(firstText)) {
|
|
1244
1260
|
if (!runCitesAReference(comments, i)) {
|
|
1245
1261
|
context.report({
|
|
@@ -2169,6 +2185,20 @@ var PURE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2169
2185
|
"startsWith",
|
|
2170
2186
|
"endsWith"
|
|
2171
2187
|
]);
|
|
2188
|
+
var SYNC_CALLBACK_METHODS = /* @__PURE__ */ new Set([
|
|
2189
|
+
"every",
|
|
2190
|
+
"filter",
|
|
2191
|
+
"findIndex",
|
|
2192
|
+
"findLast",
|
|
2193
|
+
"findLastIndex",
|
|
2194
|
+
"flatMap",
|
|
2195
|
+
"forEach",
|
|
2196
|
+
"map",
|
|
2197
|
+
"reduce",
|
|
2198
|
+
"reduceRight",
|
|
2199
|
+
"some",
|
|
2200
|
+
"sort"
|
|
2201
|
+
]);
|
|
2172
2202
|
var PURE_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2173
2203
|
"Object",
|
|
2174
2204
|
"Array",
|
|
@@ -2218,7 +2248,17 @@ function isPureCall(node) {
|
|
|
2218
2248
|
if (callee.object.type === AST_NODE_TYPES10.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
|
|
2219
2249
|
return !IMPURE_NAMESPACE_METHODS.has(`${callee.object.name}.${property.name}`);
|
|
2220
2250
|
}
|
|
2221
|
-
return PURE_METHODS.has(property.name);
|
|
2251
|
+
return PURE_METHODS.has(property.name) && (!SYNC_CALLBACK_METHODS.has(property.name) || !synchronousCallbackCanThrow(node));
|
|
2252
|
+
}
|
|
2253
|
+
function synchronousCallbackCanThrow(node) {
|
|
2254
|
+
return node.arguments.some((argument) => {
|
|
2255
|
+
if (argument.type !== AST_NODE_TYPES10.ArrowFunctionExpression && argument.type !== AST_NODE_TYPES10.FunctionExpression) return false;
|
|
2256
|
+
if (argument.async) return false;
|
|
2257
|
+
return subtreeMatches2(
|
|
2258
|
+
argument.body,
|
|
2259
|
+
(current) => current.type === AST_NODE_TYPES10.ThrowStatement || current.type === AST_NODE_TYPES10.CallExpression && current.callee.type === AST_NODE_TYPES10.MemberExpression && !current.callee.computed && current.callee.object.type === AST_NODE_TYPES10.Identifier && current.callee.object.name === "JSON" && current.callee.property.type === AST_NODE_TYPES10.Identifier && current.callee.property.name === "parse"
|
|
2260
|
+
);
|
|
2261
|
+
});
|
|
2222
2262
|
}
|
|
2223
2263
|
function isPureNew(node) {
|
|
2224
2264
|
return node.callee.type === AST_NODE_TYPES10.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
|
|
@@ -3480,6 +3520,8 @@ function typedFunction(node) {
|
|
|
3480
3520
|
|
|
3481
3521
|
// src/rules/no-long-comment.ts
|
|
3482
3522
|
var EXCESSIVE_SENTENCE_COUNT = 8;
|
|
3523
|
+
var EXCESSIVE_WORD_COUNT = 120;
|
|
3524
|
+
var PROSE_WORD_RE = /[\p{L}\p{N}][\p{L}\p{N}'’-]*/gu;
|
|
3483
3525
|
var VERSIONED_DEPENDENCY_TREE_RE = /(?:^|\/)lib\/[^/]*-?v?\d+\.\d+(?:\.\d+)?[^/]*\//iu;
|
|
3484
3526
|
function documentsTypeOrMember(sourceCode, comment) {
|
|
3485
3527
|
const token = sourceCode.getTokenAfter(comment, { includeComments: false });
|
|
@@ -3491,6 +3533,9 @@ function documentsTypeOrMember(sourceCode, comment) {
|
|
|
3491
3533
|
}
|
|
3492
3534
|
return false;
|
|
3493
3535
|
}
|
|
3536
|
+
function wordUnits(text) {
|
|
3537
|
+
return text.match(PROSE_WORD_RE)?.length ?? 0;
|
|
3538
|
+
}
|
|
3494
3539
|
var no_long_comment_default = createRule({
|
|
3495
3540
|
name: "no-long-comment",
|
|
3496
3541
|
meta: {
|
|
@@ -3508,7 +3553,7 @@ var no_long_comment_default = createRule({
|
|
|
3508
3553
|
return {
|
|
3509
3554
|
Program() {
|
|
3510
3555
|
for (const group of proseGroups(context.filename, context.sourceCode)) {
|
|
3511
|
-
if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT) continue;
|
|
3556
|
+
if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT && wordUnits(group.text) < EXCESSIVE_WORD_COUNT) continue;
|
|
3512
3557
|
context.report({ node: group.comment, messageId: "tooLong" });
|
|
3513
3558
|
}
|
|
3514
3559
|
}
|
|
@@ -8515,6 +8560,11 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8515
8560
|
type: "boolean",
|
|
8516
8561
|
description: "Skip test files, where a fixture schema belongs next to its assertion."
|
|
8517
8562
|
},
|
|
8563
|
+
memoCallees: {
|
|
8564
|
+
type: "array",
|
|
8565
|
+
items: { type: "string" },
|
|
8566
|
+
description: "Wrappers that construct their callback at most once. Defaults to lazy, memo, once, and useMemo."
|
|
8567
|
+
},
|
|
8518
8568
|
minProperties: {
|
|
8519
8569
|
type: "number",
|
|
8520
8570
|
minimum: 0,
|
|
@@ -8532,6 +8582,7 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8532
8582
|
create(context, [options]) {
|
|
8533
8583
|
const factories = new Set(options?.factories ?? DEFAULT_FACTORIES);
|
|
8534
8584
|
const ignoreTestFiles = options?.ignoreTestFiles ?? true;
|
|
8585
|
+
const memoCallees = new Set(options?.memoCallees ?? MEMO_CALLEES);
|
|
8535
8586
|
const minProperties = options?.minProperties ?? DEFAULT_MIN_PROPERTIES;
|
|
8536
8587
|
const sourceCode = context.sourceCode;
|
|
8537
8588
|
const filename = context.filename;
|
|
@@ -8551,7 +8602,7 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8551
8602
|
if (current !== node && isZodCall(current) && current.callee.type === AST_NODE_TYPES42.MemberExpression && current.callee.property.type === AST_NODE_TYPES42.Identifier && factories.has(current.callee.property.name)) {
|
|
8552
8603
|
return true;
|
|
8553
8604
|
}
|
|
8554
|
-
if (current.type === AST_NODE_TYPES42.CallExpression && (current.callee.type === AST_NODE_TYPES42.Identifier &&
|
|
8605
|
+
if (current.type === AST_NODE_TYPES42.CallExpression && (current.callee.type === AST_NODE_TYPES42.Identifier && memoCallees.has(current.callee.name) || current.callee.type === AST_NODE_TYPES42.MemberExpression && !current.callee.computed && current.callee.property.type === AST_NODE_TYPES42.Identifier && memoCallees.has(current.callee.property.name))) {
|
|
8555
8606
|
return true;
|
|
8556
8607
|
}
|
|
8557
8608
|
current = current.parent ?? void 0;
|
|
@@ -8601,6 +8652,9 @@ var prefer_module_level_schema_default = createRule({
|
|
|
8601
8652
|
if (definition.type === "ImportBinding") {
|
|
8602
8653
|
continue;
|
|
8603
8654
|
}
|
|
8655
|
+
if (definition.node.type === AST_NODE_TYPES42.VariableDeclarator && definition.node.parent.type === AST_NODE_TYPES42.VariableDeclaration && definition.node.parent.kind !== "const") {
|
|
8656
|
+
return false;
|
|
8657
|
+
}
|
|
8604
8658
|
const [defStart, defEnd] = definition.node.range;
|
|
8605
8659
|
if (defStart >= schemaStart && defEnd <= schemaEnd) {
|
|
8606
8660
|
continue;
|
|
@@ -8835,7 +8889,7 @@ function sameAccess(node, access) {
|
|
|
8835
8889
|
return node.type === AST_NODE_TYPES44.MemberExpression && !node.computed && node.object.type === AST_NODE_TYPES44.Identifier && node.object.name === access.object && node.property.type === AST_NODE_TYPES44.Identifier && node.property.name === access.property;
|
|
8836
8890
|
}
|
|
8837
8891
|
function isNullGuard(node, access) {
|
|
8838
|
-
if (node.type === AST_NODE_TYPES44.UnaryExpression && node.operator === "!" && sameAccess(node.argument, access)) return true;
|
|
8892
|
+
if (node.type === AST_NODE_TYPES44.UnaryExpression && node.operator === "!" && (sameAccess(node.argument, access) || optionalMemberLengthOf(node.argument, access))) return true;
|
|
8839
8893
|
if (node.type !== AST_NODE_TYPES44.BinaryExpression || !["==", "==="].includes(node.operator)) {
|
|
8840
8894
|
return false;
|
|
8841
8895
|
}
|
|
@@ -8851,7 +8905,11 @@ function isEmptyGuard(node, access) {
|
|
|
8851
8905
|
return memberLengthOf(node.left, access) && zero(node.right) || memberLengthOf(node.right, access) && zero(node.left);
|
|
8852
8906
|
}
|
|
8853
8907
|
function memberLengthOf(node, access) {
|
|
8854
|
-
|
|
8908
|
+
const target = node.type === AST_NODE_TYPES44.ChainExpression ? node.expression : node;
|
|
8909
|
+
return target.type === AST_NODE_TYPES44.MemberExpression && !target.computed && target.property.type === AST_NODE_TYPES44.Identifier && target.property.name === "length" && sameAccess(target.object, access);
|
|
8910
|
+
}
|
|
8911
|
+
function optionalMemberLengthOf(node, access) {
|
|
8912
|
+
return node.type === AST_NODE_TYPES44.ChainExpression && node.expression.type === AST_NODE_TYPES44.MemberExpression && node.expression.optional && memberLengthOf(node, access);
|
|
8855
8913
|
}
|
|
8856
8914
|
function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
|
|
8857
8915
|
if (fn.body.type !== AST_NODE_TYPES44.BlockStatement) return false;
|
|
@@ -8859,6 +8917,7 @@ function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
|
|
|
8859
8917
|
if (first?.type !== AST_NODE_TYPES44.IfStatement) return false;
|
|
8860
8918
|
const terminating = first.consequent.type === AST_NODE_TYPES44.ReturnStatement || first.consequent.type === AST_NODE_TYPES44.ThrowStatement || first.consequent.type === AST_NODE_TYPES44.BlockStatement && first.consequent.body.length === 1 && (first.consequent.body[0]?.type === AST_NODE_TYPES44.ReturnStatement || first.consequent.body[0]?.type === AST_NODE_TYPES44.ThrowStatement);
|
|
8861
8919
|
if (!terminating) return false;
|
|
8920
|
+
if (contains(first.consequent, visitorKeys, (node) => sameAccess(node, access))) return false;
|
|
8862
8921
|
return contains(first.test, visitorKeys, (node) => isNullGuard(node, access)) && contains(first.test, visitorKeys, (node) => isEmptyGuard(node, access));
|
|
8863
8922
|
}
|
|
8864
8923
|
function contains(node, visitorKeys, predicate) {
|
|
@@ -12605,7 +12664,7 @@ var rules = {
|
|
|
12605
12664
|
};
|
|
12606
12665
|
var meta = {
|
|
12607
12666
|
name: "@sarj/eslint-plugin",
|
|
12608
|
-
version: "11.
|
|
12667
|
+
version: "11.2.0"
|
|
12609
12668
|
};
|
|
12610
12669
|
var applicationOnlyRules = [
|
|
12611
12670
|
"no-restricted-library-load",
|