oxlint-plugin-arch 0.12.3 → 0.12.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.
@@ -0,0 +1,2 @@
1
+ import type { PresetBuilder } from '../../types/preset.types.ts';
2
+ export declare const effectGroup: PresetBuilder<'effect'>;
@@ -40,6 +40,10 @@ export declare const presetRecipes: {
40
40
  library: {
41
41
  schemas: true;
42
42
  };
43
+ effect: {
44
+ schemas: true;
45
+ effect: true;
46
+ };
43
47
  ui: {
44
48
  react: boolean;
45
49
  kit: boolean;
@@ -45,6 +45,10 @@ export declare const recipes: {
45
45
  library: {
46
46
  schemas: true;
47
47
  };
48
+ effect: {
49
+ schemas: true;
50
+ effect: true;
51
+ };
48
52
  ui: {
49
53
  react: boolean;
50
54
  kit: boolean;
@@ -18,6 +18,7 @@ var presetRecipes = {
18
18
  react: { react: true, tailwind: true, schemas: true },
19
19
  desktop: { console: true },
20
20
  library: { schemas: true },
21
+ effect: { schemas: true, effect: true },
21
22
  ui: presetUi,
22
23
  kit: presetUi,
23
24
  cli: { console: true }
@@ -399,6 +400,7 @@ var presetGroupOrder = [
399
400
  "schemas",
400
401
  "sql",
401
402
  "orpc",
403
+ "effect",
402
404
  "react",
403
405
  "forms",
404
406
  "tanstack",
@@ -460,6 +462,7 @@ var presetGroupOptions = {
460
462
  schemas: { level: "error" },
461
463
  forms: { level: "error", resolver: "standardSchemaResolver" },
462
464
  sql: { level: "error", sanitizers: ["escapeLikeWildcards"] },
465
+ effect: { level: "error", width: 160, exports: undefined, skip: undefined },
463
466
  console: { level: "error" },
464
467
  deny: { level: "error", imports: {}, calls: {} },
465
468
  externals: { level: "error", packages: presetExternals }
@@ -806,7 +809,8 @@ function presetBackendConventions(root, key, value, denied) {
806
809
  ]));
807
810
  conventions[posix2.join(servicesKey, domain)] = presetDeny(Object.fromEntries(imports));
808
811
  }
809
- for (const tests of ["tests", "test"]) {
812
+ const testFolders = ["tests", "test"];
813
+ for (const tests of testFolders) {
810
814
  if (exists(posix2.join(tests, "kits"))) {
811
815
  conventions[tests] = presetDeny(Object.fromEntries(presetKitImports.map((pattern) => [pattern, "Import the kit file you need."])));
812
816
  conventions[posix2.join(tests, "kits")] = { naming: { files: presetKitFiles } };
@@ -818,7 +822,7 @@ function presetBackendConventions(root, key, value, denied) {
818
822
  for (const child of presetDirectories(root, posix2.join(key, folder)).map((path) => posix2.relative(key, path))) {
819
823
  if (posix2.basename(child) === "migrations") {
820
824
  conventions[child] = { layout: false, naming: { files: presetMigrationFiles, unique: presetMigrationNumber } };
821
- } else if (child.split("/").length < 8) {
825
+ } else if (child.split("/").length < 8 && !testFolders.includes(posix2.basename(child))) {
822
826
  queue.push(child);
823
827
  }
824
828
  }
@@ -1070,6 +1074,34 @@ var denyGroup = (project, settings) => {
1070
1074
  return overrides;
1071
1075
  };
1072
1076
 
1077
+ // src/preset/groups/effect.ts
1078
+ var effectGroup = (project, settings) => {
1079
+ const files = [`**/${presetExtensions}`];
1080
+ const max = settings.width;
1081
+ return [
1082
+ presetOverride(files, {
1083
+ "arch/code-trivial-functions": "off",
1084
+ "arch/code-branch-once": "error",
1085
+ "arch/code-function-nesting": ["error", { max: 4 }],
1086
+ "arch/code-inline": ["error", { max, nesting: 2, keep: ["^[A-Z]", "^layer"], allow: "^(?:decode|encode)[A-Z]", services: ["of"] }],
1087
+ "arch/code-yield-argument": "error",
1088
+ "arch/layout-arrow-body": ["error", { max }],
1089
+ "arch/layout-call-arguments": ["error", { split: false, hug: { max }, join: { max, nesting: 2, keep: ["Layer.mergeAll"] } }],
1090
+ "arch/layout-call-depth": ["error", { max: 2 }],
1091
+ "arch/layout-items": "error",
1092
+ "arch/layout-pipe": "error",
1093
+ "arch/layout-ternary": ["error", { fit: false, branch: { max: 3 } }]
1094
+ }),
1095
+ presetOverride(files, {
1096
+ "arch/code-justified-call": [
1097
+ "error",
1098
+ { calls: ["Effect.promise"], message: "Effect.promise turns a rejection into a defect; otherwise use Effect.tryPromise with a tagged error." }
1099
+ ],
1100
+ "arch/code-traced": ["error", { exports: settings.exports, skip: settings.skip, message: "An exported function or service method gets a span: use Effect.fn('<name>')." }]
1101
+ }, project.testFiles)
1102
+ ];
1103
+ };
1104
+
1073
1105
  // src/preset/groups/expo.ts
1074
1106
  var expoGroup = (project, settings) => {
1075
1107
  const { expoWeb, testFiles } = project;
@@ -2184,6 +2216,7 @@ var presetBuilders = {
2184
2216
  schemas: schemasGroup,
2185
2217
  sql: sqlGroup,
2186
2218
  orpc: orpcGroup,
2219
+ effect: effectGroup,
2187
2220
  react: reactGroup,
2188
2221
  forms: formsGroup,
2189
2222
  tanstack: tanstackGroup,
@@ -0,0 +1 @@
1
+ export declare const codeBranchOnce: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const codeFunctionNesting: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const codeInline: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const codeJustifiedCall: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const codeTraced: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const codeYieldArgument: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const layoutArrowBody: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const layoutCallDepth: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const layoutItems: import("@oxlint/plugins").Rule;
@@ -0,0 +1 @@
1
+ export declare const layoutPipe: import("@oxlint/plugins").Rule;
@@ -1,2 +1,3 @@
1
1
  import type { ESTree } from '@oxlint/plugins';
2
2
  export type AstFunction = ESTree.Function | ESTree.ArrowFunctionExpression;
3
+ export type AstCall = ESTree.CallExpression | ESTree.NewExpression;
@@ -57,3 +57,25 @@ export interface CodeTrivialFunctionsGuardState {
57
57
  returned: boolean;
58
58
  globalArray: (node: ESTree.Node) => boolean;
59
59
  }
60
+ export interface CodeInlineOptions {
61
+ max?: number;
62
+ nesting?: number;
63
+ allow?: OptionsPattern;
64
+ keep?: OptionsPattern;
65
+ services?: string[];
66
+ }
67
+ export interface CodeFunctionNestingOptions {
68
+ max?: number;
69
+ }
70
+ export interface CodeJustifiedCallOptions {
71
+ calls: string[];
72
+ comment?: string;
73
+ message?: string;
74
+ }
75
+ export interface CodeTracedOptions {
76
+ untraced?: string[];
77
+ exports?: OptionsPattern;
78
+ services?: string[];
79
+ skip?: OptionsPattern;
80
+ message?: string;
81
+ }
@@ -8,6 +8,15 @@ export interface LayoutEdit {
8
8
  export interface LayoutCallArgumentsOptions {
9
9
  min?: number;
10
10
  indent?: number;
11
+ split?: boolean;
12
+ hug?: {
13
+ max: number;
14
+ };
15
+ join?: {
16
+ max: number;
17
+ nesting?: number;
18
+ keep?: string[];
19
+ };
11
20
  }
12
21
  export interface LayoutCallArrayOptions {
13
22
  callees?: string[];
@@ -52,4 +61,17 @@ export type LayoutPaddingKind = 'variable' | 'block' | 'control' | 'return' | 'o
52
61
  export interface LayoutTernaryOptions {
53
62
  max?: number;
54
63
  indent?: number;
64
+ fit?: boolean;
65
+ branch?: {
66
+ max: number;
67
+ };
68
+ }
69
+ export interface LayoutItemsOptions {
70
+ indent?: SourceIndent;
71
+ }
72
+ export interface LayoutCallDepthOptions {
73
+ max?: number;
74
+ }
75
+ export interface LayoutArrowBodyOptions {
76
+ max?: number;
55
77
  }
@@ -1,3 +1,4 @@
1
+ import type { OptionsPattern } from './options.types.ts';
1
2
  import type { OxlintConfig, OxlintOverride } from 'oxlint';
2
3
  export type PresetLevel = 'error' | 'warn';
3
4
  export type PresetSwitch = boolean | 'warn';
@@ -120,6 +121,11 @@ export interface PresetOrpcOptions {
120
121
  export interface PresetFormsOptions {
121
122
  resolver?: string;
122
123
  }
124
+ export interface PresetEffectOptions {
125
+ width?: number;
126
+ exports?: OptionsPattern;
127
+ skip?: OptionsPattern;
128
+ }
123
129
  export interface PresetSqlOptions {
124
130
  sanitizers?: string[];
125
131
  }
@@ -145,6 +151,7 @@ export interface PresetGroups {
145
151
  schemas?: PresetSwitch;
146
152
  forms?: PresetSwitch | PresetFormsOptions;
147
153
  sql?: PresetSwitch | PresetSqlOptions;
154
+ effect?: PresetSwitch | PresetEffectOptions;
148
155
  console?: boolean;
149
156
  deny?: PresetSwitch | PresetDenyOptions;
150
157
  externals?: PresetSwitch | PresetExternalsOptions;
@@ -190,6 +197,9 @@ export interface PresetResolvedGroups {
190
197
  schemas: PresetEmptyOptions;
191
198
  forms: Required<PresetFormsOptions>;
192
199
  sql: Required<PresetSqlOptions>;
200
+ effect: Pick<PresetEffectOptions, 'exports' | 'skip'> & {
201
+ width: number;
202
+ };
193
203
  console: PresetEmptyOptions;
194
204
  deny: {
195
205
  imports: Record<string, string>;
@@ -1,4 +1,4 @@
1
- import type { AstFunction } from '../types/ast.types.ts';
1
+ import type { AstCall, AstFunction } from '../types/ast.types.ts';
2
2
  import type { ESTree } from '@oxlint/plugins';
3
3
  export declare function astVisit(node: unknown, ancestors: ESTree.Node[], callback: (node: ESTree.Node, ancestors: ESTree.Node[]) => void): void;
4
4
  export declare function astMatchesCallee(name: string | undefined, callees: readonly string[], modifiers: ReadonlySet<string>): boolean;
@@ -17,3 +17,9 @@ export declare function astMemberName(node: ESTree.MemberExpression): string | u
17
17
  export declare function astDottedName(node: ESTree.Node): string | undefined;
18
18
  export declare function astCallName(node: ESTree.CallExpression): string | undefined;
19
19
  export declare function astSelectorRule(selector: string, message: string): import("@oxlint/plugins").Rule;
20
+ export declare function astIsOneLine(node: ESTree.Node): boolean;
21
+ export declare function astIsInlineFunction(node: ESTree.Node): node is AstFunction;
22
+ export declare function astIsCall(node: ESTree.Node): node is AstCall;
23
+ export declare function astIsPipe(node: AstCall): boolean;
24
+ export declare function astSome(value: unknown, test: (node: ESTree.Node) => boolean, enter?: (node: ESTree.Node) => boolean): boolean;
25
+ export declare function astCallDepth(value: unknown): number;
@@ -1,5 +1,5 @@
1
1
  import type { SourceIndent } from '../types/source.types.ts';
2
- import type { ESTree } from '@oxlint/plugins';
2
+ import type * as PluginsTypes from '@oxlint/plugins';
3
3
  export declare const sourceIndentSchema: {
4
4
  anyOf: ({
5
5
  type: string;
@@ -11,8 +11,12 @@ export declare const sourceIndentSchema: {
11
11
  enum: string[];
12
12
  })[];
13
13
  };
14
- export declare function sourceCommentText(comment: Pick<ESTree.Comment, 'type' | 'value'>): string;
14
+ export declare function sourceCommentText(comment: Pick<PluginsTypes.ESTree.Comment, 'type' | 'value'>): string;
15
15
  export declare function sourceIsDirective(text: string): boolean;
16
16
  export declare function sourceLineIndent(text: string, offset: number): string;
17
17
  export declare function sourceIndentUnit(indent?: SourceIndent): string;
18
18
  export declare function sourceNewline(text: string): string;
19
+ export declare function sourceLineStart(text: string, offset: number): number;
20
+ export declare function sourceLineEnd(text: string, offset: number): number;
21
+ export declare function sourceItemGaps(open: number, items: readonly PluginsTypes.Ranged[], close: number): PluginsTypes.Range[];
22
+ export declare function sourceRespace(fixer: PluginsTypes.Fixer, text: string, gaps: PluginsTypes.Range[], spacing: (index: number, last: boolean) => string): PluginsTypes.Fix[] | null;
@@ -327,6 +327,39 @@ function astSelectorRule(selector, message) {
327
327
  }
328
328
  });
329
329
  }
330
+ function astIsOneLine(node) {
331
+ return node.loc.start.line === node.loc.end.line;
332
+ }
333
+ function astIsInlineFunction(node) {
334
+ return node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
335
+ }
336
+ function astIsCall(node) {
337
+ return node.type === "CallExpression" || node.type === "NewExpression";
338
+ }
339
+ function astIsPipe(node) {
340
+ return node.callee.type === "MemberExpression" && astMemberName(node.callee) === "pipe";
341
+ }
342
+ function astChildren(node) {
343
+ return Object.entries(node).filter(([key]) => !astSkippedKeys.has(key)).map(([, child]) => child);
344
+ }
345
+ function astSome(value, test, enter = () => true) {
346
+ if (Array.isArray(value)) {
347
+ return value.some((child) => astSome(child, test, enter));
348
+ }
349
+ return astIsNode(value) && (test(value) || enter(value) && astChildren(value).some((child) => astSome(child, test, enter)));
350
+ }
351
+ function astCallDepth(value) {
352
+ if (Array.isArray(value)) {
353
+ return Math.max(0, ...value.map(astCallDepth));
354
+ }
355
+ if (!astIsNode(value) || astIsInlineFunction(value)) {
356
+ return 0;
357
+ }
358
+ if (astIsCall(value)) {
359
+ return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments), astCallDepth(value.callee));
360
+ }
361
+ return astCallDepth(astChildren(value));
362
+ }
330
363
 
331
364
  // src/vendor/dillon-anti-slop/shared/type-reference-name.ts
332
365
  function typeReferenceName(type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-arch",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
4
4
  "description": "Configurable architecture rules for Oxlint JavaScript plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",