@seedgrid/ai-toolkit 0.4.3 → 0.5.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.
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ // Valida as props de um componente SeedGrid contra os tipos reais (data/props.json, gerado do código).
3
+ // Substitui validate_props do MCP. Só leitura.
4
+ //
5
+ // Uso:
6
+ // node validate-props.mjs <Componente> --jsx '<SgInputNumber id="q" minValue={1} maxValue={100} />'
7
+ // node validate-props.mjs <Componente> --json '{"id":"q","minValue":1}'
8
+ // node validate-props.mjs <Componente> --props id,minValue,maxValue (só os nomes)
9
+ // node validate-props.mjs <Componente> --list (lista as props: nome, tipo, obrigatória, valores)
10
+ // node validate-props.mjs --find <texto> (componentes cujo nome contém o texto)
11
+ // Saída: 0 = ok; 1 = problema (prop inexistente, obrigatória ausente, valor fora do enum, tipo errado); 2 = uso inválido.
12
+ import { readFileSync } from 'node:fs';
13
+ import path from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+
16
+ const here = path.dirname(fileURLToPath(import.meta.url));
17
+ const data = JSON.parse(readFileSync(path.join(here, '..', 'data', 'props.json'), 'utf8'));
18
+ const args = process.argv.slice(2);
19
+ const opt = (n) => { const i = args.indexOf(n); return i >= 0 ? args[i + 1] : undefined; };
20
+ const die = (m, code = 2) => { console.error(m); process.exit(code); };
21
+
22
+ if (opt('--find')) {
23
+ const q = opt('--find').toLowerCase();
24
+ const hit = Object.keys(data).filter((k) => k.toLowerCase().includes(q));
25
+ console.log(hit.length ? hit.join(', ') : 'nenhum componente com esse nome');
26
+ process.exit(0);
27
+ }
28
+
29
+ const name = args.find((a) => !a.startsWith('--') && a !== opt('--jsx') && a !== opt('--json') && a !== opt('--props'));
30
+ if (!name) die('Informe o componente. Ex.: validate-props.mjs SgInputNumber --jsx \'<SgInputNumber id="q" minValue={1} />\'');
31
+ const comp = data[name];
32
+ if (!comp) {
33
+ const near = Object.keys(data).filter((k) => k.toLowerCase().includes(name.toLowerCase().replace(/^sg/, ''))).slice(0, 6);
34
+ die(`Componente "${name}" não existe${near.length ? `. Parecidos: ${near.join(', ')}` : ''}. Use --find <texto>.`, 1);
35
+ }
36
+ const defs = comp.props;
37
+
38
+ if (args.includes('--list')) {
39
+ console.log(`${name} (${comp.pkg}) — ${Object.keys(defs).length} props; * = obrigatória`);
40
+ for (const [k, [kind, req, en]] of Object.entries(defs)) console.log(`${req ? '*' : ' '} ${k}: ${en ? en.map((v) => `"${v}"`).join(' | ') : kind}`);
41
+ process.exit(0);
42
+ }
43
+
44
+ // Entrada: { nome: valor | undefined(tipo desconhecido) }
45
+ let given = {};
46
+ const known = new Set(); // props cujo valor não deu para avaliar (só a presença conta)
47
+ if (opt('--json')) {
48
+ try { given = JSON.parse(opt('--json')); } catch { die('--json inválido.'); }
49
+ } else if (opt('--props')) {
50
+ for (const k of opt('--props').split(',').map((x) => x.trim()).filter(Boolean)) { given[k] = undefined; known.add(k); }
51
+ } else if (opt('--jsx')) {
52
+ const src = opt('--jsx');
53
+ // atributos: nome="texto" | nome={expr} | nome (booleano) | {...spread}
54
+ const re = /([A-Za-z_][\w.-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{((?:[^{}]|\{[^{}]*\})*)\}))?|\{\s*\.\.\.[^}]*\}/g;
55
+ const tag = new RegExp(`<${name}\\b([\\s\\S]*?)\\/?>`).exec(src);
56
+ const body = tag ? tag[1] : src;
57
+ let m;
58
+ while ((m = re.exec(body))) {
59
+ if (!m[1]) continue;
60
+ const k = m[1];
61
+ if (m[2] !== undefined || m[3] !== undefined) given[k] = m[2] ?? m[3];
62
+ else if (m[4] !== undefined) {
63
+ const e = m[4].trim();
64
+ if (/^-?\d+(\.\d+)?$/.test(e)) given[k] = Number(e);
65
+ else if (e === 'true' || e === 'false') given[k] = e === 'true';
66
+ else if (/^(["'`])(.*)\1$/.test(e)) given[k] = e.slice(1, -1);
67
+ else { given[k] = undefined; known.add(k); }
68
+ } else given[k] = true;
69
+ }
70
+ } else die('Informe --jsx, --json, --props ou --list.');
71
+
72
+ const issues = [];
73
+ for (const [k, [kind, req]] of Object.entries(defs)) if (req && !(k in given)) issues.push(`FALTA obrigatória: ${k} (${kind})`);
74
+ for (const [k, v] of Object.entries(given)) {
75
+ if (k.startsWith('aria-') || k.startsWith('data-') || k === 'key' || k === 'ref') continue;
76
+ const d = defs[k];
77
+ if (!d) {
78
+ const near = Object.keys(defs).filter((x) => x.toLowerCase().includes(k.toLowerCase()) || k.toLowerCase().includes(x.toLowerCase())).slice(0, 4);
79
+ issues.push(`NÃO EXISTE: ${k}${near.length ? ` (parecidas: ${near.join(', ')})` : ''}`);
80
+ continue;
81
+ }
82
+ if (v === undefined) continue; // só presença
83
+ const [kind, , en] = d;
84
+ if (en && typeof v === 'string' && !en.includes(v)) issues.push(`VALOR inválido em ${k}: "${v}" (aceita ${en.map((x) => `"${x}"`).join(' | ')})`);
85
+ else if (kind === 'string' && !en && typeof v !== 'string') issues.push(`TIPO em ${k}: esperado string, veio ${typeof v}`);
86
+ else if (kind === 'number' && typeof v !== 'number') issues.push(`TIPO em ${k}: esperado number, veio ${typeof v}`);
87
+ else if (kind === 'boolean' && typeof v !== 'boolean') issues.push(`TIPO em ${k}: esperado boolean, veio ${typeof v}`);
88
+ else if (kind === 'array' && !Array.isArray(v)) issues.push(`TIPO em ${k}: esperado array`);
89
+ }
90
+ if (!issues.length) { console.log(`${name}: OK (${Object.keys(given).length} props conferidas contra o tipo)`); process.exit(0); }
91
+ console.log(`${name}: ${issues.length} problema(s)`);
92
+ for (const i of issues) console.log(` - ${i}`);
93
+ process.exit(1);
@@ -24,11 +24,11 @@ Base de documentação técnica do ecossistema SeedGrid, gerada a partir do cód
24
24
 
25
25
  ## Por onde começar
26
26
 
27
- - **Esqueci o nome de uma propriedade** → [[SeedGrid/Extensions/Catalogo-de-propriedades|Catálogo de propriedades]] (busque com `Ctrl+F` ou pela busca do Obsidian).
28
- - **Quais valores um enum aceita / o que cada valor faz** → [[SeedGrid/Extensions/Catalogo-de-enums|Catálogo de enums]].
27
+ - **Esqueci o nome de uma propriedade** → [[SeedGrid/Extensions/Catalogo-de-propriedades|Catálogo de propriedades]] (**~195 KB: nunca leia inteiro**; use `Grep` pelo nome ou prefixo, ex. `seedgrid.audit.`).
28
+ - **Quais valores um enum aceita / o que cada valor faz** → [[SeedGrid/Extensions/Catalogo-de-enums|Catálogo de enums]] (~29 KB: `Grep` pelo nome do enum).
29
29
  - **Quero usar o Pulse (realtime, notificações, WebSocket)** → [[SeedGrid/Produtos/Pulse/Visao-geral|Pulse]].
30
30
  - **Quero entender uma extension** → [[SeedGrid/Extensions/Indice|Índice das extensions]].
31
- - **Quero usar um componente React** → [[SeedGrid/SeedGrid-components/Indice|Índice dos componentes]].
31
+ - **Quero usar um componente React** → [[SeedGrid/SeedGrid-components/Indice|Índice dos componentes]] (por necessidade: [[SeedGrid/SeedGrid-components/Preciso-de|Preciso de X, use Y]] e a skill `sg-componente`; nomes por grupo; depois `Grep "^## SgNome"` no `API.md` do grupo e leia só a faixa).
32
32
  - **Quero saber o que depende do quê** → [[SeedGrid/Mapa-dos-repositorios|Mapa dos repositórios]].
33
33
  - **Qual versão do artefato esta documentação descreve** (e se o seu projeto usa outra) → [[SeedGrid/Versoes|Versões documentadas × atuais]].
34
34
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "contentVersion": "0.4.3",
3
+ "contentVersion": "0.5.0",
4
4
  "toolkitBase": "SeedGrid/Toolkit",
5
5
  "components": [
6
6
  {
@@ -143,6 +143,16 @@
143
143
  "scripts/adr-index.mjs"
144
144
  ]
145
145
  },
146
+ {
147
+ "id": "skill:sg-componente",
148
+ "type": "skill",
149
+ "name": "sg-componente",
150
+ "files": [
151
+ "SKILL.md",
152
+ "scripts/validate-props.mjs",
153
+ "data/props.json"
154
+ ]
155
+ },
146
156
  {
147
157
  "id": "skill:sg-plan-goal",
148
158
  "type": "skill",
@@ -162,6 +172,7 @@
162
172
  "Extensions/Catalogo-de-enums.md",
163
173
  "Extensions/Indice.md",
164
174
  "SeedGrid-components/Indice.md",
175
+ "SeedGrid-components/Preciso-de.md",
165
176
  "Mapa-dos-repositorios.md"
166
177
  ]
167
178
  }