oxlint-plugin-arch 0.2.2 → 0.2.4

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.4
4
+
5
+ - Add `trailingRoles` and `roleSeparators` so `export-file-prefix`, `declaration-name`, and `no-extra-exports` can treat `onchain-utils.ts` like `onchain.utils.ts`.
6
+
7
+ ## 0.2.3
8
+
9
+ - Add `declaration-name` so selected declarations can follow a file prefix or pattern per glob.
10
+ - Add `export-file-prefix` `singularize` so plural filenames accept singular prefixes.
11
+ - Add `no-type-declarations` to keep type aliases and interfaces out of matched files.
12
+
3
13
  ## 0.2.2
4
14
 
5
15
  - Publish compiled `dist/index.js` so Oxlint can load the package from `node_modules`.
package/README.md CHANGED
@@ -41,18 +41,19 @@ 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 25 rules across representative component, action, service, route, API, schema, and database scopes.
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.
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
- - `export-file-prefix` — require export names, or every function and type, to start with a filename-derived prefix.
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.
51
52
  - `export-name-pattern` — require export names, or every function and type, to match a configured regular expression.
52
53
  - `filename-export-name` — derive expected function names from filename templates, optionally including locals.
53
54
  - `filename-match` — require filenames to match a configured pattern.
54
55
  - `folder-prefix` — require filenames to start with their parent folder name, or the folders after a configured root.
