@sarj/eslint-plugin 19.15.0 → 19.16.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-SIHWYU24.js";
5
+ } from "./chunk-F6SYEJAW.js";
6
6
 
7
7
  // src/docs/directive-disable-enable-pair.ts
8
8
  var DIRECTIVE_DISABLE_ENABLE_PAIR_DOCUMENTATION = {
@@ -6223,14 +6223,15 @@ var REPEATED_STATIC_CALL_CASES_DOCUMENTATION = {
6223
6223
 
6224
6224
  // src/docs/require-assert-never.ts
6225
6225
  var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
6226
- summary: "Require an empty switch default to call `assertNever` so discriminated unions remain exhaustive at compile time.",
6226
+ summary: "Require a never witness in empty switch defaults so discriminated unions remain exhaustive at compile time.",
6227
6227
  rationale: "An empty default silently accepts new union members instead of making the compiler identify the missing case.",
6228
- remediation: "Call `assertNever` with the discriminant in the exhaustive switch default.",
6228
+ remediation: "Use `void (value satisfies never)` or a helper accepting never, preserving the intended runtime fallback.",
6229
6229
  category: "correctness",
6230
6230
  autofix: "safe",
6231
6231
  limitations: [
6232
6232
  "Requires type information and singleton case values covering the current union. The helper must accept never to provide a compile-time check; its spelling alone is not a proof of that contract. Review the desired runtime behavior for unexpected external values.",
6233
- "Automatic fixes reuse only an existing private ordinary assertNever function with one never parameter, explicit void return and an exactly empty body. The complete comment-free module must otherwise contain only one exported ordinary function with an explicit primitive return type, one string-literal-union parameter, a complete switch with primitive literal returns and a final empty or break default, followed by a primitive fallback return. The existing helper is called in that default, preserving unexpected-value continuation while adding the never compile guard. Throwing helpers, other statements or exports, imports, defaults, aliases and dynamic behavior remain manual."
6233
+ "Unique-symbol alternatives are compared by native compiler type identity. Distinct symbols can share the same printed type name; a handled symbol or its typed alias covers only that identity. Unavailable literal names do not establish coverage.",
6234
+ "Automatic fixes add void (parameter satisfies never), which only reads the existing parameter at runtime and introduces no helper dependency when the exported function is serialized on its own. The complete comment-free module must contain one exported ordinary function, optionally preceded by an exactly empty private ordinary assertNever helper with one never parameter and explicit void return. The dispatcher needs one string-literal-union parameter, an explicit primitive return type, a complete switch with primitive literal returns and a final empty or break default, followed by a primitive fallback return. Other module statements, imports, defaults, aliases, async functions and dynamic behavior remain manual."
6234
6235
  ],
6235
6236
  examples: [
6236
6237
  {
@@ -6263,18 +6264,18 @@ var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
6263
6264
  },
6264
6265
  {
6265
6266
  id: "safe-autofix",
6266
- title: "Reuse the existing no-op never guard",
6267
+ title: "Keep the never witness local to the dispatcher",
6267
6268
  outcome: "match",
6268
6269
  files: [
6269
6270
  {
6270
6271
  path: "src/render.ts",
6271
- source: "function assertNever(_value: never): void {}\nexport function render(kind: 'a' | 'b'): number { switch (kind) { case 'a': return 1; case 'b': return 2; default: break; } return 0; }"
6272
+ source: "export function render(kind: 'a' | 'b'): number { switch (kind) { case 'a': return 1; case 'b': return 2; default: break; } return 0; }"
6272
6273
  }
6273
6274
  ],
6274
6275
  fixedFiles: [
6275
6276
  {
6276
6277
  path: "src/render.ts",
6277
- source: "function assertNever(_value: never): void {}\nexport function render(kind: 'a' | 'b'): number { switch (kind) { case 'a': return 1; case 'b': return 2; default: assertNever(kind); break; } return 0; }"
6278
+ source: "export function render(kind: 'a' | 'b'): number { switch (kind) { case 'a': return 1; case 'b': return 2; default: void (kind satisfies never); break; } return 0; }"
6278
6279
  }
6279
6280
  ],
6280
6281
  focusPath: "src/render.ts",
@@ -31723,22 +31723,23 @@ var repeated_static_call_cases_default = defineRule({
31723
31723
 
31724
31724
  // src/rules/_empty-assertion-fix.ts
31725
31725
  function emptyAssertionFix(sourceCode2, node, defaultCase) {
31726
- if (sourceCode2.ast.body.length !== 2 || sourceCode2.getAllComments().length > 0) return null;
31727
- const [helper, statement] = sourceCode2.ast.body;
31728
- if (helper?.type !== "FunctionDeclaration" || !isEmptyAssertion(helper) || statement?.type !== "ExportNamedDeclaration" || statement.declaration?.type !== "FunctionDeclaration") {
31726
+ if (sourceCode2.getAllComments().length > 0) return null;
31727
+ const body3 = sourceCode2.ast.body;
31728
+ const statement = body3.at(-1);
31729
+ if (body3.length !== 1 && (body3.length !== 2 || body3[0]?.type !== "FunctionDeclaration" || !isEmptyAssertion(body3[0]))) {
31730
+ return null;
31731
+ }
31732
+ if (statement?.type !== "ExportNamedDeclaration" || statement.declaration?.type !== "FunctionDeclaration") {
31729
31733
  return null;
31730
31734
  }
31731
31735
  const owner = statement.declaration;
31732
31736
  if (!isLiteralDispatch(owner, node, defaultCase)) return null;
31733
31737
  const parameter = owner.params[0];
31734
- if (parameter?.type !== "Identifier" || helper.id === null) return null;
31735
- const helperName = helper.id.name;
31736
- const binding3 = findVariable(sourceCode2.getScope(defaultCase), helperName);
31737
- if (binding3?.defs.length !== 1 || binding3.defs[0]?.node !== helper) return null;
31738
+ if (parameter?.type !== "Identifier") return null;
31738
31739
  const first = sourceCode2.getFirstToken(defaultCase);
31739
31740
  const colon = first === null ? null : sourceCode2.getTokenAfter(first);
31740
31741
  if (colon?.value !== ":") return null;
31741
- return (fixer) => fixer.insertTextAfter(colon, ` ${helperName}(${parameter.name});`);
31742
+ return (fixer) => fixer.insertTextAfter(colon, ` void (${parameter.name} satisfies never);`);
31742
31743
  }
31743
31744
  function isEmptyAssertion(node) {
31744
31745
  const parameter = node.params[0];
@@ -31834,15 +31835,25 @@ function exhaustiveSwitches(file, candidates2) {
31834
31835
  ...constituents.flatMap((members2, i) => open[i] === true ? [] : members2 ?? []),
31835
31836
  ...finiteTests.filter((type) => type !== void 0)
31836
31837
  ])];
31837
- const names = file.batch(named3.map((type) => file.checker.typeToString.gen(type)));
31838
- const nameOf2 = new Map(named3.map((type, i) => [type, names[i]]));
31838
+ const printable = named3.filter((type) => (type.flags & file.flags.UniqueESSymbol) === 0);
31839
+ const names = printable.length === 0 ? [] : file.batch(printable.map((type) => file.checker.typeToString.gen(type)));
31840
+ const nameOf2 = new Map(printable.map((type, i) => [type, names[i]]));
31839
31841
  let offset = 0;
31840
31842
  return candidates2.map((_candidate, i) => {
31841
31843
  const caseTypes = finiteTests.slice(offset, offset + (tests[i]?.length ?? 0));
31842
31844
  offset += tests[i]?.length ?? 0;
31843
31845
  if (open[i] === true) return false;
31844
- const handled = new Set(caseTypes.flatMap((type) => type === void 0 ? [] : [nameOf2.get(type)]));
31845
- return (constituents[i] ?? []).every((member3) => handled.has(nameOf2.get(member3)));
31846
+ const symbols = new Set(caseTypes.flatMap((type) => type !== void 0 && (type.flags & file.flags.UniqueESSymbol) !== 0 ? [type.id] : []));
31847
+ const handled = new Set(caseTypes.flatMap((type) => {
31848
+ if (type === void 0 || (type.flags & file.flags.UniqueESSymbol) !== 0) return [];
31849
+ const name = nameOf2.get(type);
31850
+ return name === void 0 ? [] : [name];
31851
+ }));
31852
+ return (constituents[i] ?? []).every((member3) => {
31853
+ if ((member3.flags & file.flags.UniqueESSymbol) !== 0) return symbols.has(member3.id);
31854
+ const name = nameOf2.get(member3);
31855
+ return name !== void 0 && handled.has(name);
31856
+ });
31846
31857
  });
31847
31858
  }
31848
31859
  function finiteFlags(flags) {
@@ -31853,12 +31864,12 @@ var require_assert_never_default = defineRule({
31853
31864
  type: "problem",
31854
31865
  fixable: "code",
31855
31866
  docs: {
31856
- description: "Require an empty switch default to call `assertNever` so discriminated unions remain exhaustive at compile time.",
31867
+ description: "Require a never witness in empty switch defaults so discriminated unions remain exhaustive at compile time.",
31857
31868
  url: docsUrl(NAME128)
31858
31869
  },
31859
31870
  schema: [],
31860
31871
  messages: {
31861
- missingAssertNever: "Empty switch `default` case \u2014 add runtime handling or call `assertNever()` so the discriminated union is exhaustively checked at compile time."
31872
+ missingAssertNever: "Empty switch `default` case \u2014 add runtime handling or a never witness so the discriminated union is exhaustively checked at compile time."
31862
31873
  }
31863
31874
  },
31864
31875
  createOnce(context) {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  src_default
3
- } from "./chunk-SIHWYU24.js";
3
+ } from "./chunk-F6SYEJAW.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.15.0",
3
+ "version": "19.16.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",