@sarj/eslint-plugin 17.1.2 → 17.1.3

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
@@ -1076,13 +1076,13 @@ var no_test_comments_default = createRule({
1076
1076
  name: "no-test-comments",
1077
1077
  documentation: NO_TEST_COMMENTS_DOCUMENTATION,
1078
1078
  meta: {
1079
+ defaultOptions: [{}],
1079
1080
  type: "suggestion",
1080
1081
  fixable: "code",
1081
1082
  docs: { description: NO_TEST_COMMENTS_DOCUMENTATION.summary },
1082
- schema: [{ type: "object", properties: { allFiles: { type: "boolean" } }, additionalProperties: false }],
1083
+ schema: [{ type: "object", properties: { allFiles: { description: "Check every eligible test file without requiring frontend framework ownership.", type: "boolean" } }, additionalProperties: false }],
1083
1084
  messages: { testComment: "Express this explanation in the test name, fixture or assertion, then remove the comment." }
1084
1085
  },
1085
- defaultOptions: [{}],
1086
1086
  create(context, [options]) {
1087
1087
  if (!isTestFile(context) || isGeneratedFile(context, context.sourceCode.text)) return {};
1088
1088
  if (!ownsTestComments(context)) return {};
@@ -1171,13 +1171,13 @@ var no_frontend_comments_default = createRule({
1171
1171
  name: "no-frontend-comments",
1172
1172
  documentation: NO_FRONTEND_COMMENTS_DOCUMENTATION,
1173
1173
  meta: {
1174
+ defaultOptions: [{}],
1174
1175
  type: "suggestion",
1175
1176
  fixable: "code",
1176
1177
  docs: { description: NO_FRONTEND_COMMENTS_DOCUMENTATION.summary },
1177
- schema: [{ type: "object", properties: { allFiles: { type: "boolean" } }, additionalProperties: false }],
1178
+ schema: [{ type: "object", properties: { allFiles: { description: "Check comments without requiring frontend framework ownership.", type: "boolean" } }, additionalProperties: false }],
1178
1179
  messages: { noFrontendComments: "Frontend comments are prohibited; express the behavior in names, types or code and review any directive or legal contract before removing it." }
1179
1180
  },
1180
- defaultOptions: [{}],
1181
1181
  create(context, [options]) {
1182
1182
  if (isGeneratedFile(context, context.sourceCode.text) || ownsTestComments(context)) return {};
1183
1183
  const jsxRanges = [];
@@ -4832,7 +4832,7 @@ function isSearchParamReceiver(call, services) {
4832
4832
  // package.json
4833
4833
  var package_default = {
4834
4834
  name: "@sarj/eslint-plugin",
4835
- version: "17.1.2",
4835
+ version: "17.1.3",
4836
4836
  packageManager: "npm@12.2.1",
4837
4837
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
4838
4838
  type: "module",
@@ -4906,6 +4906,7 @@ var package_default = {
4906
4906
  "@vitest/eslint-plugin": "1.6.28",
4907
4907
  eslint: "10.13.0",
4908
4908
  "eslint-node-test": "1.0.1",
4909
+ "eslint-plugin-eslint-plugin": "7.6.2",
4909
4910
  "eslint-plugin-better-tailwindcss": "^4.10.0",
4910
4911
  "eslint-plugin-jest": "29.17.0",
4911
4912
  "eslint-plugin-jsdoc": "65.4.2",
@@ -4926,6 +4927,7 @@ var package_default = {
4926
4927
  jiti: "2.7.0",
4927
4928
  prettier: "3.9.10",
4928
4929
  tsup: "9.0.0",
4930
+ syncpack: "15.3.3",
4929
4931
  typescript: "npm:@typescript/typescript6@6.0.2",
4930
4932
  "typescript-eslint": "^8.72.0",
4931
4933
  uuid: "13.0.0",
@@ -9170,6 +9172,7 @@ var require_button_accessible_name_default = createRule({
9170
9172
  name: "require-button-accessible-name",
9171
9173
  documentation: REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION,
9172
9174
  meta: {
9175
+ defaultOptions: [{}],
9173
9176
  type: "problem",
9174
9177
  docs: { description: REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION.summary },
9175
9178
  schema: [
@@ -9178,6 +9181,7 @@ var require_button_accessible_name_default = createRule({
9178
9181
  properties: {
9179
9182
  components: COMPONENT_IMPORT_SCHEMA,
9180
9183
  iconModules: {
9184
+ description: "Module names whose imported components count as icons.",
9181
9185
  type: "array",
9182
9186
  items: { type: "string", minLength: 1 },
9183
9187
  uniqueItems: true
@@ -9190,7 +9194,6 @@ var require_button_accessible_name_default = createRule({
9190
9194
  missingName: "This button has no statically identifiable accessible name. Add action text, aria-label, or aria-labelledby."
9191
9195
  }
9192
9196
  },
9193
- defaultOptions: [{}],
9194
9197
  create(context, [options]) {
9195
9198
  if (isGeneratedFile(context, context.sourceCode.text) || isTestFile(context) || isStoryFile(context))
9196
9199
  return {};
@@ -9509,6 +9512,7 @@ var prefer_logical_tailwind_utilities_default = createRule({
9509
9512
  name: "prefer-logical-tailwind-utilities",
9510
9513
  documentation: PREFER_LOGICAL_TAILWIND_UTILITIES_DOCUMENTATION,
9511
9514
  meta: {
9515
+ defaultOptions: [{ enabled: true, checkInsets: false, allowUtilities: [] }],
9512
9516
  type: "suggestion",
9513
9517
  docs: {
9514
9518
  description: PREFER_LOGICAL_TAILWIND_UTILITIES_DOCUMENTATION.summary
@@ -9517,9 +9521,10 @@ var prefer_logical_tailwind_utilities_default = createRule({
9517
9521
  {
9518
9522
  type: "object",
9519
9523
  properties: {
9520
- enabled: { type: "boolean" },
9521
- checkInsets: { type: "boolean" },
9524
+ enabled: { description: "Enable replacement of physical direction utilities with logical equivalents.", type: "boolean" },
9525
+ checkInsets: { description: "Include physical inset utilities in direction checks.", type: "boolean" },
9522
9526
  allowUtilities: {
9527
+ description: "Physical utility names allowed without a logical replacement.",
9523
9528
  type: "array",
9524
9529
  items: { type: "string" },
9525
9530
  uniqueItems: true
@@ -9532,7 +9537,6 @@ var prefer_logical_tailwind_utilities_default = createRule({
9532
9537
  physicalUtility: "Use '{{replacement}}' instead of '{{utility}}' in this bidirectional UI, or explicitly allow intentional physical placement."
9533
9538
  }
9534
9539
  },
9535
- defaultOptions: [{ enabled: true, checkInsets: false, allowUtilities: [] }],
9536
9540
  create(context, [options]) {
9537
9541
  if (options?.enabled === false || isGeneratedFile(context, context.sourceCode.text) || isTestFile(context) || isStoryFile(context))
9538
9542
  return {};
@@ -9660,6 +9664,7 @@ var no_unlocalized_toast_default = createRule({
9660
9664
  name: "no-unlocalized-toast",
9661
9665
  documentation: NO_UNLOCALIZED_TOAST_DOCUMENTATION,
9662
9666
  meta: {
9667
+ defaultOptions: [{ enabled: true }],
9663
9668
  type: "suggestion",
9664
9669
  docs: { description: NO_UNLOCALIZED_TOAST_DOCUMENTATION.summary },
9665
9670
  schema: [
@@ -9669,6 +9674,7 @@ var no_unlocalized_toast_default = createRule({
9669
9674
  ...LOCALIZATION_PROPERTIES,
9670
9675
  functions: COMPONENT_IMPORT_SCHEMA,
9671
9676
  methods: {
9677
+ description: "Toast method names whose user-visible messages require localization.",
9672
9678
  type: "array",
9673
9679
  items: { type: "string", minLength: 1 },
9674
9680
  uniqueItems: true
@@ -9681,7 +9687,6 @@ var no_unlocalized_toast_default = createRule({
9681
9687
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9682
9688
  }
9683
9689
  },
9684
- defaultOptions: [{ enabled: true }],
9685
9690
  create(context, [options]) {
9686
9691
  if (localizationExcluded(context, context.sourceCode.text, options))
9687
9692
  return {};
@@ -9773,6 +9778,7 @@ var no_unlocalized_jsx_attributes_default = createRule({
9773
9778
  name: "no-unlocalized-jsx-attributes",
9774
9779
  documentation: NO_UNLOCALIZED_JSX_ATTRIBUTES_DOCUMENTATION,
9775
9780
  meta: {
9781
+ defaultOptions: [{ enabled: true }],
9776
9782
  type: "suggestion",
9777
9783
  docs: { description: NO_UNLOCALIZED_JSX_ATTRIBUTES_DOCUMENTATION.summary },
9778
9784
  schema: [
@@ -9781,6 +9787,7 @@ var no_unlocalized_jsx_attributes_default = createRule({
9781
9787
  properties: {
9782
9788
  ...LOCALIZATION_PROPERTIES,
9783
9789
  attributes: {
9790
+ description: "JSX attributes whose user-visible text requires localization.",
9784
9791
  type: "array",
9785
9792
  items: { type: "string", minLength: 1 },
9786
9793
  uniqueItems: true
@@ -9793,7 +9800,6 @@ var no_unlocalized_jsx_attributes_default = createRule({
9793
9800
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9794
9801
  }
9795
9802
  },
9796
- defaultOptions: [{ enabled: true }],
9797
9803
  create(context, [options]) {
9798
9804
  if (localizationExcluded(context, context.sourceCode.text, options))
9799
9805
  return {};
@@ -9858,6 +9864,7 @@ var no_unlocalized_jsx_text_default = createRule({
9858
9864
  name: "no-unlocalized-jsx-text",
9859
9865
  documentation: NO_UNLOCALIZED_JSX_TEXT_DOCUMENTATION,
9860
9866
  meta: {
9867
+ defaultOptions: [{ enabled: true }],
9861
9868
  type: "suggestion",
9862
9869
  docs: { description: NO_UNLOCALIZED_JSX_TEXT_DOCUMENTATION.summary },
9863
9870
  schema: [
@@ -9871,7 +9878,6 @@ var no_unlocalized_jsx_text_default = createRule({
9871
9878
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9872
9879
  }
9873
9880
  },
9874
- defaultOptions: [{ enabled: true }],
9875
9881
  create(context, [options]) {
9876
9882
  if (localizationExcluded(context, context.sourceCode.text, options))
9877
9883
  return {};
@@ -12655,6 +12661,7 @@ var no_dynamic_sql_default = createRule({
12655
12661
  name: "no-dynamic-sql",
12656
12662
  documentation: NO_DYNAMIC_SQL_DOCUMENTATION,
12657
12663
  meta: {
12664
+ defaultOptions: [{}],
12658
12665
  type: "problem",
12659
12666
  docs: {
12660
12667
  description: NO_DYNAMIC_SQL_DOCUMENTATION.summary
@@ -12677,7 +12684,6 @@ var no_dynamic_sql_default = createRule({
12677
12684
  dynamicFragment: "Runtime fragment interpolated into SQL passed to `{{method}}()`. Bind data values; select non-bindable SQL fragments from fixed, reviewed alternatives."
12678
12685
  }
12679
12686
  },
12680
- defaultOptions: [{}],
12681
12687
  create(context, [options]) {
12682
12688
  const methods = new Set(options?.methods ?? DEFAULT_METHODS);
12683
12689
  return {
@@ -12749,6 +12755,7 @@ var no_enum_default = createRule({
12749
12755
  name: "no-enum",
12750
12756
  documentation: NO_ENUM_DOCUMENTATION,
12751
12757
  meta: {
12758
+ defaultOptions: [{}],
12752
12759
  type: "suggestion",
12753
12760
  fixable: "code",
12754
12761
  docs: {
@@ -12771,7 +12778,6 @@ var no_enum_default = createRule({
12771
12778
  noEnum: 'Enums are discouraged. Use a string-literal union (e.g. `type Status = "active" | "inactive"`) or an `as const` object instead.'
12772
12779
  }
12773
12780
  },
12774
- defaultOptions: [{}],
12775
12781
  create(context, [optionsArg]) {
12776
12782
  const options = optionsArg ?? {};
12777
12783
  const ignoreFiles = options.ignoreFiles ?? [];
@@ -13318,6 +13324,7 @@ var no_fat_try_blocks_default = createRule({
13318
13324
  name: "no-fat-try-blocks",
13319
13325
  documentation: NO_FAT_TRY_BLOCKS_DOCUMENTATION,
13320
13326
  meta: {
13327
+ defaultOptions: [{ max: MAX_TRY_BODY_STATEMENTS }],
13321
13328
  type: "problem",
13322
13329
  docs: {
13323
13330
  description: "Review try blocks exceeding the configured count of syntactically selected operations."
@@ -13326,7 +13333,7 @@ var no_fat_try_blocks_default = createRule({
13326
13333
  {
13327
13334
  type: "object",
13328
13335
  properties: {
13329
- max: { type: "integer", minimum: 1 }
13336
+ max: { description: "Maximum number of statements allowed in one try body.", type: "integer", minimum: 1 }
13330
13337
  },
13331
13338
  additionalProperties: false
13332
13339
  }
@@ -13335,7 +13342,6 @@ var no_fat_try_blocks_default = createRule({
13335
13342
  fatTryBlock: "This `try` block has {{count}} syntactically selected operations (max {{max}}). Review whether they share one recovery policy; move unrelated work outside the boundary."
13336
13343
  }
13337
13344
  },
13338
- defaultOptions: [{ max: MAX_TRY_BODY_STATEMENTS }],
13339
13345
  create(context, [options]) {
13340
13346
  if (isGeneratedFile(context, context.sourceCode.text)) {
13341
13347
  return {};
@@ -13486,6 +13492,7 @@ var no_hand_rolled_sleep_default = createRule({
13486
13492
  name: "no-hand-rolled-sleep",
13487
13493
  documentation: NO_HAND_ROLLED_SLEEP_DOCUMENTATION,
13488
13494
  meta: {
13495
+ defaultOptions: [{}],
13489
13496
  type: "problem",
13490
13497
  docs: {
13491
13498
  description: "Disallow uncancellable promisified timers and timeout arms."
@@ -13512,7 +13519,6 @@ var no_hand_rolled_sleep_default = createRule({
13512
13519
  handRolledTimeoutRace: "Hand-rolled timeout arm: when the other promise wins, this timer is never cleared and keeps the event loop alive until it fires. Use `AbortSignal.timeout(ms)` and pass the signal to the operation."
13513
13520
  }
13514
13521
  },
13515
- defaultOptions: [{}],
13516
13522
  create(context, [optionsArg]) {
13517
13523
  const { filename, sourceCode } = context;
13518
13524
  if (isTestFile(context) || isScriptFile(context) || isGeneratedFile(context, sourceCode.getText())) {
@@ -15788,6 +15794,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
15788
15794
  name: "no-impossible-zod-literal-bounds",
15789
15795
  documentation: NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION,
15790
15796
  meta: {
15797
+ defaultOptions: [{}],
15791
15798
  type: "problem",
15792
15799
  docs: {
15793
15800
  description: "Disallow same-chain literal Zod bounds whose accepted set is mathematically empty."
@@ -15808,7 +15815,6 @@ var no_impossible_zod_literal_bounds_default = createRule({
15808
15815
  impossibleBounds: "This Zod {{kind}} schema accepts no values: {{lower}} conflicts with {{upper}}."
15809
15816
  }
15810
15817
  },
15811
- defaultOptions: [{}],
15812
15818
  create(context, [options]) {
15813
15819
  const sourceCode = context.sourceCode;
15814
15820
  if (isTestFile(context) || isGeneratedFile(context, sourceCode.getText())) {
@@ -16851,6 +16857,7 @@ var no_log_only_catch_default = createRule({
16851
16857
  name: "no-log-only-catch",
16852
16858
  documentation: NO_LOG_ONLY_CATCH_DOCUMENTATION,
16853
16859
  meta: {
16860
+ defaultOptions: [{}],
16854
16861
  type: "problem",
16855
16862
  docs: {
16856
16863
  description: "Disallow `catch` clauses that only log (or silently do nothing) and then swallow the error; rethrow or handle it instead."
@@ -16867,7 +16874,6 @@ var no_log_only_catch_default = createRule({
16867
16874
  emptyCatch: "Empty catch silently swallows the error. Rethrow it, handle it, or add a comment explaining why it is safe to ignore."
16868
16875
  }
16869
16876
  },
16870
- defaultOptions: [{}],
16871
16877
  create(context, [loggingOptions]) {
16872
16878
  const matcher = createLogMatcher(loggingOptions);
16873
16879
  const filename = context.filename;
@@ -18652,6 +18658,7 @@ var no_raw_fetch_outside_clients_default = createRule({
18652
18658
  name: "no-raw-fetch-outside-clients",
18653
18659
  documentation: NO_RAW_FETCH_OUTSIDE_CLIENTS_DOCUMENTATION,
18654
18660
  meta: {
18661
+ defaultOptions: [{}],
18655
18662
  type: "problem",
18656
18663
  docs: {
18657
18664
  description: "Disallow calling the global `fetch` outside the client layer; route outbound HTTP through a client module that owns retry, timeout and status handling."
@@ -18666,6 +18673,7 @@ var no_raw_fetch_outside_clients_default = createRule({
18666
18673
  description: "Regular-expression sources matched against the filename. Replaces the defaults."
18667
18674
  },
18668
18675
  basePath: {
18676
+ description: "Static application URL base path without query strings, fragments or parent segments.",
18669
18677
  type: "string",
18670
18678
  pattern: "^/(?!$)(?!.*[?#])(?!(?:.*/)?\\.\\.?(?:/|$))(?:[^/]+/)*[^/]+$"
18671
18679
  }
@@ -18677,7 +18685,6 @@ var no_raw_fetch_outside_clients_default = createRule({
18677
18685
  rawFetch: "Raw `fetch()` outside a client module. Route the call through a client (e.g. `clients/*-client.ts`) so it inherits retry, timeout and status handling and stays stubbable in tests."
18678
18686
  }
18679
18687
  },
18680
- defaultOptions: [{}],
18681
18688
  create(context, [options]) {
18682
18689
  const filename = context.filename;
18683
18690
  if (isTestFile(context) || isScriptFile(context) || NON_PRODUCTION_TREE_RE.test(filename)) {
@@ -18843,6 +18850,7 @@ var no_restricted_library_load_default = createRule({
18843
18850
  name: "no-restricted-library-load",
18844
18851
  documentation: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION,
18845
18852
  meta: {
18853
+ defaultOptions: [{ libraries: [] }],
18846
18854
  type: "problem",
18847
18855
  docs: {
18848
18856
  description: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION.summary
@@ -18854,6 +18862,7 @@ var no_restricted_library_load_default = createRule({
18854
18862
  required: ["libraries"],
18855
18863
  properties: {
18856
18864
  libraries: {
18865
+ description: "Library import and module-load restrictions.",
18857
18866
  type: "array",
18858
18867
  items: {
18859
18868
  type: "object",
@@ -18874,7 +18883,6 @@ var no_restricted_library_load_default = createRule({
18874
18883
  restrictedLibraryLoad: "{{id}}: Replace this runtime dependency reference to {{module}} with {{replacement}}.{{note}}"
18875
18884
  }
18876
18885
  },
18877
- defaultOptions: [{ libraries: [] }],
18878
18886
  create(context, [options]) {
18879
18887
  const restrictions = options.libraries;
18880
18888
  function report2(node, source) {
@@ -19852,6 +19860,7 @@ var no_secret_in_log_default = createRule({
19852
19860
  name: "no-secret-in-log",
19853
19861
  documentation: NO_SECRET_IN_LOG_DOCUMENTATION,
19854
19862
  meta: {
19863
+ defaultOptions: [{}],
19855
19864
  type: "problem",
19856
19865
  docs: {
19857
19866
  description: "Disallow passing a secret-named value or a raw request/response blob to a logging call; both leak to log sinks. Redact or omit."
@@ -19868,7 +19877,6 @@ var no_secret_in_log_default = createRule({
19868
19877
  noRawBodyInLog: "Raw `{{name}}` passed to a logging call. Request/response bodies can contain personal data or credentials. Log allowlisted non-sensitive context or use an approved redactor."
19869
19878
  }
19870
19879
  },
19871
- defaultOptions: [{}],
19872
19880
  create(context, [loggingOptions]) {
19873
19881
  const matcher = createLogMatcher(loggingOptions);
19874
19882
  const blobArmApplies = !isTestFile(context);
@@ -20899,6 +20907,7 @@ var no_sentinel_return_on_catch_default = createRule({
20899
20907
  name: "no-sentinel-return-on-catch",
20900
20908
  documentation: NO_SENTINEL_RETURN_ON_CATCH_DOCUMENTATION,
20901
20909
  meta: {
20910
+ defaultOptions: [{}],
20902
20911
  type: "problem",
20903
20912
  docs: {
20904
20913
  description: "Disallow swallowing a caught error by returning an empty sentinel unless the error is handled or the sentinel is part of the function contract."
@@ -20914,7 +20923,6 @@ var no_sentinel_return_on_catch_default = createRule({
20914
20923
  noSentinelReturn: "This `catch` block swallows the error by returning an empty sentinel without logging it. Rethrow it, log/report it, or return a typed Result."
20915
20924
  }
20916
20925
  },
20917
- defaultOptions: [{}],
20918
20926
  create(context, [loggingOptions]) {
20919
20927
  if (isGeneratedFile(context, context.sourceCode.text)) {
20920
20928
  return {};
@@ -21461,6 +21469,7 @@ var no_storage_in_stateless_modules_default = createRule({
21461
21469
  name: "no-storage-in-stateless-modules",
21462
21470
  documentation: NO_STORAGE_IN_STATELESS_MODULES_DOCUMENTATION,
21463
21471
  meta: {
21472
+ defaultOptions: [{}],
21464
21473
  type: "problem",
21465
21474
  docs: {
21466
21475
  description: "Disallow SQL or key/value access inside configured stateless modules; derive state from a system of record instead."
@@ -21487,7 +21496,6 @@ var no_storage_in_stateless_modules_default = createRule({
21487
21496
  storageInStatelessModule: "`{{method}}()` reaches for private storage inside a module declared stateless. Derive the state from a read against the system of record, or from a marker in the artefact this feature already produces."
21488
21497
  }
21489
21498
  },
21490
- defaultOptions: [{}],
21491
21499
  create(context, [options]) {
21492
21500
  if (isTestFile(context)) {
21493
21501
  return {};
@@ -23080,6 +23088,7 @@ var no_declaration_comment_wall_default = createRule({
23080
23088
  name: "no-declaration-comment-wall",
23081
23089
  documentation: NO_DECLARATION_COMMENT_WALL_DOCUMENTATION,
23082
23090
  meta: {
23091
+ defaultOptions: [WALL_DEFAULTS],
23083
23092
  type: "suggestion",
23084
23093
  fixable: "code",
23085
23094
  docs: {
@@ -23090,7 +23099,6 @@ var no_declaration_comment_wall_default = createRule({
23090
23099
  commentWall: "{{restated}} of this declaration's {{commented}} member comments only re-spell member names \u2014 delete them; if a row still needs narration, give the member a clearer name. Keep constraints, lifecycle, and rationale."
23091
23100
  }
23092
23101
  },
23093
- defaultOptions: [WALL_DEFAULTS],
23094
23102
  create(context, [provided]) {
23095
23103
  const options = { ...WALL_DEFAULTS, ...provided };
23096
23104
  const sourceCode = context.sourceCode;
@@ -23442,6 +23450,7 @@ var no_type_member_comment_wall_default = createRule({
23442
23450
  name: "no-type-member-comment-wall",
23443
23451
  documentation: NO_TYPE_MEMBER_COMMENT_WALL_DOCUMENTATION,
23444
23452
  meta: {
23453
+ defaultOptions: [WALL_DEFAULTS],
23445
23454
  type: "suggestion",
23446
23455
  fixable: "code",
23447
23456
  docs: {
@@ -23452,7 +23461,6 @@ var no_type_member_comment_wall_default = createRule({
23452
23461
  commentWall: "{{restated}} of this type's {{commented}} member comments appear to repeat names and types \u2014 review them for removal or clearer naming. Keep constraints and rationale."
23453
23462
  }
23454
23463
  },
23455
- defaultOptions: [WALL_DEFAULTS],
23456
23464
  create(context, [provided]) {
23457
23465
  const options = { ...WALL_DEFAULTS, ...provided };
23458
23466
  const sourceCode = context.sourceCode;
@@ -24011,12 +24019,12 @@ var no_first_party_module_mock_default = createRule({
24011
24019
  name: "no-first-party-module-mock",
24012
24020
  documentation: NO_FIRST_PARTY_MODULE_MOCK_DOCUMENTATION,
24013
24021
  meta: {
24022
+ defaultOptions: [{ additionalModulePrefixes: [] }],
24014
24023
  type: "problem",
24015
24024
  docs: { description: NO_FIRST_PARTY_MODULE_MOCK_DOCUMENTATION.summary },
24016
- schema: [{ type: "object", additionalProperties: false, properties: { additionalModulePrefixes: { type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true } } }],
24025
+ schema: [{ type: "object", additionalProperties: false, properties: { additionalModulePrefixes: { description: "Additional maintained module prefixes that tests must not mock.", type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true } } }],
24017
24026
  messages: { noFirstPartyModuleMock: "This test replaces the maintained module `{{module}}`. Inject a narrow collaborator or test the real module; suppress locally only when module lookup or bootstrap behavior is the contract." }
24018
24027
  },
24019
- defaultOptions: [{ additionalModulePrefixes: [] }],
24020
24028
  create(context, [options]) {
24021
24029
  if (!isTestFile(context) || isGeneratedFile(context, context.sourceCode.text)) return {};
24022
24030
  return {
@@ -26227,6 +26235,7 @@ var prefer_shadcn_primitives_default = createRule({
26227
26235
  name: "prefer-shadcn-primitives",
26228
26236
  documentation: PREFER_SHADCN_PRIMITIVES_DOCUMENTATION,
26229
26237
  meta: {
26238
+ defaultOptions: [{}],
26230
26239
  type: "suggestion",
26231
26240
  docs: {
26232
26241
  description: "Require visible raw JSX controls to use the corresponding shared shadcn primitive."
@@ -26235,8 +26244,8 @@ var prefer_shadcn_primitives_default = createRule({
26235
26244
  {
26236
26245
  type: "object",
26237
26246
  properties: {
26238
- assumeAvailable: { type: "boolean" },
26239
- detectProjectPrimitives: { type: "boolean" }
26247
+ assumeAvailable: { description: "Assume supported shared UI primitives are available in this project.", type: "boolean" },
26248
+ detectProjectPrimitives: { description: "Resolve project-owned UI primitives before recommending replacements.", type: "boolean" }
26240
26249
  },
26241
26250
  additionalProperties: false
26242
26251
  }
@@ -26245,7 +26254,6 @@ var prefer_shadcn_primitives_default = createRule({
26245
26254
  preferShadcnPrimitive: "Use the shared {{ replacement }} shadcn primitive instead of raw <{{ element }}> markup."
26246
26255
  }
26247
26256
  },
26248
- defaultOptions: [{}],
26249
26257
  create(context, [options]) {
26250
26258
  const filename = context.filename.replaceAll("\\", "/");
26251
26259
  if (isTestFile(context) || isStoryFile(context) || isGeneratedFile(context, context.sourceCode.text) || SHARED_PRIMITIVE_IMPLEMENTATION_RE.test(filename)) {
@@ -26622,6 +26630,7 @@ var prefer_module_level_constant_default = createRule({
26622
26630
  name: "prefer-module-level-constant",
26623
26631
  documentation: PREFER_MODULE_LEVEL_CONSTANT_DOCUMENTATION,
26624
26632
  meta: {
26633
+ defaultOptions: [{}],
26625
26634
  type: "suggestion",
26626
26635
  fixable: "code",
26627
26636
  docs: {
@@ -26632,9 +26641,9 @@ var prefer_module_level_constant_default = createRule({
26632
26641
  type: "object",
26633
26642
  additionalProperties: false,
26634
26643
  properties: {
26635
- minElements: { type: "number", minimum: 1 },
26636
- checkRegex: { type: "boolean" },
26637
- ignoreTestFiles: { type: "boolean" }
26644
+ minElements: { description: "Minimum collection size before recommending a module-level constant.", type: "number", minimum: 1 },
26645
+ checkRegex: { description: "Include reusable regular expression literals in hoisting checks.", type: "boolean" },
26646
+ ignoreTestFiles: { description: "Skip test files when recommending module-level constants.", type: "boolean" }
26638
26647
  }
26639
26648
  }
26640
26649
  ],
@@ -26643,7 +26652,6 @@ var prefer_module_level_constant_default = createRule({
26643
26652
  hoistRegex: "`{{name}}` is a constant regex recompiled on every call. Hoist it to module scope."
26644
26653
  }
26645
26654
  },
26646
- defaultOptions: [{}],
26647
26655
  create(context, [optionsArg]) {
26648
26656
  const options = optionsArg ?? {};
26649
26657
  const minElements = options.minElements ?? DEFAULT_MIN_ELEMENTS;
@@ -26952,6 +26960,7 @@ var prefer_module_level_schema_default = createRule({
26952
26960
  name: "prefer-module-level-schema",
26953
26961
  documentation: PREFER_MODULE_LEVEL_SCHEMA_DOCUMENTATION,
26954
26962
  meta: {
26963
+ defaultOptions: [{}],
26955
26964
  type: "problem",
26956
26965
  docs: {
26957
26966
  description: "Declare a Zod schema at module scope when it closes over nothing in the enclosing function"
@@ -26987,7 +26996,6 @@ var prefer_module_level_schema_default = createRule({
26987
26996
  hoistSchema: "Move this `{{factory}}` schema to module scope. It uses nothing from `{{owner}}`, so it is rebuilt on every call for no benefit and cannot be exported, reused, or `z.infer`-ed from where it is."
26988
26997
  }
26989
26998
  },
26990
- defaultOptions: [{}],
26991
26999
  create(context, [options]) {
26992
27000
  const factories = new Set(options?.factories ?? DEFAULT_FACTORIES);
26993
27001
  const ignoreTestFiles = options?.ignoreTestFiles ?? true;
@@ -27640,6 +27648,7 @@ var prefer_multi_value_zod_literal_default = createRule({
27640
27648
  name: "prefer-multi-value-zod-literal",
27641
27649
  documentation: PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION,
27642
27650
  meta: {
27651
+ defaultOptions: [{}],
27643
27652
  type: "suggestion",
27644
27653
  docs: {
27645
27654
  description: "Use the Zod 4 multi-value literal API instead of a union of literal schemas."
@@ -27649,7 +27658,7 @@ var prefer_multi_value_zod_literal_default = createRule({
27649
27658
  type: "object",
27650
27659
  additionalProperties: false,
27651
27660
  properties: {
27652
- zodMajorVersion: { type: "integer", minimum: 4, maximum: 4 }
27661
+ zodMajorVersion: { description: "Installed Zod major version used to validate multi-value literal support.", type: "integer", minimum: 4, maximum: 4 }
27653
27662
  }
27654
27663
  }
27655
27664
  ],
@@ -27657,7 +27666,6 @@ var prefer_multi_value_zod_literal_default = createRule({
27657
27666
  useMultiValueLiteral: "Replace this literal-schema union with {{zod}}.literal([\u2026])."
27658
27667
  }
27659
27668
  },
27660
- defaultOptions: [{}],
27661
27669
  create(context, [options]) {
27662
27670
  if (isTestFile(context) || isGeneratedFile(context, context.sourceCode.text))
27663
27671
  return {};
@@ -29732,13 +29740,14 @@ var prefer_await_in_async_return_default = createRule({
29732
29740
  name: "prefer-await-in-async-return",
29733
29741
  documentation: PREFER_AWAIT_IN_ASYNC_RETURN_DOCUMENTATION,
29734
29742
  meta: {
29743
+ defaultOptions: [{ scope: "async-return" }],
29735
29744
  type: "suggestion",
29736
29745
  docs: {
29737
29746
  description: "Prefer explicit `await` for proven Promise `.then` calls; the default scope checks direct async returns."
29738
29747
  },
29739
29748
  schema: [{
29740
29749
  type: "object",
29741
- properties: { scope: { type: "string", enum: ["async-return", "all-promise-calls"] } },
29750
+ properties: { scope: { description: "Check async return statements or every promise-valued call.", type: "string", enum: ["async-return", "all-promise-calls"] } },
29742
29751
  additionalProperties: false
29743
29752
  }],
29744
29753
  messages: {
@@ -29746,7 +29755,6 @@ var prefer_await_in_async_return_default = createRule({
29746
29755
  preferAwaitCall: "This call uses built-in Promise.then(). Use async/await, preserving rejection handling and observable scheduling when rewriting."
29747
29756
  }
29748
29757
  },
29749
- defaultOptions: [{ scope: "async-return" }],
29750
29758
  create(context, [options]) {
29751
29759
  let services;
29752
29760
  try {
@@ -30960,6 +30968,7 @@ var prefer_semantic_colors_default = createRule({
30960
30968
  name: "prefer-semantic-colors",
30961
30969
  documentation: PREFER_SEMANTIC_COLORS_DOCUMENTATION,
30962
30970
  meta: {
30971
+ defaultOptions: [{}],
30963
30972
  type: "suggestion",
30964
30973
  docs: {
30965
30974
  description: "Enforce semantic color tokens over raw Tailwind palette classes, arbitrary color values, and inline color literals."
@@ -30969,8 +30978,8 @@ var prefer_semantic_colors_default = createRule({
30969
30978
  type: "object",
30970
30979
  additionalProperties: false,
30971
30980
  properties: {
30972
- requireSemanticTokens: { type: "boolean" },
30973
- opaqueForegroundPairs: { type: "boolean" }
30981
+ requireSemanticTokens: { description: "Restrict checks to projects with an existing semantic token system.", type: "boolean" },
30982
+ opaqueForegroundPairs: { description: "Use the project semantic foreground roles to check opaque foreground and background pairs.", type: "boolean" }
30974
30983
  }
30975
30984
  }
30976
30985
  ],
@@ -30981,7 +30990,6 @@ var prefer_semantic_colors_default = createRule({
30981
30990
  opaqueForegroundPair: "'{{class}}' bypasses the declared '{{replacement}}' token paired with '{{background}}'."
30982
30991
  }
30983
30992
  },
30984
- defaultOptions: [{}],
30985
30993
  create(context, [options]) {
30986
30994
  if (STORIES_FILE_RE.test(context.filename)) return {};
30987
30995
  if (staticallyImportsExternalRenderer(context.sourceCode.ast)) return {};
@@ -31283,6 +31291,7 @@ var prefer_server_actions_default = createRule({
31283
31291
  name: "prefer-server-actions",
31284
31292
  documentation: PREFER_SERVER_ACTIONS_DOCUMENTATION,
31285
31293
  meta: {
31294
+ defaultOptions: [{}],
31286
31295
  type: "suggestion",
31287
31296
  docs: {
31288
31297
  description: "Prefer Next.js Server Actions over same-origin API mutations."
@@ -31293,6 +31302,7 @@ var prefer_server_actions_default = createRule({
31293
31302
  additionalProperties: false,
31294
31303
  properties: {
31295
31304
  basePath: {
31305
+ description: "Static application URL base path without query strings, fragments or parent segments.",
31296
31306
  type: "string",
31297
31307
  pattern: "^/(?!$)(?!.*[?#])(?!(?:.*/)?\\.\\.?(?:/|$))(?:[^/]+/)*[^/]+$"
31298
31308
  }
@@ -31303,7 +31313,6 @@ var prefer_server_actions_default = createRule({
31303
31313
  preferServerAction: "This client mutation targets a same-origin API route. Consider a Server Action to remove the hand-written API wrapper; retain authorization and validation, since the call still crosses a network boundary."
31304
31314
  }
31305
31315
  },
31306
- defaultOptions: [{}],
31307
31316
  create(context, [options]) {
31308
31317
  const filename = context.filename.replaceAll("\\", "/");
31309
31318
  if (SKIP_FILE_REGEX.test(filename)) {
@@ -32317,6 +32326,7 @@ var prefer_zod_infer_default = createRule({
32317
32326
  name: "prefer-zod-infer",
32318
32327
  documentation: PREFER_ZOD_INFER_DOCUMENTATION,
32319
32328
  meta: {
32329
+ defaultOptions: [{}],
32320
32330
  type: "problem",
32321
32331
  fixable: "code",
32322
32332
  docs: {
@@ -32328,10 +32338,11 @@ var prefer_zod_infer_default = createRule({
32328
32338
  additionalProperties: false,
32329
32339
  properties: {
32330
32340
  ignoreTypeNames: {
32341
+ description: "Regular expression patterns for type names to leave unchanged.",
32331
32342
  type: "array",
32332
32343
  items: { type: "string" }
32333
32344
  },
32334
- requireIdenticalShape: { type: "boolean" }
32345
+ requireIdenticalShape: { description: "Require the schema output and declared type to have identical property shapes.", type: "boolean" }
32335
32346
  }
32336
32347
  }
32337
32348
  ],
@@ -32340,7 +32351,6 @@ var prefer_zod_infer_default = createRule({
32340
32351
  repeatedEnumUnion: "`{{propertyName}}` repeats the literal domain already named by `{{typeName}}` and `{{schemaName}}` in multiple object types. Reuse `{{typeName}}` so the accepted values have one source of truth."
32341
32352
  }
32342
32353
  },
32343
- defaultOptions: [{}],
32344
32354
  create(context, [optionsArg]) {
32345
32355
  const ignorePatterns = (optionsArg?.ignoreTypeNames ?? []).map(
32346
32356
  (source) => new RegExp(source, "u")
@@ -33679,6 +33689,7 @@ var require_fetch_timeout_default = createRule({
33679
33689
  name: "require-fetch-timeout",
33680
33690
  documentation: REQUIRE_FETCH_TIMEOUT_DOCUMENTATION,
33681
33691
  meta: {
33692
+ defaultOptions: [{}],
33682
33693
  type: "problem",
33683
33694
  docs: {
33684
33695
  description: "Require an explicit abort signal on locally analyzable global fetch calls."
@@ -33700,7 +33711,6 @@ var require_fetch_timeout_default = createRule({
33700
33711
  missingSignal: "This `fetch()` has no explicit abort signal. Pass `AbortSignal.timeout(ms)` for a deadline, or an owner-managed signal for cancellation."
33701
33712
  }
33702
33713
  },
33703
- defaultOptions: [{}],
33704
33714
  create(context, [optionsArg]) {
33705
33715
  if (isTestFile(context) || isScriptFile(context)) {
33706
33716
  return {};
@@ -35802,6 +35812,7 @@ var stepdown_default = createRule({
35802
35812
  name: "stepdown",
35803
35813
  documentation: STEPDOWN_DOCUMENTATION,
35804
35814
  meta: {
35815
+ defaultOptions: [{}],
35805
35816
  type: "suggestion",
35806
35817
  fixable: "code",
35807
35818
  docs: {
@@ -35823,7 +35834,6 @@ var stepdown_default = createRule({
35823
35834
  helperAboveOnlyCaller: "Private helper `{{helper}}` is defined above its only caller `{{caller}}`; move it below the caller."
35824
35835
  }
35825
35836
  },
35826
- defaultOptions: [{}],
35827
35837
  create(context, [options]) {
35828
35838
  if (isTestFile(context) || isGeneratedFile(context, context.sourceCode.text))
35829
35839
  return {};
package/dist/index.js CHANGED
@@ -1025,13 +1025,13 @@ var no_test_comments_default = createRule({
1025
1025
  name: "no-test-comments",
1026
1026
  documentation: NO_TEST_COMMENTS_DOCUMENTATION,
1027
1027
  meta: {
1028
+ defaultOptions: [{}],
1028
1029
  type: "suggestion",
1029
1030
  fixable: "code",
1030
1031
  docs: { description: NO_TEST_COMMENTS_DOCUMENTATION.summary },
1031
- schema: [{ type: "object", properties: { allFiles: { type: "boolean" } }, additionalProperties: false }],
1032
+ schema: [{ type: "object", properties: { allFiles: { description: "Check every eligible test file without requiring frontend framework ownership.", type: "boolean" } }, additionalProperties: false }],
1032
1033
  messages: { testComment: "Express this explanation in the test name, fixture or assertion, then remove the comment." }
1033
1034
  },
1034
- defaultOptions: [{}],
1035
1035
  create(context, [options]) {
1036
1036
  if (!isTestFile(context) || isGeneratedFile(context, context.sourceCode.text)) return {};
1037
1037
  if (!ownsTestComments(context)) return {};
@@ -1120,13 +1120,13 @@ var no_frontend_comments_default = createRule({
1120
1120
  name: "no-frontend-comments",
1121
1121
  documentation: NO_FRONTEND_COMMENTS_DOCUMENTATION,
1122
1122
  meta: {
1123
+ defaultOptions: [{}],
1123
1124
  type: "suggestion",
1124
1125
  fixable: "code",
1125
1126
  docs: { description: NO_FRONTEND_COMMENTS_DOCUMENTATION.summary },
1126
- schema: [{ type: "object", properties: { allFiles: { type: "boolean" } }, additionalProperties: false }],
1127
+ schema: [{ type: "object", properties: { allFiles: { description: "Check comments without requiring frontend framework ownership.", type: "boolean" } }, additionalProperties: false }],
1127
1128
  messages: { noFrontendComments: "Frontend comments are prohibited; express the behavior in names, types or code and review any directive or legal contract before removing it." }
1128
1129
  },
1129
- defaultOptions: [{}],
1130
1130
  create(context, [options]) {
1131
1131
  if (isGeneratedFile(context, context.sourceCode.text) || ownsTestComments(context)) return {};
1132
1132
  const jsxRanges = [];
@@ -4781,7 +4781,7 @@ function isSearchParamReceiver(call, services) {
4781
4781
  // package.json
4782
4782
  var package_default = {
4783
4783
  name: "@sarj/eslint-plugin",
4784
- version: "17.1.2",
4784
+ version: "17.1.3",
4785
4785
  packageManager: "npm@12.2.1",
4786
4786
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
4787
4787
  type: "module",
@@ -4855,6 +4855,7 @@ var package_default = {
4855
4855
  "@vitest/eslint-plugin": "1.6.28",
4856
4856
  eslint: "10.13.0",
4857
4857
  "eslint-node-test": "1.0.1",
4858
+ "eslint-plugin-eslint-plugin": "7.6.2",
4858
4859
  "eslint-plugin-better-tailwindcss": "^4.10.0",
4859
4860
  "eslint-plugin-jest": "29.17.0",
4860
4861
  "eslint-plugin-jsdoc": "65.4.2",
@@ -4875,6 +4876,7 @@ var package_default = {
4875
4876
  jiti: "2.7.0",
4876
4877
  prettier: "3.9.10",
4877
4878
  tsup: "9.0.0",
4879
+ syncpack: "15.3.3",
4878
4880
  typescript: "npm:@typescript/typescript6@6.0.2",
4879
4881
  "typescript-eslint": "^8.72.0",
4880
4882
  uuid: "13.0.0",
@@ -9122,6 +9124,7 @@ var require_button_accessible_name_default = createRule({
9122
9124
  name: "require-button-accessible-name",
9123
9125
  documentation: REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION,
9124
9126
  meta: {
9127
+ defaultOptions: [{}],
9125
9128
  type: "problem",
9126
9129
  docs: { description: REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION.summary },
9127
9130
  schema: [
@@ -9130,6 +9133,7 @@ var require_button_accessible_name_default = createRule({
9130
9133
  properties: {
9131
9134
  components: COMPONENT_IMPORT_SCHEMA,
9132
9135
  iconModules: {
9136
+ description: "Module names whose imported components count as icons.",
9133
9137
  type: "array",
9134
9138
  items: { type: "string", minLength: 1 },
9135
9139
  uniqueItems: true
@@ -9142,7 +9146,6 @@ var require_button_accessible_name_default = createRule({
9142
9146
  missingName: "This button has no statically identifiable accessible name. Add action text, aria-label, or aria-labelledby."
9143
9147
  }
9144
9148
  },
9145
- defaultOptions: [{}],
9146
9149
  create(context, [options]) {
9147
9150
  if (isGeneratedFile(context, context.sourceCode.text) || isTestFile(context) || isStoryFile(context))
9148
9151
  return {};
@@ -9461,6 +9464,7 @@ var prefer_logical_tailwind_utilities_default = createRule({
9461
9464
  name: "prefer-logical-tailwind-utilities",
9462
9465
  documentation: PREFER_LOGICAL_TAILWIND_UTILITIES_DOCUMENTATION,
9463
9466
  meta: {
9467
+ defaultOptions: [{ enabled: true, checkInsets: false, allowUtilities: [] }],
9464
9468
  type: "suggestion",
9465
9469
  docs: {
9466
9470
  description: PREFER_LOGICAL_TAILWIND_UTILITIES_DOCUMENTATION.summary
@@ -9469,9 +9473,10 @@ var prefer_logical_tailwind_utilities_default = createRule({
9469
9473
  {
9470
9474
  type: "object",
9471
9475
  properties: {
9472
- enabled: { type: "boolean" },
9473
- checkInsets: { type: "boolean" },
9476
+ enabled: { description: "Enable replacement of physical direction utilities with logical equivalents.", type: "boolean" },
9477
+ checkInsets: { description: "Include physical inset utilities in direction checks.", type: "boolean" },
9474
9478
  allowUtilities: {
9479
+ description: "Physical utility names allowed without a logical replacement.",
9475
9480
  type: "array",
9476
9481
  items: { type: "string" },
9477
9482
  uniqueItems: true
@@ -9484,7 +9489,6 @@ var prefer_logical_tailwind_utilities_default = createRule({
9484
9489
  physicalUtility: "Use '{{replacement}}' instead of '{{utility}}' in this bidirectional UI, or explicitly allow intentional physical placement."
9485
9490
  }
9486
9491
  },
9487
- defaultOptions: [{ enabled: true, checkInsets: false, allowUtilities: [] }],
9488
9492
  create(context, [options]) {
9489
9493
  if (options?.enabled === false || isGeneratedFile(context, context.sourceCode.text) || isTestFile(context) || isStoryFile(context))
9490
9494
  return {};
@@ -9612,6 +9616,7 @@ var no_unlocalized_toast_default = createRule({
9612
9616
  name: "no-unlocalized-toast",
9613
9617
  documentation: NO_UNLOCALIZED_TOAST_DOCUMENTATION,
9614
9618
  meta: {
9619
+ defaultOptions: [{ enabled: true }],
9615
9620
  type: "suggestion",
9616
9621
  docs: { description: NO_UNLOCALIZED_TOAST_DOCUMENTATION.summary },
9617
9622
  schema: [
@@ -9621,6 +9626,7 @@ var no_unlocalized_toast_default = createRule({
9621
9626
  ...LOCALIZATION_PROPERTIES,
9622
9627
  functions: COMPONENT_IMPORT_SCHEMA,
9623
9628
  methods: {
9629
+ description: "Toast method names whose user-visible messages require localization.",
9624
9630
  type: "array",
9625
9631
  items: { type: "string", minLength: 1 },
9626
9632
  uniqueItems: true
@@ -9633,7 +9639,6 @@ var no_unlocalized_toast_default = createRule({
9633
9639
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9634
9640
  }
9635
9641
  },
9636
- defaultOptions: [{ enabled: true }],
9637
9642
  create(context, [options]) {
9638
9643
  if (localizationExcluded(context, context.sourceCode.text, options))
9639
9644
  return {};
@@ -9725,6 +9730,7 @@ var no_unlocalized_jsx_attributes_default = createRule({
9725
9730
  name: "no-unlocalized-jsx-attributes",
9726
9731
  documentation: NO_UNLOCALIZED_JSX_ATTRIBUTES_DOCUMENTATION,
9727
9732
  meta: {
9733
+ defaultOptions: [{ enabled: true }],
9728
9734
  type: "suggestion",
9729
9735
  docs: { description: NO_UNLOCALIZED_JSX_ATTRIBUTES_DOCUMENTATION.summary },
9730
9736
  schema: [
@@ -9733,6 +9739,7 @@ var no_unlocalized_jsx_attributes_default = createRule({
9733
9739
  properties: {
9734
9740
  ...LOCALIZATION_PROPERTIES,
9735
9741
  attributes: {
9742
+ description: "JSX attributes whose user-visible text requires localization.",
9736
9743
  type: "array",
9737
9744
  items: { type: "string", minLength: 1 },
9738
9745
  uniqueItems: true
@@ -9745,7 +9752,6 @@ var no_unlocalized_jsx_attributes_default = createRule({
9745
9752
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9746
9753
  }
9747
9754
  },
9748
- defaultOptions: [{ enabled: true }],
9749
9755
  create(context, [options]) {
9750
9756
  if (localizationExcluded(context, context.sourceCode.text, options))
9751
9757
  return {};
@@ -9810,6 +9816,7 @@ var no_unlocalized_jsx_text_default = createRule({
9810
9816
  name: "no-unlocalized-jsx-text",
9811
9817
  documentation: NO_UNLOCALIZED_JSX_TEXT_DOCUMENTATION,
9812
9818
  meta: {
9819
+ defaultOptions: [{ enabled: true }],
9813
9820
  type: "suggestion",
9814
9821
  docs: { description: NO_UNLOCALIZED_JSX_TEXT_DOCUMENTATION.summary },
9815
9822
  schema: [
@@ -9823,7 +9830,6 @@ var no_unlocalized_jsx_text_default = createRule({
9823
9830
  unlocalized: "Translate this user-facing literal or add an explicit localization exception."
9824
9831
  }
9825
9832
  },
9826
- defaultOptions: [{ enabled: true }],
9827
9833
  create(context, [options]) {
9828
9834
  if (localizationExcluded(context, context.sourceCode.text, options))
9829
9835
  return {};
@@ -12607,6 +12613,7 @@ var no_dynamic_sql_default = createRule({
12607
12613
  name: "no-dynamic-sql",
12608
12614
  documentation: NO_DYNAMIC_SQL_DOCUMENTATION,
12609
12615
  meta: {
12616
+ defaultOptions: [{}],
12610
12617
  type: "problem",
12611
12618
  docs: {
12612
12619
  description: NO_DYNAMIC_SQL_DOCUMENTATION.summary
@@ -12629,7 +12636,6 @@ var no_dynamic_sql_default = createRule({
12629
12636
  dynamicFragment: "Runtime fragment interpolated into SQL passed to `{{method}}()`. Bind data values; select non-bindable SQL fragments from fixed, reviewed alternatives."
12630
12637
  }
12631
12638
  },
12632
- defaultOptions: [{}],
12633
12639
  create(context, [options]) {
12634
12640
  const methods = new Set(options?.methods ?? DEFAULT_METHODS);
12635
12641
  return {
@@ -12701,6 +12707,7 @@ var no_enum_default = createRule({
12701
12707
  name: "no-enum",
12702
12708
  documentation: NO_ENUM_DOCUMENTATION,
12703
12709
  meta: {
12710
+ defaultOptions: [{}],
12704
12711
  type: "suggestion",
12705
12712
  fixable: "code",
12706
12713
  docs: {
@@ -12723,7 +12730,6 @@ var no_enum_default = createRule({
12723
12730
  noEnum: 'Enums are discouraged. Use a string-literal union (e.g. `type Status = "active" | "inactive"`) or an `as const` object instead.'
12724
12731
  }
12725
12732
  },
12726
- defaultOptions: [{}],
12727
12733
  create(context, [optionsArg]) {
12728
12734
  const options = optionsArg ?? {};
12729
12735
  const ignoreFiles = options.ignoreFiles ?? [];
@@ -13270,6 +13276,7 @@ var no_fat_try_blocks_default = createRule({
13270
13276
  name: "no-fat-try-blocks",
13271
13277
  documentation: NO_FAT_TRY_BLOCKS_DOCUMENTATION,
13272
13278
  meta: {
13279
+ defaultOptions: [{ max: MAX_TRY_BODY_STATEMENTS }],
13273
13280
  type: "problem",
13274
13281
  docs: {
13275
13282
  description: "Review try blocks exceeding the configured count of syntactically selected operations."
@@ -13278,7 +13285,7 @@ var no_fat_try_blocks_default = createRule({
13278
13285
  {
13279
13286
  type: "object",
13280
13287
  properties: {
13281
- max: { type: "integer", minimum: 1 }
13288
+ max: { description: "Maximum number of statements allowed in one try body.", type: "integer", minimum: 1 }
13282
13289
  },
13283
13290
  additionalProperties: false
13284
13291
  }
@@ -13287,7 +13294,6 @@ var no_fat_try_blocks_default = createRule({
13287
13294
  fatTryBlock: "This `try` block has {{count}} syntactically selected operations (max {{max}}). Review whether they share one recovery policy; move unrelated work outside the boundary."
13288
13295
  }
13289
13296
  },
13290
- defaultOptions: [{ max: MAX_TRY_BODY_STATEMENTS }],
13291
13297
  create(context, [options]) {
13292
13298
  if (isGeneratedFile(context, context.sourceCode.text)) {
13293
13299
  return {};
@@ -13438,6 +13444,7 @@ var no_hand_rolled_sleep_default = createRule({
13438
13444
  name: "no-hand-rolled-sleep",
13439
13445
  documentation: NO_HAND_ROLLED_SLEEP_DOCUMENTATION,
13440
13446
  meta: {
13447
+ defaultOptions: [{}],
13441
13448
  type: "problem",
13442
13449
  docs: {
13443
13450
  description: "Disallow uncancellable promisified timers and timeout arms."
@@ -13464,7 +13471,6 @@ var no_hand_rolled_sleep_default = createRule({
13464
13471
  handRolledTimeoutRace: "Hand-rolled timeout arm: when the other promise wins, this timer is never cleared and keeps the event loop alive until it fires. Use `AbortSignal.timeout(ms)` and pass the signal to the operation."
13465
13472
  }
13466
13473
  },
13467
- defaultOptions: [{}],
13468
13474
  create(context, [optionsArg]) {
13469
13475
  const { filename, sourceCode } = context;
13470
13476
  if (isTestFile(context) || isScriptFile(context) || isGeneratedFile(context, sourceCode.getText())) {
@@ -15746,6 +15752,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
15746
15752
  name: "no-impossible-zod-literal-bounds",
15747
15753
  documentation: NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION,
15748
15754
  meta: {
15755
+ defaultOptions: [{}],
15749
15756
  type: "problem",
15750
15757
  docs: {
15751
15758
  description: "Disallow same-chain literal Zod bounds whose accepted set is mathematically empty."
@@ -15766,7 +15773,6 @@ var no_impossible_zod_literal_bounds_default = createRule({
15766
15773
  impossibleBounds: "This Zod {{kind}} schema accepts no values: {{lower}} conflicts with {{upper}}."
15767
15774
  }
15768
15775
  },
15769
- defaultOptions: [{}],
15770
15776
  create(context, [options]) {
15771
15777
  const sourceCode = context.sourceCode;
15772
15778
  if (isTestFile(context) || isGeneratedFile(context, sourceCode.getText())) {
@@ -16812,6 +16818,7 @@ var no_log_only_catch_default = createRule({
16812
16818
  name: "no-log-only-catch",
16813
16819
  documentation: NO_LOG_ONLY_CATCH_DOCUMENTATION,
16814
16820
  meta: {
16821
+ defaultOptions: [{}],
16815
16822
  type: "problem",
16816
16823
  docs: {
16817
16824
  description: "Disallow `catch` clauses that only log (or silently do nothing) and then swallow the error; rethrow or handle it instead."
@@ -16828,7 +16835,6 @@ var no_log_only_catch_default = createRule({
16828
16835
  emptyCatch: "Empty catch silently swallows the error. Rethrow it, handle it, or add a comment explaining why it is safe to ignore."
16829
16836
  }
16830
16837
  },
16831
- defaultOptions: [{}],
16832
16838
  create(context, [loggingOptions]) {
16833
16839
  const matcher = createLogMatcher(loggingOptions);
16834
16840
  const filename = context.filename;
@@ -18613,6 +18619,7 @@ var no_raw_fetch_outside_clients_default = createRule({
18613
18619
  name: "no-raw-fetch-outside-clients",
18614
18620
  documentation: NO_RAW_FETCH_OUTSIDE_CLIENTS_DOCUMENTATION,
18615
18621
  meta: {
18622
+ defaultOptions: [{}],
18616
18623
  type: "problem",
18617
18624
  docs: {
18618
18625
  description: "Disallow calling the global `fetch` outside the client layer; route outbound HTTP through a client module that owns retry, timeout and status handling."
@@ -18627,6 +18634,7 @@ var no_raw_fetch_outside_clients_default = createRule({
18627
18634
  description: "Regular-expression sources matched against the filename. Replaces the defaults."
18628
18635
  },
18629
18636
  basePath: {
18637
+ description: "Static application URL base path without query strings, fragments or parent segments.",
18630
18638
  type: "string",
18631
18639
  pattern: "^/(?!$)(?!.*[?#])(?!(?:.*/)?\\.\\.?(?:/|$))(?:[^/]+/)*[^/]+$"
18632
18640
  }
@@ -18638,7 +18646,6 @@ var no_raw_fetch_outside_clients_default = createRule({
18638
18646
  rawFetch: "Raw `fetch()` outside a client module. Route the call through a client (e.g. `clients/*-client.ts`) so it inherits retry, timeout and status handling and stays stubbable in tests."
18639
18647
  }
18640
18648
  },
18641
- defaultOptions: [{}],
18642
18649
  create(context, [options]) {
18643
18650
  const filename = context.filename;
18644
18651
  if (isTestFile(context) || isScriptFile(context) || NON_PRODUCTION_TREE_RE.test(filename)) {
@@ -18804,6 +18811,7 @@ var no_restricted_library_load_default = createRule({
18804
18811
  name: "no-restricted-library-load",
18805
18812
  documentation: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION,
18806
18813
  meta: {
18814
+ defaultOptions: [{ libraries: [] }],
18807
18815
  type: "problem",
18808
18816
  docs: {
18809
18817
  description: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION.summary
@@ -18815,6 +18823,7 @@ var no_restricted_library_load_default = createRule({
18815
18823
  required: ["libraries"],
18816
18824
  properties: {
18817
18825
  libraries: {
18826
+ description: "Library import and module-load restrictions.",
18818
18827
  type: "array",
18819
18828
  items: {
18820
18829
  type: "object",
@@ -18835,7 +18844,6 @@ var no_restricted_library_load_default = createRule({
18835
18844
  restrictedLibraryLoad: "{{id}}: Replace this runtime dependency reference to {{module}} with {{replacement}}.{{note}}"
18836
18845
  }
18837
18846
  },
18838
- defaultOptions: [{ libraries: [] }],
18839
18847
  create(context, [options]) {
18840
18848
  const restrictions = options.libraries;
18841
18849
  function report2(node, source) {
@@ -19816,6 +19824,7 @@ var no_secret_in_log_default = createRule({
19816
19824
  name: "no-secret-in-log",
19817
19825
  documentation: NO_SECRET_IN_LOG_DOCUMENTATION,
19818
19826
  meta: {
19827
+ defaultOptions: [{}],
19819
19828
  type: "problem",
19820
19829
  docs: {
19821
19830
  description: "Disallow passing a secret-named value or a raw request/response blob to a logging call; both leak to log sinks. Redact or omit."
@@ -19832,7 +19841,6 @@ var no_secret_in_log_default = createRule({
19832
19841
  noRawBodyInLog: "Raw `{{name}}` passed to a logging call. Request/response bodies can contain personal data or credentials. Log allowlisted non-sensitive context or use an approved redactor."
19833
19842
  }
19834
19843
  },
19835
- defaultOptions: [{}],
19836
19844
  create(context, [loggingOptions]) {
19837
19845
  const matcher = createLogMatcher(loggingOptions);
19838
19846
  const blobArmApplies = !isTestFile(context);
@@ -20863,6 +20871,7 @@ var no_sentinel_return_on_catch_default = createRule({
20863
20871
  name: "no-sentinel-return-on-catch",
20864
20872
  documentation: NO_SENTINEL_RETURN_ON_CATCH_DOCUMENTATION,
20865
20873
  meta: {
20874
+ defaultOptions: [{}],
20866
20875
  type: "problem",
20867
20876
  docs: {
20868
20877
  description: "Disallow swallowing a caught error by returning an empty sentinel unless the error is handled or the sentinel is part of the function contract."
@@ -20878,7 +20887,6 @@ var no_sentinel_return_on_catch_default = createRule({
20878
20887
  noSentinelReturn: "This `catch` block swallows the error by returning an empty sentinel without logging it. Rethrow it, log/report it, or return a typed Result."
20879
20888
  }
20880
20889
  },
20881
- defaultOptions: [{}],
20882
20890
  create(context, [loggingOptions]) {
20883
20891
  if (isGeneratedFile(context, context.sourceCode.text)) {
20884
20892
  return {};
@@ -21425,6 +21433,7 @@ var no_storage_in_stateless_modules_default = createRule({
21425
21433
  name: "no-storage-in-stateless-modules",
21426
21434
  documentation: NO_STORAGE_IN_STATELESS_MODULES_DOCUMENTATION,
21427
21435
  meta: {
21436
+ defaultOptions: [{}],
21428
21437
  type: "problem",
21429
21438
  docs: {
21430
21439
  description: "Disallow SQL or key/value access inside configured stateless modules; derive state from a system of record instead."
@@ -21451,7 +21460,6 @@ var no_storage_in_stateless_modules_default = createRule({
21451
21460
  storageInStatelessModule: "`{{method}}()` reaches for private storage inside a module declared stateless. Derive the state from a read against the system of record, or from a marker in the artefact this feature already produces."
21452
21461
  }
21453
21462
  },
21454
- defaultOptions: [{}],
21455
21463
  create(context, [options]) {
21456
21464
  if (isTestFile(context)) {
21457
21465
  return {};
@@ -23044,6 +23052,7 @@ var no_declaration_comment_wall_default = createRule({
23044
23052
  name: "no-declaration-comment-wall",
23045
23053
  documentation: NO_DECLARATION_COMMENT_WALL_DOCUMENTATION,
23046
23054
  meta: {
23055
+ defaultOptions: [WALL_DEFAULTS],
23047
23056
  type: "suggestion",
23048
23057
  fixable: "code",
23049
23058
  docs: {
@@ -23054,7 +23063,6 @@ var no_declaration_comment_wall_default = createRule({
23054
23063
  commentWall: "{{restated}} of this declaration's {{commented}} member comments only re-spell member names \u2014 delete them; if a row still needs narration, give the member a clearer name. Keep constraints, lifecycle, and rationale."
23055
23064
  }
23056
23065
  },
23057
- defaultOptions: [WALL_DEFAULTS],
23058
23066
  create(context, [provided]) {
23059
23067
  const options = { ...WALL_DEFAULTS, ...provided };
23060
23068
  const sourceCode = context.sourceCode;
@@ -23406,6 +23414,7 @@ var no_type_member_comment_wall_default = createRule({
23406
23414
  name: "no-type-member-comment-wall",
23407
23415
  documentation: NO_TYPE_MEMBER_COMMENT_WALL_DOCUMENTATION,
23408
23416
  meta: {
23417
+ defaultOptions: [WALL_DEFAULTS],
23409
23418
  type: "suggestion",
23410
23419
  fixable: "code",
23411
23420
  docs: {
@@ -23416,7 +23425,6 @@ var no_type_member_comment_wall_default = createRule({
23416
23425
  commentWall: "{{restated}} of this type's {{commented}} member comments appear to repeat names and types \u2014 review them for removal or clearer naming. Keep constraints and rationale."
23417
23426
  }
23418
23427
  },
23419
- defaultOptions: [WALL_DEFAULTS],
23420
23428
  create(context, [provided]) {
23421
23429
  const options = { ...WALL_DEFAULTS, ...provided };
23422
23430
  const sourceCode = context.sourceCode;
@@ -23977,12 +23985,12 @@ var no_first_party_module_mock_default = createRule({
23977
23985
  name: "no-first-party-module-mock",
23978
23986
  documentation: NO_FIRST_PARTY_MODULE_MOCK_DOCUMENTATION,
23979
23987
  meta: {
23988
+ defaultOptions: [{ additionalModulePrefixes: [] }],
23980
23989
  type: "problem",
23981
23990
  docs: { description: NO_FIRST_PARTY_MODULE_MOCK_DOCUMENTATION.summary },
23982
- schema: [{ type: "object", additionalProperties: false, properties: { additionalModulePrefixes: { type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true } } }],
23991
+ schema: [{ type: "object", additionalProperties: false, properties: { additionalModulePrefixes: { description: "Additional maintained module prefixes that tests must not mock.", type: "array", items: { type: "string", minLength: 1 }, uniqueItems: true } } }],
23983
23992
  messages: { noFirstPartyModuleMock: "This test replaces the maintained module `{{module}}`. Inject a narrow collaborator or test the real module; suppress locally only when module lookup or bootstrap behavior is the contract." }
23984
23993
  },
23985
- defaultOptions: [{ additionalModulePrefixes: [] }],
23986
23994
  create(context, [options]) {
23987
23995
  if (!isTestFile(context) || isGeneratedFile(context, context.sourceCode.text)) return {};
23988
23996
  return {
@@ -26196,6 +26204,7 @@ var prefer_shadcn_primitives_default = createRule({
26196
26204
  name: "prefer-shadcn-primitives",
26197
26205
  documentation: PREFER_SHADCN_PRIMITIVES_DOCUMENTATION,
26198
26206
  meta: {
26207
+ defaultOptions: [{}],
26199
26208
  type: "suggestion",
26200
26209
  docs: {
26201
26210
  description: "Require visible raw JSX controls to use the corresponding shared shadcn primitive."
@@ -26204,8 +26213,8 @@ var prefer_shadcn_primitives_default = createRule({
26204
26213
  {
26205
26214
  type: "object",
26206
26215
  properties: {
26207
- assumeAvailable: { type: "boolean" },
26208
- detectProjectPrimitives: { type: "boolean" }
26216
+ assumeAvailable: { description: "Assume supported shared UI primitives are available in this project.", type: "boolean" },
26217
+ detectProjectPrimitives: { description: "Resolve project-owned UI primitives before recommending replacements.", type: "boolean" }
26209
26218
  },
26210
26219
  additionalProperties: false
26211
26220
  }
@@ -26214,7 +26223,6 @@ var prefer_shadcn_primitives_default = createRule({
26214
26223
  preferShadcnPrimitive: "Use the shared {{ replacement }} shadcn primitive instead of raw <{{ element }}> markup."
26215
26224
  }
26216
26225
  },
26217
- defaultOptions: [{}],
26218
26226
  create(context, [options]) {
26219
26227
  const filename = context.filename.replaceAll("\\", "/");
26220
26228
  if (isTestFile(context) || isStoryFile(context) || isGeneratedFile(context, context.sourceCode.text) || SHARED_PRIMITIVE_IMPLEMENTATION_RE.test(filename)) {
@@ -26591,6 +26599,7 @@ var prefer_module_level_constant_default = createRule({
26591
26599
  name: "prefer-module-level-constant",
26592
26600
  documentation: PREFER_MODULE_LEVEL_CONSTANT_DOCUMENTATION,
26593
26601
  meta: {
26602
+ defaultOptions: [{}],
26594
26603
  type: "suggestion",
26595
26604
  fixable: "code",
26596
26605
  docs: {
@@ -26601,9 +26610,9 @@ var prefer_module_level_constant_default = createRule({
26601
26610
  type: "object",
26602
26611
  additionalProperties: false,
26603
26612
  properties: {
26604
- minElements: { type: "number", minimum: 1 },
26605
- checkRegex: { type: "boolean" },
26606
- ignoreTestFiles: { type: "boolean" }
26613
+ minElements: { description: "Minimum collection size before recommending a module-level constant.", type: "number", minimum: 1 },
26614
+ checkRegex: { description: "Include reusable regular expression literals in hoisting checks.", type: "boolean" },
26615
+ ignoreTestFiles: { description: "Skip test files when recommending module-level constants.", type: "boolean" }
26607
26616
  }
26608
26617
  }
26609
26618
  ],
@@ -26612,7 +26621,6 @@ var prefer_module_level_constant_default = createRule({
26612
26621
  hoistRegex: "`{{name}}` is a constant regex recompiled on every call. Hoist it to module scope."
26613
26622
  }
26614
26623
  },
26615
- defaultOptions: [{}],
26616
26624
  create(context, [optionsArg]) {
26617
26625
  const options = optionsArg ?? {};
26618
26626
  const minElements = options.minElements ?? DEFAULT_MIN_ELEMENTS;
@@ -26921,6 +26929,7 @@ var prefer_module_level_schema_default = createRule({
26921
26929
  name: "prefer-module-level-schema",
26922
26930
  documentation: PREFER_MODULE_LEVEL_SCHEMA_DOCUMENTATION,
26923
26931
  meta: {
26932
+ defaultOptions: [{}],
26924
26933
  type: "problem",
26925
26934
  docs: {
26926
26935
  description: "Declare a Zod schema at module scope when it closes over nothing in the enclosing function"
@@ -26956,7 +26965,6 @@ var prefer_module_level_schema_default = createRule({
26956
26965
  hoistSchema: "Move this `{{factory}}` schema to module scope. It uses nothing from `{{owner}}`, so it is rebuilt on every call for no benefit and cannot be exported, reused, or `z.infer`-ed from where it is."
26957
26966
  }
26958
26967
  },
26959
- defaultOptions: [{}],
26960
26968
  create(context, [options]) {
26961
26969
  const factories = new Set(options?.factories ?? DEFAULT_FACTORIES);
26962
26970
  const ignoreTestFiles = options?.ignoreTestFiles ?? true;
@@ -27615,6 +27623,7 @@ var prefer_multi_value_zod_literal_default = createRule({
27615
27623
  name: "prefer-multi-value-zod-literal",
27616
27624
  documentation: PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION,
27617
27625
  meta: {
27626
+ defaultOptions: [{}],
27618
27627
  type: "suggestion",
27619
27628
  docs: {
27620
27629
  description: "Use the Zod 4 multi-value literal API instead of a union of literal schemas."
@@ -27624,7 +27633,7 @@ var prefer_multi_value_zod_literal_default = createRule({
27624
27633
  type: "object",
27625
27634
  additionalProperties: false,
27626
27635
  properties: {
27627
- zodMajorVersion: { type: "integer", minimum: 4, maximum: 4 }
27636
+ zodMajorVersion: { description: "Installed Zod major version used to validate multi-value literal support.", type: "integer", minimum: 4, maximum: 4 }
27628
27637
  }
27629
27638
  }
27630
27639
  ],
@@ -27632,7 +27641,6 @@ var prefer_multi_value_zod_literal_default = createRule({
27632
27641
  useMultiValueLiteral: "Replace this literal-schema union with {{zod}}.literal([\u2026])."
27633
27642
  }
27634
27643
  },
27635
- defaultOptions: [{}],
27636
27644
  create(context, [options]) {
27637
27645
  if (isTestFile(context) || isGeneratedFile(context, context.sourceCode.text))
27638
27646
  return {};
@@ -29715,13 +29723,14 @@ var prefer_await_in_async_return_default = createRule({
29715
29723
  name: "prefer-await-in-async-return",
29716
29724
  documentation: PREFER_AWAIT_IN_ASYNC_RETURN_DOCUMENTATION,
29717
29725
  meta: {
29726
+ defaultOptions: [{ scope: "async-return" }],
29718
29727
  type: "suggestion",
29719
29728
  docs: {
29720
29729
  description: "Prefer explicit `await` for proven Promise `.then` calls; the default scope checks direct async returns."
29721
29730
  },
29722
29731
  schema: [{
29723
29732
  type: "object",
29724
- properties: { scope: { type: "string", enum: ["async-return", "all-promise-calls"] } },
29733
+ properties: { scope: { description: "Check async return statements or every promise-valued call.", type: "string", enum: ["async-return", "all-promise-calls"] } },
29725
29734
  additionalProperties: false
29726
29735
  }],
29727
29736
  messages: {
@@ -29729,7 +29738,6 @@ var prefer_await_in_async_return_default = createRule({
29729
29738
  preferAwaitCall: "This call uses built-in Promise.then(). Use async/await, preserving rejection handling and observable scheduling when rewriting."
29730
29739
  }
29731
29740
  },
29732
- defaultOptions: [{ scope: "async-return" }],
29733
29741
  create(context, [options]) {
29734
29742
  let services;
29735
29743
  try {
@@ -30943,6 +30951,7 @@ var prefer_semantic_colors_default = createRule({
30943
30951
  name: "prefer-semantic-colors",
30944
30952
  documentation: PREFER_SEMANTIC_COLORS_DOCUMENTATION,
30945
30953
  meta: {
30954
+ defaultOptions: [{}],
30946
30955
  type: "suggestion",
30947
30956
  docs: {
30948
30957
  description: "Enforce semantic color tokens over raw Tailwind palette classes, arbitrary color values, and inline color literals."
@@ -30952,8 +30961,8 @@ var prefer_semantic_colors_default = createRule({
30952
30961
  type: "object",
30953
30962
  additionalProperties: false,
30954
30963
  properties: {
30955
- requireSemanticTokens: { type: "boolean" },
30956
- opaqueForegroundPairs: { type: "boolean" }
30964
+ requireSemanticTokens: { description: "Restrict checks to projects with an existing semantic token system.", type: "boolean" },
30965
+ opaqueForegroundPairs: { description: "Use the project semantic foreground roles to check opaque foreground and background pairs.", type: "boolean" }
30957
30966
  }
30958
30967
  }
30959
30968
  ],
@@ -30964,7 +30973,6 @@ var prefer_semantic_colors_default = createRule({
30964
30973
  opaqueForegroundPair: "'{{class}}' bypasses the declared '{{replacement}}' token paired with '{{background}}'."
30965
30974
  }
30966
30975
  },
30967
- defaultOptions: [{}],
30968
30976
  create(context, [options]) {
30969
30977
  if (STORIES_FILE_RE.test(context.filename)) return {};
30970
30978
  if (staticallyImportsExternalRenderer(context.sourceCode.ast)) return {};
@@ -31266,6 +31274,7 @@ var prefer_server_actions_default = createRule({
31266
31274
  name: "prefer-server-actions",
31267
31275
  documentation: PREFER_SERVER_ACTIONS_DOCUMENTATION,
31268
31276
  meta: {
31277
+ defaultOptions: [{}],
31269
31278
  type: "suggestion",
31270
31279
  docs: {
31271
31280
  description: "Prefer Next.js Server Actions over same-origin API mutations."
@@ -31276,6 +31285,7 @@ var prefer_server_actions_default = createRule({
31276
31285
  additionalProperties: false,
31277
31286
  properties: {
31278
31287
  basePath: {
31288
+ description: "Static application URL base path without query strings, fragments or parent segments.",
31279
31289
  type: "string",
31280
31290
  pattern: "^/(?!$)(?!.*[?#])(?!(?:.*/)?\\.\\.?(?:/|$))(?:[^/]+/)*[^/]+$"
31281
31291
  }
@@ -31286,7 +31296,6 @@ var prefer_server_actions_default = createRule({
31286
31296
  preferServerAction: "This client mutation targets a same-origin API route. Consider a Server Action to remove the hand-written API wrapper; retain authorization and validation, since the call still crosses a network boundary."
31287
31297
  }
31288
31298
  },
31289
- defaultOptions: [{}],
31290
31299
  create(context, [options]) {
31291
31300
  const filename = context.filename.replaceAll("\\", "/");
31292
31301
  if (SKIP_FILE_REGEX.test(filename)) {
@@ -32300,6 +32309,7 @@ var prefer_zod_infer_default = createRule({
32300
32309
  name: "prefer-zod-infer",
32301
32310
  documentation: PREFER_ZOD_INFER_DOCUMENTATION,
32302
32311
  meta: {
32312
+ defaultOptions: [{}],
32303
32313
  type: "problem",
32304
32314
  fixable: "code",
32305
32315
  docs: {
@@ -32311,10 +32321,11 @@ var prefer_zod_infer_default = createRule({
32311
32321
  additionalProperties: false,
32312
32322
  properties: {
32313
32323
  ignoreTypeNames: {
32324
+ description: "Regular expression patterns for type names to leave unchanged.",
32314
32325
  type: "array",
32315
32326
  items: { type: "string" }
32316
32327
  },
32317
- requireIdenticalShape: { type: "boolean" }
32328
+ requireIdenticalShape: { description: "Require the schema output and declared type to have identical property shapes.", type: "boolean" }
32318
32329
  }
32319
32330
  }
32320
32331
  ],
@@ -32323,7 +32334,6 @@ var prefer_zod_infer_default = createRule({
32323
32334
  repeatedEnumUnion: "`{{propertyName}}` repeats the literal domain already named by `{{typeName}}` and `{{schemaName}}` in multiple object types. Reuse `{{typeName}}` so the accepted values have one source of truth."
32324
32335
  }
32325
32336
  },
32326
- defaultOptions: [{}],
32327
32337
  create(context, [optionsArg]) {
32328
32338
  const ignorePatterns = (optionsArg?.ignoreTypeNames ?? []).map(
32329
32339
  (source) => new RegExp(source, "u")
@@ -33662,6 +33672,7 @@ var require_fetch_timeout_default = createRule({
33662
33672
  name: "require-fetch-timeout",
33663
33673
  documentation: REQUIRE_FETCH_TIMEOUT_DOCUMENTATION,
33664
33674
  meta: {
33675
+ defaultOptions: [{}],
33665
33676
  type: "problem",
33666
33677
  docs: {
33667
33678
  description: "Require an explicit abort signal on locally analyzable global fetch calls."
@@ -33683,7 +33694,6 @@ var require_fetch_timeout_default = createRule({
33683
33694
  missingSignal: "This `fetch()` has no explicit abort signal. Pass `AbortSignal.timeout(ms)` for a deadline, or an owner-managed signal for cancellation."
33684
33695
  }
33685
33696
  },
33686
- defaultOptions: [{}],
33687
33697
  create(context, [optionsArg]) {
33688
33698
  if (isTestFile(context) || isScriptFile(context)) {
33689
33699
  return {};
@@ -35791,6 +35801,7 @@ var stepdown_default = createRule({
35791
35801
  name: "stepdown",
35792
35802
  documentation: STEPDOWN_DOCUMENTATION,
35793
35803
  meta: {
35804
+ defaultOptions: [{}],
35794
35805
  type: "suggestion",
35795
35806
  fixable: "code",
35796
35807
  docs: {
@@ -35812,7 +35823,6 @@ var stepdown_default = createRule({
35812
35823
  helperAboveOnlyCaller: "Private helper `{{helper}}` is defined above its only caller `{{caller}}`; move it below the caller."
35813
35824
  }
35814
35825
  },
35815
- defaultOptions: [{}],
35816
35826
  create(context, [options]) {
35817
35827
  if (isTestFile(context) || isGeneratedFile(context, context.sourceCode.text))
35818
35828
  return {};
@@ -199,7 +199,7 @@ async function verifyRuleExamples(rule, setup = {}) {
199
199
  files: ["**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}"],
200
200
  languageOptions: { parser: exampleParser, parserOptions: { project: tsconfig, tsconfigRootDir: root, disallowAutomaticSingleRunInference: true } },
201
201
  plugins: { "@sarj": { rules: { [spec.ruleId]: rule } } },
202
- rules: { [ruleId]: ["error", ...example.ruleOptions ?? rule.defaultOptions ?? []] }
202
+ rules: { [ruleId]: ["error", ...example.ruleOptions ?? rule.meta.defaultOptions ?? rule.defaultOptions ?? []] }
203
203
  };
204
204
  await verifyExample(new import_eslint.Linter({ cwd: root }), config, example, root, ruleId, setup.formatFixedSource);
205
205
  } finally {
@@ -165,7 +165,7 @@ async function verifyRuleExamples(rule, setup = {}) {
165
165
  files: ["**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}"],
166
166
  languageOptions: { parser: exampleParser, parserOptions: { project: tsconfig, tsconfigRootDir: root, disallowAutomaticSingleRunInference: true } },
167
167
  plugins: { "@sarj": { rules: { [spec.ruleId]: rule } } },
168
- rules: { [ruleId]: ["error", ...example.ruleOptions ?? rule.defaultOptions ?? []] }
168
+ rules: { [ruleId]: ["error", ...example.ruleOptions ?? rule.meta.defaultOptions ?? rule.defaultOptions ?? []] }
169
169
  };
170
170
  await verifyExample(new Linter({ cwd: root }), config, example, root, ruleId, setup.formatFixedSource);
171
171
  } finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "17.1.2",
3
+ "version": "17.1.3",
4
4
  "packageManager": "npm@12.2.1",
5
5
  "description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",
@@ -74,6 +74,7 @@
74
74
  "@vitest/eslint-plugin": "1.6.28",
75
75
  "eslint": "10.13.0",
76
76
  "eslint-node-test": "1.0.1",
77
+ "eslint-plugin-eslint-plugin": "7.6.2",
77
78
  "eslint-plugin-better-tailwindcss": "^4.10.0",
78
79
  "eslint-plugin-jest": "29.17.0",
79
80
  "eslint-plugin-jsdoc": "65.4.2",
@@ -94,6 +95,7 @@
94
95
  "jiti": "2.7.0",
95
96
  "prettier": "3.9.10",
96
97
  "tsup": "9.0.0",
98
+ "syncpack": "15.3.3",
97
99
  "typescript": "npm:@typescript/typescript6@6.0.2",
98
100
  "typescript-eslint": "^8.72.0",
99
101
  "uuid": "13.0.0",