@oc-mui/eslint-config
v1.1.1
Published
Shared ESLint configuration (wrapper-library and architectural boundary rules) for the Opencast Management UI and its plugins.
Readme
@oc-mui/eslint-config
Shared ESLint configurations for the workspace. Every package extends one of these so the rule set stays consistent.
Configurations
| Subpath | Extends | Use it for |
|---------|---------|------------|
| @oc-mui/eslint-config/base | ESLint recommended + @typescript-eslint recommended + Prettier + Turbo + only-warn | Any non-React package. |
| @oc-mui/eslint-config/react-internal | The base config + React + React Hooks + browser globals + auto React-version detection. | React apps and component libraries. |
| @oc-mui/eslint-config/type-aware | Optional type-aware rules (no-floating-promises, no-misused-promises). Requires TS type info; slower. | Packages where strict Promise handling matters. |
Usage
// eslint.config.js (non-React package)
import { config } from "@oc-mui/eslint-config/base";
export default config;// eslint.config.js (React app or component library)
import { config as base } from "@oc-mui/eslint-config/base";
import { config as react } from "@oc-mui/eslint-config/react-internal";
export default [
...base,
...react,
// package-specific overrides
];What the base config enforces
- The wrapper rule:
no-restricted-importsblocks direct imports of@tanstack/react-router,@tanstack/react-query,i18next,react-i18next,jotai,@dnd-kit/*— those must go through@oc-mui/router,@oc-mui/query,@oc-mui/i18n,@oc-mui/store, and@oc-mui/ui(SortableList) for drag-and-drop. Each wrapper package has an explicit exception for itself. - Architectural boundaries via
eslint-plugin-boundaries: apps can import from packages and plugins; plugins from packages (and@oc-mui/plugin-core); packages from packages. Cross-plugin imports are caught. See the comment block inbase.jsunder "Known limitations" for the exact element/rule matrix. - GraphQL operation naming via the custom
local/graphql-operation-namingrule (inrules/): everyquery/mutation/subscription/fragmentdeclared in agql\`template literal or.graphqlfile must be prefixed with the owning plugin's namespace in PascalCase (orMuifor shared-core code inpackages/query/`). Implements CONTRACTS.md §6. - No raw palette colour classes via the custom
local/no-palette-classesrule (inrules/): Tailwind's numbered palette classes (text-gray-900,border-slate-300, …) are forbidden in string/template literals — use the semantic tokens fromdocs/extend/styling.mdinstead. The shadcn-generatedcomponents/ui/layer is excluded.
Custom rules
Live under rules/ and are exported as a tiny local plugin (rules/index.js). The plugin is wired in base.js under the name local, so configurations refer to rules as local/<rule-name>. Two rules live here today: local/graphql-operation-naming and local/no-palette-classes.
Run the rule tests:
pnpm --filter @oc-mui/eslint-config testLayer
Core infrastructure. Depends on nothing in the workspace.
See also
base.js— the source of truth, with inline rationale comments for non-obvious rules.docs/reference/open-followups.md§3 — known boundaries-plugin limitations and the planned v6 migration.
