oxlint-plugin-arch 0.2.3 → 0.2.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.5
4
+
5
+ - Add `no-inline-types` to require named object and function types in function signatures, with separate parameter, return, and function-type options.
6
+ - Add `only-export-constants` to restrict exports to local `const` bindings, with opt-ins for function values, type exports, and re-exports.
7
+ - Add `no-member-comments` to remove comments on object/type members while preserving directives and optional `Why:` explanations.
8
+ - Document the new rule options and syntax-only limits, extend the full configuration example to all 30 rules, and sync the optional vendored skill assets.
9
+
10
+ ## 0.2.4
11
+
12
+ - Add `trailingRoles` and `roleSeparators` so `export-file-prefix`, `declaration-name`, and `no-extra-exports` can treat `onchain-utils.ts` like `onchain.utils.ts`.
13
+
3
14
  ## 0.2.3
4
15
 
5
16
  - Add `declaration-name` so selected declarations can follow a file prefix or pattern per glob.
package/README.md CHANGED
@@ -41,23 +41,24 @@ Then point `jsPlugins[].specifier` at the copied entry file instead of the packa
41
41
  ## Configuration examples
42
42
 
43
43
  - [`examples/minimal.oxlint.config.ts`](examples/minimal.oxlint.config.ts) — three small rules showing plugin registration, glob ownership, and options.
44
- - [`examples/full.oxlint.config.ts`](examples/full.oxlint.config.ts) — all 27 rules across representative component, action, service, route, API, schema, and database scopes.
44
+ - [`examples/full.oxlint.config.ts`](examples/full.oxlint.config.ts) — all 30 rules across representative component, action, service, constant, route, API, schema, and database scopes.
45
45
 
46
46
  Copy the shapes that match your repository; do not copy globs or naming policy blindly.
47
47
 
48
48
  ## Rules
49
49
 
50
- - `declaration-name` — require selected declarations to match a filename-derived prefix or a consumer pattern.
51
- - `export-file-prefix` — require export names, or every function and type, to start with a filename-derived prefix, optionally singularized.
50
+ - `declaration-name` — require selected declarations to match a filename-derived prefix or a consumer pattern. Optional `trailingRoles` treat `onchain-utils.ts` like `onchain.utils.ts`.
51
+ - `export-file-prefix` — require export names, or every function and type, to start with a filename-derived prefix, optionally singularized. Optional `trailingRoles` drop a configured role suffix from that prefix.
52
52
  - `export-name-pattern` — require export names, or every function and type, to match a configured regular expression.
53
53
  - `filename-export-name` — derive expected function names from filename templates, optionally including locals.
54
54
  - `filename-match` — require filenames to match a configured pattern.
55
55
  - `folder-prefix` — require filenames to start with their parent folder name, or the folders after a configured root.
56
- - `no-extra-exports` — restrict files to configured export templates.
56
+ - `no-extra-exports` — restrict files to configured export templates. Optional `trailingRoles` apply to `{Domain}` the same way as the prefix rules.
57
57
  - `no-extra-factory-keys` — restrict direct factory return keys.
58
58
  - `no-file-level-helpers` — keep unapproved helpers out of module scope.
59
59
  - `no-imported-type-alias` — reject exported aliases that only rename imported types.
60
60
  - `no-inline-schema-elements` — require named schemas inside configured combinators.
