synthesisui 0.16.248 → 0.16.250
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/dist/absorb-plan.js +14 -3
- package/dist/commands/absorb.js +32 -10
- package/dist/commands/doctor.js +76 -11
- package/dist/commands/import.js +1 -1
- package/dist/commands/mcp.js +42 -2
- package/dist/commands/status.js +14 -0
- package/dist/doctor/component-gate.js +7 -0
- package/dist/doctor/coverage.js +32 -3
- package/dist/doctor/their-names.js +2 -11
- package/dist/doctor/tokens.js +47 -1
- package/dist/install-marks.js +1 -1
- package/package.json +1 -1
package/dist/absorb-plan.js
CHANGED
|
@@ -170,15 +170,26 @@ export function describeAbsorb(plan) {
|
|
|
170
170
|
return [
|
|
171
171
|
"Nothing to absorb: every repeated value your code writes by hand already has a name in the system.",
|
|
172
172
|
];
|
|
173
|
-
|
|
173
|
+
/**
|
|
174
|
+
* A SEÇÃO DOS QUE JÁ TÊM NOME SÓ EXISTE SE ALGUM TIVER - e no dia 1 nenhum tem.
|
|
175
|
+
*
|
|
176
|
+
* Quem começa do zero não declarou um token ainda, então isto abria com "0 of 4 values
|
|
177
|
+
* already have a name" e uma lista vazia: a primeira frase do comando dizendo um zero que
|
|
178
|
+
* não é notícia nenhuma, antes da única seção que importa para ela.
|
|
179
|
+
*/
|
|
180
|
+
if (ready.length > 0)
|
|
181
|
+
lines.push(`${ready.length} of ${plan.entries.length} values already have a name in YOUR vocabulary - those travel as they are:`);
|
|
174
182
|
for (const e of ready.slice(0, 8))
|
|
175
183
|
lines.push(` ${e.value.padEnd(24)} ${e.path.padEnd(28)} ${e.files} file${e.files === 1 ? "" : "s"}${e.theirName ? ` · your ${e.theirName}` : ""}`);
|
|
176
184
|
if (ready.length > 8)
|
|
177
185
|
lines.push(` (${ready.length - 8} more)`);
|
|
178
186
|
if (pending.length > 0) {
|
|
179
187
|
const close = pending.filter((e) => e.near);
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
if (ready.length > 0)
|
|
189
|
+
lines.push("");
|
|
190
|
+
lines.push(ready.length > 0
|
|
191
|
+
? `${pending.length} nobody names yet. Naming is a design decision, so those wait for a word from you:`
|
|
192
|
+
: `${pending.length} repeated values, and none of them has a name yet. Naming is a design decision, so each waits for a word from you:`);
|
|
182
193
|
for (const e of pending.slice(0, 8))
|
|
183
194
|
lines.push(` ${e.value.padEnd(24)} ${`<${e.kind}, ${e.files} file${e.files === 1 ? "" : "s"}>`.padEnd(28)} ${e.near ? `≈ your ${e.near.name} (${e.near.away})` : 'path: ""'}`);
|
|
184
195
|
if (pending.length > 8)
|
package/dist/commands/absorb.js
CHANGED
|
@@ -32,11 +32,23 @@ export async function absorb(opts) {
|
|
|
32
32
|
if (opts.send)
|
|
33
33
|
return sendProposal(root, path, opts.registry);
|
|
34
34
|
const installed = await loadSystem(root);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
/**
|
|
36
|
+
* SEM SISTEMA INSTALADO ISTO CONTINUA VALENDO - e recusar aqui fechava o dia 1.
|
|
37
|
+
*
|
|
38
|
+
* Este comando recusava com "não há nada para absorver PARA DENTRO", o que confundia o
|
|
39
|
+
* DESTINO com o TRABALHO. O trabalho é ler os valores que ela escreveu à mão e propor um
|
|
40
|
+
* nome para cada um; ele não depende de sistema nenhum, e as quatro coisas de que ele
|
|
41
|
+
* precisa já funcionam sem um: a tabela vem vazia (nada tem nome, então tudo é candidato),
|
|
42
|
+
* o vocabulário lido é o DELA, e a fundação existente é um conjunto vazio.
|
|
43
|
+
*
|
|
44
|
+
* Quem começa do zero era justamente quem mais precisava disto e quem menos podia rodar:
|
|
45
|
+
* ela escreve o primeiro componente, o doctor diz "9 valores à mão, nenhum tem nome", e o
|
|
46
|
+
* comando que dá nome respondia que não. Caminhado num projeto em branco em 18/08.
|
|
47
|
+
*
|
|
48
|
+
* O DESTINO É QUE MUDA, e ele se resolve sozinho: sem sistema, os tokens pertencem ao CSS
|
|
49
|
+
* dela - o mesmo caminho que `absorb: "code"` já servia a quem escolheu. Ver `sendProposal`.
|
|
50
|
+
*/
|
|
51
|
+
const hasSystem = Boolean(installed.table.slug);
|
|
40
52
|
const measured = await measuredScope(root);
|
|
41
53
|
const rel = scopePaths(measured);
|
|
42
54
|
const roots = rel.length > 0 ? rel.map((s) => resolve(root, s)) : [root];
|
|
@@ -61,7 +73,9 @@ export async function absorb(opts) {
|
|
|
61
73
|
reports.push(scanSource(file.slice(root.length + 1), source, installed.table));
|
|
62
74
|
}
|
|
63
75
|
const plan = absorbPlan(diagnose(reports), theirs, pathsInSystem(installed.documents), opts.cap ?? 40);
|
|
64
|
-
console.log(section(
|
|
76
|
+
console.log(section(hasSystem
|
|
77
|
+
? "What the system could absorb"
|
|
78
|
+
: "Name what you wrote by hand"));
|
|
65
79
|
console.log(body(paint.dim(`read from ${rel.length > 0 ? rel.join(", ") : "this project"} · your own vocabulary read from the root`)));
|
|
66
80
|
console.log("");
|
|
67
81
|
for (const line of describeAbsorb(plan))
|
|
@@ -69,7 +83,7 @@ export async function absorb(opts) {
|
|
|
69
83
|
if (plan.entries.length === 0)
|
|
70
84
|
return;
|
|
71
85
|
const proposal = {
|
|
72
|
-
slug: installed.table.slug,
|
|
86
|
+
slug: installed.table.slug ?? null,
|
|
73
87
|
at: new Date().toISOString(),
|
|
74
88
|
scope: rel,
|
|
75
89
|
entries: plan.entries,
|
|
@@ -146,17 +160,25 @@ async function sendProposal(root, path, registry) {
|
|
|
146
160
|
* colar. Nunca escrevemos no arquivo do cliente - e o import seguinte lê os tokens de volta, o que faz
|
|
147
161
|
* o caminho fechar sem nós tocarmos em nada.
|
|
148
162
|
*/
|
|
149
|
-
|
|
163
|
+
/**
|
|
164
|
+
* E SEM SISTEMA O DESTINO NÃO É UMA PREFERÊNCIA, é a única resposta que existe: os tokens
|
|
165
|
+
* pertencem ao CSS dela, porque não há outro lugar. Um `system` configurado aqui apontaria
|
|
166
|
+
* para um slug nulo e a chamada morreria num 404 depois de ela ter nomeado tudo à mão.
|
|
167
|
+
*/
|
|
168
|
+
const configured = (await readProjectConfig(root)).absorb ?? "system";
|
|
169
|
+
const target = proposal.slug ? configured : "code";
|
|
150
170
|
if (target === "code") {
|
|
151
171
|
console.log(section("Paste this into your own vocabulary"));
|
|
152
|
-
console.log(body(paint.dim(
|
|
172
|
+
console.log(body(paint.dim(proposal.slug
|
|
173
|
+
? "Your config says absorbed values belong in your CSS, so nothing was sent."
|
|
174
|
+
: "You have no system yet, so these belong in your own CSS - nothing was sent, and nothing needed an account.")));
|
|
153
175
|
console.log("");
|
|
154
176
|
console.log(" :root {");
|
|
155
177
|
for (const e of ready)
|
|
156
178
|
console.log(` --${e.path.replace(/\./g, "-")}: ${e.value};`);
|
|
157
179
|
console.log(" }");
|
|
158
180
|
console.log("");
|
|
159
|
-
console.log(body("The next import or `sync` reads these back as tokens you declared, and from then on the doctor
|
|
181
|
+
console.log(body("The next import or `sync` reads these back as tokens you declared, and from then on the doctor holds your code to them by your own names."));
|
|
160
182
|
return;
|
|
161
183
|
}
|
|
162
184
|
const token = await readToken();
|
package/dist/commands/doctor.js
CHANGED
|
@@ -401,6 +401,18 @@ function verdict(d, hasSystem, overruled, conflicts) {
|
|
|
401
401
|
body("installed. Nothing to fix, and nothing to compare against."),
|
|
402
402
|
];
|
|
403
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* O DIA ZERO - e o comando que serve a ele não era dito em lugar nenhum.
|
|
406
|
+
*
|
|
407
|
+
* "Dê um nome a eles" seguido de `init --ds <slug>` e o link da galeria oferece UMA saída, e
|
|
408
|
+
* ela é adotar o vocabulário de outra pessoa. A outra saída existe, faz exatamente o que a
|
|
409
|
+
* frase promete, e roda aqui mesmo sem conta e sem rede: `absorb` lê os valores repetidos e
|
|
410
|
+
* pede um nome para cada um. Ele passou a rodar sem sistema instalado neste mesmo PR, e uma
|
|
411
|
+
* capacidade que a pessoa precisa adivinhar não existe.
|
|
412
|
+
*
|
|
413
|
+
* A ordem é a da decisão dela: nomear o que ela já escreveu vem antes de escolher o de
|
|
414
|
+
* alguém, porque o primeiro é sobre o código que está na tela dela agora.
|
|
415
|
+
*/
|
|
404
416
|
if (!hasSystem) {
|
|
405
417
|
const distinct = new Set(d.findings.map((f) => f.literal.toLowerCase()));
|
|
406
418
|
return [
|
|
@@ -408,7 +420,10 @@ function verdict(d, hasSystem, overruled, conflicts) {
|
|
|
408
420
|
body(`${distinct.size} distinct design values are written by hand here.`),
|
|
409
421
|
body("No design system is installed, so none of them has a name yet."),
|
|
410
422
|
"",
|
|
411
|
-
body("
|
|
423
|
+
body("Name them yourself - this reads them and asks you for the words:"),
|
|
424
|
+
snippet(["npx synthesisui@latest absorb"]),
|
|
425
|
+
"",
|
|
426
|
+
body("Or start from a system somebody already published:"),
|
|
412
427
|
snippet(["npx synthesisui@latest init --ds <slug>"]),
|
|
413
428
|
body("Browse systems at https://www.synthesisui.com/gallery"),
|
|
414
429
|
];
|
|
@@ -784,7 +799,19 @@ export async function doctor(opts) {
|
|
|
784
799
|
* na mesma tela (dono: "fiquei perdido"). Ou o número não significa nada, ou existe uma lista de
|
|
785
800
|
* prioridades; as duas não cabem juntas.
|
|
786
801
|
*/
|
|
787
|
-
|
|
802
|
+
/**
|
|
803
|
+
* A FIAÇÃO SÓ EXISTE PARA UM SISTEMA NOSSO - e usar "tem nomes" no lugar disso recusava o
|
|
804
|
+
* `--fix` a quem nunca instalou nada (medido em 18/08, no caminho de quem começa do zero).
|
|
805
|
+
*
|
|
806
|
+
* Ela escreve os tokens dela no próprio `:root`, o doctor passa a dizer "7 dos seus valores
|
|
807
|
+
* têm nome", e o `--fix` respondia "trocar agora apontaria para variáveis que o navegador não
|
|
808
|
+
* resolve". Ele resolve: o CSS é dela e já está na página. A frase era literalmente falsa, e
|
|
809
|
+
* ela aparece no primeiro comando que promete adotar.
|
|
810
|
+
*
|
|
811
|
+
* `table.source` é a distinção certa e ela já estava aqui, uma linha abaixo, em `unwired`:
|
|
812
|
+
* `"yours"` e `"adopted"` são o vocabulário dela, e não há duas linhas para ligar.
|
|
813
|
+
*/
|
|
814
|
+
const blocked = table.source === "installed" && (!wiring.imported || !wiring.scoped);
|
|
788
815
|
const unwired = table.source === "installed" &&
|
|
789
816
|
(!wiring.imported || !wiring.scoped || fontsPending);
|
|
790
817
|
if (unwired) {
|
|
@@ -897,7 +924,15 @@ export async function doctor(opts) {
|
|
|
897
924
|
if (hasSystem && measurable) {
|
|
898
925
|
console.log("");
|
|
899
926
|
console.log(body(`Token coverage ${meter(d.coverage)} ${paint.strong(`${String(d.coverage).padStart(3)}%`)}`));
|
|
900
|
-
console.log(body(paint.dim(
|
|
927
|
+
console.log(body(paint.dim(
|
|
928
|
+
/**
|
|
929
|
+
* DE QUEM É O VOCABULÁRIO, dito na própria linha.
|
|
930
|
+
*
|
|
931
|
+
* `systemName` cai em "this system" quando não há um instalado - e aí a tabela é a DELA,
|
|
932
|
+
* lida das folhas dela. "8 from this system" lê como se existisse um sistema nosso no
|
|
933
|
+
* projeto, e não existe: são os tokens que ela mesma declarou, usados no código dela.
|
|
934
|
+
*/
|
|
935
|
+
` ${d.tokenUses} ${table.source === "installed" ? `from ${systemName}` : "through your own tokens"}${d.ownUses > 0 ? `, ${d.ownUses} from your own tokens` : ""}, ${d.findings.length} by hand${d.phantomUses > 0 ? `, ${d.phantomUses} naming nothing` : ""}`)));
|
|
901
936
|
/**
|
|
902
937
|
* A CAMADA DE TOKEN DELE, CONTADA - e a decisão é do dono, em 13/08.
|
|
903
938
|
*
|
|
@@ -911,7 +946,22 @@ export async function doctor(opts) {
|
|
|
911
946
|
* `--ds-*` também segura. Apontar uma para a outra é uma linha por variável, num arquivo só - e
|
|
912
947
|
* os 122 usos seguem o sistema sem tocar em um componente sequer.
|
|
913
948
|
*/
|
|
914
|
-
|
|
949
|
+
/**
|
|
950
|
+
* E ESTE BLOCO SÓ EXISTE CONTRA UM SISTEMA NOSSO - ele estava se comparando consigo mesmo.
|
|
951
|
+
*
|
|
952
|
+
* `mirrored` marca um token dela quando a tabela segura aquele valor. Quando a tabela É a
|
|
953
|
+
* dela, ela foi construída a partir daquelas mesmas declarações, então TODO token dela sai
|
|
954
|
+
* espelhado por construção - 4 de 4 no projeto que caminhei em 18/08. E a linha seguinte
|
|
955
|
+
* mandava apontá-los para `--ds-*` num projeto que não tem um único `--ds-*`: um conselho
|
|
956
|
+
* impossível de seguir, no primeiro relatório que ela lê.
|
|
957
|
+
*
|
|
958
|
+
* O `used 0x` era falso pelo mesmo motivo: os usos dos tokens dela foram contados na linha
|
|
959
|
+
* de cima, porque contra a tabela dela eles SÃO o vocabulário conhecido.
|
|
960
|
+
*
|
|
961
|
+
* Quando não há sistema nosso, "os seus tokens" e "o sistema" são a mesma coisa, e não há
|
|
962
|
+
* nada a apontar - a linha de cima já disse tudo o que é verdade.
|
|
963
|
+
*/
|
|
964
|
+
if (d.ownTokens > 0 && table.source === "installed") {
|
|
915
965
|
console.log(body(paint.dim(` ${d.ownTokens} token${d.ownTokens === 1 ? "" : "s"} of your own, used ${d.ownUses}x${d.ownMirrored > 0 ? ` - ${d.ownMirrored} hold a value ${systemName} also names` : ""}`)));
|
|
916
966
|
if (d.ownMirrored > 0)
|
|
917
967
|
console.log(body(paint.dim(` point those at the \`--ds-*\` that holds it: ${d.ownMirrored} lines, one file`)));
|
|
@@ -1671,16 +1721,31 @@ export async function doctor(opts) {
|
|
|
1671
1721
|
*/
|
|
1672
1722
|
if (table.source === "yours") {
|
|
1673
1723
|
console.log("");
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1724
|
+
/**
|
|
1725
|
+
* E O COMANDO OFERECIDO É O QUE FAZ O SISTEMA DELA.
|
|
1726
|
+
*
|
|
1727
|
+
* O comentário que estava aqui já dizia a coisa certa - *"este leitor JÁ TEM um design
|
|
1728
|
+
* system, então 'instale o nosso' significaria substituir o dele, e um CTA que finge o
|
|
1729
|
+
* contrário é o tipo de exagero confiante que custa confiança"* - e a linha logo abaixo
|
|
1730
|
+
* oferecia `init --ds <slug>` mais a galeria, que é literalmente instalar o de outra
|
|
1731
|
+
* pessoa. O diagnóstico estava escrito e o conserto não (medido em 18/08).
|
|
1732
|
+
*
|
|
1733
|
+
* O comando que serve a ela existe e é outro: `import` lê o repositório DELA e devolve
|
|
1734
|
+
* um sistema com o vocabulário dela dentro. Caminhado num projeto em branco: quatro
|
|
1735
|
+
* tokens próprios e um componente saíram como "1 of 1 components came out with a
|
|
1736
|
+
* blueprint - 100%".
|
|
1737
|
+
*
|
|
1738
|
+
* A galeria continua dita, uma linha abaixo e em voz baixa: forkar um sistema pronto é
|
|
1739
|
+
* uma escolha legítima, só não é a primeira coisa a oferecer a quem já tem o dela.
|
|
1740
|
+
*/
|
|
1679
1741
|
console.log(body("Your tokens exist. What your agent is missing is a contract:"));
|
|
1680
1742
|
console.log(body("rules it reads BEFORE writing UI, and a manifest of what exists."));
|
|
1681
1743
|
console.log("");
|
|
1682
|
-
console.log(paint.blue(snippet(["npx synthesisui@latest
|
|
1683
|
-
console.log(body(paint.dim("
|
|
1744
|
+
console.log(paint.blue(snippet(["npx synthesisui@latest import --dry"])));
|
|
1745
|
+
console.log(body(paint.dim("reads THIS repo and turns your own vocabulary into that contract -")));
|
|
1746
|
+
console.log(body(paint.dim("local, free, and it writes nothing but the measurement.")));
|
|
1747
|
+
console.log("");
|
|
1748
|
+
console.log(body(paint.dim("Or start from a system somebody already published, if you would rather:")));
|
|
1684
1749
|
console.log(body(paint.blue("https://www.synthesisui.com/gallery")));
|
|
1685
1750
|
}
|
|
1686
1751
|
console.log("");
|
package/dist/commands/import.js
CHANGED
|
@@ -1586,7 +1586,7 @@ export async function takeCensus(root, opts) {
|
|
|
1586
1586
|
islandRead: islandClassesRead,
|
|
1587
1587
|
refused: new Set(skips.map((s) => s.file)),
|
|
1588
1588
|
}));
|
|
1589
|
-
const coverageLines = describeCoverage(coverage, composition);
|
|
1589
|
+
const coverageLines = describeCoverage(coverage, composition, skips.length);
|
|
1590
1590
|
if (coverageLines.length > 0) {
|
|
1591
1591
|
say("");
|
|
1592
1592
|
say(section("What this version reads, on your files"));
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1147,6 +1147,45 @@ const BY_COMPONENT = {
|
|
|
1147
1147
|
describe_component: "describe",
|
|
1148
1148
|
add_component: "add",
|
|
1149
1149
|
};
|
|
1150
|
+
/**
|
|
1151
|
+
* QUAL ARGUMENTO CARREGA O ASSUNTO DE CADA CHAMADA - e sem isto a medição não responde nada.
|
|
1152
|
+
*
|
|
1153
|
+
* Medido em 18/08: 2 das 15 ferramentas gravavam O QUE foi pedido; as outras 13 gravavam o
|
|
1154
|
+
* próprio nome. `compose_context` estava entre as 13 - e ela é a ÚNICA que emite `composed`,
|
|
1155
|
+
* que é o sinal inteiro de "aqui faltou uma receita". O banco acumulava "compose_context: 47"
|
|
1156
|
+
* e nunca "a família `field`: 12", e é o segundo número que abre uma candidata a receita.
|
|
1157
|
+
*
|
|
1158
|
+
* Esperar volume não consertaria isso: o dado que estava sendo guardado não responde a
|
|
1159
|
+
* pergunta, então o relógio da espera não estava correndo.
|
|
1160
|
+
*
|
|
1161
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
1162
|
+
* O QUE ENTRA, E O QUE NÃO ENTRA DE PROPÓSITO
|
|
1163
|
+
*
|
|
1164
|
+
* Entra o que é um NOME - do vocabulário dela ou do nosso. Ficam de fora, e não por
|
|
1165
|
+
* esquecimento:
|
|
1166
|
+
*
|
|
1167
|
+
* find_token `value` é um valor do repositório dele (`#4f46e5`)
|
|
1168
|
+
* check_file `path` é um caminho do repositório dele
|
|
1169
|
+
* playbook `section` é navegação nossa, e não diz nada sobre o sistema dele
|
|
1170
|
+
*
|
|
1171
|
+
* Os dois primeiros são dado DELE, e a nossa tabela de contadores não é lugar para eles. O
|
|
1172
|
+
* `SLUG` do outro lado já os rejeitaria em silêncio; não mandar é dizer a mesma coisa em voz
|
|
1173
|
+
* alta. `list_components`, `system_doctrine`, `recipe_vocabulary` e `refresh_system` não têm
|
|
1174
|
+
* assunto nenhum - a pergunta É o sistema inteiro.
|
|
1175
|
+
*
|
|
1176
|
+
* `validate_recipes` no plural é um LOTE, e um lote não tem um assunto só.
|
|
1177
|
+
*/
|
|
1178
|
+
const SUBJECT_ARG = {
|
|
1179
|
+
describe_component: "name",
|
|
1180
|
+
add_component: "name",
|
|
1181
|
+
/** A família pedida - o sinal que o A1 precisa e que não estava sendo guardado. */
|
|
1182
|
+
compose_context: "family",
|
|
1183
|
+
/** O que ela pediu e o sistema não tinha: a lacuna, com nome. */
|
|
1184
|
+
request_component: "name",
|
|
1185
|
+
request_rule: "name",
|
|
1186
|
+
request_token: "name",
|
|
1187
|
+
validate_recipe: "name",
|
|
1188
|
+
};
|
|
1150
1189
|
/**
|
|
1151
1190
|
* O ÚNICO PONTO DE INSTRUMENTAÇÃO - e é isto que o dono pediu (18/08): *"vira
|
|
1152
1191
|
* comportamento padrão e não depende de disciplina futura."*
|
|
@@ -1163,8 +1202,9 @@ async function callTool(root, name, args,
|
|
|
1163
1202
|
cli) {
|
|
1164
1203
|
const answer = await runTool(root, name, args);
|
|
1165
1204
|
const gesture = BY_COMPONENT[name];
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1205
|
+
const subject = SUBJECT_ARG[name];
|
|
1206
|
+
const target = subject
|
|
1207
|
+
? String(args[subject] ?? "")
|
|
1168
1208
|
.trim()
|
|
1169
1209
|
.toLowerCase()
|
|
1170
1210
|
: "";
|
package/dist/commands/status.js
CHANGED
|
@@ -52,7 +52,21 @@ export async function status(opts) {
|
|
|
52
52
|
}
|
|
53
53
|
console.log(section("Status"));
|
|
54
54
|
if (installed.length === 0) {
|
|
55
|
+
/**
|
|
56
|
+
* NADA INSTALADO NÃO SIGNIFICA NADA A OFERECER, e mandar `list` era o conselho da outra pessoa.
|
|
57
|
+
*
|
|
58
|
+
* `list` mostra a GALERIA - sistemas que outros publicaram. Quem roda isto num repositório que
|
|
59
|
+
* já tem o próprio vocabulário recebia "escolha o de alguém", quando o comando que serve a ela
|
|
60
|
+
* lê o repositório DELA. O `doctor` cometia o mesmo desvio no parágrafo final, e ali o
|
|
61
|
+
* comentário até diagnosticava (medido em 18/08).
|
|
62
|
+
*
|
|
63
|
+
* As duas continuam ditas, na ordem certa: o dela primeiro, o de outra pessoa como alternativa.
|
|
64
|
+
*/
|
|
55
65
|
console.log(body("No design system installed in this project, so there is nothing to be in sync with."));
|
|
66
|
+
console.log("");
|
|
67
|
+
console.log(body("Make one out of this repo:"));
|
|
68
|
+
console.log(paint.blue(snippet(["npx synthesisui@latest import --dry"])));
|
|
69
|
+
console.log(body("Or bring in one somebody published:"));
|
|
56
70
|
console.log(paint.blue(snippet(["npx synthesisui@latest list"])));
|
|
57
71
|
return;
|
|
58
72
|
}
|
|
@@ -304,6 +304,13 @@ export function groupSkips(skips) {
|
|
|
304
304
|
*
|
|
305
305
|
* The sentence a person needs in order to trust a number that just dropped by an
|
|
306
306
|
* order of magnitude - and to notice if it dropped too far.
|
|
307
|
+
*
|
|
308
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
309
|
+
* E ELA VIAJA COLADA À MANCHETE (dono, 18/08).
|
|
310
|
+
*
|
|
311
|
+
* "340 de 340 com blueprint - 100%" sozinho é autoelogio: um portão que admite
|
|
312
|
+
* pouco fecha 100% fácil. As duas linhas juntas são uma promessa que se pode
|
|
313
|
+
* conferir - o que entrou, e o que ficou de fora com o motivo de cada um.
|
|
307
314
|
*/
|
|
308
315
|
export function describeGate(kept, skipped) {
|
|
309
316
|
if (skipped === 0) {
|
package/dist/doctor/coverage.js
CHANGED
|
@@ -110,7 +110,7 @@ export function summarizeCoverage(counts, components, read, declarations) {
|
|
|
110
110
|
/**
|
|
111
111
|
* The report, in the words a person needs before they decide whether to import.
|
|
112
112
|
*
|
|
113
|
-
* Leads with the number that matters - how many components came out with a
|
|
113
|
+
* Leads with the number that matters - how many components came out with a blueprint - and
|
|
114
114
|
* then names every shape that is not fully read, with the reason. No percentages without
|
|
115
115
|
* the count behind them: "75%" of an unknown total is a marketing number.
|
|
116
116
|
*/
|
|
@@ -123,12 +123,41 @@ export function describeCoverage(c,
|
|
|
123
123
|
* arranjo e fluxo, e é isso que a receita deles carrega. Medido no dashboard dele: 235 de
|
|
124
124
|
* 271 (04/08).
|
|
125
125
|
*/
|
|
126
|
-
composition
|
|
126
|
+
composition,
|
|
127
|
+
/**
|
|
128
|
+
* O QUE O PORTÃO DEIXOU DE FORA - e ele viaja COLADO à manchete (dono, 18/08).
|
|
129
|
+
*
|
|
130
|
+
* A explicação longa e a lista nominal continuam onde sempre estiveram, 79
|
|
131
|
+
* linhas abaixo. O que sobe para cá é só o número, porque é ele que impede a
|
|
132
|
+
* manchete de ser autoelogio: um portão que admite pouco fecha 100% fácil, e
|
|
133
|
+
* as duas contas juntas são uma promessa que se pode conferir.
|
|
134
|
+
*/
|
|
135
|
+
leftOut) {
|
|
127
136
|
if (c.components === 0)
|
|
128
137
|
return [];
|
|
129
138
|
const lines = [];
|
|
130
139
|
const pct = Math.round((c.read / c.components) * 100);
|
|
131
|
-
|
|
140
|
+
/**
|
|
141
|
+
* A MANCHETE É BLUEPRINT POR COMPONENTE, e não fragmento de estilo (dono, 18/08).
|
|
142
|
+
*
|
|
143
|
+
* As duas contas existiam, e a que liderava era a errada. "62% dos fragmentos
|
|
144
|
+
* interpretados" mistura no mesmo denominador coisas que NÃO PODEM ser lidas
|
|
145
|
+
* por natureza - medido no repo real: 120 fragmentos são `computed`, o valor
|
|
146
|
+
* nasce no navegador e não está no código em nível nenhum; 4 são partials que
|
|
147
|
+
* o build dele nem compila. Perseguir 100% ali é perseguir um número que
|
|
148
|
+
* obriga a mentir.
|
|
149
|
+
*
|
|
150
|
+
* A conta que pode fechar em 100%, e que é o objetivo do recurso, é esta:
|
|
151
|
+
* dos componentes ADMITIDOS, quantos saíram com blueprint. Medido no
|
|
152
|
+
* `frontend-hub`: 340 de 340.
|
|
153
|
+
*
|
|
154
|
+
* `blueprint` é o nome público do que a plataforma produz; `recipe` continua
|
|
155
|
+
* sendo o nome interno, no documento e no código.
|
|
156
|
+
*/
|
|
157
|
+
lines.push(`${c.read} of ${c.components} components came out with a blueprint - ${pct}%, ${c.declarations} declarations in total. This is measured on your files, not an estimate.`);
|
|
158
|
+
if (leftOut && leftOut > 0) {
|
|
159
|
+
lines.push(` and ${leftOut} export${leftOut === 1 ? "" : "s"} did not become one - each is named below with the reason, so a 100% here never means "we admitted little".`);
|
|
160
|
+
}
|
|
132
161
|
if (composition && composition > 0) {
|
|
133
162
|
lines.push(
|
|
134
163
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FAMILY_PREFIX, familySays, normalizeValue, } from "./tokens.js";
|
|
1
|
+
import { FAMILY_PREFIX, familySays, formDecides, normalizeValue, UNAMBIGUOUS, } from "./tokens.js";
|
|
2
2
|
/**
|
|
3
3
|
* COMO ELE CHAMA O VALOR - para a gente parar de renomear as variáveis dele.
|
|
4
4
|
*
|
|
@@ -47,14 +47,6 @@ import { FAMILY_PREFIX, familySays, normalizeValue, } from "./tokens.js";
|
|
|
47
47
|
* que o próprio css dele nomeia `--dashboard-font-family`. É pouco, e é o único grupo que sobrou do
|
|
48
48
|
* item que eu tinha nomeado - os `em` saíram na leva anterior.
|
|
49
49
|
*/
|
|
50
|
-
const UNAMBIGUOUS = {
|
|
51
|
-
/** `#rrggbbaa`, que é onde toda a família de dialetos cai. */
|
|
52
|
-
color: /^#[0-9a-f]{8}$/,
|
|
53
|
-
/** `s` e `ms` não aparecem em nenhuma outra família do contrato. */
|
|
54
|
-
motion: /^-?[\d.]+ms$/,
|
|
55
|
-
/** Uma pilha de fontes: tem vírgula, ou é uma das palavras genéricas do CSS. */
|
|
56
|
-
font: /,|^(?:serif|sans-serif|monospace|cursive|fantasy|system-ui)$/,
|
|
57
|
-
};
|
|
58
50
|
const segments = (name) => name.replace(/^--/, "").split("-");
|
|
59
51
|
/**
|
|
60
52
|
* QUAL DOS NOMES DELE, quando mais de um segura o mesmo valor - e são 18 no repo real.
|
|
@@ -142,8 +134,7 @@ export function theirNames(ours, theirs) {
|
|
|
142
134
|
* Recusar aqui não perde informação: sem alias, `nameToWrite` cai no NOSSO token, que é da
|
|
143
135
|
* família certa porque foi o prefixo dela que o trouxe a este laço.
|
|
144
136
|
*/
|
|
145
|
-
const
|
|
146
|
-
const usable = formDecides
|
|
137
|
+
const usable = formDecides(value)
|
|
147
138
|
? candidates
|
|
148
139
|
: candidates.filter((n) => familySays(kind, n));
|
|
149
140
|
if (usable.length === 0)
|
package/dist/doctor/tokens.js
CHANGED
|
@@ -569,6 +569,27 @@ export const FAMILY_WORDS = {
|
|
|
569
569
|
* `--dashboard-radius-lg` é um raio e o primeiro segmento é o namespace dele. Olhar só o começo
|
|
570
570
|
* recusaria um nome certo por causa de um prefixo de produto, que é a metade oposta do mesmo erro.
|
|
571
571
|
*/
|
|
572
|
+
/**
|
|
573
|
+
* OS VALORES CUJA FORMA JÁ DIZ A FAMÍLIA - e por isso o nome não precisa dizer.
|
|
574
|
+
*
|
|
575
|
+
* Morava em `their-names.ts`, privada, e a falta dela aqui foi medida no corpus: filtrar por
|
|
576
|
+
* palavra sem esta porta trocou `--brand-500` por `--loader-color` num hex. Os dois são cor, e
|
|
577
|
+
* o segundo só ganhou por ter a palavra "color" no nome - a doc de `FAMILY_WORDS` já avisava
|
|
578
|
+
* que 748 dos 755 nomes sem palavra de categoria são cor.
|
|
579
|
+
*
|
|
580
|
+
* O que fica de fora é o COMPRIMENTO, e fica de propósito: `24px` pode ser raio, espaçamento ou
|
|
581
|
+
* tamanho de fonte, e ali o nome é a única pista que existe.
|
|
582
|
+
*/
|
|
583
|
+
export const UNAMBIGUOUS = {
|
|
584
|
+
/** `#rrggbbaa`, que é onde toda a família de dialetos cai. */
|
|
585
|
+
color: /^#[0-9a-f]{8}$/,
|
|
586
|
+
/** `s` e `ms` não aparecem em nenhuma outra família do contrato. */
|
|
587
|
+
motion: /^-?[\d.]+ms$/,
|
|
588
|
+
/** Uma pilha de fontes: tem vírgula, ou é uma das palavras genéricas do CSS. */
|
|
589
|
+
font: /,|^(?:serif|sans-serif|monospace|cursive|fantasy|system-ui)$/,
|
|
590
|
+
};
|
|
591
|
+
/** A forma deste valor já decide a família dele, então a palavra no nome não precisa. */
|
|
592
|
+
export const formDecides = (value) => Object.values(UNAMBIGUOUS).some((f) => f.test(value));
|
|
572
593
|
export const familySays = (kind, name) => {
|
|
573
594
|
const words = FAMILY_WORDS[kind] ?? [];
|
|
574
595
|
const segments = name.replace(/^--/, "").toLowerCase().split("-");
|
|
@@ -596,8 +617,33 @@ export function tokenMatch(table, literal, kind) {
|
|
|
596
617
|
const hit = table.byValue.get(normalizeValue(literal, table.rootPx));
|
|
597
618
|
if (!hit || hit.length === 0)
|
|
598
619
|
return null;
|
|
620
|
+
/**
|
|
621
|
+
* O PREFIXO É NOSSO; O NOME PODE SER DELA - e olhar só o prefixo reprovava todo o vocabulário
|
|
622
|
+
* dela como coincidência entre famílias (medido em 18/08, no caminho de quem começa do zero).
|
|
623
|
+
*
|
|
624
|
+
* `--ds-radius-md` carrega a família por construção, e é isso que o prefixo lê. `--radius-card`
|
|
625
|
+
* não carrega prefixo nenhum, então nenhum token dela casava e TODO achado saía marcado como
|
|
626
|
+
* erro de categoria - com a frase se contradizendo na mesma linha: "no radius named for it ·
|
|
627
|
+
* the value lives as --radius-card". O `--fix` então deixava de trocar exatamente os valores
|
|
628
|
+
* que ela acabou de nomear.
|
|
629
|
+
*
|
|
630
|
+
* `familySays` é a resposta e ela já existia para o outro lado da mesma pergunta (`their-names`,
|
|
631
|
+
* `absorb-plan`): a família sai de QUALQUER segmento do nome, então o namespace de produto dela
|
|
632
|
+
* não atrapalha. Os dois caminhos somam - a garantia por construção continua valendo primeiro.
|
|
633
|
+
*/
|
|
599
634
|
const prefix = kind ? FAMILY_PREFIX[kind] : undefined;
|
|
600
|
-
|
|
635
|
+
/**
|
|
636
|
+
* E A PALAVRA SÓ DECIDE QUANDO A FORMA NÃO DECIDE - a mesma porta que `their-names` usa.
|
|
637
|
+
*
|
|
638
|
+
* Sem ela, filtrar por palavra num hex escolhia `--loader-color` em vez de `--brand-500`
|
|
639
|
+
* (medido no corpus dourado): os dois são cor, e o segundo perdia por não ter a palavra
|
|
640
|
+
* "color" no nome. Num comprimento cru é o contrário - ali a palavra é a única pista.
|
|
641
|
+
*/
|
|
642
|
+
const byWord = kind && !formDecides(normalizeValue(literal, table.rootPx));
|
|
643
|
+
const family = kind
|
|
644
|
+
? hit.filter((n) => (prefix ? n.startsWith(prefix) : false) ||
|
|
645
|
+
(byWord ? familySays(kind, n) : false))
|
|
646
|
+
: [];
|
|
601
647
|
const pool = family.length > 0 ? family : hit;
|
|
602
648
|
// Semantic roles name intent; primitives name a shelf. Prefer intent.
|
|
603
649
|
const semantic = pool.find((n) => n.includes("-semantic-"));
|
package/dist/install-marks.js
CHANGED
|
@@ -159,7 +159,7 @@ export const MATERIALISER_SINCE = "0.16.241";
|
|
|
159
159
|
* `var(--text-caption)` - um token de tipo numa posição de raio. Medido no repositório real: 290
|
|
160
160
|
* sugestões com a categoria trocada, 66 delas graváveis por um `--fix --write`.
|
|
161
161
|
*/
|
|
162
|
-
export const CHECKER_SINCE = "0.16.
|
|
162
|
+
export const CHECKER_SINCE = "0.16.250";
|
|
163
163
|
/**
|
|
164
164
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
165
165
|
*
|
package/package.json
CHANGED