oxlint-plugin-arch 0.6.0 → 0.6.1

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1
4
+
5
+ - Relax the preset's shadcn defaults for stock composition, so strict consumers need no overrides: exact padding groups on `CardContent`/`PopoverContent`, gap and padding on `TabsContent`, and gap on `Tabs`/`HoverCardContent`/`SidebarHeader`/`BreadcrumbList`; exact `truncate` everywhere. Controls such as `Button` stay protected.
6
+ - Allow safe-area padding values (`env(safe-area-inset-*)` and `max(--spacing(*),env(safe-area-inset-*))` on padding sides/axes) in `shadcn/no-arbitrary-values`. Literal floors such as `max(1rem,…)` stay rejected.
7
+ - Allow the stock Sonner hooks `toaster` and `toast` only in each web root's `components/ui/sonner.tsx`. No new preset options.
8
+
3
9
  ## 0.6.0
4
10
 
5
11
  - Add `tests.profile` (`fixtures` by default, or `standard`), explicit custom test/assertion names, parameterized-test recognition and assertion-based narrowing guidance. Both profiles retain assertion, mock and type-safety checks; fixtures additionally require named fixture/support imports.
package/README.md CHANGED
@@ -105,7 +105,19 @@ Available policies: `typePlacement`, `typeSafety`, `serviceStructure`, `fileLayo
105
105
 
106
106
  `severity` defaults to `error` and accepts `warn`. File and function limits default to 400 and 32. React Compiler is assumed by default: manual memoization is banned and the four React performance rules against render-time function/object/array/JSX props are off. `react: { compiler: false }` allows manual memoization and enables those four rules. `react: { componentProps: false }` turns off only `arch/component-props` (props typed with `interface XProps` directly above each component); it is on by default. `shadcn: false` disables shadcn integration while retaining Tailwind checks. `tailwind` accepts `cssEntryPoint`, `cssEntryPointsByRoot` and `rootFontSize`; `shadcn` accepts `uiImportPath` and `componentImportSources`. UI-kit files remain linted, with architecture/appearance exceptions rather than a global ignore.
107
107
 
108
- Shadcn allows caller-owned layout and standard opacity utilities. Add product-specific component contracts through `policies.shadcn` or native overrides, keeping `layout` and `opacity` in replacement allowances.
108
+ Shadcn allows caller-owned layout, standard opacity utilities and exact `truncate` (including variant forms). Stock composition slots also allow these class groups:
109
+
110
+ | Components | Additional groups |
111
+ | --- | --- |
112
+ | `CardContent`, `PopoverContent` | `p`, `px`, `py`, `ps`, `pe`, `pt`, `pr`, `pb`, `pl` |
113
+ | `TabsContent` | The padding groups above plus `gap`, `gap-x`, `gap-y` |
114
+ | `Tabs`, `HoverCardContent`, `SidebarHeader`, `BreadcrumbList` | `gap`, `gap-x`, `gap-y` |
115
+
116
+ These are exact component-name contracts, not blanket content/spacing exceptions. Each keeps `layout`, `opacity` and `truncate`; controls such as `Button` still reject padding and gap overrides. A contract's `allow` replaces the baseline, and the last matching contract wins. Native file-specific rule options replace contract arrays rather than merging them.
117
+
118
+ Arbitrary padding values may use `env(safe-area-inset-top)`, `env(safe-area-inset-right)`, `env(safe-area-inset-bottom)` or `env(safe-area-inset-left)` with any padding group above. Padding sides/axes (not `p`) also allow `max(--spacing(*),env(safe-area-inset-…))`, for example `pb-[max(--spacing(4),env(safe-area-inset-bottom))]`. Literal floors such as `max(1rem,env(…))` remain rejected. These are narrow class globs, **not CSS-expression validation**: the wildcard inside `--spacing(...)` can still match malformed arguments or extra arithmetic. The allowance does not bypass component restyling checks.
119
+
120
+ Only `<web root>/src/components/ui/sonner.tsx` allows the stock Sonner selector hooks `toaster` and `toast`; all other unknown classes remain checked, including in UI files. These defaults need no extra preset options or consumer overrides.
109
121
 
110
122
  Module configuration, lookup tables, limits and defaults belong in domain `.constants.ts` files, including frontend services. All frontend constant declarations carry the domain prefix (for example `BOT_MODEL_PRIORITY`). Frontend service scopes enable `modules/domain-constants` with `includeData: true`: it detects module-level literal/object/array data, literal calculations and seeded Map/Set tables, plus the existing uppercase constants. Function-local calculations and call-created service instances remain in their owner; empty Map/Set state is not classified as configuration. This is syntactic enforcement, not semantic data-flow analysis: imported aliases and arbitrary call-created configuration still need review. Backend rule defaults are unchanged. Every scope follows the configured architecture roots; a web `.server.ts` file remains frontend-owned.
111
123
 
@@ -1042,15 +1042,35 @@ function presetReactConfig(context) {
1042
1042
  ]))));
1043
1043
  }
1044
1044
  if (Object.keys(css).length && options.shadcn !== false) {
1045
+ const allow = ["layout", "opacity", "truncate"];
1046
+ const padding = ["p", "px", "py", "ps", "pe", "pt", "pr", "pb", "pl"];
1047
+ const gap = ["gap", "gap-x", "gap-y"];
1048
+ const safeArea = padding.flatMap((group) => ["top", "right", "bottom", "left"].flatMap((side) => [
1049
+ `${group}-[env(safe-area-inset-${side})]`,
1050
+ ...group === "p" ? [] : [`${group}-[max(--spacing(*),env(safe-area-inset-${side}))]`]
1051
+ ]));
1045
1052
  policies.shadcn = [
1046
1053
  presetOverride(webFiles, {
1047
- "shadcn/no-restyle": ["error", { allow: ["layout", "opacity"] }],
1048
- "shadcn/no-arbitrary-values": ["error", { allow: ["layout"] }],
1054
+ "shadcn/no-restyle": [
1055
+ "error",
1056
+ {
1057
+ allow,
1058
+ contracts: [
1059
+ { pattern: "^(CardContent|PopoverContent)$", allow: [...allow, ...padding] },
1060
+ { pattern: "^TabsContent$", allow: [...allow, ...gap, ...padding] },
1061
+ { pattern: "^(Tabs|HoverCardContent|SidebarHeader|BreadcrumbList)$", allow: [...allow, ...gap] }
1062
+ ]
1063
+ }
1064
+ ],
1065
+ "shadcn/no-arbitrary-values": ["error", { allow: ["layout", ...safeArea] }],
1049
1066
  "shadcn/require-static-classes": "error",
1050
1067
  "modules/dynamic-classes": "error"
1051
1068
  }, ui),
1052
1069
  presetOverride(webFiles, {
1053
1070
  "shadcn/no-unknown-classes": ["error", { allow: [] }]
1071
+ }),
1072
+ presetOverride(presetScopes(web, "components/ui/sonner.tsx"), {
1073
+ "shadcn/no-unknown-classes": ["error", { allow: ["toaster", "toast"] }]
1054
1074
  })
1055
1075
  ];
1056
1076
  }
@@ -1042,15 +1042,35 @@ function presetReactConfig(context) {
1042
1042
  ]))));
1043
1043
  }
1044
1044
  if (Object.keys(css).length && options.shadcn !== false) {
1045
+ const allow = ["layout", "opacity", "truncate"];
1046
+ const padding = ["p", "px", "py", "ps", "pe", "pt", "pr", "pb", "pl"];
1047
+ const gap = ["gap", "gap-x", "gap-y"];
1048
+ const safeArea = padding.flatMap((group) => ["top", "right", "bottom", "left"].flatMap((side) => [
1049
+ `${group}-[env(safe-area-inset-${side})]`,
1050
+ ...group === "p" ? [] : [`${group}-[max(--spacing(*),env(safe-area-inset-${side}))]`]
1051
+ ]));
1045
1052
  policies.shadcn = [
1046
1053
  presetOverride(webFiles, {
1047
- "shadcn/no-restyle": ["error", { allow: ["layout", "opacity"] }],
1048
- "shadcn/no-arbitrary-values": ["error", { allow: ["layout"] }],
1054
+ "shadcn/no-restyle": [
1055
+ "error",
1056
+ {
1057
+ allow,
1058
+ contracts: [
1059
+ { pattern: "^(CardContent|PopoverContent)$", allow: [...allow, ...padding] },
1060
+ { pattern: "^TabsContent$", allow: [...allow, ...gap, ...padding] },
1061
+ { pattern: "^(Tabs|HoverCardContent|SidebarHeader|BreadcrumbList)$", allow: [...allow, ...gap] }
1062
+ ]
1063
+ }
1064
+ ],
1065
+ "shadcn/no-arbitrary-values": ["error", { allow: ["layout", ...safeArea] }],
1049
1066
  "shadcn/require-static-classes": "error",
1050
1067
  "modules/dynamic-classes": "error"
1051
1068
  }, ui),
1052
1069
  presetOverride(webFiles, {
1053
1070
  "shadcn/no-unknown-classes": ["error", { allow: [] }]
1071
+ }),
1072
+ presetOverride(presetScopes(web, "components/ui/sonner.tsx"), {
1073
+ "shadcn/no-unknown-classes": ["error", { allow: ["toaster", "toast"] }]
1054
1074
  })
1055
1075
  ];
1056
1076
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-arch",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Configurable architecture rules for Oxlint JavaScript plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",