@wellingtonhlc/shared-ui 0.24.4 → 0.24.5

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 CHANGED
@@ -64,6 +64,33 @@ Nao inclua:
64
64
  | `npm run storybook` | Sobe o Storybook local. |
65
65
  | `npm run build-storybook` | Gera build estatico do Storybook. |
66
66
 
67
+ ## Validadores para consumidores
68
+
69
+ O pacote publica o CLI `shared-ui-check-page-actions` para validar o contrato de actions em projetos consumidores.
70
+
71
+ Contrato esperado:
72
+
73
+ - `AppLayout.actions` e somente o slot de layout.
74
+ - `Page.Actions` e o root visual da barra.
75
+ - Props como `helpContent`, `helpLabel`, `position`, `align` e `size` pertencem ao `Page.Actions`.
76
+ - Nao usar `ActionBar.*`, `Page.Root actions=...` dentro de `AppLayout`, Fragment, `div` ou `Page.ActionButton` solto como root de `AppLayout.actions`.
77
+
78
+ Uso recomendado no consumidor:
79
+
80
+ ```json
81
+ {
82
+ "scripts": {
83
+ "check:page-actions": "shared-ui-check-page-actions"
84
+ }
85
+ }
86
+ ```
87
+
88
+ Tambem e possivel apontar um diretorio explicitamente:
89
+
90
+ ```bash
91
+ shared-ui-check-page-actions ./src
92
+ ```
93
+
67
94
  ## Storybook
68
95
 
69
96
  O Storybook esta na linha `10.4.6` (`storybook`, `@storybook/react-vite`, `@storybook/addon-docs` e `@storybook/addon-a11y`).
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ export interface PageActionsCheckResult {
3
+ errors: string[];
4
+ scannedFiles: number;
5
+ sourceRoot: string;
6
+ }
7
+ export declare function checkPageActionsContract(rootDir?: string): PageActionsCheckResult;
8
+ export declare function runPageActionsContractCli(args?: string[]): PageActionsCheckResult;
9
+ //# sourceMappingURL=check-page-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-page-actions.d.ts","sourceRoot":"","sources":["../../src/cli/check-page-actions.ts"],"names":[],"mappings":";AAQA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAqCD,wBAAgB,wBAAwB,CAAC,OAAO,SAAgB,GAAG,sBAAsB,CAyDxF;AAED,wBAAgB,yBAAyB,CAAC,IAAI,WAAwB,0BAerE"}
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const extensions = new Set(['.ts', '.tsx']);
6
+ const ignoredDirectories = new Set(['node_modules', 'dist', 'build', 'coverage']);
7
+ function normalizePath(root, filePath) {
8
+ return path.relative(root, filePath).split(path.sep).join('/');
9
+ }
10
+ function* walk(directory) {
11
+ if (!fs.existsSync(directory))
12
+ return;
13
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
14
+ if (ignoredDirectories.has(entry.name))
15
+ continue;
16
+ const fullPath = path.join(directory, entry.name);
17
+ if (entry.isDirectory()) {
18
+ yield* walk(fullPath);
19
+ continue;
20
+ }
21
+ if (extensions.has(path.extname(entry.name))) {
22
+ yield fullPath;
23
+ }
24
+ }
25
+ }
26
+ function collectMatches(text, pattern, message, root, filePath, errors) {
27
+ for (const match of text.matchAll(pattern)) {
28
+ const before = text.slice(0, match.index);
29
+ const line = before.split(/\r?\n/).length;
30
+ errors.push(`${normalizePath(root, filePath)}:${line}: ${message}`);
31
+ }
32
+ }
33
+ export function checkPageActionsContract(rootDir = process.cwd()) {
34
+ const root = path.resolve(rootDir);
35
+ const sourceRoot = fs.existsSync(path.join(root, 'src')) ? path.join(root, 'src') : root;
36
+ const errors = [];
37
+ let scannedFiles = 0;
38
+ for (const filePath of walk(sourceRoot)) {
39
+ scannedFiles += 1;
40
+ const text = fs.readFileSync(filePath, 'utf8');
41
+ collectMatches(text, /ActionBar\./g, 'use Page.Actions, Page.ActionButton e Page.ActionsSeparator no lugar de ActionBar.*', root, filePath, errors);
42
+ collectMatches(text, /<Page\.Root\b[^>]*\bactions\s*=/gs, 'nao aninhe Page.Root actions dentro de AppLayout; use AppLayout.actions com Page.Actions', root, filePath, errors);
43
+ collectMatches(text, /<AppLayout\b[\s\S]*?\bactions\s*=\s*{\s*<>/g, 'AppLayout.actions nao deve receber Fragment como root; use Page.Actions ou componente *Actions', root, filePath, errors);
44
+ collectMatches(text, /<AppLayout\b[\s\S]*?\bactions\s*=\s*{\s*<div\b/g, 'AppLayout.actions nao deve receber div como root; use Page.Actions ou componente *Actions', root, filePath, errors);
45
+ collectMatches(text, /<AppLayout\b[\s\S]*?\bactions\s*=\s*{\s*<Page\.ActionButton\b/g, 'AppLayout.actions nao deve receber Page.ActionButton solto; envolva em Page.Actions', root, filePath, errors);
46
+ }
47
+ return { errors, scannedFiles, sourceRoot };
48
+ }
49
+ export function runPageActionsContractCli(args = process.argv.slice(2)) {
50
+ const rootDir = args[0] ?? process.cwd();
51
+ const result = checkPageActionsContract(rootDir);
52
+ if (result.errors.length > 0) {
53
+ console.error('Falha na verificacao de Page Actions:');
54
+ for (const error of result.errors)
55
+ console.error('- ' + error);
56
+ process.exitCode = 1;
57
+ return result;
58
+ }
59
+ console.log(`Page Actions OK: ${result.scannedFiles} arquivo(s) verificado(s); AppLayout.actions usa Page.Actions direta ou indiretamente.`);
60
+ return result;
61
+ }
62
+ const currentFilePath = fileURLToPath(import.meta.url);
63
+ const entryFilePath = process.argv[1] ? path.resolve(process.argv[1]) : '';
64
+ if (entryFilePath === currentFilePath) {
65
+ runPageActionsContractCli();
66
+ }
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@wellingtonhlc/shared-ui",
3
- "version": "0.24.4",
3
+ "version": "0.24.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "shared-ui-check-page-actions": "dist/cli/check-page-actions.js"
10
+ },
8
11
  "files": [
9
12
  "dist",
10
13
  "README.md"
@@ -58,6 +61,7 @@
58
61
  "@testing-library/jest-dom": "^6.9.1",
59
62
  "@testing-library/react": "^16.3.2",
60
63
  "@testing-library/user-event": "^14.6.1",
64
+ "@types/node": "^26.0.0",
61
65
  "@types/react": "^19.1.2",
62
66
  "@types/react-dom": "^19.1.2",
63
67
  "autoprefixer": "^10.5.0",