@seedgrid/ai-toolkit 0.4.4 → 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.
- package/package.json +1 -1
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +1 -1
- package/seedgridKB/SeedGrid/SeedGrid-components/Preciso-de.md +165 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +1 -1
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-componente/SKILL.md +23 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-componente/data/props.json +1 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-componente/scripts/validate-props.mjs +93 -0
- package/seedgridKB/SeedGrid/Visao-geral.md +1 -1
- package/seedgridKB/manifest.json +12 -2
|
@@ -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);
|
|
@@ -28,7 +28,7 @@ Base de documentação técnica do ecossistema SeedGrid, gerada a partir do cód
|
|
|
28
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]] (nomes por grupo; depois `Grep "^## SgNome"` no `API.md` do grupo e leia só a faixa).
|
|
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
|
|
package/seedgridKB/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"contentVersion": "0.
|
|
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,7 +172,7 @@
|
|
|
162
172
|
"Extensions/Catalogo-de-enums.md",
|
|
163
173
|
"Extensions/Indice.md",
|
|
164
174
|
"SeedGrid-components/Indice.md",
|
|
165
|
-
"SeedGrid-components/
|
|
175
|
+
"SeedGrid-components/Preciso-de.md",
|
|
166
176
|
"Mapa-dos-repositorios.md"
|
|
167
177
|
]
|
|
168
178
|
}
|