synthesisui 0.16.252 → 0.16.253
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/commands/import.js +63 -0
- package/dist/name-claim.js +71 -0
- package/package.json +1 -1
package/dist/commands/import.js
CHANGED
|
@@ -35,6 +35,7 @@ import { definitionSpan, parseClass, readInlineStyle, rootClasses, rootTag, tran
|
|
|
35
35
|
import { transcribeVariants } from "../doctor/variant-read.js";
|
|
36
36
|
import { frontierKind, packageRoot } from "../frontier-kind.js";
|
|
37
37
|
import { withLibraryStructure } from "../library-structure.js";
|
|
38
|
+
import { claimName } from "../name-claim.js";
|
|
38
39
|
import { body, paint, section } from "../output.js";
|
|
39
40
|
import { phase, startProgress } from "../progress.js";
|
|
40
41
|
import { detectStack, resolveDeps, stackVersions } from "../stack.js";
|
|
@@ -394,6 +395,16 @@ export async function takeCensus(root, opts) {
|
|
|
394
395
|
const internal = await internalSpecifiers(root);
|
|
395
396
|
const defined = [];
|
|
396
397
|
/** Nome → arquivo e fonte, para toda leitura por componente - ver o preenchimento abaixo. */
|
|
398
|
+
/**
|
|
399
|
+
* QUEM DETÉM CADA NOME - e o registro de quem pediu o mesmo.
|
|
400
|
+
*
|
|
401
|
+
* Os oito mapas deste laço são indexados por nome de componente, então dois
|
|
402
|
+
* `Card.tsx` disputam a mesma chave e o último do `walk` sobrescrevia os
|
|
403
|
+
* outros em silêncio. Medido no repo do dono: 20 nomes colidem no repo
|
|
404
|
+
* inteiro, 14 dentro de um app, e um dos quatro `Card` é o do design system
|
|
405
|
+
* dele. Ver `name-claim.ts` para o desempate e por que ele é por estrutura.
|
|
406
|
+
*/
|
|
407
|
+
const claims = { by: new Map(), collisions: [] };
|
|
397
408
|
const sourceOf = new Map();
|
|
398
409
|
/** Nome → o que a peça é, quando o portão soube dizer. Ver `CensusLook.kind`. */
|
|
399
410
|
const kindOf = new Map();
|
|
@@ -592,6 +603,21 @@ export async function takeCensus(root, opts) {
|
|
|
592
603
|
because: verdict.because,
|
|
593
604
|
});
|
|
594
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* O NOME É DISPUTADO AQUI, ANTES DE QUALQUER ESCRITA.
|
|
608
|
+
*
|
|
609
|
+
* Filtrar `found` fecha a porta de uma vez: os oito mapas deste laço
|
|
610
|
+
* derivam dele, então um componente que não detém o nome simplesmente não
|
|
611
|
+
* chega a nenhum deles - em vez de oito guardas que alguém esquece de
|
|
612
|
+
* repetir na nona escrita.
|
|
613
|
+
*
|
|
614
|
+
* O descarte NÃO é silencioso: `claims.collisions` guarda os dois caminhos
|
|
615
|
+
* e o censo os carrega. Trazer as duas receitas exige o contexto viajando
|
|
616
|
+
* na chave, que é a fatia dos grupos.
|
|
617
|
+
*/
|
|
618
|
+
const claimed = found.filter((d) => claimName(claims, d.name, rel));
|
|
619
|
+
found.length = 0;
|
|
620
|
+
found.push(...claimed);
|
|
595
621
|
for (const d of found) {
|
|
596
622
|
const props = readDefinitionProps(d.name, src);
|
|
597
623
|
propsOf.set(d.name, props);
|
|
@@ -1880,6 +1906,14 @@ export async function takeCensus(root, opts) {
|
|
|
1880
1906
|
...(Object.keys(keyframes).length > 0 ? { keyframes } : {}),
|
|
1881
1907
|
...(animations.size > 0 ? { animations: [...animations].sort() } : {}),
|
|
1882
1908
|
...(brokenRefs.length > 0 ? { brokenRefs } : {}),
|
|
1909
|
+
/**
|
|
1910
|
+
* OS NOMES DISPUTADOS - ver `name-claim.ts`.
|
|
1911
|
+
*
|
|
1912
|
+
* Aditivo e omitido quando vazio, que é o caso de toda biblioteca sã: no repo
|
|
1913
|
+
* do dono, `packages/ui` produz zero e o repo inteiro produz 20. Um campo que
|
|
1914
|
+
* só aparece quando há algo a dizer não muda nada para quem já lê o censo.
|
|
1915
|
+
*/
|
|
1916
|
+
...(claims.collisions.length > 0 ? { collisions: claims.collisions } : {}),
|
|
1883
1917
|
...(conventions.length > 0 ? { conventions } : {}),
|
|
1884
1918
|
classStyle,
|
|
1885
1919
|
...(Object.keys(looks).length > 0 ? { looks } : {}),
|
|
@@ -2055,8 +2089,37 @@ async function summarize(c, root, scope) {
|
|
|
2055
2089
|
}
|
|
2056
2090
|
}
|
|
2057
2091
|
sayConventions(c);
|
|
2092
|
+
sayCollisions(c);
|
|
2058
2093
|
await sayBrokenRefs(c, root, scope);
|
|
2059
2094
|
}
|
|
2095
|
+
/**
|
|
2096
|
+
* DOIS ARQUIVOS, UM NOME - dito, com os dois caminhos.
|
|
2097
|
+
*
|
|
2098
|
+
* O silêncio aqui era o pior tipo: a pessoa recebe 36 componentes onde o repo
|
|
2099
|
+
* tem 39, e nada no relatório sugere que três existiram. Medido no monorepo do
|
|
2100
|
+
* dono: 20 nomes no repo inteiro, e um dos quatro `Card.tsx` é o do design system
|
|
2101
|
+
* dele competindo com dois que vivem sob rotas.
|
|
2102
|
+
*
|
|
2103
|
+
* A frase diz o que fazer, e são duas coisas diferentes: um escopo mais estreito
|
|
2104
|
+
* quando os homônimos são de outro projeto, ou um rename quando são do mesmo.
|
|
2105
|
+
*/
|
|
2106
|
+
function sayCollisions(c) {
|
|
2107
|
+
const all = c.collisions ?? [];
|
|
2108
|
+
if (all.length === 0)
|
|
2109
|
+
return;
|
|
2110
|
+
const names = new Set(all.map((x) => x.name));
|
|
2111
|
+
console.log("");
|
|
2112
|
+
console.log(section("Two files, one name"));
|
|
2113
|
+
console.log(body(`${names.size} name${names.size === 1 ? "" : "s"} ${names.size === 1 ? "is" : "are"} defined more than once in what was measured, so ${all.length} definition${all.length === 1 ? "" : "s"} did not make it into this system. The one closest to the root of the scope kept the name - never the order the disk happened to return.`));
|
|
2114
|
+
console.log("");
|
|
2115
|
+
for (const x of all.slice(0, 6)) {
|
|
2116
|
+
console.log(body(`${paint.strong(x.name)} ${paint.faint("kept")} ${x.kept}\n ${paint.faint("dropped")} ${x.dropped}`));
|
|
2117
|
+
}
|
|
2118
|
+
if (all.length > 6)
|
|
2119
|
+
console.log(body(paint.faint(`(${all.length - 6} more)`)));
|
|
2120
|
+
console.log("");
|
|
2121
|
+
console.log(body(paint.faint("If the homonyms belong to different projects, a narrower --scope is the answer and nothing is lost. If they belong to the same one, renaming in your code is - two components with one name is one name your agent cannot resolve either.")));
|
|
2122
|
+
}
|
|
2060
2123
|
/**
|
|
2061
2124
|
* THEIR VOCABULARY, MEASURED. This section exists so every later finding can be
|
|
2062
2125
|
* phrased as "you already do X, and here you did not" instead of "adopt ours".
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UM NOME, UM COMPONENTE - e o que fazer quando dois pedem o mesmo.
|
|
3
|
+
*
|
|
4
|
+
* O laço de leitura do import escreve em oito mapas indexados por NOME de
|
|
5
|
+
* componente (`looks`, `sourceOf`, `kindOf`, `propsOf`, `runtimeOf`,
|
|
6
|
+
* `variantAxes`, `islands`, `keyframes`). Dois `Card.tsx` em pastas diferentes
|
|
7
|
+
* disputam a mesma chave, e até aqui o último que o `walk` visitou sobrescrevia
|
|
8
|
+
* os outros - em silêncio, e por uma ordem que é do sistema de arquivos e não
|
|
9
|
+
* uma decisão de ninguém.
|
|
10
|
+
*
|
|
11
|
+
* Medido no monorepo do dono (19/08): 20 nomes colidem no repo inteiro, 14 dentro
|
|
12
|
+
* de `apps/web-dashboard/src`, e quatro arquivos se chamam `Card.tsx` - um deles
|
|
13
|
+
* é o `Card` do design system dele, e dois estão sob `_legacy`. `packages/ui`
|
|
14
|
+
* sozinho não tem colisão nenhuma: o problema mora em escopo largo, que é
|
|
15
|
+
* exatamente o default que a flexibilidade pede.
|
|
16
|
+
*
|
|
17
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
18
|
+
* O DESEMPATE É POR ESTRUTURA, E DETERMINÍSTICO
|
|
19
|
+
*
|
|
20
|
+
* A intuição primeira era "quem o pacote EXPORTA fica com o nome", e ela não
|
|
21
|
+
* responde: `publicApi().exports` é um conjunto de NOMES, e os dois candidatos
|
|
22
|
+
* têm o mesmo nome. Escolher pelo que o pacote realmente publica exige o grafo a
|
|
23
|
+
* partir da entrada do manifesto, e essa é a fatia que também entrega os grupos.
|
|
24
|
+
*
|
|
25
|
+
* Então: menos segmentos de caminho vence, e empate resolve alfabeticamente. É
|
|
26
|
+
* pouco, e é honesto - a diferença que importa é que a resposta deixa de mudar
|
|
27
|
+
* conforme a ordem em que o disco devolve os arquivos.
|
|
28
|
+
*
|
|
29
|
+
* E NUNCA POR NOME DE PASTA. Descartar `_legacy` por se chamar `_legacy` é a lei
|
|
30
|
+
* 14 sendo furada: no repo dele `_legacy` tem 178 arquivos e 106 estão VIVOS,
|
|
31
|
+
* montados por rota (medido 07/08). Classificação é por estrutura, nunca por nome.
|
|
32
|
+
*
|
|
33
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
34
|
+
* O PERDEDOR NÃO ENTRA, E ISSO É DITO
|
|
35
|
+
*
|
|
36
|
+
* Esta fatia não traz as duas receitas - trazer os dois `Card` exige o contexto
|
|
37
|
+
* viajando na chave, que é a fatia dos GRUPOS. O que ela conserta é a perda
|
|
38
|
+
* calada: cada descarte vira uma linha do censo com os dois caminhos, e o
|
|
39
|
+
* relatório os imprime. Uma lacuna declarada é confiança; calada é bug.
|
|
40
|
+
*/
|
|
41
|
+
/** Profundidade como o caminho a declara - o número de pastas até o arquivo. */
|
|
42
|
+
const depth = (file) => file.split("/").length;
|
|
43
|
+
/**
|
|
44
|
+
* ESTE ARQUIVO FICA COM ESTE NOME?
|
|
45
|
+
*
|
|
46
|
+
* `true` quando ele detém o nome depois desta chamada - e aí quem chamou pode
|
|
47
|
+
* escrever nos mapas. `false` quando outro arquivo o detém, e a disputa foi
|
|
48
|
+
* registrada em `collisions`.
|
|
49
|
+
*
|
|
50
|
+
* Idempotente para o mesmo arquivo: o laço lê um arquivo uma vez, mas um
|
|
51
|
+
* componente pode ser reivindicado por mais de um caminho de código, e cobrar
|
|
52
|
+
* uma colisão de um arquivo contra si mesmo seria inventar um conflito.
|
|
53
|
+
*/
|
|
54
|
+
export function claimName(claims, name, file) {
|
|
55
|
+
const held = claims.by.get(name);
|
|
56
|
+
if (held === undefined) {
|
|
57
|
+
claims.by.set(name, file);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (held === file)
|
|
61
|
+
return true;
|
|
62
|
+
const incumbentWins = depth(held) < depth(file) ||
|
|
63
|
+
(depth(held) === depth(file) && held.localeCompare(file) <= 0);
|
|
64
|
+
if (incumbentWins) {
|
|
65
|
+
claims.collisions.push({ name, kept: held, dropped: file });
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
claims.by.set(name, file);
|
|
69
|
+
claims.collisions.push({ name, kept: file, dropped: held });
|
|
70
|
+
return true;
|
|
71
|
+
}
|
package/package.json
CHANGED