@sarj/eslint-plugin 19.10.0 → 19.12.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/catalog.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  publicDocumentation,
3
3
  ruleSpec,
4
4
  src_default
5
- } from "./chunk-ZWOGM4CV.js";
5
+ } from "./chunk-7SYRLUE7.js";
6
6
 
7
7
  // src/docs/directive-disable-enable-pair.ts
8
8
  var DIRECTIVE_DISABLE_ENABLE_PAIR_DOCUMENTATION = {
@@ -4163,7 +4163,7 @@ var PREFER_CODED_ERROR_RESULT_DOCUMENTATION = {
4163
4163
  "Checks source-resolved local unions with required literal ok/success booleans, or status/state/kind/type/tag values ok/success versus err/error/failure/failed (case insensitive). Conflicting outcome tags abstain. A shared outcome tag does not also count as a domain error code. Named and namespace neverthrow Result/ResultAsync imports establish their generic error position.",
4164
4164
  "Presence-selected unions require an error property on every failure branch and the same single required non-control value property on every success branch. Optional error/value fields, multiple value keys, loading states and error branches carrying the success value abstain. Required errorMessage and Error-suffixed failure channels are also reviewed; multiple custom channels abstain and a primary error payload retains precedence.",
4165
4165
  "Broad string and unknown error channels, unshadowed native Error-family types and open string/unknown code fields receive review. Explicit Any stays with the existing no-explicit-any rule. Finite literal codes need no invented payload. Imported domain errors, validation-library errors, generic error parameters, ordinary formatters, legitimate absence and redacted failure states remain valid.",
4166
- "Local aliases, unmerged interfaces without inheritance and generic substitutions are bounded to 16 resolution levels, 64 union members and 256 traversal steps. Imported local declarations, conditional/intersection/mapped types and unresolved contracts abstain. Optional discriminants, independent success/error payloads and partial-data failures are excluded.",
4166
+ "Local aliases, unmerged interfaces without inheritance and generic substitutions are bounded to 16 resolution levels, 64 union members and 256 traversal steps. Transparent aliases retain the proven neverthrow Result/ResultAsync error position, including renamed/namespace imports, generic defaults and unshadowed native Promise/PromiseLike wrappers. Imported local declarations, conditional/intersection/mapped types and unresolved contracts abstain. Optional discriminants, independent success/error payloads and partial-data failures are excluded.",
4167
4167
  "Required code/kind/type/tag fields of unresolved or imported type defer to the type checker; a finite code does not prove that its cases or payloads are useful. Generic error parameters are retained rather than guessed. Ordinary string formatters, absence, validation-library errors and redacted failure states without a string payload are not flagged.",
4168
4168
  "A directly returned failure object, neverthrow err/errAsync call or new Err with an interpolated template or proven string concatenation receives review. Without a code, the diagnostic asks for a domain contract; with a literal code, it asks for consumer formatting. Literal-only compositions, including earlier stable local constants, remain valid codes. Nested plain error objects, expression-bodied arrows and one direct await are supported. Import identity and value-space shadowing are checked; arbitrary aliases, spreads, accessors, computed keys, helper formatting calls and nonliteral codes abstain. This proves formatting ownership, not which context the domain must expose; presentation adapters remain a reviewed exception.",
4169
4169
  "This warning requests domain review: an infrastructure adapter may intentionally retain unknown/Error, and a final presentation boundary may accept every failure and render one message. Neither proves a recoverable domain rejection. No fix invents error codes, fields, handlers or changes serialization, exception unwinding, transactions, retries or logging."
@@ -4173,6 +4173,36 @@ var PREFER_CODED_ERROR_RESULT_DOCUMENTATION = {
4173
4173
  "https://github.com/supermacro/neverthrow"
4174
4174
  ],
4175
4175
  examples: [
4176
+ {
4177
+ id: "aliased-library-message",
4178
+ scenarioId: "aliased-library-error",
4179
+ title: "A transparent alias must preserve the library error contract",
4180
+ outcome: "match",
4181
+ files: [
4182
+ {
4183
+ path: "app/result.ts",
4184
+ source: "import type { Result as NativeResult } from 'neverthrow'; type Saved<T, E> = Promise<NativeResult<T, E>>; export type Output = Saved<number, string>;"
4185
+ }
4186
+ ],
4187
+ focusPath: "app/result.ts",
4188
+ expectedCount: 1,
4189
+ public: true
4190
+ },
4191
+ {
4192
+ id: "aliased-library-domain-error",
4193
+ scenarioId: "aliased-library-error",
4194
+ title: "Keep a finite error code and only the context its consumer needs",
4195
+ outcome: "no-match",
4196
+ files: [
4197
+ {
4198
+ path: "app/result.ts",
4199
+ source: "import type { Result as NativeResult } from 'neverthrow'; type Saved<T, E> = Promise<NativeResult<T, E>>; export type Output = Saved<number, { code: 'duplicate'; name: string } | { code: 'denied' }>;"
4200
+ }
4201
+ ],
4202
+ focusPath: "app/result.ts",
4203
+ expectedCount: 0,
4204
+ public: true
4205
+ },
4176
4206
  {
4177
4207
  id: "presence-selected-message",
4178
4208
  scenarioId: "presence-selected-result",
@@ -21588,14 +21588,15 @@ function resolve2(value, source, depth = 0) {
21588
21588
  if (depth >= MAX_DEPTH) return null;
21589
21589
  const node = value.node;
21590
21590
  if (node.type !== "TSTypeReference") return value;
21591
- if (node.typeName.type !== "Identifier") return null;
21591
+ if (node.typeName.type !== "Identifier")
21592
+ return libraryResult(node, source) ? value : null;
21592
21593
  const variable = typeBinding(source, node.typeName);
21593
21594
  if (variable === null || variable.defs.length === 0) return value;
21594
21595
  const bound = value.bindings.get(variable);
21595
21596
  if (bound !== void 0) return resolve2(bound, source, depth + 1);
21596
21597
  const declaration = variable.defs.length === 1 ? variable.defs[0]?.node : void 0;
21597
21598
  if (declaration?.type !== "TSTypeAliasDeclaration" && declaration?.type !== "TSInterfaceDeclaration")
21598
- return null;
21599
+ return libraryResult(node, source) ? value : null;
21599
21600
  if (declaration.type === "TSInterfaceDeclaration" && declaration.extends.length !== 0)
21600
21601
  return null;
21601
21602
  const bindings = bindArguments(declaration, node, value, source);
@@ -21761,6 +21762,26 @@ function openStringField(fields2, owner, source, names, budget) {
21761
21762
  }
21762
21763
  return null;
21763
21764
  }
21765
+ function outcomeFailures(value, source, depth = 0, budget = { remaining: MAX_TYPE_STEPS }) {
21766
+ if (depth >= MAX_DEPTH || --budget.remaining < 0) return [];
21767
+ const resolved = resolve2(value, source);
21768
+ if (resolved === null) return [];
21769
+ const structural = failureMessages(resolved, source);
21770
+ if (structural.length !== 0) return structural;
21771
+ const library = libraryError(resolved, source);
21772
+ if (library !== null) return [library];
21773
+ const node = resolved.node;
21774
+ if (node.type !== "TSTypeReference") return [];
21775
+ if (node.typeName.type !== "Identifier" || !["Promise", "PromiseLike"].includes(node.typeName.name) || (typeBinding(source, node.typeName)?.defs.length ?? 0) !== 0 || node.typeArguments?.params.length !== 1)
21776
+ return [];
21777
+ const argument = node.typeArguments.params[0];
21778
+ return argument === void 0 ? [] : outcomeFailures(
21779
+ { ...resolved, node: argument, origin: argument },
21780
+ source,
21781
+ depth + 1,
21782
+ budget
21783
+ );
21784
+ }
21764
21785
  function failureMessages(value, source) {
21765
21786
  const members2 = variants(value, source);
21766
21787
  if (members2 === null || members2.length < 2) return [];
@@ -21853,14 +21874,18 @@ function variants(value, source, depth = 0, budget = { remaining: MAX_TYPE_STEPS
21853
21874
  }
21854
21875
  return result;
21855
21876
  }
21856
- function libraryError(reference, source) {
21857
- if (reference.typeArguments?.params.length !== 2) return null;
21858
- if (!["Result", "ResultAsync"].includes(
21859
- libraryName(reference.typeName, source, true) ?? ""
21860
- ))
21877
+ function libraryError(value, source) {
21878
+ const reference = value.node;
21879
+ if (reference.type !== "TSTypeReference" || !libraryResult(reference, source))
21861
21880
  return null;
21881
+ if (reference.typeArguments?.params.length !== 2) return null;
21862
21882
  const error = reference.typeArguments.params[1];
21863
- return error === void 0 ? null : weakError(view(error), source);
21883
+ return error === void 0 ? null : weakError({ ...value, node: error, origin: error }, source);
21884
+ }
21885
+ function libraryResult(reference, source) {
21886
+ return ["Result", "ResultAsync"].includes(
21887
+ libraryName(reference.typeName, source, true) ?? ""
21888
+ );
21864
21889
  }
21865
21890
  function libraryName(node, source, typeSpace) {
21866
21891
  const reference = libraryReference(node);
@@ -21886,16 +21911,6 @@ function libraryReference(node) {
21886
21911
  return { root: node.object, member: node.property.name };
21887
21912
  return null;
21888
21913
  }
21889
- function weakAnnotation(node, source, depth = 0, budget = { remaining: MAX_TYPE_STEPS }) {
21890
- if (depth >= MAX_DEPTH || --budget.remaining < 0) return false;
21891
- if (failureMessages(view(node), source).length !== 0) return true;
21892
- if (node.type !== "TSTypeReference") return false;
21893
- if (libraryError(node, source) !== null) return true;
21894
- if (node.typeName.type !== "Identifier" || !["Promise", "PromiseLike"].includes(node.typeName.name) || typeBinding(source, node.typeName) !== null || node.typeArguments?.params.length !== 1)
21895
- return false;
21896
- const argument = node.typeArguments.params[0];
21897
- return argument !== void 0 && weakAnnotation(argument, source, depth + 1, budget);
21898
- }
21899
21914
  function renderedFailure(node, source) {
21900
21915
  let value = unwrapExpression(node);
21901
21916
  if (value.type === "AwaitExpression")
@@ -22017,9 +22032,7 @@ var prefer_coded_error_result_default = defineRule({
22017
22032
  createOnce(context) {
22018
22033
  const reported = /* @__PURE__ */ new Set();
22019
22034
  function check(node) {
22020
- const candidates2 = failureMessages(view(node), context.sourceCode);
22021
- const library = node.type === "TSTypeReference" ? libraryError(node, context.sourceCode) : null;
22022
- for (const candidate2 of library === null ? candidates2 : [...candidates2, library]) {
22035
+ for (const candidate2 of outcomeFailures(view(node), context.sourceCode)) {
22023
22036
  if (reported.has(candidate2)) continue;
22024
22037
  reported.add(candidate2);
22025
22038
  context.report({
@@ -22033,7 +22046,7 @@ var prefer_coded_error_result_default = defineRule({
22033
22046
  const rendered = renderedFailure(value, context.sourceCode);
22034
22047
  if (rendered === null || reported.has(rendered.node)) return;
22035
22048
  const contract = owner.returnType?.typeAnnotation;
22036
- if (contract !== void 0 && weakAnnotation(contract, context.sourceCode))
22049
+ if (contract !== void 0 && outcomeFailures(view(contract), context.sourceCode).length !== 0)
22037
22050
  return;
22038
22051
  reported.add(rendered.node);
22039
22052
  context.report(rendered);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  src_default
3
- } from "./chunk-ZWOGM4CV.js";
3
+ } from "./chunk-7SYRLUE7.js";
4
4
  export {
5
5
  src_default as default
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "19.10.0",
3
+ "version": "19.12.0",
4
4
  "packageManager": "npm@12.2.1",
5
5
  "description": "Custom Oxlint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",