61
+ - `no-inline-types` — require named object and function types in parameter and return annotations. See [options and scope](#no-inline-types).
61
62
  - `no-local-schema-construction` — reject runtime schema-library imports and local schema construction, with consumer-chosen severity, messages, and path exceptions.
62
63
  - `no-rederive-schema` — reject type derivation from configured imported schemas.
63
64
  - `no-restricted-files` — reject files selected by a consumer-owned forbidden glob.
@@ -67,8 +68,10 @@ Copy the shapes that match your repository; do not copy globs or naming policy b
67
68
  - `no-top-level-functions` — reject top-level functions and optional re-exports.
68
69
  - `no-trivial-functions` — reject empty or passthrough top-level functions.
69
70
  - `no-type-declarations` — reject type aliases and interfaces in matched files.
71
+ - `no-member-comments` — remove leading and same-line trailing comments on object-type members: interface properties and methods, index/call/construct signatures, type-literal members (including inline function parameter types), object literal properties, and object spreads. Autofix removes the comment and any blank line that followed it, consumes the spacing in front of a trailing comment so no line is left with trailing whitespace, and never removes the member. A contiguous run of comments is reported once and removed by a single fix, so `--fix` converges in one pass. `allowWhy` defaults to `true`: comments beginning with `Why: ` (after whitespace/JSDoc decoration), including contiguous `//` continuation lines, are preserved. Set `{ allowWhy: false }` to ban those too. The rule checks the prefix, not whether the rationale is meaningful. Directive comments are always preserved, whatever `allowWhy` says: `@ts-ignore`, `@ts-expect-error`, `@ts-nocheck`, `eslint-`/`oxlint-disable`/`enable`, `prettier-ignore`, `biome-ignore`, `c8`/`v8`/`istanbul ignore`, and webpack magic comments. Declaration, function-body, class-field, enum-member, union-member, and plain function-parameter comments are out of scope, as are comments inside destructuring patterns and array literals. Enable with `'arch/no-member-comments': ['error', { allowWhy: true }]` in a `**/*.{ts,tsx}` override.
70
72
  - `no-unescaped-like` — require configured sanitizers for configured query methods.
71
73
  - `only-export-components` — allow only React component and type exports.
74
+ - `only-export-constants` — allow only local `const` exports, with opt-ins for function values, types, and re-exports. See [options and scope](#only-export-constants).
72
75
  - `require-file-factory` — derive and require a filename-based factory function.
73
76
  - `require-object-params` — require exported functions to use object-shaped parameters.
74
77
  - `require-orpc-output` — require named oRPC output schemas.
@@ -77,6 +80,62 @@ Copy the shapes that match your repository; do not copy globs or naming policy b
77
80
 
78
81
  Every rule file includes plain-English behavior and examples. Rule tests under `src/tests/` show complete option shapes.
79
82
 
83
+ ### `no-inline-types`
84
+
85
+ Require named types in function signatures, including local functions, callbacks, methods, constructors, and overloads. Checks explicit annotations only; inferred types, variable annotations, generic constraints, and named type/interface definitions are not changed or banned. Use `no-type-declarations` separately to control where named types may live.
86
+
87
+ | Option | Default | Behavior |
88
+ | --- | --- | --- |
89
+ | `parameters` | `true` | Check parameter annotations, including destructuring, defaults, rest parameters, and constructor parameter properties. |
90
+ | `returns` | `true` | Check explicit return annotations. |
91
+ | `functionTypes` | `true` | Also reject inline function and constructor types. When `false`, object types nested inside those annotations are still checked. |
92
+
93
+ Object/function types nested in arrays, tuples, unions, intersections, or generic arguments are checked too (`Promise<{ id: string }>` fails). A rejected outer type is reported once, not again for each nested member.
94
+
95
+ ```ts
96
+ // In the consumer's override for service files:
97
+ 'arch/no-inline-types': ['error', {
98
+ parameters: true,
99
+ returns: true,
100
+ functionTypes: true,
101
+ }]
102
+
103
+ // Pass
104
+ function save(input: SaveInput): SaveResult { return persist(input) }
105
+ // Fail
106
+ function save(input: { id: string }): { ok: boolean } { return persist(input) }
107
+ ```
108
+
109
+ ### `only-export-constants`
110
+
111
+ Require every runtime export to reference a local `const` binding. Supports direct exports, destructuring, renamed exports, and default exports of local constants. Non-exported declarations are unrestricted.
112
+
113
+ | Option | Default | Behavior |
114
+ | --- | --- | --- |
115
+ | `allowFunctionValues` | `false` | Allow function-valued `const` bindings, not exported function declarations. |
116
+ | `allowTypeExports` | `false` | Allow type aliases, interfaces, and type-only exports, including type-only re-exports. |
117
+ | `allowReExports` | `false` | Allow runtime re-exports (`export ... from`, `export *`) and exports of imported bindings. Their declaration kind cannot be verified locally. |
118
+
119
+ `let`, `var`, function/class/enum/namespace declarations, class-valued constants, bare default expressions, and TypeScript `export =` / `export as namespace` are rejected. Name the default value with a local `const` first. Type-only re-exports use `allowTypeExports`, independently of `allowReExports`.
120
+
121
+ This is a syntax rule, not a deep-immutability or runtime-type check. It recognizes direct function/class values, TypeScript expression wrappers, and local identifier aliases. It does not infer values returned by calls, imported values, member accesses, destructuring, or object contents. Objects and arrays do not need `as const` or `Object.freeze()`.
122
+
123
+ ```ts
124
+ // In the consumer's override for constant files:
125
+ 'arch/only-export-constants': ['error', {
126
+ allowFunctionValues: false,
127
+ allowTypeExports: false,
128
+ allowReExports: false,
129
+ }]
130
+
131
+ // Pass
132
+ const retryLimit = 3
133
+ export { retryLimit }
134
+ // Fail
135
+ export let retryCount = 0
136
+ export const retry = () => run()
137
+ ```
138
+
80
139
  ## Development
81
140
 
82
141
  ```bash
package/dist/index.js CHANGED
@@ -181,7 +181,7 @@ function declarationsIsTrivialFunction(node) {
181
181
  if (!node.body || node.body.type !== "BlockStatement") {
182
182
  return false;
183
183
  }
184
- const statements = node.body.body.filter((statement2) => statement2.type !== "EmptyStatement" && !(statement2.type === "ExpressionStatement" && statement2.directive));
184
+ const statements = node.body.body.filter((statement) => statement.type !== "EmptyStatement" && !(statement.type === "ExpressionStatement" && statement.directive));
185
185
  if (statements.length === 0) {
186
186
  return true;
187
187
  }
@@ -422,9 +422,37 @@ function namingMatchTemplate(basename, template, placeholderPattern = "[a-z0-9-]
422
422
  }
423
423
  return new RegExp(`^${pattern}$`).exec(basename)?.groups ?? null;
424
424
  }
425
+ var namingStemModes = ["before-first-dot", "full-basename"];
425
426
  function namingNormalized(value, normalize) {
426
427
  return normalize === "none" ? value : value.replaceAll(/[-_]/g, "").toLowerCase();
427
428
  }
429
+ function namingFileStem(basename, mode = "before-first-dot", trailingRoles = [], roleSeparators = [".", "-"]) {
430
+ const stem = mode === "full-basename" ? basename : basename.split(".")[0] ?? "";
431
+ const roles = [...new Set(trailingRoles.filter(Boolean))].sort((left, right) => right.length - left.length);
432
+ const separators = [...new Set(roleSeparators.filter(Boolean))];
433
+ if (roles.length === 0 || separators.length === 0) {
434
+ return stem;
435
+ }
436
+ let remaining = stem;
437
+ let changed = true;
438
+ while (changed) {
439
+ changed = false;
440
+ for (const role of roles) {
441
+ for (const separator of separators) {
442
+ const suffix = `${separator}${role}`;
443
+ if (remaining.length > suffix.length && remaining.endsWith(suffix)) {
444
+ remaining = remaining.slice(0, -suffix.length);
445
+ changed = true;
446
+ break;
447
+ }
448
+ }
449
+ if (changed) {
450
+ break;
451
+ }
452
+ }
453
+ }
454
+ return remaining;
455
+ }
428
456
  function namingFilePrefixes(stem, normalize = "remove-separators", singularize = "none") {
429
457
  const prefixes = [namingNormalized(stem, normalize)];
430
458
  const parts = stem.split(/[-_]+/).filter(Boolean);
@@ -699,7 +727,9 @@ var declarationName = defineRule({
699
727
  },
700
728
  pattern: { type: "string" },
701
729
  flags: { type: "string" },
702
- stem: { type: "string", enum: ["before-first-dot", "full-basename"] },
730
+ stem: { type: "string", enum: [...namingStemModes] },
731
+ trailingRoles: { type: "array", items: { type: "string" } },
732
+ roleSeparators: { type: "array", items: { type: "string" } },
703
733
  normalize: { type: "string", enum: ["remove-separators", "none"] },
704
734
  singularize: { type: "string", enum: ["none", "trailing-s"] },
705
735
  allowPattern: { type: "string" }
@@ -713,19 +743,19 @@ var declarationName = defineRule({
713
743
  createOnce(context) {
714
744
  return {
715
745
  Program(program) {
716
- const options2 = optionsFirst(context, {
746
+ const options = optionsFirst(context, {
717
747
  stem: "before-first-dot",
718
748
  normalize: "remove-separators"
719
749
  });
720
- const allowed = options2.allowPattern ? new RegExp(options2.allowPattern) : null;
721
- const expected = options2.pattern ? new RegExp(options2.pattern, options2.flags) : null;
750
+ const allowed = options.allowPattern ? new RegExp(options.allowPattern) : null;
751
+ const expected = options.pattern ? new RegExp(options.pattern, options.flags) : null;
722
752
  const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
723
- const stem = options2.stem === "full-basename" ? basename : basename.split(".")[0] ?? "";
724
- const prefixes = namingFilePrefixes(stem, options2.normalize ?? "remove-separators", options2.singularize ?? "none");
753
+ const stem = namingFileStem(basename, options.stem, options.trailingRoles, options.roleSeparators);
754
+ const prefixes = namingFilePrefixes(stem, options.normalize ?? "remove-separators", options.singularize ?? "none");
725
755
  const seen = new Set;
726
- for (const item of declarationsCollectNamed(program, options2.kinds)) {
756
+ for (const item of declarationsCollectNamed(program, options.kinds)) {
727
757
  const key = `${item.name}:${item.node.start}:${item.node.end}`;
728
- const comparableName = options2.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
758
+ const comparableName = options.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
729
759
  const matches = expected ? expected.test(item.name) : prefixes.some((prefix) => comparableName.startsWith(prefix));
730
760
  if (seen.has(key) || allowed?.test(item.name) || matches) {
731
761
  continue;
@@ -734,7 +764,7 @@ var declarationName = defineRule({
734
764
  context.report({
735
765
  node: item.node,
736
766
  messageId: expected ? "pattern" : "prefix",
737
- data: expected ? { name: item.name, pattern: options2.pattern ?? "" } : { name: item.name, prefix: prefixes.join(" or ") }
767
+ data: expected ? { name: item.name, pattern: options.pattern ?? "" } : { name: item.name, prefix: prefixes.join(" or ") }
738
768
  });
739
769
  }
740
770
  }
@@ -751,7 +781,9 @@ var exportFilePrefix = defineRule2({
751
781
  type: "object",
752
782
  additionalProperties: false,
753
783
  properties: {
754
- stem: { type: "string", enum: ["before-first-dot", "full-basename"] },
784
+ stem: { type: "string", enum: [...namingStemModes] },
785
+ trailingRoles: { type: "array", items: { type: "string" } },
786
+ roleSeparators: { type: "array", items: { type: "string" } },
755
787
  normalize: { type: "string", enum: ["remove-separators", "none"] },
756
788
  singularize: { type: "string", enum: ["none", "trailing-s"] },
757
789
  allDeclarations: { type: "boolean" },
@@ -765,22 +797,22 @@ var exportFilePrefix = defineRule2({
765
797
  createOnce(context) {
766
798
  return {
767
799
  Program(program) {
768
- const options2 = optionsFirst(context, {
800
+ const options = optionsFirst(context, {
769
801
  stem: "before-first-dot",
770
802
  normalize: "remove-separators"
771
803
  });
772
804
  const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
773
- const stem = options2.stem === "full-basename" ? basename : basename.split(".")[0] ?? "";
774
- const prefixes = namingFilePrefixes(stem, options2.normalize ?? "remove-separators", options2.singularize ?? "none");
775
- const allowed = options2.allowPattern ? new RegExp(options2.allowPattern) : null;
776
- const names = options2.allDeclarations ? declarationsCollectNamed(program) : exportsCollect(program).map((binding) => ({
805
+ const stem = namingFileStem(basename, options.stem, options.trailingRoles, options.roleSeparators);
806
+ const prefixes = namingFilePrefixes(stem, options.normalize ?? "remove-separators", options.singularize ?? "none");
807
+ const allowed = options.allowPattern ? new RegExp(options.allowPattern) : null;
808
+ const names = options.allDeclarations ? declarationsCollectNamed(program) : exportsCollect(program).map((binding) => ({
777
809
  name: binding.localName ?? binding.exportedName,
778
810
  node: binding.node
779
811
  }));
780
812
  const seen = new Set;
781
813
  for (const item of names) {
782
814
  const key = `${item.name}:${item.node.start}:${item.node.end}`;
783
- const comparableName = options2.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
815
+ const comparableName = options.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
784
816
  if (seen.has(key) || allowed?.test(item.name) || prefixes.some((prefix) => comparableName.startsWith(prefix))) {
785
817
  continue;
786
818
  }
@@ -1003,7 +1035,9 @@ var noExtraExports = defineRule7({
1003
1035
  additionalProperties: false,
1004
1036
  properties: {
1005
1037
  names: { type: "array", items: { type: "string" } },
1006
- domainStem: { type: "string", enum: ["before-first-dot", "full-basename"] },
1038
+ domainStem: { type: "string", enum: [...namingStemModes] },
1039
+ trailingRoles: { type: "array", items: { type: "string" } },
1040
+ roleSeparators: { type: "array", items: { type: "string" } },
1007
1041
  allowTypeExports: { type: "boolean" }
1008
1042
  },
1009
1043
  required: ["names"]
@@ -1015,12 +1049,12 @@ var noExtraExports = defineRule7({
1015
1049
  createOnce(context) {
1016
1050
  return {
1017
1051
  Program(program) {
1018
- const options2 = optionsFirst(context);
1052
+ const options = optionsFirst(context);
1019
1053
  const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
1020
- const domain = options2.domainStem === "full-basename" ? basename : basename.split(".")[0] ?? "";
1021
- const allowed = options2.names.map((template) => template.replaceAll("{Domain}", namingPascalCase(domain)).replaceAll("{domain}", namingCamelCase(domain)));
1054
+ const domain = namingFileStem(basename, options.domainStem, options.trailingRoles, options.roleSeparators);
1055
+ const allowed = options.names.map((template) => template.replaceAll("{Domain}", namingPascalCase(domain)).replaceAll("{domain}", namingCamelCase(domain)));
1022
1056
  for (const binding of exportsCollect(program)) {
1023
- if (options2.allowTypeExports && binding.typeOnly) {
1057
+ if (options.allowTypeExports && binding.typeOnly) {
1024
1058
  continue;
1025
1059
  }
1026
1060
  const name = binding.localName ?? binding.exportedName;
@@ -1210,14 +1244,14 @@ var noInlineSchemaElements = defineRule11({
1210
1244
  if (node.callee.type !== "MemberExpression") {
1211
1245
  return;
1212
1246
  }
1213
- const options2 = optionsFirst(context);
1214
- const namespaces = new Set(options2.namespaces);
1247
+ const options = optionsFirst(context);
1248
+ const namespaces = new Set(options.namespaces);
1215
1249
  const method = astStaticMemberName(node.callee);
1216
- if (!schemasIsCall(node, namespaces) || !method || !options2.methods.includes(method)) {
1250
+ if (!schemasIsCall(node, namespaces) || !method || !options.methods.includes(method)) {
1217
1251
  return;
1218
1252
  }
1219
1253
  for (const element of schemasElements(node)) {
1220
- if (!schemasIsAllowedElement(element, options2.allowZodScalars, namespaces, new Set(options2.structuralMethods))) {
1254
+ if (!schemasIsAllowedElement(element, options.allowZodScalars, namespaces, new Set(options.structuralMethods))) {
1221
1255
  context.report({
1222
1256
  node: element,
1223
1257
  messageId: "inline",
@@ -1230,14 +1264,76 @@ var noInlineSchemaElements = defineRule11({
1230
1264
  }
1231
1265
  });
1232
1266
 
1233
- // src/rules/no-local-schema-construction.ts
1267
+ // src/rules/no-inline-types.ts
1234
1268
  import { defineRule as defineRule12 } from "@oxlint/plugins";
1269
+ function parameterAnnotation(parameter) {
1270
+ if (parameter.type === "TSParameterProperty") {
1271
+ return parameterAnnotation(parameter.parameter);
1272
+ }
1273
+ if (parameter.type === "AssignmentPattern") {
1274
+ return parameterAnnotation(parameter.left);
1275
+ }
1276
+ return parameter.typeAnnotation;
1277
+ }
1278
+ var noInlineTypes = defineRule12({
1279
+ meta: {
1280
+ type: "problem",
1281
+ schema: [{
1282
+ type: "object",
1283
+ additionalProperties: false,
1284
+ properties: {
1285
+ parameters: { type: "boolean" },
1286
+ returns: { type: "boolean" },
1287
+ functionTypes: { type: "boolean" }
1288
+ }
1289
+ }],
1290
+ messages: {
1291
+ inlineType: "Use a named type instead of an inline {{kind}} type in this {{position}} annotation."
1292
+ }
1293
+ },
1294
+ createOnce(context) {
1295
+ return {
1296
+ Program(program) {
1297
+ const { parameters = true, returns = true, functionTypes = true } = optionsFirst(context, {});
1298
+ const isInline = (node) => node.type === "TSTypeLiteral" || functionTypes && (node.type === "TSFunctionType" || node.type === "TSConstructorType");
1299
+ function check(annotation, position) {
1300
+ astVisit(annotation, [], (node, ancestors) => {
1301
+ if (!isInline(node) || ancestors.some(isInline)) {
1302
+ return;
1303
+ }
1304
+ context.report({
1305
+ node,
1306
+ messageId: "inlineType",
1307
+ data: { kind: node.type === "TSTypeLiteral" ? "object" : "function", position }
1308
+ });
1309
+ });
1310
+ }
1311
+ astVisit(program, [], (node) => {
1312
+ if (node.type !== "FunctionDeclaration" && node.type !== "FunctionExpression" && node.type !== "ArrowFunctionExpression" && node.type !== "TSDeclareFunction" && node.type !== "TSEmptyBodyFunctionExpression") {
1313
+ return;
1314
+ }
1315
+ if (parameters) {
1316
+ for (const parameter of node.params) {
1317
+ check(parameterAnnotation(parameter), "parameter");
1318
+ }
1319
+ }
1320
+ if (returns) {
1321
+ check(node.returnType, "return");
1322
+ }
1323
+ });
1324
+ }
1325
+ };
1326
+ }
1327
+ });
1328
+
1329
+ // src/rules/no-local-schema-construction.ts
1330
+ import { defineRule as defineRule13 } from "@oxlint/plugins";
1235
1331
  var defaultRuntimeImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
1236
1332
  var defaultConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
1237
1333
  function formatMessage(template, data) {
1238
1334
  return Object.entries(data).reduce((result, [key, value]) => result.replaceAll(`{{${key}}}`, value), template);
1239
1335
  }
1240
- var noLocalSchemaConstruction = defineRule12({
1336
+ var noLocalSchemaConstruction = defineRule13({
1241
1337
  meta: {
1242
1338
  type: "problem",
1243
1339
  schema: [{
@@ -1348,9 +1444,105 @@ var noLocalSchemaConstruction = defineRule12({
1348
1444
  }
1349
1445
  });
1350
1446
 
1447
+ // src/rules/no-member-comments.ts
1448
+ import { defineRule as defineRule14 } from "@oxlint/plugins";
1449
+ var DIRECTIVE = /^\s*(?:@ts-(?:ignore|expect-error|nocheck)|(?:es|ox)lint-(?:disable|enable)|prettier-ignore|biome-ignore|[cv]8 ignore|istanbul ignore|webpack[A-Z])/;
1450
+ var noMemberComments = defineRule14({
1451
+ meta: {
1452
+ type: "suggestion",
1453
+ fixable: "code",
1454
+ schema: [{
1455
+ type: "object",
1456
+ additionalProperties: false,
1457
+ properties: {
1458
+ allowWhy: { type: "boolean", default: true }
1459
+ }
1460
+ }],
1461
+ messages: {
1462
+ memberComment: "Remove this comment from the type member."
1463
+ }
1464
+ },
1465
+ createOnce(context) {
1466
+ const reported = new Set;
1467
+ function checkMember(node) {
1468
+ const parent = node.parent;
1469
+ if (parent.type !== "TSInterfaceBody" && parent.type !== "TSTypeLiteral" && parent.type !== "ObjectExpression")
1470
+ return;
1471
+ const source = context.sourceCode;
1472
+ const { allowWhy = true } = optionsFirst(context, {});
1473
+ const previousToken = source.getTokenBefore(node);
1474
+ const comments = [
1475
+ ...source.getCommentsBefore(node).filter((comment) => !previousToken || previousToken.range[0] === parent.range[0] || previousToken.loc.end.line !== comment.loc.start.line),
1476
+ ...source.getCommentsAfter(node).filter((comment) => comment.loc.start.line === node.loc.end.line)
1477
+ ].filter((comment) => comment.range[0] > parent.range[0] && comment.range[1] < parent.range[1]);
1478
+ let whyContinuation = false;
1479
+ let previousLine = -1;
1480
+ const removable = [];
1481
+ for (const comment of comments) {
1482
+ const value = (comment.type === "Block" ? comment.value.replace(/^\s*\* ?/gm, "") : comment.value).trimStart();
1483
+ const isWhy = value.startsWith("Why: ") || comment.type === "Line" && whyContinuation && comment.loc.start.line === previousLine + 1;
1484
+ whyContinuation = comment.type === "Line" && isWhy;
1485
+ previousLine = comment.loc.end.line;
1486
+ if (reported.has(comment.range[0]))
1487
+ continue;
1488
+ reported.add(comment.range[0]);
1489
+ if (allowWhy && isWhy)
1490
+ continue;
1491
+ if (DIRECTIVE.test(value))
1492
+ continue;
1493
+ removable.push(comment);
1494
+ }
1495
+ for (let index = 0;index < removable.length; ) {
1496
+ let last = index;
1497
+ while (last + 1 < removable.length && removable[last + 1].loc.start.line === removable[last].loc.end.line + 1)
1498
+ last++;
1499
+ const first = removable[index];
1500
+ const final = removable[last];
1501
+ index = last + 1;
1502
+ context.report({
1503
+ loc: { start: first.loc.start, end: final.loc.end },
1504
+ messageId: "memberComment",
1505
+ fix(fixer) {
1506
+ const text = source.text;
1507
+ const lineStart = text.lastIndexOf(`
1508
+ `, first.range[0] - 1) + 1;
1509
+ const before = text.slice(lineStart, first.range[0]);
1510
+ const start = first.range[0] - (/[\t ]*$/.exec(before)?.[0].length ?? 0);
1511
+ const after = text.slice(final.range[1]);
1512
+ const trailingLines = after.match(/^[\t ]*\r?\n(?:[\t ]*\r?\n)*/);
1513
+ if (trailingLines) {
1514
+ const end = final.range[1] + trailingLines[0].length;
1515
+ if (/^[\t ]*$/.test(before))
1516
+ return fixer.removeRange([lineStart, end]);
1517
+ const newline = trailingLines[0].includes(`\r
1518
+ `) ? `\r
1519
+ ` : `
1520
+ `;
1521
+ return fixer.replaceTextRange([start, end], newline);
1522
+ }
1523
+ return fixer.removeRange([start, final.range[1]]);
1524
+ }
1525
+ });
1526
+ }
1527
+ }
1528
+ return {
1529
+ Program() {
1530
+ reported.clear();
1531
+ },
1532
+ TSPropertySignature: checkMember,
1533
+ TSMethodSignature: checkMember,
1534
+ TSIndexSignature: checkMember,
1535
+ TSCallSignatureDeclaration: checkMember,
1536
+ TSConstructSignatureDeclaration: checkMember,
1537
+ Property: checkMember,
1538
+ SpreadElement: checkMember
1539
+ };
1540
+ }
1541
+ });
1542
+
1351
1543
  // src/rules/no-rederive-schema.ts
1352
- import { defineRule as defineRule13 } from "@oxlint/plugins";
1353
- var noRederiveSchema = defineRule13({
1544
+ import { defineRule as defineRule15 } from "@oxlint/plugins";
1545
+ var noRederiveSchema = defineRule15({
1354
1546
  meta: {
1355
1547
  type: "problem",
1356
1548
  schema: [{
@@ -1395,8 +1587,8 @@ var noRederiveSchema = defineRule13({
1395
1587
  });
1396
1588
 
1397
1589
  // src/rules/no-restricted-files.ts
1398
- import { defineRule as defineRule14 } from "@oxlint/plugins";
1399
- var noRestrictedFiles = defineRule14({
1590
+ import { defineRule as defineRule16 } from "@oxlint/plugins";
1591
+ var noRestrictedFiles = defineRule16({
1400
1592
  meta: {
1401
1593
  type: "problem",
1402
1594
  schema: [{
@@ -1426,7 +1618,7 @@ var noRestrictedFiles = defineRule14({
1426
1618
  });
1427
1619
 
1428
1620
  // src/rules/no-restricted-token.ts
1429
- import { defineRule as defineRule15 } from "@oxlint/plugins";
1621
+ import { defineRule as defineRule17 } from "@oxlint/plugins";
1430
1622
  function tokenIsTypeOnlyImport(node) {
1431
1623
  const parent = node.parent;
1432
1624
  if (parent?.type === "ImportSpecifier") {
@@ -1434,7 +1626,7 @@ function tokenIsTypeOnlyImport(node) {
1434
1626
  }
1435
1627
  return (parent?.type === "ImportDefaultSpecifier" || parent?.type === "ImportNamespaceSpecifier") && parent.parent.type === "ImportDeclaration" && parent.parent.importKind === "type";
1436
1628
  }
1437
- var noRestrictedToken = defineRule15({
1629
+ var noRestrictedToken = defineRule17({
1438
1630
  meta: {
1439
1631
  type: "problem",
1440
1632
  schema: [{
@@ -1454,9 +1646,9 @@ var noRestrictedToken = defineRule15({
1454
1646
  createOnce(context) {
1455
1647
  return {
1456
1648
  before() {
1457
- const options2 = optionsFirst(context);
1649
+ const options = optionsFirst(context);
1458
1650
  const filename = namingPosixPath(context.filename);
1459
- const allowed = options2.allowIn.some((suffix) => filename.endsWith(suffix)) || (options2.allowPathPatterns ?? []).some((pattern) => new RegExp(pattern).test(filename));
1651
+ const allowed = options.allowIn.some((suffix) => filename.endsWith(suffix)) || (options.allowPathPatterns ?? []).some((pattern) => new RegExp(pattern).test(filename));
1460
1652
  if (allowed) {
1461
1653
  return false;
1462
1654
  }
@@ -1476,8 +1668,8 @@ var noRestrictedToken = defineRule15({
1476
1668
  });
1477
1669
 
1478
1670
  // src/rules/no-runtime-in-types.ts
1479
- import { defineRule as defineRule16 } from "@oxlint/plugins";
1480
- var noRuntimeInTypes = defineRule16({
1671
+ import { defineRule as defineRule18 } from "@oxlint/plugins";
1672
+ var noRuntimeInTypes = defineRule18({
1481
1673
  meta: {
1482
1674
  type: "problem",
1483
1675
  schema: [{
@@ -1527,7 +1719,7 @@ var noRuntimeInTypes = defineRule16({
1527
1719
  });
1528
1720
 
1529
1721
  // src/rules/no-single-use-scalar-schema.ts
1530
- import { defineRule as defineRule17 } from "@oxlint/plugins";
1722
+ import { defineRule as defineRule19 } from "@oxlint/plugins";
1531
1723
  function isScalarSchema(node, namespaces, structuralMethods) {
1532
1724
  if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
1533
1725
  return false;
@@ -1549,8 +1741,8 @@ function isDirectObjectField(identifier, ancestors, namespaces, structuralMethod
1549
1741
  const method = call.callee.type === "MemberExpression" ? astStaticMemberName(call.callee) : undefined;
1550
1742
  return Boolean(method === "object" && structuralMethods.has(method) && call.arguments.includes(object));
1551
1743
  }
1552
- function isAllowedStructuralElement(identifier, initializer, ancestors, options2, namespaces, structuralMethods) {
1553
- if (!options2.allowZodScalars || !schemasIsAllowedElement(initializer, true, namespaces, structuralMethods)) {
1744
+ function isAllowedStructuralElement(identifier, initializer, ancestors, options, namespaces, structuralMethods) {
1745
+ if (!options.allowZodScalars || !schemasIsAllowedElement(initializer, true, namespaces, structuralMethods)) {
1554
1746
  return false;
1555
1747
  }
1556
1748
  const parent = ancestors.at(-1);
@@ -1559,9 +1751,9 @@ function isAllowedStructuralElement(identifier, initializer, ancestors, options2
1559
1751
  return false;
1560
1752
  }
1561
1753
  const method = call.callee.type === "MemberExpression" ? astStaticMemberName(call.callee) : undefined;
1562
- return Boolean(method && options2.methods.includes(method) && schemasElements(call).includes(identifier));
1754
+ return Boolean(method && options.methods.includes(method) && schemasElements(call).includes(identifier));
1563
1755
  }
1564
- var noSingleUseScalarSchema = defineRule17({
1756
+ var noSingleUseScalarSchema = defineRule19({
1565
1757
  meta: {
1566
1758
  type: "suggestion",
1567
1759
  schema: [{
@@ -1596,9 +1788,9 @@ var noSingleUseScalarSchema = defineRule17({
1596
1788
  }
1597
1789
  },
1598
1790
  "Program:exit"(program) {
1599
- const options2 = optionsFirst(context);
1600
- const namespaces = new Set(options2.namespaces);
1601
- const structuralMethods = new Set(options2.structuralMethods);
1791
+ const options = optionsFirst(context);
1792
+ const namespaces = new Set(options.namespaces);
1793
+ const structuralMethods = new Set(options.structuralMethods);
1602
1794
  const exportedNames = new Set(exportsCollect(program).flatMap((binding) => binding.localName ? [binding.localName] : []));
1603
1795
  for (const declarator of candidates) {
1604
1796
  const name = declarator.id.type === "Identifier" ? declarator.id.name : undefined;
@@ -1607,14 +1799,14 @@ var noSingleUseScalarSchema = defineRule17({
1607
1799
  continue;
1608
1800
  }
1609
1801
  const variable = context.sourceCode.getDeclaredVariables(declarator).find((candidate) => candidate.name === name);
1610
- const references = variable?.references.filter((reference2) => reference2.isRead()) ?? [];
1802
+ const references = variable?.references.filter((reference) => reference.isRead()) ?? [];
1611
1803
  if (references.length !== 1) {
1612
1804
  continue;
1613
1805
  }
1614
1806
  const reference = references[0];
1615
1807
  const identifier = reference.identifier;
1616
1808
  const ancestors = context.sourceCode.getAncestors(identifier);
1617
- const inlineable = isDirectObjectField(identifier, ancestors, namespaces, structuralMethods) || isAllowedStructuralElement(identifier, initializer, ancestors, options2, namespaces, structuralMethods);
1809
+ const inlineable = isDirectObjectField(identifier, ancestors, namespaces, structuralMethods) || isAllowedStructuralElement(identifier, initializer, ancestors, options, namespaces, structuralMethods);
1618
1810
  if (inlineable) {
1619
1811
  context.report({
1620
1812
  node: declarator.id,
@@ -1629,8 +1821,8 @@ var noSingleUseScalarSchema = defineRule17({
1629
1821
  });
1630
1822
 
1631
1823
  // src/rules/no-top-level-functions.ts
1632
- import { defineRule as defineRule18 } from "@oxlint/plugins";
1633
- var noTopLevelFunctions = defineRule18({
1824
+ import { defineRule as defineRule20 } from "@oxlint/plugins";
1825
+ var noTopLevelFunctions = defineRule20({
1634
1826
  meta: {
1635
1827
  type: "problem",
1636
1828
  schema: [{
@@ -1687,8 +1879,8 @@ var noTopLevelFunctions = defineRule18({
1687
1879
  });
1688
1880
 
1689
1881
  // src/rules/no-trivial-functions.ts
1690
- import { defineRule as defineRule19 } from "@oxlint/plugins";
1691
- var noTrivialFunctions = defineRule19({
1882
+ import { defineRule as defineRule21 } from "@oxlint/plugins";
1883
+ var noTrivialFunctions = defineRule21({
1692
1884
  meta: {
1693
1885
  type: "problem",
1694
1886
  schema: [{
@@ -1726,8 +1918,8 @@ var noTrivialFunctions = defineRule19({
1726
1918
  });
1727
1919
 
1728
1920
  // src/rules/no-type-declarations.ts
1729
- import { defineRule as defineRule20 } from "@oxlint/plugins";
1730
- var noTypeDeclarations = defineRule20({
1921
+ import { defineRule as defineRule22 } from "@oxlint/plugins";
1922
+ var noTypeDeclarations = defineRule22({
1731
1923
  meta: {
1732
1924
  type: "problem",
1733
1925
  schema: [{
@@ -1762,8 +1954,8 @@ var noTypeDeclarations = defineRule20({
1762
1954
  });
1763
1955
 
1764
1956
  // src/rules/no-unescaped-like.ts
1765
- import { defineRule as defineRule21 } from "@oxlint/plugins";
1766
- var noUnescapedLike = defineRule21({
1957
+ import { defineRule as defineRule23 } from "@oxlint/plugins";
1958
+ var noUnescapedLike = defineRule23({
1767
1959
  meta: {
1768
1960
  type: "problem",
1769
1961
  schema: [{
@@ -1782,21 +1974,21 @@ var noUnescapedLike = defineRule21({
1782
1974
  let sanitized = new Set;
1783
1975
  return {
1784
1976
  Program(program) {
1785
- const { sanitizers: sanitizers2, allowSanitizedBindings = true } = optionsFirst(context);
1786
- sanitized = allowSanitizedBindings ? sanitizersConfiguredBindings(program, new Set(sanitizers2)) : new Set;
1977
+ const { sanitizers, allowSanitizedBindings = true } = optionsFirst(context);
1978
+ sanitized = allowSanitizedBindings ? sanitizersConfiguredBindings(program, new Set(sanitizers)) : new Set;
1787
1979
  },
1788
1980
  CallExpression(node) {
1789
1981
  if (node.callee.type !== "MemberExpression") {
1790
1982
  return;
1791
1983
  }
1792
- const { methods, sanitizers: sanitizers2 } = optionsFirst(context);
1984
+ const { methods, sanitizers } = optionsFirst(context);
1793
1985
  const method = astStaticMemberName(node.callee);
1794
1986
  if (!method || !methods.includes(method)) {
1795
1987
  return;
1796
1988
  }
1797
1989
  const value = node.arguments.at(-1);
1798
1990
  const allowedIdentifier = value?.type === "Identifier" && sanitized.has(value.name);
1799
- if (!sanitizersCallsConfigured(value, new Set(sanitizers2)) && !allowedIdentifier) {
1991
+ if (!sanitizersCallsConfigured(value, new Set(sanitizers)) && !allowedIdentifier) {
1800
1992
  context.report({
1801
1993
  node: value ?? node,
1802
1994
  messageId: "unescaped",
@@ -1809,8 +2001,8 @@ var noUnescapedLike = defineRule21({
1809
2001
  });
1810
2002
 
1811
2003
  // src/rules/only-export-components.ts
1812
- import { defineRule as defineRule22 } from "@oxlint/plugins";
1813
- var onlyExportComponents = defineRule22({
2004
+ import { defineRule as defineRule24 } from "@oxlint/plugins";
2005
+ var onlyExportComponents = defineRule24({
1814
2006
  meta: {
1815
2007
  type: "problem",
1816
2008
  schema: [{
@@ -1865,9 +2057,146 @@ var onlyExportComponents = defineRule22({
1865
2057
  }
1866
2058
  });
1867
2059
 
2060
+ // src/rules/only-export-constants.ts
2061
+ import { defineRule as defineRule25 } from "@oxlint/plugins";
2062
+ function bindingNames(pattern) {
2063
+ switch (pattern.type) {
2064
+ case "Identifier":
2065
+ return [pattern.name];
2066
+ case "AssignmentPattern":
2067
+ return bindingNames(pattern.left);
2068
+ case "RestElement":
2069
+ return bindingNames(pattern.argument);
2070
+ case "ArrayPattern":
2071
+ return pattern.elements.flatMap((element) => element ? bindingNames(element) : []);
2072
+ case "ObjectPattern":
2073
+ return pattern.properties.flatMap((property) => bindingNames(property.type === "RestElement" ? property : property.value));
2074
+ }
2075
+ }
2076
+ function moduleName(node) {
2077
+ return node.type === "Identifier" ? node.name : node.value;
2078
+ }
2079
+ function unwrap(expression) {
2080
+ if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "TSInstantiationExpression") {
2081
+ return unwrap(expression.expression);
2082
+ }
2083
+ return expression;
2084
+ }
2085
+ function collectBindings(program) {
2086
+ const bindings = new Map;
2087
+ for (const statement of program.body) {
2088
+ if (statement.type === "ImportDeclaration") {
2089
+ for (const specifier of statement.specifiers) {
2090
+ bindings.set(specifier.local.name, {
2091
+ kind: statement.importKind === "type" || specifier.type === "ImportSpecifier" && specifier.importKind === "type" ? "type" : "import"
2092
+ });
2093
+ }
2094
+ continue;
2095
+ }
2096
+ const declaration = statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" ? statement.declaration : statement;
2097
+ if (declaration?.type === "TSImportEqualsDeclaration") {
2098
+ bindings.set(declaration.id.name, { kind: declaration.importKind === "type" ? "type" : "import" });
2099
+ } else if (declaration?.type === "VariableDeclaration") {
2100
+ for (const item of declaration.declarations) {
2101
+ for (const name of bindingNames(item.id)) {
2102
+ bindings.set(name, {
2103
+ kind: declaration.kind === "const" ? "const" : "other",
2104
+ value: item.id.type === "Identifier" ? item.init : undefined
2105
+ });
2106
+ }
2107
+ }
2108
+ } else if (declaration && "id" in declaration && declaration.id?.type === "Identifier") {
2109
+ bindings.set(declaration.id.name, {
2110
+ kind: declaration.type === "TSTypeAliasDeclaration" || declaration.type === "TSInterfaceDeclaration" ? "type" : declaration.type === "FunctionDeclaration" || declaration.type === "TSDeclareFunction" ? "function" : declaration.type === "ClassDeclaration" ? "class" : "other"
2111
+ });
2112
+ }
2113
+ }
2114
+ return bindings;
2115
+ }
2116
+ var onlyExportConstants = defineRule25({
2117
+ meta: {
2118
+ type: "problem",
2119
+ schema: [{
2120
+ type: "object",
2121
+ additionalProperties: false,
2122
+ properties: {
2123
+ allowFunctionValues: { type: "boolean" },
2124
+ allowTypeExports: { type: "boolean" },
2125
+ allowReExports: { type: "boolean" }
2126
+ }
2127
+ }],
2128
+ messages: {
2129
+ nonConstant: "Export '{{name}}' must be a local const binding with an allowed value; types and re-exports require explicit options."
2130
+ }
2131
+ },
2132
+ createOnce(context) {
2133
+ return {
2134
+ Program(program) {
2135
+ const { allowFunctionValues = false, allowTypeExports = false, allowReExports = false } = optionsFirst(context, {});
2136
+ const bindings = collectBindings(program);
2137
+ function hasForbiddenValue(binding, seen = new Set) {
2138
+ if (seen.has(binding) || binding.kind === "class") {
2139
+ return true;
2140
+ }
2141
+ if (binding.kind === "function") {
2142
+ return !allowFunctionValues;
2143
+ }
2144
+ if (!binding.value) {
2145
+ return false;
2146
+ }
2147
+ seen.add(binding);
2148
+ const value = unwrap(binding.value);
2149
+ if (value.type === "ArrowFunctionExpression" || value.type === "FunctionExpression") {
2150
+ return !allowFunctionValues;
2151
+ }
2152
+ if (value.type === "ClassExpression") {
2153
+ return true;
2154
+ }
2155
+ const target = value.type === "Identifier" ? bindings.get(value.name) : undefined;
2156
+ return target ? hasForbiddenValue(target, seen) : false;
2157
+ }
2158
+ function check(node, name, localName, typeOnly = false, reExport = false) {
2159
+ const binding = localName ? bindings.get(localName) : undefined;
2160
+ const allowed = typeOnly || !reExport && binding?.kind === "type" ? allowTypeExports : reExport || binding?.kind === "import" ? allowReExports : binding?.kind === "const" && !hasForbiddenValue(binding);
2161
+ if (!allowed) {
2162
+ context.report({ node, messageId: "nonConstant", data: { name } });
2163
+ }
2164
+ }
2165
+ for (const statement of program.body) {
2166
+ if (statement.type === "ExportAllDeclaration") {
2167
+ check(statement, "*", undefined, statement.exportKind === "type", true);
2168
+ } else if (statement.type === "ExportDefaultDeclaration") {
2169
+ const declaration = statement.declaration;
2170
+ check(statement, "default", declaration.type === "Identifier" ? declaration.name : undefined, declaration.type === "TSInterfaceDeclaration");
2171
+ } else if (statement.type === "TSExportAssignment") {
2172
+ check(statement, "export =");
2173
+ } else if (statement.type === "TSNamespaceExportDeclaration") {
2174
+ check(statement, statement.id.name);
2175
+ } else if (statement.type === "ExportNamedDeclaration") {
2176
+ const declaration = statement.declaration;
2177
+ if (declaration?.type === "VariableDeclaration") {
2178
+ for (const item of declaration.declarations) {
2179
+ for (const name of bindingNames(item.id)) {
2180
+ check(item, name, name);
2181
+ }
2182
+ }
2183
+ } else if (declaration) {
2184
+ const name = "id" in declaration && declaration.id?.type === "Identifier" ? declaration.id.name : "<anonymous>";
2185
+ check(declaration, name, name);
2186
+ }
2187
+ for (const specifier of statement.specifiers) {
2188
+ check(specifier, moduleName(specifier.exported), moduleName(specifier.local), statement.exportKind === "type" || specifier.exportKind === "type", Boolean(statement.source));
2189
+ }
2190
+ }
2191
+ }
2192
+ }
2193
+ };
2194
+ }
2195
+ });
2196
+
1868
2197
  // src/rules/require-file-factory.ts
1869
- import { defineRule as defineRule23 } from "@oxlint/plugins";
1870
- var requireFileFactory = defineRule23({
2198
+ import { defineRule as defineRule26 } from "@oxlint/plugins";
2199
+ var requireFileFactory = defineRule26({
1871
2200
  meta: {
1872
2201
  type: "problem",
1873
2202
  schema: [{
@@ -1913,8 +2242,8 @@ var requireFileFactory = defineRule23({
1913
2242
  });
1914
2243
 
1915
2244
  // src/rules/require-object-params.ts
1916
- import { defineRule as defineRule24 } from "@oxlint/plugins";
1917
- var requireObjectParams = defineRule24({
2245
+ import { defineRule as defineRule27 } from "@oxlint/plugins";
2246
+ var requireObjectParams = defineRule27({
1918
2247
  meta: {
1919
2248
  type: "problem",
1920
2249
  schema: [],
@@ -1940,8 +2269,8 @@ var requireObjectParams = defineRule24({
1940
2269
  });
1941
2270
 
1942
2271
  // src/rules/require-orpc-output.ts
1943
- import { defineRule as defineRule25 } from "@oxlint/plugins";
1944
- var requireOrpcOutput = defineRule25({
2272
+ import { defineRule as defineRule28 } from "@oxlint/plugins";
2273
+ var requireOrpcOutput = defineRule28({
1945
2274
  meta: {
1946
2275
  type: "problem",
1947
2276
  schema: [{
@@ -1983,8 +2312,8 @@ var requireOrpcOutput = defineRule25({
1983
2312
  });
1984
2313
 
1985
2314
  // src/rules/require-paired-call.ts
1986
- import { defineRule as defineRule26 } from "@oxlint/plugins";
1987
- var requirePairedCall = defineRule26({
2315
+ import { defineRule as defineRule29 } from "@oxlint/plugins";
2316
+ var requirePairedCall = defineRule29({
1988
2317
  meta: {
1989
2318
  type: "problem",
1990
2319
  schema: [{
@@ -2039,8 +2368,8 @@ var requirePairedCall = defineRule26({
2039
2368
  });
2040
2369
 
2041
2370
  // src/rules/route-surface.ts
2042
- import { defineRule as defineRule27 } from "@oxlint/plugins";
2043
- var routeSurface = defineRule27({
2371
+ import { defineRule as defineRule30 } from "@oxlint/plugins";
2372
+ var routeSurface = defineRule30({
2044
2373
  meta: {
2045
2374
  type: "problem",
2046
2375
  schema: [{
@@ -2096,7 +2425,9 @@ var src_default = eslintCompatPlugin({
2096
2425
  "no-file-level-helpers": noFileLevelHelpers,
2097
2426
  "no-imported-type-alias": noImportedTypeAlias,
2098
2427
  "no-inline-schema-elements": noInlineSchemaElements,
2428
+ "no-inline-types": noInlineTypes,
2099
2429
  "no-local-schema-construction": noLocalSchemaConstruction,
2430
+ "no-member-comments": noMemberComments,
2100
2431
  "no-rederive-schema": noRederiveSchema,
2101
2432
  "no-restricted-files": noRestrictedFiles,
2102
2433
  "no-restricted-token": noRestrictedToken,
@@ -2107,6 +2438,7 @@ var src_default = eslintCompatPlugin({
2107
2438
  "no-type-declarations": noTypeDeclarations,
2108
2439
  "no-unescaped-like": noUnescapedLike,
2109
2440
  "only-export-components": onlyExportComponents,
2441
+ "only-export-constants": onlyExportConstants,
2110
2442
  "require-file-factory": requireFileFactory,
2111
2443
  "require-object-params": requireObjectParams,
2112
2444
  "require-orpc-output": requireOrpcOutput,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-arch",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Configurable architecture rules for Oxlint JavaScript plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",