@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.js
CHANGED
|
@@ -2755,16 +2755,299 @@ var no_cors_wildcard_with_credentials_default = ESLintUtils21.RuleCreator(
|
|
|
2755
2755
|
}
|
|
2756
2756
|
});
|
|
2757
2757
|
|
|
2758
|
+
// src/rules/no-silent-promise-catch.ts
|
|
2759
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES12, ESLintUtils as ESLintUtils22 } from "@typescript-eslint/utils";
|
|
2760
|
+
|
|
2761
|
+
// src/rules/_paths.ts
|
|
2762
|
+
var TEST_FILE_RE = /(\.(test|spec)\.)|([\\/]__tests__[\\/])/;
|
|
2763
|
+
var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
|
|
2764
|
+
function isTestFile(filename) {
|
|
2765
|
+
return TEST_FILE_RE.test(filename);
|
|
2766
|
+
}
|
|
2767
|
+
function isScriptFile(filename) {
|
|
2768
|
+
return SCRIPT_FILE_RE.test(filename);
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
// src/rules/no-silent-promise-catch.ts
|
|
2772
|
+
function isBodyParseCall(node) {
|
|
2773
|
+
return node.type === AST_NODE_TYPES12.CallExpression && node.arguments.length === 0 && node.callee.type === AST_NODE_TYPES12.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES12.Identifier && (node.callee.property.name === "json" || node.callee.property.name === "text");
|
|
2774
|
+
}
|
|
2775
|
+
function isSilentExpression(node) {
|
|
2776
|
+
switch (node.type) {
|
|
2777
|
+
case AST_NODE_TYPES12.Literal:
|
|
2778
|
+
return !("regex" in node);
|
|
2779
|
+
case AST_NODE_TYPES12.Identifier:
|
|
2780
|
+
return node.name === "undefined";
|
|
2781
|
+
case AST_NODE_TYPES12.UnaryExpression:
|
|
2782
|
+
return node.operator === "void" && node.argument.type === AST_NODE_TYPES12.Literal;
|
|
2783
|
+
case AST_NODE_TYPES12.ObjectExpression:
|
|
2784
|
+
return node.properties.length === 0;
|
|
2785
|
+
case AST_NODE_TYPES12.ArrayExpression:
|
|
2786
|
+
return node.elements.length === 0;
|
|
2787
|
+
case AST_NODE_TYPES12.TSAsExpression:
|
|
2788
|
+
return isSilentExpression(node.expression);
|
|
2789
|
+
default:
|
|
2790
|
+
return false;
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
function isSilentHandler(handler) {
|
|
2794
|
+
const body = handler.body;
|
|
2795
|
+
if (body.type !== AST_NODE_TYPES12.BlockStatement) {
|
|
2796
|
+
return isSilentExpression(body);
|
|
2797
|
+
}
|
|
2798
|
+
if (body.body.length === 0) {
|
|
2799
|
+
return true;
|
|
2800
|
+
}
|
|
2801
|
+
if (body.body.length === 1) {
|
|
2802
|
+
const only = body.body[0];
|
|
2803
|
+
if (only !== void 0 && only.type === AST_NODE_TYPES12.ReturnStatement) {
|
|
2804
|
+
return only.argument === null || isSilentExpression(only.argument);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
return false;
|
|
2808
|
+
}
|
|
2809
|
+
var no_silent_promise_catch_default = ESLintUtils22.RuleCreator(
|
|
2810
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2811
|
+
)({
|
|
2812
|
+
name: "no-silent-promise-catch",
|
|
2813
|
+
meta: {
|
|
2814
|
+
type: "problem",
|
|
2815
|
+
docs: {
|
|
2816
|
+
description: "Disallow `.catch()` handlers that silently swallow the rejection (e.g. `.catch(() => null)`); log, rethrow, or handle the error."
|
|
2817
|
+
},
|
|
2818
|
+
schema: [],
|
|
2819
|
+
messages: {
|
|
2820
|
+
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."
|
|
2821
|
+
}
|
|
2822
|
+
},
|
|
2823
|
+
defaultOptions: [],
|
|
2824
|
+
create(context) {
|
|
2825
|
+
if (isTestFile(context.filename)) {
|
|
2826
|
+
return {};
|
|
2827
|
+
}
|
|
2828
|
+
return {
|
|
2829
|
+
CallExpression(node) {
|
|
2830
|
+
if (node.callee.type !== AST_NODE_TYPES12.MemberExpression || node.callee.computed || node.callee.property.type !== AST_NODE_TYPES12.Identifier || node.callee.property.name !== "catch") {
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
if (isBodyParseCall(node.callee.object)) {
|
|
2834
|
+
return;
|
|
2835
|
+
}
|
|
2836
|
+
if (node.arguments.length !== 1) {
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
const handler = node.arguments[0];
|
|
2840
|
+
if (handler === void 0 || handler.type !== AST_NODE_TYPES12.ArrowFunctionExpression && handler.type !== AST_NODE_TYPES12.FunctionExpression) {
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
if (isSilentHandler(handler)) {
|
|
2844
|
+
context.report({ node, messageId: "silentCatch" });
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
});
|
|
2850
|
+
|
|
2851
|
+
// src/rules/require-fetch-timeout.ts
|
|
2852
|
+
import {
|
|
2853
|
+
AST_NODE_TYPES as AST_NODE_TYPES13,
|
|
2854
|
+
ASTUtils,
|
|
2855
|
+
ESLintUtils as ESLintUtils23
|
|
2856
|
+
} from "@typescript-eslint/utils";
|
|
2857
|
+
var GLOBAL_OBJECTS = /* @__PURE__ */ new Set([
|
|
2858
|
+
"globalThis",
|
|
2859
|
+
"window",
|
|
2860
|
+
"self"
|
|
2861
|
+
]);
|
|
2862
|
+
function matchesAnyPattern2(filename, patterns) {
|
|
2863
|
+
for (const pattern of patterns) {
|
|
2864
|
+
const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
|
|
2865
|
+
if (new RegExp(`^${regexSource}$`).test(filename)) {
|
|
2866
|
+
return true;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
return false;
|
|
2870
|
+
}
|
|
2871
|
+
function initProvablyLacksSignal(init) {
|
|
2872
|
+
if (init.type !== AST_NODE_TYPES13.ObjectExpression) {
|
|
2873
|
+
return false;
|
|
2874
|
+
}
|
|
2875
|
+
for (const prop of init.properties) {
|
|
2876
|
+
if (prop.type === AST_NODE_TYPES13.SpreadElement) {
|
|
2877
|
+
return false;
|
|
2878
|
+
}
|
|
2879
|
+
if (prop.key.type === AST_NODE_TYPES13.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES13.Literal && prop.key.value === "signal") {
|
|
2880
|
+
return false;
|
|
2881
|
+
}
|
|
2882
|
+
if (prop.computed) {
|
|
2883
|
+
return false;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return true;
|
|
2887
|
+
}
|
|
2888
|
+
function isStringish(node) {
|
|
2889
|
+
return node.type === AST_NODE_TYPES13.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES13.TemplateLiteral;
|
|
2890
|
+
}
|
|
2891
|
+
var require_fetch_timeout_default = ESLintUtils23.RuleCreator(
|
|
2892
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2893
|
+
)({
|
|
2894
|
+
name: "require-fetch-timeout",
|
|
2895
|
+
meta: {
|
|
2896
|
+
type: "problem",
|
|
2897
|
+
docs: {
|
|
2898
|
+
description: "Require an abort `signal` (e.g. `AbortSignal.timeout(ms)`) on global `fetch()` calls so stalled upstreams cannot hang the caller forever."
|
|
2899
|
+
},
|
|
2900
|
+
schema: [
|
|
2901
|
+
{
|
|
2902
|
+
type: "object",
|
|
2903
|
+
additionalProperties: false,
|
|
2904
|
+
properties: {
|
|
2905
|
+
allowIn: {
|
|
2906
|
+
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`).",
|
|
2907
|
+
type: "array",
|
|
2908
|
+
items: { type: "string" }
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
],
|
|
2913
|
+
messages: {
|
|
2914
|
+
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."
|
|
2915
|
+
}
|
|
2916
|
+
},
|
|
2917
|
+
defaultOptions: [{}],
|
|
2918
|
+
create(context, [optionsArg]) {
|
|
2919
|
+
if (isTestFile(context.filename) || isScriptFile(context.filename)) {
|
|
2920
|
+
return {};
|
|
2921
|
+
}
|
|
2922
|
+
const allowIn = optionsArg?.allowIn ?? [];
|
|
2923
|
+
if (allowIn.length > 0 && matchesAnyPattern2(context.filename, allowIn)) {
|
|
2924
|
+
return {};
|
|
2925
|
+
}
|
|
2926
|
+
function resolvesToGlobal(identifier) {
|
|
2927
|
+
const scope = context.sourceCode.getScope(identifier);
|
|
2928
|
+
const variable = ASTUtils.findVariable(scope, identifier.name);
|
|
2929
|
+
return variable === null || variable.defs.length === 0;
|
|
2930
|
+
}
|
|
2931
|
+
function isGlobalFetchCall(callee) {
|
|
2932
|
+
if (callee.type === AST_NODE_TYPES13.Identifier) {
|
|
2933
|
+
return callee.name === "fetch" && resolvesToGlobal(callee);
|
|
2934
|
+
}
|
|
2935
|
+
return callee.type === AST_NODE_TYPES13.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES13.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES13.Identifier && GLOBAL_OBJECTS.has(callee.object.name) && resolvesToGlobal(callee.object);
|
|
2936
|
+
}
|
|
2937
|
+
return {
|
|
2938
|
+
CallExpression(node) {
|
|
2939
|
+
if (!isGlobalFetchCall(node.callee)) {
|
|
2940
|
+
return;
|
|
2941
|
+
}
|
|
2942
|
+
const [first, init] = node.arguments;
|
|
2943
|
+
if (node.arguments.length === 1 && first !== void 0 && !isStringish(first)) {
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
if (init === void 0 || initProvablyLacksSignal(init)) {
|
|
2947
|
+
context.report({ node, messageId: "missingSignal" });
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
|
|
2954
|
+
// src/rules/require-schema-validate-search.ts
|
|
2955
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
|
|
2956
|
+
var VALIDATOR_METHODS = /* @__PURE__ */ new Set([
|
|
2957
|
+
"parse",
|
|
2958
|
+
"safeParse",
|
|
2959
|
+
"decode"
|
|
2960
|
+
]);
|
|
2961
|
+
function isConstTypeAnnotation(typeAnnotation) {
|
|
2962
|
+
return typeAnnotation.type === AST_NODE_TYPES14.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES14.Identifier && typeAnnotation.typeName.name === "const";
|
|
2963
|
+
}
|
|
2964
|
+
function isValidatorCall(node) {
|
|
2965
|
+
return node.callee.type === AST_NODE_TYPES14.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES14.Identifier && VALIDATOR_METHODS.has(node.callee.property.name);
|
|
2966
|
+
}
|
|
2967
|
+
function findCastExpression(node, insideValidatorArg) {
|
|
2968
|
+
if ((node.type === AST_NODE_TYPES14.TSAsExpression || node.type === AST_NODE_TYPES14.TSTypeAssertion) && !isConstTypeAnnotation(node.typeAnnotation) && !insideValidatorArg) {
|
|
2969
|
+
return node;
|
|
2970
|
+
}
|
|
2971
|
+
if (node.type === AST_NODE_TYPES14.CallExpression && isValidatorCall(node)) {
|
|
2972
|
+
const inCallee = findCastExpression(node.callee, insideValidatorArg);
|
|
2973
|
+
if (inCallee !== null) {
|
|
2974
|
+
return inCallee;
|
|
2975
|
+
}
|
|
2976
|
+
for (const arg of node.arguments) {
|
|
2977
|
+
const found = findCastExpression(arg, true);
|
|
2978
|
+
if (found !== null) {
|
|
2979
|
+
return found;
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
return null;
|
|
2983
|
+
}
|
|
2984
|
+
for (const key of Object.keys(node)) {
|
|
2985
|
+
if (key === "parent") {
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const value = node[key];
|
|
2989
|
+
const children = Array.isArray(value) ? value : [value];
|
|
2990
|
+
for (const child of children) {
|
|
2991
|
+
if (child !== null && typeof child === "object" && "type" in child && typeof child.type === "string") {
|
|
2992
|
+
const found = findCastExpression(
|
|
2993
|
+
child,
|
|
2994
|
+
insideValidatorArg
|
|
2995
|
+
);
|
|
2996
|
+
if (found !== null) {
|
|
2997
|
+
return found;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
return null;
|
|
3003
|
+
}
|
|
3004
|
+
var require_schema_validate_search_default = ESLintUtils24.RuleCreator(
|
|
3005
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3006
|
+
)({
|
|
3007
|
+
name: "require-schema-validate-search",
|
|
3008
|
+
meta: {
|
|
3009
|
+
type: "problem",
|
|
3010
|
+
docs: {
|
|
3011
|
+
description: "Disallow `as` casts inside hand-rolled `validateSearch` functions; use a schema validator (e.g. zodValidator) so search params are validated at runtime."
|
|
3012
|
+
},
|
|
3013
|
+
schema: [],
|
|
3014
|
+
messages: {
|
|
3015
|
+
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."
|
|
3016
|
+
}
|
|
3017
|
+
},
|
|
3018
|
+
defaultOptions: [],
|
|
3019
|
+
create(context) {
|
|
3020
|
+
if (isTestFile(context.filename)) {
|
|
3021
|
+
return {};
|
|
3022
|
+
}
|
|
3023
|
+
return {
|
|
3024
|
+
Property(node) {
|
|
3025
|
+
const isValidateSearchKey = !node.computed && node.key.type === AST_NODE_TYPES14.Identifier && node.key.name === "validateSearch" || node.key.type === AST_NODE_TYPES14.Literal && node.key.value === "validateSearch";
|
|
3026
|
+
if (!isValidateSearchKey) {
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
if (node.value.type !== AST_NODE_TYPES14.ArrowFunctionExpression && node.value.type !== AST_NODE_TYPES14.FunctionExpression) {
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
const cast = findCastExpression(node.value.body, false);
|
|
3033
|
+
if (cast !== null) {
|
|
3034
|
+
context.report({ node: cast, messageId: "castInValidateSearch" });
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
});
|
|
3040
|
+
|
|
2758
3041
|
// src/rules/no-fat-try-blocks.ts
|
|
2759
3042
|
import {
|
|
2760
|
-
ESLintUtils as
|
|
2761
|
-
AST_NODE_TYPES as
|
|
3043
|
+
ESLintUtils as ESLintUtils25,
|
|
3044
|
+
AST_NODE_TYPES as AST_NODE_TYPES15
|
|
2762
3045
|
} from "@typescript-eslint/utils";
|
|
2763
3046
|
var MAX_TRY_BODY_STATEMENTS = 3;
|
|
2764
3047
|
var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set([
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
3048
|
+
AST_NODE_TYPES15.FunctionDeclaration,
|
|
3049
|
+
AST_NODE_TYPES15.FunctionExpression,
|
|
3050
|
+
AST_NODE_TYPES15.ArrowFunctionExpression
|
|
2768
3051
|
]);
|
|
2769
3052
|
var PURE_METHODS = /* @__PURE__ */ new Set([
|
|
2770
3053
|
"map",
|
|
@@ -2862,20 +3145,20 @@ function isNode4(value) {
|
|
|
2862
3145
|
}
|
|
2863
3146
|
function isPureCall(node) {
|
|
2864
3147
|
const callee = node.callee;
|
|
2865
|
-
if (callee.type !==
|
|
3148
|
+
if (callee.type !== AST_NODE_TYPES15.MemberExpression) {
|
|
2866
3149
|
return false;
|
|
2867
3150
|
}
|
|
2868
3151
|
const property = callee.property;
|
|
2869
|
-
if (property.type !==
|
|
3152
|
+
if (property.type !== AST_NODE_TYPES15.Identifier) {
|
|
2870
3153
|
return false;
|
|
2871
3154
|
}
|
|
2872
|
-
if (callee.object.type ===
|
|
3155
|
+
if (callee.object.type === AST_NODE_TYPES15.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
|
|
2873
3156
|
return true;
|
|
2874
3157
|
}
|
|
2875
3158
|
return PURE_METHODS.has(property.name);
|
|
2876
3159
|
}
|
|
2877
3160
|
function isPureNew(node) {
|
|
2878
|
-
return node.callee.type ===
|
|
3161
|
+
return node.callee.type === AST_NODE_TYPES15.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
|
|
2879
3162
|
}
|
|
2880
3163
|
function subtreeMatches(stmt, predicate) {
|
|
2881
3164
|
let found = false;
|
|
@@ -2912,14 +3195,14 @@ function subtreeMatches(stmt, predicate) {
|
|
|
2912
3195
|
visit(stmt);
|
|
2913
3196
|
return found;
|
|
2914
3197
|
}
|
|
2915
|
-
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type ===
|
|
3198
|
+
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type === AST_NODE_TYPES15.AwaitExpression);
|
|
2916
3199
|
var hasThrowingCallOrNew = (stmt) => subtreeMatches(
|
|
2917
3200
|
stmt,
|
|
2918
|
-
(n) => n.type ===
|
|
3201
|
+
(n) => n.type === AST_NODE_TYPES15.CallExpression && !isPureCall(n) || n.type === AST_NODE_TYPES15.NewExpression && !isPureNew(n)
|
|
2919
3202
|
);
|
|
2920
3203
|
function unwrap2(expr) {
|
|
2921
3204
|
let current = expr;
|
|
2922
|
-
while (current.type ===
|
|
3205
|
+
while (current.type === AST_NODE_TYPES15.ChainExpression || current.type === AST_NODE_TYPES15.TSNonNullExpression) {
|
|
2923
3206
|
current = current.expression;
|
|
2924
3207
|
}
|
|
2925
3208
|
return current;
|
|
@@ -2928,7 +3211,7 @@ function canThrow(stmt) {
|
|
|
2928
3211
|
if (hasAwait(stmt)) {
|
|
2929
3212
|
return true;
|
|
2930
3213
|
}
|
|
2931
|
-
if (stmt.type ===
|
|
3214
|
+
if (stmt.type === AST_NODE_TYPES15.ExpressionStatement && unwrap2(stmt.expression).type === AST_NODE_TYPES15.CallExpression) {
|
|
2932
3215
|
return false;
|
|
2933
3216
|
}
|
|
2934
3217
|
return hasThrowingCallOrNew(stmt);
|
|
@@ -2939,9 +3222,9 @@ function handlerRethrows(handler) {
|
|
|
2939
3222
|
}
|
|
2940
3223
|
const body = handler.body.body;
|
|
2941
3224
|
const last = body[body.length - 1];
|
|
2942
|
-
return last !== void 0 && last.type ===
|
|
3225
|
+
return last !== void 0 && last.type === AST_NODE_TYPES15.ThrowStatement;
|
|
2943
3226
|
}
|
|
2944
|
-
var no_fat_try_blocks_default =
|
|
3227
|
+
var no_fat_try_blocks_default = ESLintUtils25.RuleCreator(
|
|
2945
3228
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2946
3229
|
)({
|
|
2947
3230
|
name: "no-fat-try-blocks",
|
|
@@ -2982,7 +3265,7 @@ var no_fat_try_blocks_default = ESLintUtils22.RuleCreator(
|
|
|
2982
3265
|
});
|
|
2983
3266
|
|
|
2984
3267
|
// src/rules/no-secret-in-log.ts
|
|
2985
|
-
import { ESLintUtils as
|
|
3268
|
+
import { ESLintUtils as ESLintUtils26 } from "@typescript-eslint/utils";
|
|
2986
3269
|
var LOG_METHODS2 = /* @__PURE__ */ new Set([
|
|
2987
3270
|
"debug",
|
|
2988
3271
|
"info",
|
|
@@ -3180,7 +3463,7 @@ function propertyKeyName2(prop) {
|
|
|
3180
3463
|
}
|
|
3181
3464
|
return null;
|
|
3182
3465
|
}
|
|
3183
|
-
var no_secret_in_log_default =
|
|
3466
|
+
var no_secret_in_log_default = ESLintUtils26.RuleCreator(
|
|
3184
3467
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3185
3468
|
)({
|
|
3186
3469
|
name: "no-secret-in-log",
|
|
@@ -3248,15 +3531,15 @@ var no_secret_in_log_default = ESLintUtils23.RuleCreator(
|
|
|
3248
3531
|
});
|
|
3249
3532
|
|
|
3250
3533
|
// src/rules/no-unsafe-cast.ts
|
|
3251
|
-
import { ESLintUtils as
|
|
3252
|
-
import { AST_NODE_TYPES as
|
|
3534
|
+
import { ESLintUtils as ESLintUtils27 } from "@typescript-eslint/utils";
|
|
3535
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES16 } from "@typescript-eslint/utils";
|
|
3253
3536
|
function isAnyAnnotation(node) {
|
|
3254
|
-
return node.type ===
|
|
3537
|
+
return node.type === AST_NODE_TYPES16.TSAnyKeyword;
|
|
3255
3538
|
}
|
|
3256
3539
|
function isConstAssertion(typeAnnotation) {
|
|
3257
|
-
return typeAnnotation.type ===
|
|
3540
|
+
return typeAnnotation.type === AST_NODE_TYPES16.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES16.Identifier && typeAnnotation.typeName.name === "const";
|
|
3258
3541
|
}
|
|
3259
|
-
var no_unsafe_cast_default =
|
|
3542
|
+
var no_unsafe_cast_default = ESLintUtils27.RuleCreator(
|
|
3260
3543
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3261
3544
|
)({
|
|
3262
3545
|
name: "no-unsafe-cast",
|
|
@@ -3282,7 +3565,7 @@ var no_unsafe_cast_default = ESLintUtils24.RuleCreator(
|
|
|
3282
3565
|
return;
|
|
3283
3566
|
}
|
|
3284
3567
|
const inner = node.expression;
|
|
3285
|
-
if (inner.type ===
|
|
3568
|
+
if (inner.type === AST_NODE_TYPES16.TSAsExpression || inner.type === AST_NODE_TYPES16.TSTypeAssertion) {
|
|
3286
3569
|
context.report({ node, messageId: "doubleCast" });
|
|
3287
3570
|
}
|
|
3288
3571
|
}
|
|
@@ -3295,8 +3578,8 @@ var no_unsafe_cast_default = ESLintUtils24.RuleCreator(
|
|
|
3295
3578
|
|
|
3296
3579
|
// src/rules/prefer-string-literal-union.ts
|
|
3297
3580
|
import {
|
|
3298
|
-
ESLintUtils as
|
|
3299
|
-
AST_NODE_TYPES as
|
|
3581
|
+
ESLintUtils as ESLintUtils28,
|
|
3582
|
+
AST_NODE_TYPES as AST_NODE_TYPES17
|
|
3300
3583
|
} from "@typescript-eslint/utils";
|
|
3301
3584
|
import * as ts from "typescript";
|
|
3302
3585
|
var CHOICE_TOKENS = /* @__PURE__ */ new Set([
|
|
@@ -3340,19 +3623,19 @@ function isChoiceLikeName(name) {
|
|
|
3340
3623
|
return CHOICE_TOKENS.has(lastWord(name));
|
|
3341
3624
|
}
|
|
3342
3625
|
function keyName(key) {
|
|
3343
|
-
if (key.type ===
|
|
3626
|
+
if (key.type === AST_NODE_TYPES17.Identifier) {
|
|
3344
3627
|
return key.name;
|
|
3345
3628
|
}
|
|
3346
|
-
if (key.type ===
|
|
3629
|
+
if (key.type === AST_NODE_TYPES17.Literal && typeof key.value === "string") {
|
|
3347
3630
|
return key.value;
|
|
3348
3631
|
}
|
|
3349
3632
|
return null;
|
|
3350
3633
|
}
|
|
3351
3634
|
function isStringLiteralMember(t) {
|
|
3352
|
-
return t.type ===
|
|
3635
|
+
return t.type === AST_NODE_TYPES17.TSLiteralType && t.literal.type === AST_NODE_TYPES17.Literal && typeof t.literal.value === "string";
|
|
3353
3636
|
}
|
|
3354
3637
|
function isStringLiteralUnion(node) {
|
|
3355
|
-
if (node?.type !==
|
|
3638
|
+
if (node?.type !== AST_NODE_TYPES17.TSUnionType) {
|
|
3356
3639
|
return false;
|
|
3357
3640
|
}
|
|
3358
3641
|
return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
|
|
@@ -3381,12 +3664,12 @@ function bindingSourceExpression(decl) {
|
|
|
3381
3664
|
return ts.isForOfStatement(node) ? node.expression : node.initializer;
|
|
3382
3665
|
}
|
|
3383
3666
|
function refKey(node) {
|
|
3384
|
-
if (node.type ===
|
|
3667
|
+
if (node.type === AST_NODE_TYPES17.Identifier) {
|
|
3385
3668
|
return node.name;
|
|
3386
3669
|
}
|
|
3387
|
-
if (node.type ===
|
|
3670
|
+
if (node.type === AST_NODE_TYPES17.MemberExpression && !node.computed) {
|
|
3388
3671
|
const inner = refKey(node.object);
|
|
3389
|
-
if (inner === null || node.property.type !==
|
|
3672
|
+
if (inner === null || node.property.type !== AST_NODE_TYPES17.Identifier) {
|
|
3390
3673
|
return null;
|
|
3391
3674
|
}
|
|
3392
3675
|
return `${inner}.${node.property.name}`;
|
|
@@ -3394,12 +3677,12 @@ function refKey(node) {
|
|
|
3394
3677
|
return null;
|
|
3395
3678
|
}
|
|
3396
3679
|
function strLiteral(node) {
|
|
3397
|
-
if (node.type ===
|
|
3680
|
+
if (node.type === AST_NODE_TYPES17.Literal && typeof node.value === "string") {
|
|
3398
3681
|
return node.value;
|
|
3399
3682
|
}
|
|
3400
3683
|
return null;
|
|
3401
3684
|
}
|
|
3402
|
-
var prefer_string_literal_union_default =
|
|
3685
|
+
var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
|
|
3403
3686
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3404
3687
|
)({
|
|
3405
3688
|
name: "prefer-string-literal-union",
|
|
@@ -3423,7 +3706,7 @@ var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
|
|
|
3423
3706
|
}
|
|
3424
3707
|
let services;
|
|
3425
3708
|
try {
|
|
3426
|
-
services =
|
|
3709
|
+
services = ESLintUtils28.getParserServices(context);
|
|
3427
3710
|
} catch {
|
|
3428
3711
|
services = null;
|
|
3429
3712
|
}
|
|
@@ -3507,7 +3790,7 @@ var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
|
|
|
3507
3790
|
containersWithUnion.add(container);
|
|
3508
3791
|
return;
|
|
3509
3792
|
}
|
|
3510
|
-
if (typeNode?.type !==
|
|
3793
|
+
if (typeNode?.type !== AST_NODE_TYPES17.TSStringKeyword) {
|
|
3511
3794
|
return;
|
|
3512
3795
|
}
|
|
3513
3796
|
const name = keyName(key);
|
|
@@ -3595,10 +3878,10 @@ var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
|
|
|
3595
3878
|
}
|
|
3596
3879
|
};
|
|
3597
3880
|
function refKeyText(node) {
|
|
3598
|
-
if (node.type ===
|
|
3881
|
+
if (node.type === AST_NODE_TYPES17.BinaryExpression) {
|
|
3599
3882
|
return refKey(node.left) ?? refKey(node.right) ?? "value";
|
|
3600
3883
|
}
|
|
3601
|
-
if (node.type ===
|
|
3884
|
+
if (node.type === AST_NODE_TYPES17.SwitchStatement) {
|
|
3602
3885
|
return refKey(node.discriminant) ?? "value";
|
|
3603
3886
|
}
|
|
3604
3887
|
return "value";
|
|
@@ -3607,7 +3890,7 @@ var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
|
|
|
3607
3890
|
});
|
|
3608
3891
|
|
|
3609
3892
|
// src/rules/single-public-export.ts
|
|
3610
|
-
import { ESLintUtils as
|
|
3893
|
+
import { ESLintUtils as ESLintUtils29, AST_NODE_TYPES as AST_NODE_TYPES18 } from "@typescript-eslint/utils";
|
|
3611
3894
|
var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
|
|
3612
3895
|
"util",
|
|
3613
3896
|
"utils",
|
|
@@ -3630,7 +3913,7 @@ var ACRONYM_OVERRIDES = [
|
|
|
3630
3913
|
[/gRPC/g, "Grpc"]
|
|
3631
3914
|
];
|
|
3632
3915
|
var CAMEL_BOUNDARY_RE = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g;
|
|
3633
|
-
var
|
|
3916
|
+
var TEST_FILE_RE2 = /\.(test|spec)\.[cm]?[jt]sx?$/i;
|
|
3634
3917
|
var SCRIPT_EXT_RE = /\.[cm]?[jt]sx?$/i;
|
|
3635
3918
|
var basename = (filename) => filename.split(/[/\\]/).pop() ?? filename;
|
|
3636
3919
|
var stemOf = (base) => base.replace(SCRIPT_EXT_RE, "");
|
|
@@ -3641,12 +3924,12 @@ var kebabCase2 = (name) => {
|
|
|
3641
3924
|
}
|
|
3642
3925
|
return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
|
|
3643
3926
|
};
|
|
3644
|
-
var isFunctionExpression = (node) => node !== null && (node.type ===
|
|
3927
|
+
var isFunctionExpression = (node) => node !== null && (node.type === AST_NODE_TYPES18.ArrowFunctionExpression || node.type === AST_NODE_TYPES18.FunctionExpression);
|
|
3645
3928
|
var functionConstName = (decl) => {
|
|
3646
3929
|
if (decl.declarations.length !== 1) return null;
|
|
3647
3930
|
const [declarator] = decl.declarations;
|
|
3648
3931
|
if (declarator === void 0) return null;
|
|
3649
|
-
if (declarator.id.type !==
|
|
3932
|
+
if (declarator.id.type !== AST_NODE_TYPES18.Identifier) return null;
|
|
3650
3933
|
if (!isFunctionExpression(declarator.init)) return null;
|
|
3651
3934
|
return declarator.id.name;
|
|
3652
3935
|
};
|
|
@@ -3660,20 +3943,20 @@ var summarizeExports = (body) => {
|
|
|
3660
3943
|
};
|
|
3661
3944
|
for (const statement of body) {
|
|
3662
3945
|
switch (statement.type) {
|
|
3663
|
-
case
|
|
3946
|
+
case AST_NODE_TYPES18.ExportAllDeclaration:
|
|
3664
3947
|
hasReExport = true;
|
|
3665
3948
|
break;
|
|
3666
|
-
case
|
|
3949
|
+
case AST_NODE_TYPES18.ExportDefaultDeclaration: {
|
|
3667
3950
|
names += 1;
|
|
3668
3951
|
const decl = statement.declaration;
|
|
3669
|
-
if (decl.type ===
|
|
3952
|
+
if (decl.type === AST_NODE_TYPES18.FunctionDeclaration && decl.id !== null) {
|
|
3670
3953
|
candidate = { name: decl.id.name, node: statement };
|
|
3671
|
-
} else if (decl.type ===
|
|
3954
|
+
} else if (decl.type === AST_NODE_TYPES18.ClassDeclaration && decl.id !== null) {
|
|
3672
3955
|
candidate = { name: decl.id.name, node: statement };
|
|
3673
3956
|
}
|
|
3674
3957
|
break;
|
|
3675
3958
|
}
|
|
3676
|
-
case
|
|
3959
|
+
case AST_NODE_TYPES18.ExportNamedDeclaration: {
|
|
3677
3960
|
if (statement.source !== null) {
|
|
3678
3961
|
hasReExport = true;
|
|
3679
3962
|
break;
|
|
@@ -3684,15 +3967,15 @@ var summarizeExports = (body) => {
|
|
|
3684
3967
|
break;
|
|
3685
3968
|
}
|
|
3686
3969
|
switch (decl.type) {
|
|
3687
|
-
case
|
|
3970
|
+
case AST_NODE_TYPES18.FunctionDeclaration:
|
|
3688
3971
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3689
3972
|
else names += 1;
|
|
3690
3973
|
break;
|
|
3691
|
-
case
|
|
3974
|
+
case AST_NODE_TYPES18.ClassDeclaration:
|
|
3692
3975
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3693
3976
|
else names += 1;
|
|
3694
3977
|
break;
|
|
3695
|
-
case
|
|
3978
|
+
case AST_NODE_TYPES18.VariableDeclaration: {
|
|
3696
3979
|
const fnName = functionConstName(decl);
|
|
3697
3980
|
if (fnName !== null && decl.declarations.length === 1) {
|
|
3698
3981
|
addCandidate(fnName, statement);
|
|
@@ -3712,7 +3995,7 @@ var summarizeExports = (body) => {
|
|
|
3712
3995
|
}
|
|
3713
3996
|
return { names, hasReExport, candidate };
|
|
3714
3997
|
};
|
|
3715
|
-
var single_public_export_default =
|
|
3998
|
+
var single_public_export_default = ESLintUtils29.RuleCreator(
|
|
3716
3999
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3717
4000
|
)({
|
|
3718
4001
|
name: "single-public-export",
|
|
@@ -3730,7 +4013,7 @@ var single_public_export_default = ESLintUtils26.RuleCreator(
|
|
|
3730
4013
|
create(context) {
|
|
3731
4014
|
const base = basename(context.filename);
|
|
3732
4015
|
if (base.endsWith(".d.ts")) return {};
|
|
3733
|
-
if (
|
|
4016
|
+
if (TEST_FILE_RE2.test(base)) return {};
|
|
3734
4017
|
const stem = stemOf(base);
|
|
3735
4018
|
if (!JUNK_DRAWER_STEMS.has(stem.toLowerCase())) return {};
|
|
3736
4019
|
return {
|
|
@@ -3778,12 +4061,15 @@ var rules = {
|
|
|
3778
4061
|
"no-secret-in-log": no_secret_in_log_default,
|
|
3779
4062
|
"no-unsafe-cast": no_unsafe_cast_default,
|
|
3780
4063
|
"prefer-string-literal-union": prefer_string_literal_union_default,
|
|
3781
|
-
"single-public-export": single_public_export_default
|
|
4064
|
+
"single-public-export": single_public_export_default,
|
|
4065
|
+
"no-silent-promise-catch": no_silent_promise_catch_default,
|
|
4066
|
+
"require-fetch-timeout": require_fetch_timeout_default,
|
|
4067
|
+
"require-schema-validate-search": require_schema_validate_search_default
|
|
3782
4068
|
};
|
|
3783
4069
|
var plugin = {
|
|
3784
4070
|
meta: {
|
|
3785
4071
|
name: "@sarj/eslint-plugin",
|
|
3786
|
-
version: "2.
|
|
4072
|
+
version: "2.7.0"
|
|
3787
4073
|
},
|
|
3788
4074
|
rules,
|
|
3789
4075
|
configs: {
|
|
@@ -3815,7 +4101,11 @@ var plugin = {
|
|
|
3815
4101
|
"@sarj/no-secret-in-log": "warn",
|
|
3816
4102
|
"@sarj/no-unsafe-cast": "warn",
|
|
3817
4103
|
"@sarj/single-public-export": "warn",
|
|
3818
|
-
"@sarj/prefer-string-literal-union": "warn"
|
|
4104
|
+
"@sarj/prefer-string-literal-union": "warn",
|
|
4105
|
+
// Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
|
|
4106
|
+
"@sarj/require-fetch-timeout": "warn",
|
|
4107
|
+
"@sarj/no-silent-promise-catch": "warn",
|
|
4108
|
+
"@sarj/require-schema-validate-search": "warn"
|
|
3819
4109
|
}
|
|
3820
4110
|
},
|
|
3821
4111
|
strict: {
|
|
@@ -3851,7 +4141,11 @@ var plugin = {
|
|
|
3851
4141
|
"@sarj/no-unsafe-cast": "warn",
|
|
3852
4142
|
"@sarj/single-public-export": "error",
|
|
3853
4143
|
// High-volume/stylistic — warn until rollout proves FP rate.
|
|
3854
|
-
"@sarj/prefer-string-literal-union": "warn"
|
|
4144
|
+
"@sarj/prefer-string-literal-union": "warn",
|
|
4145
|
+
// Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
|
|
4146
|
+
"@sarj/require-fetch-timeout": "error",
|
|
4147
|
+
"@sarj/no-silent-promise-catch": "error",
|
|
4148
|
+
"@sarj/require-schema-validate-search": "error"
|
|
3855
4149
|
}
|
|
3856
4150
|
}
|
|
3857
4151
|
}
|