@sarj/eslint-plugin 15.28.0 → 15.28.1

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 CHANGED
@@ -20078,7 +20078,7 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
20078
20078
  rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
20079
20079
  remediation: "Pass an abort signal, such as `AbortSignal.timeout(ms)`, in the fetch init.",
20080
20080
  category: "correctness",
20081
- limitations: ["Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Forwarded Request objects can carry an existing signal."],
20081
+ limitations: ["Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Literal null, global undefined, and void 0 do not provide a signal. Unknown spreads and dynamic values are not inferred. Forwarded Request objects can carry an existing signal."],
20082
20082
  examples: [
20083
20083
  { id: "bounded-fetch", title: "Bound the request", outcome: "no-match", files: [{ path: "src/client.ts", source: "await fetch(url, { signal: AbortSignal.timeout(5000) });" }], focusPath: "src/client.ts", expectedCount: 0, public: true },
20084
20084
  { id: "unbounded-fetch", title: "Do not leave fetch unbounded", outcome: "match", files: [{ path: "src/client.ts", source: "await fetch('https://api.example.com/items');" }], focusPath: "src/client.ts", expectedCount: 1, public: true }
@@ -20098,22 +20098,23 @@ function matchesAnyPattern3(filename, patterns) {
20098
20098
  }
20099
20099
  return false;
20100
20100
  }
