@cratis/eslint-plugin-components 0.0.0

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/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # @cratis/eslint-plugin-components
2
+
3
+ ESLint rules for projects that consume Cratis Components. Compose these on top of the
4
+ Cratis base config, [`@cratis/eslint-config`](https://www.npmjs.com/package/@cratis/eslint-config).
5
+
6
+ | Rule | What it does |
7
+ |---|---|
8
+ | `no-root-barrel-import` | Disallows importing from the `@cratis/components` root barrel. Use a subpath export (`@cratis/components/CommandDialog`, `@cratis/components/DataPage`, `@cratis/components/Toolbar`, …) — the root pulls the whole optional-peer-heavy surface and hides intent. |
9
+ | `no-primereact-dialog` | Disallows importing `Dialog` from `primereact/dialog`. Use `CommandDialog` from `@cratis/components/CommandDialog`, or `Dialog` from `@cratis/components/Dialogs` — the wrappers add Arc command binding, overlay/focus fixes, and theming. |
10
+
11
+ Both cover `import` and re-`export … from` forms.
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ yarn add -D @cratis/eslint-plugin-components @cratis/eslint-config eslint
17
+ ```
18
+
19
+ ## Use
20
+
21
+ ```js
22
+ // eslint.config.mjs
23
+ import cratis from '@cratis/eslint-config';
24
+ import components from '@cratis/eslint-plugin-components';
25
+
26
+ export default [
27
+ ...cratis.configs.consumer,
28
+ ...components.configs.recommended,
29
+ // …your project rules
30
+ ];
31
+ ```
32
+
33
+ ### Options
34
+
35
+ ```js
36
+ '@cratis/components/no-root-barrel-import': ['error', {
37
+ packageName: '@cratis/components', // barrel to forbid
38
+ allow: [], // exact specifiers to permit
39
+ }],
40
+ '@cratis/components/no-primereact-dialog': ['error', {
41
+ source: 'primereact/dialog', // module to forbid
42
+ }],
43
+ ```
package/index.js ADDED
@@ -0,0 +1,41 @@
1
+ import { createRequire } from 'node:module';
2
+ import { noPrimereactDialog } from './lib/noPrimereactDialog.js';
3
+ import { noRootBarrelImport } from './lib/noRootBarrelImport.js';
4
+
5
+ const { version } = createRequire(import.meta.url)('./package.json');
6
+
7
+ // A single flat-config plugin object — meta + rules + self-referencing configs — per the
8
+ // ESLint flat-config plugin convention. The default export IS the plugin, so consumers
9
+ // get `components.meta`, `components.rules`, and `components.configs` directly. Composes
10
+ // on top of @cratis/eslint-config.
11
+ const plugin = {
12
+ meta: { name: '@cratis/eslint-plugin-components', version },
13
+ rules: {
14
+ 'no-primereact-dialog': noPrimereactDialog,
15
+ 'no-root-barrel-import': noRootBarrelImport,
16
+ },
17
+ configs: {},
18
+ };
19
+
20
+ // configs reference the plugin itself, so they are assigned after it exists.
21
+ //
22
+ // import cratis from '@cratis/eslint-config';
23
+ // import components from '@cratis/eslint-plugin-components';
24
+ // export default [...cratis.configs.consumer, ...components.configs.recommended];
25
+ Object.assign(plugin.configs, {
26
+ recommended: [
27
+ {
28
+ name: '@cratis/components/recommended',
29
+ files: ['**/*.ts', '**/*.tsx'],
30
+ plugins: { '@cratis/components': plugin },
31
+ rules: {
32
+ '@cratis/components/no-primereact-dialog': 'error',
33
+ '@cratis/components/no-root-barrel-import': 'error',
34
+ },
35
+ },
36
+ ],
37
+ });
38
+
39
+ export default plugin;
40
+ export const { configs, rules, meta } = plugin;
41
+ export { noPrimereactDialog, noRootBarrelImport };
@@ -0,0 +1,45 @@
1
+ const DEFAULTS = { source: 'primereact/dialog' };
2
+
3
+ // Disallow importing PrimeReact's Dialog directly. Cratis Components wraps it with
4
+ // behavior (Arc command binding, overlay/focus fixes, theming) via CommandDialog and the
5
+ // Dialogs surface; reaching past those to `primereact/dialog` bypasses all of it. Covers
6
+ // `import` and re-`export … from` forms.
7
+ export const noPrimereactDialog = {
8
+ meta: {
9
+ type: 'suggestion',
10
+ docs: {
11
+ description: 'Disallow importing Dialog from primereact/dialog; use the Cratis Components dialog wrappers.',
12
+ recommended: true,
13
+ url: 'https://github.com/Cratis/Components/blob/main/ESLint/README.md',
14
+ },
15
+ schema: [{
16
+ type: 'object',
17
+ properties: {
18
+ source: { type: 'string' },
19
+ },
20
+ additionalProperties: false,
21
+ }],
22
+ messages: {
23
+ useWrapper: "Do not import from '{{source}}'. Use CommandDialog from '@cratis/components/CommandDialog', or Dialog from '@cratis/components/Dialogs'.",
24
+ },
25
+ },
26
+ create(context) {
27
+ const options = { ...DEFAULTS, ...(context.options[0] ?? {}) };
28
+
29
+ const check = node => {
30
+ const source = node.source;
31
+ if (!source || typeof source.value !== 'string') return;
32
+ if (source.value === options.source) {
33
+ context.report({ node: source, messageId: 'useWrapper', data: { source: options.source } });
34
+ }
35
+ };
36
+
37
+ return {
38
+ ImportDeclaration: check,
39
+ ExportNamedDeclaration: check,
40
+ ExportAllDeclaration: check,
41
+ };
42
+ },
43
+ };
44
+
45
+ export default noPrimereactDialog;
@@ -0,0 +1,48 @@
1
+ const DEFAULTS = { packageName: '@cratis/components', allow: [] };
2
+
3
+ // Disallow importing from the Cratis Components root barrel. The package exposes
4
+ // purpose-built subpath exports (`@cratis/components/CommandDialog`,
5
+ // `@cratis/components/DataPage`, `@cratis/components/Toolbar`, …); importing the root
6
+ // pulls the whole optional-peer-heavy surface and hides intent. Covers `import` and
7
+ // re-`export … from` forms.
8
+ export const noRootBarrelImport = {
9
+ meta: {
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Disallow importing from the @cratis/components root barrel; use a subpath export.',
13
+ recommended: true,
14
+ url: 'https://github.com/Cratis/Components/blob/main/ESLint/README.md',
15
+ },
16
+ schema: [{
17
+ type: 'object',
18
+ properties: {
19
+ packageName: { type: 'string' },
20
+ allow: { type: 'array', items: { type: 'string' } },
21
+ },
22
+ additionalProperties: false,
23
+ }],
24
+ messages: {
25
+ useSubpath: "Import from a '{{packageName}}' subpath (e.g. '{{packageName}}/CommandDialog'), not the package root barrel.",
26
+ },
27
+ },
28
+ create(context) {
29
+ const options = { ...DEFAULTS, ...(context.options[0] ?? {}) };
30
+ const allow = new Set(options.allow);
31
+
32
+ const check = node => {
33
+ const source = node.source;
34
+ if (!source || typeof source.value !== 'string') return;
35
+ if (source.value === options.packageName && !allow.has(source.value)) {
36
+ context.report({ node: source, messageId: 'useSubpath', data: { packageName: options.packageName } });
37
+ }
38
+ };
39
+
40
+ return {
41
+ ImportDeclaration: check,
42
+ ExportNamedDeclaration: check,
43
+ ExportAllDeclaration: check,
44
+ };
45
+ },
46
+ };
47
+
48
+ export default noRootBarrelImport;
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@cratis/eslint-plugin-components",
3
+ "version": "0.0.0",
4
+ "description": "Cratis Components ESLint rules: import from subpaths, not the root barrel, and use the Cratis dialog wrappers instead of primereact/dialog. Compose on top of @cratis/eslint-config.",
5
+ "author": "Cratis",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Cratis/Components"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "keywords": [
16
+ "eslint",
17
+ "eslintplugin",
18
+ "eslint-plugin",
19
+ "cratis",
20
+ "components"
21
+ ],
22
+ "files": [
23
+ "index.js",
24
+ "lib",
25
+ "README.md"
26
+ ],
27
+ "exports": {
28
+ "./package.json": "./package.json",
29
+ ".": "./index.js"
30
+ },
31
+ "scripts": {
32
+ "test": "yarn g:test",
33
+ "ci": "yarn g:test"
34
+ },
35
+ "peerDependencies": {
36
+ "eslint": ">=9"
37
+ }
38
+ }