55
- - `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.
56
57
  - `no-extra-factory-keys` — restrict direct factory return keys.
57
58
  - `no-file-level-helpers` — keep unapproved helpers out of module scope.
58
59
  - `no-imported-type-alias` — reject exported aliases that only rename imported types.
@@ -65,6 +66,7 @@ Copy the shapes that match your repository; do not copy globs or naming policy b
65
66
  - `no-single-use-scalar-schema` — reject local scalar Zod aliases used once where they can be safely inlined.
66
67
  - `no-top-level-functions` — reject top-level functions and optional re-exports.
67
68
  - `no-trivial-functions` — reject empty or passthrough top-level functions.
69
+ - `no-type-declarations` — reject type aliases and interfaces in matched files.
68
70
  - `no-unescaped-like` — require configured sanitizers for configured query methods.
69
71
  - `only-export-components` — allow only React component and type exports.
70
72
  - `require-file-factory` — derive and require a filename-based factory function.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
2
  import { eslintCompatPlugin } from "@oxlint/plugins";
3
3
 
4
- // src/rules/export-file-prefix.ts
4
+ // src/rules/declaration-name.ts
5
5
  import { defineRule } from "@oxlint/plugins";
6
6
 
7
7
  // src/utils/helpers/ast.ts
@@ -194,16 +194,42 @@ function declarationsIsTrivialFunction(node) {
194
194
  }
195
195
  return statement.type === "ExpressionStatement" && declarationsIsTrivialExpression(statement.expression);
196
196
  }
197
- function declarationsCollectNamed(root) {
197
+ var declarationsKinds = ["function", "const", "let", "var", "class", "type", "interface", "enum"];
198
+ function declarationsNamedKind(node, ancestors) {
199
+ if (node.type === "FunctionDeclaration") {
200
+ return "function";
201
+ }
202
+ if (node.type === "ClassDeclaration") {
203
+ return "class";
204
+ }
205
+ if (node.type === "TSTypeAliasDeclaration") {
206
+ return "type";
207
+ }
208
+ if (node.type === "TSInterfaceDeclaration") {
209
+ return "interface";
210
+ }
211
+ if (node.type === "TSEnumDeclaration") {
212
+ return "enum";
213
+ }
214
+ if (node.type !== "VariableDeclarator") {
215
+ return;
216
+ }
217
+ const declaration = ancestors.findLast((ancestor) => ancestor.type === "VariableDeclaration");
218
+ return declaration?.type === "VariableDeclaration" && (declaration.kind === "const" || declaration.kind === "let" || declaration.kind === "var") ? declaration.kind : undefined;
219
+ }
220
+ function declarationsCollectNamed(root, kinds) {
221
+ const allowed = kinds && kinds.length > 0 ? new Set(kinds) : null;
198
222
  const result = [];
199
223
  astVisit(root, [], (node, ancestors) => {
200
- if ((node.type === "FunctionDeclaration" || node.type === "ClassDeclaration" || node.type === "TSTypeAliasDeclaration" || node.type === "TSInterfaceDeclaration" || node.type === "TSEnumDeclaration") && node.id?.name) {
201
- result.push({ name: node.id.name, node });
224
+ const kind = declarationsNamedKind(node, ancestors);
225
+ const name = node.type === "VariableDeclarator" && node.id.type === "Identifier" ? node.id.name : ("id" in node) && node.id && ("name" in node.id) ? node.id.name : undefined;
226
+ if (!kind || !name || allowed && !allowed.has(kind)) {
202
227
  return;
203
228
  }
204
- if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && !ancestors.some((ancestor) => ancestor.type === "ForStatement" || ancestor.type === "ForInStatement" || ancestor.type === "ForOfStatement")) {
205
- result.push({ name: node.id.name, node });
229
+ if (node.type === "VariableDeclarator" && ancestors.some((ancestor) => ancestor.type === "ForStatement" || ancestor.type === "ForInStatement" || ancestor.type === "ForOfStatement")) {
230
+ return;
206
231
  }
232
+ result.push({ name, node, kind });
207
233
  });
208
234
  return result;
209
235
  }
@@ -396,6 +422,46 @@ function namingMatchTemplate(basename, template, placeholderPattern = "[a-z0-9-]
396
422
  }
397
423
  return new RegExp(`^${pattern}$`).exec(basename)?.groups ?? null;
398
424
  }
425
+ var namingStemModes = ["before-first-dot", "full-basename"];
426
+ function namingNormalized(value, normalize) {
427
+ return normalize === "none" ? value : value.replaceAll(/[-_]/g, "").toLowerCase();
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
+ }
456
+ function namingFilePrefixes(stem, normalize = "remove-separators", singularize = "none") {
457
+ const prefixes = [namingNormalized(stem, normalize)];
458
+ const parts = stem.split(/[-_]+/).filter(Boolean);
459
+ const last = parts.at(-1) ?? "";
460
+ if (singularize === "trailing-s" && last.endsWith("s") && last.length > 1) {
461
+ prefixes.push(namingNormalized([...parts.slice(0, -1), last.slice(0, -1)].join("-"), normalize));
462
+ }
463
+ return [...new Set(prefixes.filter(Boolean))];
464
+ }
399
465
 
400
466
  // src/utils/helpers/factories.ts
401
467
  function factoriesExpandTemplate(template, groups) {
@@ -647,16 +713,79 @@ function schemasIsAllowedElement(node, allowScalars, namespaces, structuralMetho
647
713
  function schemasTypeOperator(node, namespaces, operators) {
648
714
  return node.typeName.type === "TSQualifiedName" && node.typeName.left.type === "Identifier" && namespaces.has(node.typeName.left.name) && operators.has(node.typeName.right.name) ? node.typeName.right.name : undefined;
649
715
  }
716
+ // src/rules/declaration-name.ts
717
+ var declarationName = defineRule({
718
+ meta: {
719
+ type: "problem",
720
+ schema: [{
721
+ type: "object",
722
+ additionalProperties: false,
723
+ properties: {
724
+ kinds: {
725
+ type: "array",
726
+ items: { type: "string", enum: [...declarationsKinds] }
727
+ },
728
+ pattern: { type: "string" },
729
+ flags: { type: "string" },
730
+ stem: { type: "string", enum: [...namingStemModes] },
731
+ trailingRoles: { type: "array", items: { type: "string" } },
732
+ roleSeparators: { type: "array", items: { type: "string" } },
733
+ normalize: { type: "string", enum: ["remove-separators", "none"] },
734
+ singularize: { type: "string", enum: ["none", "trailing-s"] },
735
+ allowPattern: { type: "string" }
736
+ }
737
+ }],
738
+ messages: {
739
+ prefix: "'{{name}}' must start with file prefix '{{prefix}}'.",
740
+ pattern: "'{{name}}' must match {{pattern}}."
741
+ }
742
+ },
743
+ createOnce(context) {
744
+ return {
745
+ Program(program) {
746
+ const options2 = optionsFirst(context, {
747
+ stem: "before-first-dot",
748
+ normalize: "remove-separators"
749
+ });
750
+ const allowed = options2.allowPattern ? new RegExp(options2.allowPattern) : null;
751
+ const expected = options2.pattern ? new RegExp(options2.pattern, options2.flags) : null;
752
+ const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
753
+ const stem = namingFileStem(basename, options2.stem, options2.trailingRoles, options2.roleSeparators);
754
+ const prefixes = namingFilePrefixes(stem, options2.normalize ?? "remove-separators", options2.singularize ?? "none");
755
+ const seen = new Set;
756
+ for (const item of declarationsCollectNamed(program, options2.kinds)) {
757
+ const key = `${item.name}:${item.node.start}:${item.node.end}`;
758
+ const comparableName = options2.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
759
+ const matches = expected ? expected.test(item.name) : prefixes.some((prefix) => comparableName.startsWith(prefix));
760
+ if (seen.has(key) || allowed?.test(item.name) || matches) {
761
+ continue;
762
+ }
763
+ seen.add(key);
764
+ context.report({
765
+ node: item.node,
766
+ messageId: expected ? "pattern" : "prefix",
767
+ data: expected ? { name: item.name, pattern: options2.pattern ?? "" } : { name: item.name, prefix: prefixes.join(" or ") }
768
+ });
769
+ }
770
+ }
771
+ };
772
+ }
773
+ });
774
+
650
775
  // src/rules/export-file-prefix.ts
651
- var exportFilePrefix = defineRule({
776
+ import { defineRule as defineRule2 } from "@oxlint/plugins";
777
+ var exportFilePrefix = defineRule2({
652
778
  meta: {
653
779
  type: "problem",
654
780
  schema: [{
655
781
  type: "object",
656
782
  additionalProperties: false,
657
783
  properties: {
658
- 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" } },
659
787
  normalize: { type: "string", enum: ["remove-separators", "none"] },
788
+ singularize: { type: "string", enum: ["none", "trailing-s"] },
660
789
  allDeclarations: { type: "boolean" },
661
790
  allowPattern: { type: "string" }
662
791
  }
@@ -673,8 +802,8 @@ var exportFilePrefix = defineRule({
673
802
  normalize: "remove-separators"
674
803
  });
675
804
  const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
676
- const stem = options2.stem === "full-basename" ? basename : basename.split(".")[0] ?? "";
677
- const prefix = options2.normalize === "none" ? stem : stem.replaceAll(/[-_]/g, "").toLowerCase();
805
+ const stem = namingFileStem(basename, options2.stem, options2.trailingRoles, options2.roleSeparators);
806
+ const prefixes = namingFilePrefixes(stem, options2.normalize ?? "remove-separators", options2.singularize ?? "none");
678
807
  const allowed = options2.allowPattern ? new RegExp(options2.allowPattern) : null;
679
808
  const names = options2.allDeclarations ? declarationsCollectNamed(program) : exportsCollect(program).map((binding) => ({
680
809
  name: binding.localName ?? binding.exportedName,
@@ -684,14 +813,14 @@ var exportFilePrefix = defineRule({
684
813
  for (const item of names) {
685
814
  const key = `${item.name}:${item.node.start}:${item.node.end}`;
686
815
  const comparableName = options2.normalize === "none" ? item.name : item.name.replaceAll("_", "").toLowerCase();
687
- if (seen.has(key) || allowed?.test(item.name) || comparableName.startsWith(prefix)) {
816
+ if (seen.has(key) || allowed?.test(item.name) || prefixes.some((prefix) => comparableName.startsWith(prefix))) {
688
817
  continue;
689
818
  }
690
819
  seen.add(key);
691
820
  context.report({
692
821
  node: item.node,
693
822
  messageId: "prefix",
694
- data: { name: item.name, prefix }
823
+ data: { name: item.name, prefix: prefixes.join(" or ") }
695
824
  });
696
825
  }
697
826
  }
@@ -700,8 +829,8 @@ var exportFilePrefix = defineRule({
700
829
  });
701
830
 
702
831
  // src/rules/export-name-pattern.ts
703
- import { defineRule as defineRule2 } from "@oxlint/plugins";
704
- var exportNamePattern = defineRule2({
832
+ import { defineRule as defineRule3 } from "@oxlint/plugins";
833
+ var exportNamePattern = defineRule3({
705
834
  meta: {
706
835
  type: "problem",
707
836
  schema: [{
@@ -751,8 +880,8 @@ var exportNamePattern = defineRule2({
751
880
  });
752
881
 
753
882
  // src/rules/filename-export-name.ts
754
- import { defineRule as defineRule3 } from "@oxlint/plugins";
755
- var filenameExportName = defineRule3({
883
+ import { defineRule as defineRule4 } from "@oxlint/plugins";
884
+ var filenameExportName = defineRule4({
756
885
  meta: {
757
886
  type: "problem",
758
887
  schema: [{
@@ -813,8 +942,8 @@ var filenameExportName = defineRule3({
813
942
  });
814
943
 
815
944
  // src/rules/filename-match.ts
816
- import { defineRule as defineRule4 } from "@oxlint/plugins";
817
- var filenameMatch = defineRule4({
945
+ import { defineRule as defineRule5 } from "@oxlint/plugins";
946
+ var filenameMatch = defineRule5({
818
947
  meta: {
819
948
  type: "problem",
820
949
  schema: [{
@@ -848,8 +977,8 @@ var filenameMatch = defineRule4({
848
977
  });
849
978
 
850
979
  // src/rules/folder-prefix.ts
851
- import { defineRule as defineRule5 } from "@oxlint/plugins";
852
- var folderPrefix = defineRule5({
980
+ import { defineRule as defineRule6 } from "@oxlint/plugins";
981
+ var folderPrefix = defineRule6({
853
982
  meta: {
854
983
  type: "problem",
855
984
  schema: [{
@@ -897,8 +1026,8 @@ var folderPrefix = defineRule5({
897
1026
  });
898
1027
 
899
1028
  // src/rules/no-extra-exports.ts
900
- import { defineRule as defineRule6 } from "@oxlint/plugins";
901
- var noExtraExports = defineRule6({
1029
+ import { defineRule as defineRule7 } from "@oxlint/plugins";
1030
+ var noExtraExports = defineRule7({
902
1031
  meta: {
903
1032
  type: "problem",
904
1033
  schema: [{
@@ -906,7 +1035,9 @@ var noExtraExports = defineRule6({
906
1035
  additionalProperties: false,
907
1036
  properties: {
908
1037
  names: { type: "array", items: { type: "string" } },
909
- 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" } },
910
1041
  allowTypeExports: { type: "boolean" }
911
1042
  },
912
1043
  required: ["names"]
@@ -920,7 +1051,7 @@ var noExtraExports = defineRule6({
920
1051
  Program(program) {
921
1052
  const options2 = optionsFirst(context);
922
1053
  const basename = namingFileBasename(context.filename).replace(/\.(tsx?|jsx?)$/, "");
923
- const domain = options2.domainStem === "full-basename" ? basename : basename.split(".")[0] ?? "";
1054
+ const domain = namingFileStem(basename, options2.domainStem, options2.trailingRoles, options2.roleSeparators);
924
1055
  const allowed = options2.names.map((template) => template.replaceAll("{Domain}", namingPascalCase(domain)).replaceAll("{domain}", namingCamelCase(domain)));
925
1056
  for (const binding of exportsCollect(program)) {
926
1057
  if (options2.allowTypeExports && binding.typeOnly) {
@@ -941,8 +1072,8 @@ var noExtraExports = defineRule6({
941
1072
  });
942
1073
 
943
1074
  // src/rules/no-extra-factory-keys.ts
944
- import { defineRule as defineRule7 } from "@oxlint/plugins";
945
- var noExtraFactoryKeys = defineRule7({
1075
+ import { defineRule as defineRule8 } from "@oxlint/plugins";
1076
+ var noExtraFactoryKeys = defineRule8({
946
1077
  meta: {
947
1078
  type: "problem",
948
1079
  schema: [{
@@ -982,8 +1113,8 @@ var noExtraFactoryKeys = defineRule7({
982
1113
  });
983
1114
 
984
1115
  // src/rules/no-file-level-helpers.ts
985
- import { defineRule as defineRule8 } from "@oxlint/plugins";
986
- var noFileLevelHelpers = defineRule8({
1116
+ import { defineRule as defineRule9 } from "@oxlint/plugins";
1117
+ var noFileLevelHelpers = defineRule9({
987
1118
  meta: {
988
1119
  type: "problem",
989
1120
  schema: [{
@@ -1025,7 +1156,7 @@ var noFileLevelHelpers = defineRule8({
1025
1156
  });
1026
1157
 
1027
1158
  // src/rules/no-imported-type-alias.ts
1028
- import { defineRule as defineRule9 } from "@oxlint/plugins";
1159
+ import { defineRule as defineRule10 } from "@oxlint/plugins";
1029
1160
  function importedAliasTarget(declaration, imports) {
1030
1161
  if (declaration?.type !== "TSTypeAliasDeclaration" || declaration.typeAnnotation.type !== "TSTypeReference" || declaration.typeAnnotation.typeName.type !== "Identifier" || !imports.has(declaration.typeAnnotation.typeName.name)) {
1031
1162
  return;
@@ -1035,7 +1166,7 @@ function importedAliasTarget(declaration, imports) {
1035
1166
  function specifierLocalName(specifier) {
1036
1167
  return specifier.local.type === "Identifier" ? specifier.local.name : specifier.local.value;
1037
1168
  }
1038
- var noImportedTypeAlias = defineRule9({
1169
+ var noImportedTypeAlias = defineRule10({
1039
1170
  meta: {
1040
1171
  type: "problem",
1041
1172
  schema: [],
@@ -1085,8 +1216,8 @@ var noImportedTypeAlias = defineRule9({
1085
1216
  });
1086
1217
 
1087
1218
  // src/rules/no-inline-schema-elements.ts
1088
- import { defineRule as defineRule10 } from "@oxlint/plugins";
1089
- var noInlineSchemaElements = defineRule10({
1219
+ import { defineRule as defineRule11 } from "@oxlint/plugins";
1220
+ var noInlineSchemaElements = defineRule11({
1090
1221
  meta: {
1091
1222
  type: "problem",
1092
1223
  schema: [{
@@ -1134,13 +1265,13 @@ var noInlineSchemaElements = defineRule10({
1134
1265
  });
1135
1266
 
1136
1267
  // src/rules/no-local-schema-construction.ts
1137
- import { defineRule as defineRule11 } from "@oxlint/plugins";
1268
+ import { defineRule as defineRule12 } from "@oxlint/plugins";
1138
1269
  var defaultRuntimeImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
1139
1270
  var defaultConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
1140
1271
  function formatMessage(template, data) {
1141
1272
  return Object.entries(data).reduce((result, [key, value]) => result.replaceAll(`{{${key}}}`, value), template);
1142
1273
  }
1143
- var noLocalSchemaConstruction = defineRule11({
1274
+ var noLocalSchemaConstruction = defineRule12({
1144
1275
  meta: {
1145
1276
  type: "problem",
1146
1277
  schema: [{
@@ -1252,8 +1383,8 @@ var noLocalSchemaConstruction = defineRule11({
1252
1383
  });
1253
1384
 
1254
1385
  // src/rules/no-rederive-schema.ts
1255
- import { defineRule as defineRule12 } from "@oxlint/plugins";
1256
- var noRederiveSchema = defineRule12({
1386
+ import { defineRule as defineRule13 } from "@oxlint/plugins";
1387
+ var noRederiveSchema = defineRule13({
1257
1388
  meta: {
1258
1389
  type: "problem",
1259
1390
  schema: [{
@@ -1298,8 +1429,8 @@ var noRederiveSchema = defineRule12({
1298
1429
  });
1299
1430
 
1300
1431
  // src/rules/no-restricted-files.ts
1301
- import { defineRule as defineRule13 } from "@oxlint/plugins";
1302
- var noRestrictedFiles = defineRule13({
1432
+ import { defineRule as defineRule14 } from "@oxlint/plugins";
1433
+ var noRestrictedFiles = defineRule14({
1303
1434
  meta: {
1304
1435
  type: "problem",
1305
1436
  schema: [{
@@ -1329,7 +1460,7 @@ var noRestrictedFiles = defineRule13({
1329
1460
  });
1330
1461
 
1331
1462
  // src/rules/no-restricted-token.ts
1332
- import { defineRule as defineRule14 } from "@oxlint/plugins";
1463
+ import { defineRule as defineRule15 } from "@oxlint/plugins";
1333
1464
  function tokenIsTypeOnlyImport(node) {
1334
1465
  const parent = node.parent;
1335
1466
  if (parent?.type === "ImportSpecifier") {
@@ -1337,7 +1468,7 @@ function tokenIsTypeOnlyImport(node) {
1337
1468
  }
1338
1469
  return (parent?.type === "ImportDefaultSpecifier" || parent?.type === "ImportNamespaceSpecifier") && parent.parent.type === "ImportDeclaration" && parent.parent.importKind === "type";
1339
1470
  }
1340
- var noRestrictedToken = defineRule14({
1471
+ var noRestrictedToken = defineRule15({
1341
1472
  meta: {
1342
1473
  type: "problem",
1343
1474
  schema: [{
@@ -1379,8 +1510,8 @@ var noRestrictedToken = defineRule14({
1379
1510
  });
1380
1511
 
1381
1512
  // src/rules/no-runtime-in-types.ts
1382
- import { defineRule as defineRule15 } from "@oxlint/plugins";
1383
- var noRuntimeInTypes = defineRule15({
1513
+ import { defineRule as defineRule16 } from "@oxlint/plugins";
1514
+ var noRuntimeInTypes = defineRule16({
1384
1515
  meta: {
1385
1516
  type: "problem",
1386
1517
  schema: [{
@@ -1430,7 +1561,7 @@ var noRuntimeInTypes = defineRule15({
1430
1561
  });
1431
1562
 
1432
1563
  // src/rules/no-single-use-scalar-schema.ts
1433
- import { defineRule as defineRule16 } from "@oxlint/plugins";
1564
+ import { defineRule as defineRule17 } from "@oxlint/plugins";
1434
1565
  function isScalarSchema(node, namespaces, structuralMethods) {
1435
1566
  if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
1436
1567
  return false;
@@ -1464,7 +1595,7 @@ function isAllowedStructuralElement(identifier, initializer, ancestors, options2
1464
1595
  const method = call.callee.type === "MemberExpression" ? astStaticMemberName(call.callee) : undefined;
1465
1596
  return Boolean(method && options2.methods.includes(method) && schemasElements(call).includes(identifier));
1466
1597
  }
1467
- var noSingleUseScalarSchema = defineRule16({
1598
+ var noSingleUseScalarSchema = defineRule17({
1468
1599
  meta: {
1469
1600
  type: "suggestion",
1470
1601
  schema: [{
@@ -1532,8 +1663,8 @@ var noSingleUseScalarSchema = defineRule16({
1532
1663
  });
1533
1664
 
1534
1665
  // src/rules/no-top-level-functions.ts
1535
- import { defineRule as defineRule17 } from "@oxlint/plugins";
1536
- var noTopLevelFunctions = defineRule17({
1666
+ import { defineRule as defineRule18 } from "@oxlint/plugins";
1667
+ var noTopLevelFunctions = defineRule18({
1537
1668
  meta: {
1538
1669
  type: "problem",
1539
1670
  schema: [{
@@ -1590,8 +1721,8 @@ var noTopLevelFunctions = defineRule17({
1590
1721
  });
1591
1722
 
1592
1723
  // src/rules/no-trivial-functions.ts
1593
- import { defineRule as defineRule18 } from "@oxlint/plugins";
1594
- var noTrivialFunctions = defineRule18({
1724
+ import { defineRule as defineRule19 } from "@oxlint/plugins";
1725
+ var noTrivialFunctions = defineRule19({
1595
1726
  meta: {
1596
1727
  type: "problem",
1597
1728
  schema: [{
@@ -1628,9 +1759,45 @@ var noTrivialFunctions = defineRule18({
1628
1759
  }
1629
1760
  });
1630
1761
 
1762
+ // src/rules/no-type-declarations.ts
1763
+ import { defineRule as defineRule20 } from "@oxlint/plugins";
1764
+ var noTypeDeclarations = defineRule20({
1765
+ meta: {
1766
+ type: "problem",
1767
+ schema: [{
1768
+ type: "object",
1769
+ additionalProperties: false,
1770
+ properties: {
1771
+ allowPattern: { type: "string" }
1772
+ }
1773
+ }],
1774
+ messages: {
1775
+ typeDeclaration: "Type '{{name}}' must not be declared in this file."
1776
+ }
1777
+ },
1778
+ createOnce(context) {
1779
+ return {
1780
+ Program(program) {
1781
+ const { allowPattern } = optionsFirst(context, {});
1782
+ const allowed = allowPattern ? new RegExp(allowPattern) : null;
1783
+ for (const item of declarationsCollectNamed(program)) {
1784
+ if (item.node.type !== "TSTypeAliasDeclaration" && item.node.type !== "TSInterfaceDeclaration" || allowed?.test(item.name)) {
1785
+ continue;
1786
+ }
1787
+ context.report({
1788
+ node: item.node,
1789
+ messageId: "typeDeclaration",
1790
+ data: { name: item.name }
1791
+ });
1792
+ }
1793
+ }
1794
+ };
1795
+ }
1796
+ });
1797
+
1631
1798
  // src/rules/no-unescaped-like.ts
1632
- import { defineRule as defineRule19 } from "@oxlint/plugins";
1633
- var noUnescapedLike = defineRule19({
1799
+ import { defineRule as defineRule21 } from "@oxlint/plugins";
1800
+ var noUnescapedLike = defineRule21({
1634
1801
  meta: {
1635
1802
  type: "problem",
1636
1803
  schema: [{
@@ -1676,8 +1843,8 @@ var noUnescapedLike = defineRule19({
1676
1843
  });
1677
1844
 
1678
1845
  // src/rules/only-export-components.ts
1679
- import { defineRule as defineRule20 } from "@oxlint/plugins";
1680
- var onlyExportComponents = defineRule20({
1846
+ import { defineRule as defineRule22 } from "@oxlint/plugins";
1847
+ var onlyExportComponents = defineRule22({
1681
1848
  meta: {
1682
1849
  type: "problem",
1683
1850
  schema: [{
@@ -1733,8 +1900,8 @@ var onlyExportComponents = defineRule20({
1733
1900
  });
1734
1901
 
1735
1902
  // src/rules/require-file-factory.ts
1736
- import { defineRule as defineRule21 } from "@oxlint/plugins";
1737
- var requireFileFactory = defineRule21({
1903
+ import { defineRule as defineRule23 } from "@oxlint/plugins";
1904
+ var requireFileFactory = defineRule23({
1738
1905
  meta: {
1739
1906
  type: "problem",
1740
1907
  schema: [{
@@ -1780,8 +1947,8 @@ var requireFileFactory = defineRule21({
1780
1947
  });
1781
1948
 
1782
1949
  // src/rules/require-object-params.ts
1783
- import { defineRule as defineRule22 } from "@oxlint/plugins";
1784
- var requireObjectParams = defineRule22({
1950
+ import { defineRule as defineRule24 } from "@oxlint/plugins";
1951
+ var requireObjectParams = defineRule24({
1785
1952
  meta: {
1786
1953
  type: "problem",
1787
1954
  schema: [],
@@ -1807,8 +1974,8 @@ var requireObjectParams = defineRule22({
1807
1974
  });
1808
1975
 
1809
1976
  // src/rules/require-orpc-output.ts
1810
- import { defineRule as defineRule23 } from "@oxlint/plugins";
1811
- var requireOrpcOutput = defineRule23({
1977
+ import { defineRule as defineRule25 } from "@oxlint/plugins";
1978
+ var requireOrpcOutput = defineRule25({
1812
1979
  meta: {
1813
1980
  type: "problem",
1814
1981
  schema: [{
@@ -1850,8 +2017,8 @@ var requireOrpcOutput = defineRule23({
1850
2017
  });
1851
2018
 
1852
2019
  // src/rules/require-paired-call.ts
1853
- import { defineRule as defineRule24 } from "@oxlint/plugins";
1854
- var requirePairedCall = defineRule24({
2020
+ import { defineRule as defineRule26 } from "@oxlint/plugins";
2021
+ var requirePairedCall = defineRule26({
1855
2022
  meta: {
1856
2023
  type: "problem",
1857
2024
  schema: [{
@@ -1906,8 +2073,8 @@ var requirePairedCall = defineRule24({
1906
2073
  });
1907
2074
 
1908
2075
  // src/rules/route-surface.ts
1909
- import { defineRule as defineRule25 } from "@oxlint/plugins";
1910
- var routeSurface = defineRule25({
2076
+ import { defineRule as defineRule27 } from "@oxlint/plugins";
2077
+ var routeSurface = defineRule27({
1911
2078
  meta: {
1912
2079
  type: "problem",
1913
2080
  schema: [{
@@ -1952,6 +2119,7 @@ var routeSurface = defineRule25({
1952
2119
  var src_default = eslintCompatPlugin({
1953
2120
  meta: { name: "arch" },
1954
2121
  rules: {
2122
+ "declaration-name": declarationName,
1955
2123
  "export-file-prefix": exportFilePrefix,
1956
2124
  "export-name-pattern": exportNamePattern,
1957
2125
  "filename-export-name": filenameExportName,
@@ -1970,6 +2138,7 @@ var src_default = eslintCompatPlugin({
1970
2138
  "no-single-use-scalar-schema": noSingleUseScalarSchema,
1971
2139
  "no-top-level-functions": noTopLevelFunctions,
1972
2140
  "no-trivial-functions": noTrivialFunctions,
2141
+ "no-type-declarations": noTypeDeclarations,
1973
2142
  "no-unescaped-like": noUnescapedLike,
1974
2143
  "only-export-components": onlyExportComponents,
1975
2144
  "require-file-factory": requireFileFactory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-arch",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Configurable architecture rules for Oxlint JavaScript plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",