@sarj/eslint-plugin 2.6.0 → 2.7.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 +344 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +350 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2774,13 +2774,292 @@ var no_cors_wildcard_with_credentials_default = import_utils23.ESLintUtils.RuleC
|
|
|
2774
2774
|
}
|
|
2775
2775
|
});
|
|
2776
2776
|
|
|
2777
|
-
// src/rules/no-
|
|
2777
|
+
// src/rules/no-silent-promise-catch.ts
|
|
2778
2778
|
var import_utils24 = require("@typescript-eslint/utils");
|
|
2779
|
+
|
|
2780
|
+
// src/rules/_paths.ts
|
|
2781
|
+
var TEST_FILE_RE = /(\.(test|spec)\.)|([\\/]__tests__[\\/])/;
|
|
2782
|
+
var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
|
|
2783
|
+
function isTestFile(filename) {
|
|
2784
|
+
return TEST_FILE_RE.test(filename);
|
|
2785
|
+
}
|
|
2786
|
+
function isScriptFile(filename) {
|
|
2787
|
+
return SCRIPT_FILE_RE.test(filename);
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
// src/rules/no-silent-promise-catch.ts
|
|
2791
|
+
function isBodyParseCall(node) {
|
|
2792
|
+
return node.type === import_utils24.AST_NODE_TYPES.CallExpression && node.arguments.length === 0 && node.callee.type === import_utils24.AST_NODE_TYPES.MemberExpression && !node.callee.computed && node.callee.property.type === import_utils24.AST_NODE_TYPES.Identifier && (node.callee.property.name === "json" || node.callee.property.name === "text");
|
|
2793
|
+
}
|
|
2794
|
+
function isSilentExpression(node) {
|
|
2795
|
+
switch (node.type) {
|
|
2796
|
+
case import_utils24.AST_NODE_TYPES.Literal:
|
|
2797
|
+
return !("regex" in node);
|
|
2798
|
+
case import_utils24.AST_NODE_TYPES.Identifier:
|
|
2799
|
+
return node.name === "undefined";
|
|
2800
|
+
case import_utils24.AST_NODE_TYPES.UnaryExpression:
|
|
2801
|
+
return node.operator === "void" && node.argument.type === import_utils24.AST_NODE_TYPES.Literal;
|
|
2802
|
+
case import_utils24.AST_NODE_TYPES.ObjectExpression:
|
|
2803
|
+
return node.properties.length === 0;
|
|
2804
|
+
case import_utils24.AST_NODE_TYPES.ArrayExpression:
|
|
2805
|
+
return node.elements.length === 0;
|
|
2806
|
+
case import_utils24.AST_NODE_TYPES.TSAsExpression:
|
|
2807
|
+
return isSilentExpression(node.expression);
|
|
2808
|
+
default:
|
|
2809
|
+
return false;
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
function isSilentHandler(handler) {
|
|
2813
|
+
const body = handler.body;
|
|
2814
|
+
if (body.type !== import_utils24.AST_NODE_TYPES.BlockStatement) {
|
|
2815
|
+
return isSilentExpression(body);
|
|
2816
|
+
}
|
|
2817
|
+
if (body.body.length === 0) {
|
|
2818
|
+
return true;
|
|
2819
|
+
}
|
|
2820
|
+
if (body.body.length === 1) {
|
|
2821
|
+
const only = body.body[0];
|
|
2822
|
+
if (only !== void 0 && only.type === import_utils24.AST_NODE_TYPES.ReturnStatement) {
|
|
2823
|
+
return only.argument === null || isSilentExpression(only.argument);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
return false;
|
|
2827
|
+
}
|
|
2828
|
+
var no_silent_promise_catch_default = import_utils24.ESLintUtils.RuleCreator(
|
|
2829
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2830
|
+
)({
|
|
2831
|
+
name: "no-silent-promise-catch",
|
|
2832
|
+
meta: {
|
|
2833
|
+
type: "problem",
|
|
2834
|
+
docs: {
|
|
2835
|
+
description: "Disallow `.catch()` handlers that silently swallow the rejection (e.g. `.catch(() => null)`); log, rethrow, or handle the error."
|
|
2836
|
+
},
|
|
2837
|
+
schema: [],
|
|
2838
|
+
messages: {
|
|
2839
|
+
silentCatch: "This `.catch()` swallows the rejection without logging, rethrowing, or handling it \u2014 failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate."
|
|
2840
|
+
}
|
|
2841
|
+
},
|
|
2842
|
+
defaultOptions: [],
|
|
2843
|
+
create(context) {
|
|
2844
|
+
if (isTestFile(context.filename)) {
|
|
2845
|
+
return {};
|
|
2846
|
+
}
|
|
2847
|
+
return {
|
|
2848
|
+
CallExpression(node) {
|
|
2849
|
+
if (node.callee.type !== import_utils24.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.property.type !== import_utils24.AST_NODE_TYPES.Identifier || node.callee.property.name !== "catch") {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
if (isBodyParseCall(node.callee.object)) {
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
if (node.arguments.length !== 1) {
|
|
2856
|
+
return;
|
|
2857
|
+
}
|
|
2858
|
+
const handler = node.arguments[0];
|
|
2859
|
+
if (handler === void 0 || handler.type !== import_utils24.AST_NODE_TYPES.ArrowFunctionExpression && handler.type !== import_utils24.AST_NODE_TYPES.FunctionExpression) {
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2862
|
+
if (isSilentHandler(handler)) {
|
|
2863
|
+
context.report({ node, messageId: "silentCatch" });
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
});
|
|
2869
|
+
|
|
2870
|
+
// src/rules/require-fetch-timeout.ts
|
|
2871
|
+
var import_utils25 = require("@typescript-eslint/utils");
|
|
2872
|
+
var GLOBAL_OBJECTS = /* @__PURE__ */ new Set([
|
|
2873
|
+
"globalThis",
|
|
2874
|
+
"window",
|
|
2875
|
+
"self"
|
|
2876
|
+
]);
|
|
2877
|
+
function matchesAnyPattern2(filename, patterns) {
|
|
2878
|
+
for (const pattern of patterns) {
|
|
2879
|
+
const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
|
|
2880
|
+
if (new RegExp(`^${regexSource}$`).test(filename)) {
|
|
2881
|
+
return true;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
return false;
|
|
2885
|
+
}
|
|
2886
|
+
function initProvablyLacksSignal(init) {
|
|
2887
|
+
if (init.type !== import_utils25.AST_NODE_TYPES.ObjectExpression) {
|
|
2888
|
+
return false;
|
|
2889
|
+
}
|
|
2890
|
+
for (const prop of init.properties) {
|
|
2891
|
+
if (prop.type === import_utils25.AST_NODE_TYPES.SpreadElement) {
|
|
2892
|
+
return false;
|
|
2893
|
+
}
|
|
2894
|
+
if (prop.key.type === import_utils25.AST_NODE_TYPES.Identifier && prop.key.name === "signal" || prop.key.type === import_utils25.AST_NODE_TYPES.Literal && prop.key.value === "signal") {
|
|
2895
|
+
return false;
|
|
2896
|
+
}
|
|
2897
|
+
if (prop.computed) {
|
|
2898
|
+
return false;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
return true;
|
|
2902
|
+
}
|
|
2903
|
+
function isStringish(node) {
|
|
2904
|
+
return node.type === import_utils25.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils25.AST_NODE_TYPES.TemplateLiteral;
|
|
2905
|
+
}
|
|
2906
|
+
var require_fetch_timeout_default = import_utils25.ESLintUtils.RuleCreator(
|
|
2907
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2908
|
+
)({
|
|
2909
|
+
name: "require-fetch-timeout",
|
|
2910
|
+
meta: {
|
|
2911
|
+
type: "problem",
|
|
2912
|
+
docs: {
|
|
2913
|
+
description: "Require an abort `signal` (e.g. `AbortSignal.timeout(ms)`) on global `fetch()` calls so stalled upstreams cannot hang the caller forever."
|
|
2914
|
+
},
|
|
2915
|
+
schema: [
|
|
2916
|
+
{
|
|
2917
|
+
type: "object",
|
|
2918
|
+
additionalProperties: false,
|
|
2919
|
+
properties: {
|
|
2920
|
+
allowIn: {
|
|
2921
|
+
description: "Glob patterns for wrapper modules exempt from the rule. Matched against the ABSOLUTE file path, so anchor with a `**/` prefix (e.g. `**/http-client.ts`).",
|
|
2922
|
+
type: "array",
|
|
2923
|
+
items: { type: "string" }
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
],
|
|
2928
|
+
messages: {
|
|
2929
|
+
missingSignal: "This `fetch()` has no abort `signal` \u2014 a stalled upstream will hang it forever. Pass `{ signal: AbortSignal.timeout(ms) }` or a signal from an AbortController."
|
|
2930
|
+
}
|
|
2931
|
+
},
|
|
2932
|
+
defaultOptions: [{}],
|
|
2933
|
+
create(context, [optionsArg]) {
|
|
2934
|
+
if (isTestFile(context.filename) || isScriptFile(context.filename)) {
|
|
2935
|
+
return {};
|
|
2936
|
+
}
|
|
2937
|
+
const allowIn = optionsArg?.allowIn ?? [];
|
|
2938
|
+
if (allowIn.length > 0 && matchesAnyPattern2(context.filename, allowIn)) {
|
|
2939
|
+
return {};
|
|
2940
|
+
}
|
|
2941
|
+
function resolvesToGlobal(identifier) {
|
|
2942
|
+
const scope = context.sourceCode.getScope(identifier);
|
|
2943
|
+
const variable = import_utils25.ASTUtils.findVariable(scope, identifier.name);
|
|
2944
|
+
return variable === null || variable.defs.length === 0;
|
|
2945
|
+
}
|
|
2946
|
+
function isGlobalFetchCall(callee) {
|
|
2947
|
+
if (callee.type === import_utils25.AST_NODE_TYPES.Identifier) {
|
|
2948
|
+
return callee.name === "fetch" && resolvesToGlobal(callee);
|
|
2949
|
+
}
|
|
2950
|
+
return callee.type === import_utils25.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils25.AST_NODE_TYPES.Identifier && callee.property.name === "fetch" && callee.object.type === import_utils25.AST_NODE_TYPES.Identifier && GLOBAL_OBJECTS.has(callee.object.name) && resolvesToGlobal(callee.object);
|
|
2951
|
+
}
|
|
2952
|
+
return {
|
|
2953
|
+
CallExpression(node) {
|
|
2954
|
+
if (!isGlobalFetchCall(node.callee)) {
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
const [first, init] = node.arguments;
|
|
2958
|
+
if (node.arguments.length === 1 && first !== void 0 && !isStringish(first)) {
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
if (init === void 0 || initProvablyLacksSignal(init)) {
|
|
2962
|
+
context.report({ node, messageId: "missingSignal" });
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
});
|
|
2968
|
+
|
|
2969
|
+
// src/rules/require-schema-validate-search.ts
|
|
2970
|
+
var import_utils26 = require("@typescript-eslint/utils");
|
|
2971
|
+
var VALIDATOR_METHODS = /* @__PURE__ */ new Set([
|
|
2972
|
+
"parse",
|
|
2973
|
+
"safeParse",
|
|
2974
|
+
"decode"
|
|
2975
|
+
]);
|
|
2976
|
+
function isConstTypeAnnotation(typeAnnotation) {
|
|
2977
|
+
return typeAnnotation.type === import_utils26.AST_NODE_TYPES.TSTypeReference && typeAnnotation.typeName.type === import_utils26.AST_NODE_TYPES.Identifier && typeAnnotation.typeName.name === "const";
|
|
2978
|
+
}
|
|
2979
|
+
function isValidatorCall(node) {
|
|
2980
|
+
return node.callee.type === import_utils26.AST_NODE_TYPES.MemberExpression && !node.callee.computed && node.callee.property.type === import_utils26.AST_NODE_TYPES.Identifier && VALIDATOR_METHODS.has(node.callee.property.name);
|
|
2981
|
+
}
|
|
2982
|
+
function findCastExpression(node, insideValidatorArg) {
|
|
2983
|
+
if ((node.type === import_utils26.AST_NODE_TYPES.TSAsExpression || node.type === import_utils26.AST_NODE_TYPES.TSTypeAssertion) && !isConstTypeAnnotation(node.typeAnnotation) && !insideValidatorArg) {
|
|
2984
|
+
return node;
|
|
2985
|
+
}
|
|
2986
|
+
if (node.type === import_utils26.AST_NODE_TYPES.CallExpression && isValidatorCall(node)) {
|
|
2987
|
+
const inCallee = findCastExpression(node.callee, insideValidatorArg);
|
|
2988
|
+
if (inCallee !== null) {
|
|
2989
|
+
return inCallee;
|
|
2990
|
+
}
|
|
2991
|
+
for (const arg of node.arguments) {
|
|
2992
|
+
const found = findCastExpression(arg, true);
|
|
2993
|
+
if (found !== null) {
|
|
2994
|
+
return found;
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
return null;
|
|
2998
|
+
}
|
|
2999
|
+
for (const key of Object.keys(node)) {
|
|
3000
|
+
if (key === "parent") {
|
|
3001
|
+
continue;
|
|
3002
|
+
}
|
|
3003
|
+
const value = node[key];
|
|
3004
|
+
const children = Array.isArray(value) ? value : [value];
|
|
3005
|
+
for (const child of children) {
|
|
3006
|
+
if (child !== null && typeof child === "object" && "type" in child && typeof child.type === "string") {
|
|
3007
|
+
const found = findCastExpression(
|
|
3008
|
+
child,
|
|
3009
|
+
insideValidatorArg
|
|
3010
|
+
);
|
|
3011
|
+
if (found !== null) {
|
|
3012
|
+
return found;
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
return null;
|
|
3018
|
+
}
|
|
3019
|
+
var require_schema_validate_search_default = import_utils26.ESLintUtils.RuleCreator(
|
|
3020
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3021
|
+
)({
|
|
3022
|
+
name: "require-schema-validate-search",
|
|
3023
|
+
meta: {
|
|
3024
|
+
type: "problem",
|
|
3025
|
+
docs: {
|
|
3026
|
+
description: "Disallow `as` casts inside hand-rolled `validateSearch` functions; use a schema validator (e.g. zodValidator) so search params are validated at runtime."
|
|
3027
|
+
},
|
|
3028
|
+
schema: [],
|
|
3029
|
+
messages: {
|
|
3030
|
+
castInValidateSearch: "This `validateSearch` asserts the search-param shape with `as` instead of validating it \u2014 malformed query params flow through typed as clean data. Use a schema validator (e.g. `zodValidator(searchSchema)` or `searchSchema.parse`) instead of casting."
|
|
3031
|
+
}
|
|
3032
|
+
},
|
|
3033
|
+
defaultOptions: [],
|
|
3034
|
+
create(context) {
|
|
3035
|
+
if (isTestFile(context.filename)) {
|
|
3036
|
+
return {};
|
|
3037
|
+
}
|
|
3038
|
+
return {
|
|
3039
|
+
Property(node) {
|
|
3040
|
+
const isValidateSearchKey = !node.computed && node.key.type === import_utils26.AST_NODE_TYPES.Identifier && node.key.name === "validateSearch" || node.key.type === import_utils26.AST_NODE_TYPES.Literal && node.key.value === "validateSearch";
|
|
3041
|
+
if (!isValidateSearchKey) {
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
if (node.value.type !== import_utils26.AST_NODE_TYPES.ArrowFunctionExpression && node.value.type !== import_utils26.AST_NODE_TYPES.FunctionExpression) {
|
|
3045
|
+
return;
|
|
3046
|
+
}
|
|
3047
|
+
const cast = findCastExpression(node.value.body, false);
|
|
3048
|
+
if (cast !== null) {
|
|
3049
|
+
context.report({ node: cast, messageId: "castInValidateSearch" });
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
});
|
|
3055
|
+
|
|
3056
|
+
// src/rules/no-fat-try-blocks.ts
|
|
3057
|
+
var import_utils27 = require("@typescript-eslint/utils");
|
|
2779
3058
|
var MAX_TRY_BODY_STATEMENTS = 3;
|
|
2780
3059
|
var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set([
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
3060
|
+
import_utils27.AST_NODE_TYPES.FunctionDeclaration,
|
|
3061
|
+
import_utils27.AST_NODE_TYPES.FunctionExpression,
|
|
3062
|
+
import_utils27.AST_NODE_TYPES.ArrowFunctionExpression
|
|
2784
3063
|
]);
|
|
2785
3064
|
var PURE_METHODS = /* @__PURE__ */ new Set([
|
|
2786
3065
|
"map",
|
|
@@ -2878,20 +3157,20 @@ function isNode4(value) {
|
|
|
2878
3157
|
}
|
|
2879
3158
|
function isPureCall(node) {
|
|
2880
3159
|
const callee = node.callee;
|
|
2881
|
-
if (callee.type !==
|
|
3160
|
+
if (callee.type !== import_utils27.AST_NODE_TYPES.MemberExpression) {
|
|
2882
3161
|
return false;
|
|
2883
3162
|
}
|
|
2884
3163
|
const property = callee.property;
|
|
2885
|
-
if (property.type !==
|
|
3164
|
+
if (property.type !== import_utils27.AST_NODE_TYPES.Identifier) {
|
|
2886
3165
|
return false;
|
|
2887
3166
|
}
|
|
2888
|
-
if (callee.object.type ===
|
|
3167
|
+
if (callee.object.type === import_utils27.AST_NODE_TYPES.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
|
|
2889
3168
|
return true;
|
|
2890
3169
|
}
|
|
2891
3170
|
return PURE_METHODS.has(property.name);
|
|
2892
3171
|
}
|
|
2893
3172
|
function isPureNew(node) {
|
|
2894
|
-
return node.callee.type ===
|
|
3173
|
+
return node.callee.type === import_utils27.AST_NODE_TYPES.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
|
|
2895
3174
|
}
|
|
2896
3175
|
function subtreeMatches(stmt, predicate) {
|
|
2897
3176
|
let found = false;
|
|
@@ -2928,14 +3207,14 @@ function subtreeMatches(stmt, predicate) {
|
|
|
2928
3207
|
visit(stmt);
|
|
2929
3208
|
return found;
|
|
2930
3209
|
}
|
|
2931
|
-
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type ===
|
|
3210
|
+
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type === import_utils27.AST_NODE_TYPES.AwaitExpression);
|
|
2932
3211
|
var hasThrowingCallOrNew = (stmt) => subtreeMatches(
|
|
2933
3212
|
stmt,
|
|
2934
|
-
(n) => n.type ===
|
|
3213
|
+
(n) => n.type === import_utils27.AST_NODE_TYPES.CallExpression && !isPureCall(n) || n.type === import_utils27.AST_NODE_TYPES.NewExpression && !isPureNew(n)
|
|
2935
3214
|
);
|
|
2936
3215
|
function unwrap2(expr) {
|
|
2937
3216
|
let current = expr;
|
|
2938
|
-
while (current.type ===
|
|
3217
|
+
while (current.type === import_utils27.AST_NODE_TYPES.ChainExpression || current.type === import_utils27.AST_NODE_TYPES.TSNonNullExpression) {
|
|
2939
3218
|
current = current.expression;
|
|
2940
3219
|
}
|
|
2941
3220
|
return current;
|
|
@@ -2944,7 +3223,7 @@ function canThrow(stmt) {
|
|
|
2944
3223
|
if (hasAwait(stmt)) {
|
|
2945
3224
|
return true;
|
|
2946
3225
|
}
|
|
2947
|
-
if (stmt.type ===
|
|
3226
|
+
if (stmt.type === import_utils27.AST_NODE_TYPES.ExpressionStatement && unwrap2(stmt.expression).type === import_utils27.AST_NODE_TYPES.CallExpression) {
|
|
2948
3227
|
return false;
|
|
2949
3228
|
}
|
|
2950
3229
|
return hasThrowingCallOrNew(stmt);
|
|
@@ -2955,9 +3234,9 @@ function handlerRethrows(handler) {
|
|
|
2955
3234
|
}
|
|
2956
3235
|
const body = handler.body.body;
|
|
2957
3236
|
const last = body[body.length - 1];
|
|
2958
|
-
return last !== void 0 && last.type ===
|
|
3237
|
+
return last !== void 0 && last.type === import_utils27.AST_NODE_TYPES.ThrowStatement;
|
|
2959
3238
|
}
|
|
2960
|
-
var no_fat_try_blocks_default =
|
|
3239
|
+
var no_fat_try_blocks_default = import_utils27.ESLintUtils.RuleCreator(
|
|
2961
3240
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2962
3241
|
)({
|
|
2963
3242
|
name: "no-fat-try-blocks",
|
|
@@ -2998,7 +3277,7 @@ var no_fat_try_blocks_default = import_utils24.ESLintUtils.RuleCreator(
|
|
|
2998
3277
|
});
|
|
2999
3278
|
|
|
3000
3279
|
// src/rules/no-secret-in-log.ts
|
|
3001
|
-
var
|
|
3280
|
+
var import_utils28 = require("@typescript-eslint/utils");
|
|
3002
3281
|
var LOG_METHODS2 = /* @__PURE__ */ new Set([
|
|
3003
3282
|
"debug",
|
|
3004
3283
|
"info",
|
|
@@ -3196,7 +3475,7 @@ function propertyKeyName2(prop) {
|
|
|
3196
3475
|
}
|
|
3197
3476
|
return null;
|
|
3198
3477
|
}
|
|
3199
|
-
var no_secret_in_log_default =
|
|
3478
|
+
var no_secret_in_log_default = import_utils28.ESLintUtils.RuleCreator(
|
|
3200
3479
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3201
3480
|
)({
|
|
3202
3481
|
name: "no-secret-in-log",
|
|
@@ -3264,15 +3543,15 @@ var no_secret_in_log_default = import_utils25.ESLintUtils.RuleCreator(
|
|
|
3264
3543
|
});
|
|
3265
3544
|
|
|
3266
3545
|
// src/rules/no-unsafe-cast.ts
|
|
3267
|
-
var
|
|
3268
|
-
var
|
|
3546
|
+
var import_utils29 = require("@typescript-eslint/utils");
|
|
3547
|
+
var import_utils30 = require("@typescript-eslint/utils");
|
|
3269
3548
|
function isAnyAnnotation(node) {
|
|
3270
|
-
return node.type ===
|
|
3549
|
+
return node.type === import_utils30.AST_NODE_TYPES.TSAnyKeyword;
|
|
3271
3550
|
}
|
|
3272
3551
|
function isConstAssertion(typeAnnotation) {
|
|
3273
|
-
return typeAnnotation.type ===
|
|
3552
|
+
return typeAnnotation.type === import_utils30.AST_NODE_TYPES.TSTypeReference && typeAnnotation.typeName.type === import_utils30.AST_NODE_TYPES.Identifier && typeAnnotation.typeName.name === "const";
|
|
3274
3553
|
}
|
|
3275
|
-
var no_unsafe_cast_default =
|
|
3554
|
+
var no_unsafe_cast_default = import_utils29.ESLintUtils.RuleCreator(
|
|
3276
3555
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3277
3556
|
)({
|
|
3278
3557
|
name: "no-unsafe-cast",
|
|
@@ -3298,7 +3577,7 @@ var no_unsafe_cast_default = import_utils26.ESLintUtils.RuleCreator(
|
|
|
3298
3577
|
return;
|
|
3299
3578
|
}
|
|
3300
3579
|
const inner = node.expression;
|
|
3301
|
-
if (inner.type ===
|
|
3580
|
+
if (inner.type === import_utils30.AST_NODE_TYPES.TSAsExpression || inner.type === import_utils30.AST_NODE_TYPES.TSTypeAssertion) {
|
|
3302
3581
|
context.report({ node, messageId: "doubleCast" });
|
|
3303
3582
|
}
|
|
3304
3583
|
}
|
|
@@ -3310,7 +3589,7 @@ var no_unsafe_cast_default = import_utils26.ESLintUtils.RuleCreator(
|
|
|
3310
3589
|
});
|
|
3311
3590
|
|
|
3312
3591
|
// src/rules/prefer-string-literal-union.ts
|
|
3313
|
-
var
|
|
3592
|
+
var import_utils31 = require("@typescript-eslint/utils");
|
|
3314
3593
|
var ts = __toESM(require("typescript"), 1);
|
|
3315
3594
|
var CHOICE_TOKENS = /* @__PURE__ */ new Set([
|
|
3316
3595
|
"status",
|
|
@@ -3353,19 +3632,19 @@ function isChoiceLikeName(name) {
|
|
|
3353
3632
|
return CHOICE_TOKENS.has(lastWord(name));
|
|
3354
3633
|
}
|
|
3355
3634
|
function keyName(key) {
|
|
3356
|
-
if (key.type ===
|
|
3635
|
+
if (key.type === import_utils31.AST_NODE_TYPES.Identifier) {
|
|
3357
3636
|
return key.name;
|
|
3358
3637
|
}
|
|
3359
|
-
if (key.type ===
|
|
3638
|
+
if (key.type === import_utils31.AST_NODE_TYPES.Literal && typeof key.value === "string") {
|
|
3360
3639
|
return key.value;
|
|
3361
3640
|
}
|
|
3362
3641
|
return null;
|
|
3363
3642
|
}
|
|
3364
3643
|
function isStringLiteralMember(t) {
|
|
3365
|
-
return t.type ===
|
|
3644
|
+
return t.type === import_utils31.AST_NODE_TYPES.TSLiteralType && t.literal.type === import_utils31.AST_NODE_TYPES.Literal && typeof t.literal.value === "string";
|
|
3366
3645
|
}
|
|
3367
3646
|
function isStringLiteralUnion(node) {
|
|
3368
|
-
if (node?.type !==
|
|
3647
|
+
if (node?.type !== import_utils31.AST_NODE_TYPES.TSUnionType) {
|
|
3369
3648
|
return false;
|
|
3370
3649
|
}
|
|
3371
3650
|
return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
|
|
@@ -3394,12 +3673,12 @@ function bindingSourceExpression(decl) {
|
|
|
3394
3673
|
return ts.isForOfStatement(node) ? node.expression : node.initializer;
|
|
3395
3674
|
}
|
|
3396
3675
|
function refKey(node) {
|
|
3397
|
-
if (node.type ===
|
|
3676
|
+
if (node.type === import_utils31.AST_NODE_TYPES.Identifier) {
|
|
3398
3677
|
return node.name;
|
|
3399
3678
|
}
|
|
3400
|
-
if (node.type ===
|
|
3679
|
+
if (node.type === import_utils31.AST_NODE_TYPES.MemberExpression && !node.computed) {
|
|
3401
3680
|
const inner = refKey(node.object);
|
|
3402
|
-
if (inner === null || node.property.type !==
|
|
3681
|
+
if (inner === null || node.property.type !== import_utils31.AST_NODE_TYPES.Identifier) {
|
|
3403
3682
|
return null;
|
|
3404
3683
|
}
|
|
3405
3684
|
return `${inner}.${node.property.name}`;
|
|
@@ -3407,12 +3686,12 @@ function refKey(node) {
|
|
|
3407
3686
|
return null;
|
|
3408
3687
|
}
|
|
3409
3688
|
function strLiteral(node) {
|
|
3410
|
-
if (node.type ===
|
|
3689
|
+
if (node.type === import_utils31.AST_NODE_TYPES.Literal && typeof node.value === "string") {
|
|
3411
3690
|
return node.value;
|
|
3412
3691
|
}
|
|
3413
3692
|
return null;
|
|
3414
3693
|
}
|
|
3415
|
-
var prefer_string_literal_union_default =
|
|
3694
|
+
var prefer_string_literal_union_default = import_utils31.ESLintUtils.RuleCreator(
|
|
3416
3695
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3417
3696
|
)({
|
|
3418
3697
|
name: "prefer-string-literal-union",
|
|
@@ -3436,7 +3715,7 @@ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator
|
|
|
3436
3715
|
}
|
|
3437
3716
|
let services;
|
|
3438
3717
|
try {
|
|
3439
|
-
services =
|
|
3718
|
+
services = import_utils31.ESLintUtils.getParserServices(context);
|
|
3440
3719
|
} catch {
|
|
3441
3720
|
services = null;
|
|
3442
3721
|
}
|
|
@@ -3520,7 +3799,7 @@ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator
|
|
|
3520
3799
|
containersWithUnion.add(container);
|
|
3521
3800
|
return;
|
|
3522
3801
|
}
|
|
3523
|
-
if (typeNode?.type !==
|
|
3802
|
+
if (typeNode?.type !== import_utils31.AST_NODE_TYPES.TSStringKeyword) {
|
|
3524
3803
|
return;
|
|
3525
3804
|
}
|
|
3526
3805
|
const name = keyName(key);
|
|
@@ -3608,10 +3887,10 @@ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator
|
|
|
3608
3887
|
}
|
|
3609
3888
|
};
|
|
3610
3889
|
function refKeyText(node) {
|
|
3611
|
-
if (node.type ===
|
|
3890
|
+
if (node.type === import_utils31.AST_NODE_TYPES.BinaryExpression) {
|
|
3612
3891
|
return refKey(node.left) ?? refKey(node.right) ?? "value";
|
|
3613
3892
|
}
|
|
3614
|
-
if (node.type ===
|
|
3893
|
+
if (node.type === import_utils31.AST_NODE_TYPES.SwitchStatement) {
|
|
3615
3894
|
return refKey(node.discriminant) ?? "value";
|
|
3616
3895
|
}
|
|
3617
3896
|
return "value";
|
|
@@ -3620,7 +3899,7 @@ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator
|
|
|
3620
3899
|
});
|
|
3621
3900
|
|
|
3622
3901
|
// src/rules/single-public-export.ts
|
|
3623
|
-
var
|
|
3902
|
+
var import_utils32 = require("@typescript-eslint/utils");
|
|
3624
3903
|
var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
|
|
3625
3904
|
"util",
|
|
3626
3905
|
"utils",
|
|
@@ -3643,7 +3922,7 @@ var ACRONYM_OVERRIDES = [
|
|
|
3643
3922
|
[/gRPC/g, "Grpc"]
|
|
3644
3923
|
];
|
|
3645
3924
|
var CAMEL_BOUNDARY_RE = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g;
|
|
3646
|
-
var
|
|
3925
|
+
var TEST_FILE_RE2 = /\.(test|spec)\.[cm]?[jt]sx?$/i;
|
|
3647
3926
|
var SCRIPT_EXT_RE = /\.[cm]?[jt]sx?$/i;
|
|
3648
3927
|
var basename = (filename) => filename.split(/[/\\]/).pop() ?? filename;
|
|
3649
3928
|
var stemOf = (base) => base.replace(SCRIPT_EXT_RE, "");
|
|
@@ -3654,12 +3933,12 @@ var kebabCase2 = (name) => {
|
|
|
3654
3933
|
}
|
|
3655
3934
|
return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
|
|
3656
3935
|
};
|
|
3657
|
-
var isFunctionExpression = (node) => node !== null && (node.type ===
|
|
3936
|
+
var isFunctionExpression = (node) => node !== null && (node.type === import_utils32.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils32.AST_NODE_TYPES.FunctionExpression);
|
|
3658
3937
|
var functionConstName = (decl) => {
|
|
3659
3938
|
if (decl.declarations.length !== 1) return null;
|
|
3660
3939
|
const [declarator] = decl.declarations;
|
|
3661
3940
|
if (declarator === void 0) return null;
|
|
3662
|
-
if (declarator.id.type !==
|
|
3941
|
+
if (declarator.id.type !== import_utils32.AST_NODE_TYPES.Identifier) return null;
|
|
3663
3942
|
if (!isFunctionExpression(declarator.init)) return null;
|
|
3664
3943
|
return declarator.id.name;
|
|
3665
3944
|
};
|
|
@@ -3673,20 +3952,20 @@ var summarizeExports = (body) => {
|
|
|
3673
3952
|
};
|
|
3674
3953
|
for (const statement of body) {
|
|
3675
3954
|
switch (statement.type) {
|
|
3676
|
-
case
|
|
3955
|
+
case import_utils32.AST_NODE_TYPES.ExportAllDeclaration:
|
|
3677
3956
|
hasReExport = true;
|
|
3678
3957
|
break;
|
|
3679
|
-
case
|
|
3958
|
+
case import_utils32.AST_NODE_TYPES.ExportDefaultDeclaration: {
|
|
3680
3959
|
names += 1;
|
|
3681
3960
|
const decl = statement.declaration;
|
|
3682
|
-
if (decl.type ===
|
|
3961
|
+
if (decl.type === import_utils32.AST_NODE_TYPES.FunctionDeclaration && decl.id !== null) {
|
|
3683
3962
|
candidate = { name: decl.id.name, node: statement };
|
|
3684
|
-
} else if (decl.type ===
|
|
3963
|
+
} else if (decl.type === import_utils32.AST_NODE_TYPES.ClassDeclaration && decl.id !== null) {
|
|
3685
3964
|
candidate = { name: decl.id.name, node: statement };
|
|
3686
3965
|
}
|
|
3687
3966
|
break;
|
|
3688
3967
|
}
|
|
3689
|
-
case
|
|
3968
|
+
case import_utils32.AST_NODE_TYPES.ExportNamedDeclaration: {
|
|
3690
3969
|
if (statement.source !== null) {
|
|
3691
3970
|
hasReExport = true;
|
|
3692
3971
|
break;
|
|
@@ -3697,15 +3976,15 @@ var summarizeExports = (body) => {
|
|
|
3697
3976
|
break;
|
|
3698
3977
|
}
|
|
3699
3978
|
switch (decl.type) {
|
|
3700
|
-
case
|
|
3979
|
+
case import_utils32.AST_NODE_TYPES.FunctionDeclaration:
|
|
3701
3980
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3702
3981
|
else names += 1;
|
|
3703
3982
|
break;
|
|
3704
|
-
case
|
|
3983
|
+
case import_utils32.AST_NODE_TYPES.ClassDeclaration:
|
|
3705
3984
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3706
3985
|
else names += 1;
|
|
3707
3986
|
break;
|
|
3708
|
-
case
|
|
3987
|
+
case import_utils32.AST_NODE_TYPES.VariableDeclaration: {
|
|
3709
3988
|
const fnName = functionConstName(decl);
|
|
3710
3989
|
if (fnName !== null && decl.declarations.length === 1) {
|
|
3711
3990
|
addCandidate(fnName, statement);
|
|
@@ -3725,7 +4004,7 @@ var summarizeExports = (body) => {
|
|
|
3725
4004
|
}
|
|
3726
4005
|
return { names, hasReExport, candidate };
|
|
3727
4006
|
};
|
|
3728
|
-
var single_public_export_default =
|
|
4007
|
+
var single_public_export_default = import_utils32.ESLintUtils.RuleCreator(
|
|
3729
4008
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3730
4009
|
)({
|
|
3731
4010
|
name: "single-public-export",
|
|
@@ -3743,7 +4022,7 @@ var single_public_export_default = import_utils29.ESLintUtils.RuleCreator(
|
|
|
3743
4022
|
create(context) {
|
|
3744
4023
|
const base = basename(context.filename);
|
|
3745
4024
|
if (base.endsWith(".d.ts")) return {};
|
|
3746
|
-
if (
|
|
4025
|
+
if (TEST_FILE_RE2.test(base)) return {};
|
|
3747
4026
|
const stem = stemOf(base);
|
|
3748
4027
|
if (!JUNK_DRAWER_STEMS.has(stem.toLowerCase())) return {};
|
|
3749
4028
|
return {
|
|
@@ -3791,12 +4070,15 @@ var rules = {
|
|
|
3791
4070
|
"no-secret-in-log": no_secret_in_log_default,
|
|
3792
4071
|
"no-unsafe-cast": no_unsafe_cast_default,
|
|
3793
4072
|
"prefer-string-literal-union": prefer_string_literal_union_default,
|
|
3794
|
-
"single-public-export": single_public_export_default
|
|
4073
|
+
"single-public-export": single_public_export_default,
|
|
4074
|
+
"no-silent-promise-catch": no_silent_promise_catch_default,
|
|
4075
|
+
"require-fetch-timeout": require_fetch_timeout_default,
|
|
4076
|
+
"require-schema-validate-search": require_schema_validate_search_default
|
|
3795
4077
|
};
|
|
3796
4078
|
var plugin = {
|
|
3797
4079
|
meta: {
|
|
3798
4080
|
name: "@sarj/eslint-plugin",
|
|
3799
|
-
version: "2.
|
|
4081
|
+
version: "2.7.0"
|
|
3800
4082
|
},
|
|
3801
4083
|
rules,
|
|
3802
4084
|
configs: {
|
|
@@ -3828,7 +4110,11 @@ var plugin = {
|
|
|
3828
4110
|
"@sarj/no-secret-in-log": "warn",
|
|
3829
4111
|
"@sarj/no-unsafe-cast": "warn",
|
|
3830
4112
|
"@sarj/single-public-export": "warn",
|
|
3831
|
-
"@sarj/prefer-string-literal-union": "warn"
|
|
4113
|
+
"@sarj/prefer-string-literal-union": "warn",
|
|
4114
|
+
// Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
|
|
4115
|
+
"@sarj/require-fetch-timeout": "warn",
|
|
4116
|
+
"@sarj/no-silent-promise-catch": "warn",
|
|
4117
|
+
"@sarj/require-schema-validate-search": "warn"
|
|
3832
4118
|
}
|
|
3833
4119
|
},
|
|
3834
4120
|
strict: {
|
|
@@ -3864,7 +4150,11 @@ var plugin = {
|
|
|
3864
4150
|
"@sarj/no-unsafe-cast": "warn",
|
|
3865
4151
|
"@sarj/single-public-export": "error",
|
|
3866
4152
|
// High-volume/stylistic — warn until rollout proves FP rate.
|
|
3867
|
-
"@sarj/prefer-string-literal-union": "warn"
|
|
4153
|
+
"@sarj/prefer-string-literal-union": "warn",
|
|
4154
|
+
// Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
|
|
4155
|
+
"@sarj/require-fetch-timeout": "error",
|
|
4156
|
+
"@sarj/no-silent-promise-catch": "error",
|
|
4157
|
+
"@sarj/require-schema-validate-search": "error"
|
|
3868
4158
|
}
|
|
3869
4159
|
}
|
|
3870
4160
|
}
|