20101
- function initProvablyLacksSignal(init) {
20102
- if (init.type !== import_utils110.AST_NODE_TYPES.ObjectExpression) {
20103
- return false;
20104
- }
20101
+ function initProvablyLacksSignal(init, resolvesToGlobal) {
20102
+ if (init.type !== import_utils110.AST_NODE_TYPES.ObjectExpression) return false;
20103
+ let lacksSignal = true;
20105
20104
  for (const prop of init.properties) {
20106
20105
  if (prop.type === import_utils110.AST_NODE_TYPES.SpreadElement) {
20107
- return false;
20108
- }
20109
- if (prop.key.type === import_utils110.AST_NODE_TYPES.Identifier && prop.key.name === "signal" || prop.key.type === import_utils110.AST_NODE_TYPES.Literal && prop.key.value === "signal") {
20110
- return false;
20106
+ lacksSignal = false;
20107
+ continue;
20111
20108
  }
20112
- if (prop.computed) {
20113
- return false;
20109
+ const isSignal = !prop.computed && prop.key.type === import_utils110.AST_NODE_TYPES.Identifier && prop.key.name === "signal" || prop.key.type === import_utils110.AST_NODE_TYPES.Literal && prop.key.value === "signal";
20110
+ if (isSignal) {
20111
+ const value = prop.value;
20112
+ lacksSignal = prop.kind === "init" && !prop.method && (value.type === import_utils110.AST_NODE_TYPES.Literal && value.value === null || value.type === import_utils110.AST_NODE_TYPES.Identifier && value.name === "undefined" && resolvesToGlobal(value) || value.type === import_utils110.AST_NODE_TYPES.UnaryExpression && value.operator === "void" && value.argument.type === import_utils110.AST_NODE_TYPES.Literal && value.argument.value === 0);
20113
+ } else if (prop.computed && prop.key.type !== import_utils110.AST_NODE_TYPES.Literal) {
20114
+ lacksSignal = false;
20114
20115
  }
20115
20116
  }
20116
- return true;
20117
+ return lacksSignal;
20117
20118
  }
20118
20119
  function isInlineUrl(node, resolvesToGlobal) {
20119
20120
  return node.type === import_utils110.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils110.AST_NODE_TYPES.TemplateLiteral || node.type === import_utils110.AST_NODE_TYPES.NewExpression && node.callee.type === import_utils110.AST_NODE_TYPES.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
@@ -20170,7 +20171,7 @@ var require_fetch_timeout_default = createRule({
20170
20171
  );
20171
20172
  if (variable?.defs.length !== 1) return false;
20172
20173
  const definition = variable.defs[0];
20173
- if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !== import_utils110.AST_NODE_TYPES.ObjectExpression || !initProvablyLacksSignal(definition.node.init)) {
20174
+ if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !== import_utils110.AST_NODE_TYPES.ObjectExpression || !initProvablyLacksSignal(definition.node.init, resolvesToGlobal)) {
20174
20175
  return false;
20175
20176
  }
20176
20177
  for (const reference of variable.references) {
@@ -20202,7 +20203,7 @@ var require_fetch_timeout_default = createRule({
20202
20203
  if (first !== void 0 && (node.arguments.length === 1 && !isInlineUrl(first, resolvesToGlobal) || isForwardedRequest(first))) {
20203
20204
  return;
20204
20205
  }
20205
- if (init === void 0 || initProvablyLacksSignal(init) || init.type === import_utils110.AST_NODE_TYPES.Identifier && localConstInitProvablyLacksSignal(init)) {
20206
+ if (init === void 0 || initProvablyLacksSignal(init, resolvesToGlobal) || init.type === import_utils110.AST_NODE_TYPES.Identifier && localConstInitProvablyLacksSignal(init)) {
20206
20207
  context.report({ node, messageId: "missingSignal" });
20207
20208
  }
20208
20209
  }
@@ -23354,7 +23355,7 @@ var RULES = {
23354
23355
  };
23355
23356
  var meta = {
23356
23357
  name: "@sarj/eslint-plugin",
23357
- version: "15.28.0"
23358
+ version: "15.28.1"
23358
23359
  };
23359
23360
  var APPLICATION_ONLY_RULES = [];
23360
23361
  var LIBRARY_IMPORT_POLICY = ["error", {
package/dist/index.d.cts CHANGED
@@ -916,7 +916,7 @@ type FlatPreset = {
916
916
  declare const PLUGIN: {
917
917
  readonly meta: {
918
918
  readonly name: "@sarj/eslint-plugin";
919
- readonly version: "15.28.0";
919
+ readonly version: "15.28.1";
920
920
  };
921
921
  readonly rules: {
922
922
  readonly "no-conditional-empty-object-spread": DocumentedRule<[], "avoid">;
package/dist/index.d.ts CHANGED
@@ -916,7 +916,7 @@ type FlatPreset = {
916
916
  declare const PLUGIN: {
917
917
  readonly meta: {
918
918
  readonly name: "@sarj/eslint-plugin";
919
- readonly version: "15.28.0";
919
+ readonly version: "15.28.1";
920
920
  };
921
921
  readonly rules: {
922
922
  readonly "no-conditional-empty-object-spread": DocumentedRule<[], "avoid">;
package/dist/index.js CHANGED
@@ -20093,7 +20093,7 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
20093
20093
  rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
20094
20094
  remediation: "Pass an abort signal, such as `AbortSignal.timeout(ms)`, in the fetch init.",
20095
20095
  category: "correctness",
20096
- limitations: ["Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Forwarded Request objects can carry an existing signal."],
20096
+ limitations: ["Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Literal null, global undefined, and void 0 do not provide a signal. Unknown spreads and dynamic values are not inferred. Forwarded Request objects can carry an existing signal."],
20097
20097
  examples: [
20098
20098
  { id: "bounded-fetch", title: "Bound the request", outcome: "no-match", files: [{ path: "src/client.ts", source: "await fetch(url, { signal: AbortSignal.timeout(5000) });" }], focusPath: "src/client.ts", expectedCount: 0, public: true },
20099
20099
  { id: "unbounded-fetch", title: "Do not leave fetch unbounded", outcome: "match", files: [{ path: "src/client.ts", source: "await fetch('https://api.example.com/items');" }], focusPath: "src/client.ts", expectedCount: 1, public: true }
@@ -20113,22 +20113,23 @@ function matchesAnyPattern3(filename, patterns) {
20113
20113
  }
20114
20114
  return false;
20115
20115
  }
20116
- function initProvablyLacksSignal(init) {
20117
- if (init.type !== AST_NODE_TYPES93.ObjectExpression) {
20118
- return false;
20119
- }
20116
+ function initProvablyLacksSignal(init, resolvesToGlobal) {
20117
+ if (init.type !== AST_NODE_TYPES93.ObjectExpression) return false;
20118
+ let lacksSignal = true;
20120
20119
  for (const prop of init.properties) {
20121
20120
  if (prop.type === AST_NODE_TYPES93.SpreadElement) {
20122
- return false;
20123
- }
20124
- if (prop.key.type === AST_NODE_TYPES93.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES93.Literal && prop.key.value === "signal") {
20125
- return false;
20121
+ lacksSignal = false;
20122
+ continue;
20126
20123
  }
20127
- if (prop.computed) {
20128
- return false;
20124
+ const isSignal = !prop.computed && prop.key.type === AST_NODE_TYPES93.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES93.Literal && prop.key.value === "signal";
20125
+ if (isSignal) {
20126
+ const value = prop.value;
20127
+ lacksSignal = prop.kind === "init" && !prop.method && (value.type === AST_NODE_TYPES93.Literal && value.value === null || value.type === AST_NODE_TYPES93.Identifier && value.name === "undefined" && resolvesToGlobal(value) || value.type === AST_NODE_TYPES93.UnaryExpression && value.operator === "void" && value.argument.type === AST_NODE_TYPES93.Literal && value.argument.value === 0);
20128
+ } else if (prop.computed && prop.key.type !== AST_NODE_TYPES93.Literal) {
20129
+ lacksSignal = false;
20129
20130
  }
20130
20131
  }
20131
- return true;
20132
+ return lacksSignal;
20132
20133
  }
20133
20134
  function isInlineUrl(node, resolvesToGlobal) {
20134
20135
  return node.type === AST_NODE_TYPES93.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES93.TemplateLiteral || node.type === AST_NODE_TYPES93.NewExpression && node.callee.type === AST_NODE_TYPES93.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
@@ -20185,7 +20186,7 @@ var require_fetch_timeout_default = createRule({
20185
20186
  );
20186
20187
  if (variable?.defs.length !== 1) return false;
20187
20188
  const definition = variable.defs[0];
20188
- if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !== AST_NODE_TYPES93.ObjectExpression || !initProvablyLacksSignal(definition.node.init)) {
20189
+ if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !== AST_NODE_TYPES93.ObjectExpression || !initProvablyLacksSignal(definition.node.init, resolvesToGlobal)) {
20189
20190
  return false;
20190
20191
  }
20191
20192
  for (const reference of variable.references) {
@@ -20217,7 +20218,7 @@ var require_fetch_timeout_default = createRule({
20217
20218
  if (first !== void 0 && (node.arguments.length === 1 && !isInlineUrl(first, resolvesToGlobal) || isForwardedRequest(first))) {
20218
20219
  return;
20219
20220
  }
20220
- if (init === void 0 || initProvablyLacksSignal(init) || init.type === AST_NODE_TYPES93.Identifier && localConstInitProvablyLacksSignal(init)) {
20221
+ if (init === void 0 || initProvablyLacksSignal(init, resolvesToGlobal) || init.type === AST_NODE_TYPES93.Identifier && localConstInitProvablyLacksSignal(init)) {
20221
20222
  context.report({ node, messageId: "missingSignal" });
20222
20223
  }
20223
20224
  }
@@ -23375,7 +23376,7 @@ var RULES = {
23375
23376
  };
23376
23377
  var meta = {
23377
23378
  name: "@sarj/eslint-plugin",
23378
- version: "15.28.0"
23379
+ version: "15.28.1"
23379
23380
  };
23380
23381
  var APPLICATION_ONLY_RULES = [];
23381
23382
  var LIBRARY_IMPORT_POLICY = ["error", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "15.28.0",
3
+ "version": "15.28.1",
4
4
  "packageManager": "npm@12.1.0",
5
5
  "description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",