synthesisui 0.16.199 → 0.16.200
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
CHANGED
|
@@ -172,6 +172,29 @@ async function sheetWithImports(path, seen = new Set(), depth = 0) {
|
|
|
172
172
|
async function exists(path) {
|
|
173
173
|
return await readFile(path, "utf8").then(() => true, () => false);
|
|
174
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* SOB QUE NOME O ESCOPO É IMPORTADO - a única forma de reconhecer a linha da própria biblioteca.
|
|
177
|
+
*
|
|
178
|
+
* O app dele importa `@frontend-hub/ui`; o `packages/ui/package.json` declara esse nome. É a mesma
|
|
179
|
+
* regra que a lei 13 já usa para desempatar `workspace:` contra semver, um passo antes: o MANIFESTO
|
|
180
|
+
* responde, e não o nome do componente nem o formato do caminho.
|
|
181
|
+
*
|
|
182
|
+
* Ausente quando o escopo não é um pacote - e aí a evidência só é somada quando o nome chega de UMA
|
|
183
|
+
* origem interna, que é a mesma resposta por outro caminho.
|
|
184
|
+
*/
|
|
185
|
+
async function publishedAs(root) {
|
|
186
|
+
const raw = await readFile(join(root, "package.json"), "utf8").catch(() => null);
|
|
187
|
+
if (!raw)
|
|
188
|
+
return null;
|
|
189
|
+
try {
|
|
190
|
+
const name = JSON.parse(raw).name;
|
|
191
|
+
return typeof name === "string" && name ? name : null;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/** Um manifesto ilegível custa a evidência daquele escopo, nunca a medição. */
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
175
198
|
async function harvestOwnCss(root,
|
|
176
199
|
/**
|
|
177
200
|
* O LEDGER TAMBÉM COME AQUI, e por um motivo de promessa: este é o único laço que vê TODO
|
|
@@ -1065,7 +1088,18 @@ export async function takeCensus(root, opts) {
|
|
|
1065
1088
|
*/
|
|
1066
1089
|
const turnedAway = new Set(skips.map((s) => s.name));
|
|
1067
1090
|
const inventory = allComposed.filter((c) => !turnedAway.has(c.name));
|
|
1068
|
-
|
|
1091
|
+
/**
|
|
1092
|
+
* COMPOSTO POR ELE, e não por qualquer um que use esse nome - a mesma lei, o terceiro sítio.
|
|
1093
|
+
*
|
|
1094
|
+
* Este conjunto responde "preciso criar uma linha a partir da DECLARAÇÃO, ou já existe uma linha
|
|
1095
|
+
* de uso?". Com uma linha por nome, "existe" era inequívoco. Com uma linha por nome+origem, um
|
|
1096
|
+
* `Toggle` do `@base-ui/react` respondia que sim - e o `Toggle` que ele declara em
|
|
1097
|
+
* `packages/ui/atoms` ficava SEM LINHA NENHUMA, que é o mesmo desaparecimento do test50 chegando
|
|
1098
|
+
* por outra porta.
|
|
1099
|
+
*
|
|
1100
|
+
* A linha de terceiro não responde por ele: só conta como composto o que veio de dentro.
|
|
1101
|
+
*/
|
|
1102
|
+
const composed = new Set(inventory.filter((c) => !c.from).map((c) => c.name));
|
|
1069
1103
|
const fromTypes = defined
|
|
1070
1104
|
.filter((d) => !composed.has(d.name))
|
|
1071
1105
|
.map((d) => ({
|
|
@@ -1160,8 +1194,64 @@ export async function takeCensus(root, opts) {
|
|
|
1160
1194
|
* the laws read, and it is the reason this pass exists: three files agreeing is
|
|
1161
1195
|
* what makes a habit, and a library has one file per component.
|
|
1162
1196
|
*/
|
|
1163
|
-
|
|
1164
|
-
|
|
1197
|
+
/**
|
|
1198
|
+
* A ORIGEM DECIDE, E AUSÊNCIA DE ORIGEM NÃO É UMA ORIGEM - lei 13, no segundo sítio.
|
|
1199
|
+
*
|
|
1200
|
+
* `tallyToInventory` já separa as linhas por nome+origem, e o censo mostra isso funcionando em 8
|
|
1201
|
+
* nomes (`Tooltip`, `Popover.*`, `AnimatePresence`, `Toggle`). Aqui a evidência voltava a casar por
|
|
1202
|
+
* NOME, e o filtro era `!c.from` - que junta três coisas diferentes numa só: o que é dele, o que
|
|
1203
|
+
* tem origem misturada, e o que não tem origem NENHUMA.
|
|
1204
|
+
*
|
|
1205
|
+
* O que isso produziu, medido no repo do dono em 10/08: o `Button` DELE publicava
|
|
1206
|
+
* `variant = ["ocean", "outlined", "contained"]`. `outlined` e `contained` são do MUI, e os
|
|
1207
|
+
* `declaredAxes` dele não têm nenhum dos dois - as opções que ele declara são `ocean`, `royal`,
|
|
1208
|
+
* `ai-outline`, `danger` e mais cinco. Os oito arquivos que importam o Button do MUI já eram
|
|
1209
|
+
* separados pelo `from`; o vazamento veio de um arquivo com 25 usos de `<Button>` e NENHUM import
|
|
1210
|
+
* de `Button` - origem desconhecida, tratada como dele.
|
|
1211
|
+
*
|
|
1212
|
+
* E "DE DENTRO" NÃO ERA UMA ORIGEM, era uma vizinhança: `OWN` valia para todo caminho interno,
|
|
1213
|
+
* então o `Button` da biblioteca dele e o `Button` do Chakra re-exportado atrás do alias `@/` eram
|
|
1214
|
+
* a MESMA linha. Exigir só `own` trocava o vazamento de terceiro por um vazamento de vizinho, e
|
|
1215
|
+
* pior: seis leis - `enlarge`, `on`, `hover`, `click`, `asChild`, `onlyBorder` - escritas sobre um
|
|
1216
|
+
* componente dele que não tem nenhuma dessas props. A origem agora é o especificador inteiro, e a
|
|
1217
|
+
* evidência casa com a linha que veio da PRÓPRIA biblioteca.
|
|
1218
|
+
*
|
|
1219
|
+
* Sem conseguir dizer QUAL linha é a da biblioteca, ninguém soma nada: a direção conservadora é a
|
|
1220
|
+
* mesma dos dois lados - deixar de somar evidência custa uma contagem, somar a errada custa uma
|
|
1221
|
+
* LEI escrita sobre a biblioteca de outra pessoa.
|
|
1222
|
+
*/
|
|
1223
|
+
/** Os nomes que a biblioteca declara - a pergunta aqui é de PERTENCIMENTO, não de origem. */
|
|
1224
|
+
const inScope = new Set(scoped.map((c) => c.name));
|
|
1225
|
+
/** `root` aqui já É a pasta do escopo - `runImport` resolve `--scope` antes de chamar. */
|
|
1226
|
+
const published = await publishedAs(root);
|
|
1227
|
+
const evidence = new Map();
|
|
1228
|
+
/** Os nomes que chegam de mais de um lugar de dentro - a lacuna, contada para ser dita. */
|
|
1229
|
+
const ambiguous = [];
|
|
1230
|
+
const byName = new Map();
|
|
1231
|
+
for (const c of usedThere) {
|
|
1232
|
+
if (!c.own)
|
|
1233
|
+
continue;
|
|
1234
|
+
byName.set(c.name, [...(byName.get(c.name) ?? []), c]);
|
|
1235
|
+
}
|
|
1236
|
+
for (const [name, rows] of byName) {
|
|
1237
|
+
/**
|
|
1238
|
+
* A LINHA DA BIBLIOTECA, quando dá para nomeá-la: o app importa o pacote que o escopo publica.
|
|
1239
|
+
* É a resposta exata, e ela não depende de resolver caminho nenhum.
|
|
1240
|
+
*/
|
|
1241
|
+
const mine = published
|
|
1242
|
+
? rows.filter((r) => r.origin === published || r.origin?.startsWith(`${published}/`))
|
|
1243
|
+
: [];
|
|
1244
|
+
if (mine.length === 1) {
|
|
1245
|
+
evidence.set(name, mine[0]);
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
/** Sem pacote para casar, uma origem interna só também é resposta: não há o que confundir. */
|
|
1249
|
+
if (mine.length === 0 && rows.length === 1) {
|
|
1250
|
+
evidence.set(name, rows[0]);
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
ambiguous.push(name);
|
|
1254
|
+
}
|
|
1165
1255
|
const merged = scoped.map((c) => {
|
|
1166
1256
|
const e = evidence.get(c.name);
|
|
1167
1257
|
if (!e)
|
|
@@ -1198,7 +1288,15 @@ export async function takeCensus(root, opts) {
|
|
|
1198
1288
|
: {}),
|
|
1199
1289
|
};
|
|
1200
1290
|
});
|
|
1201
|
-
|
|
1291
|
+
/**
|
|
1292
|
+
* O QUE O APP TEM E A BIBLIOTECA NÃO - e a mesma lei: só entra o que tem origem DELE.
|
|
1293
|
+
*
|
|
1294
|
+
* A frase que sai daqui diz "estes são componentes seus que vivem só no app". Sem `own`, um nome
|
|
1295
|
+
* de origem desconhecida entrava na lista, e a tela oferecia ao cliente um componente que pode ser
|
|
1296
|
+
* de terceiro - a mesma acusação que o `<Button variant="contained">` sem import produzia do
|
|
1297
|
+
* outro lado.
|
|
1298
|
+
*/
|
|
1299
|
+
const theirsOnly = usedThere.filter((c) => c.own && !inScope.has(c.name));
|
|
1202
1300
|
// The verdict travels WITH the payload: the platform reads one reading rather
|
|
1203
1301
|
// than computing a second opinion from the same numbers, which is how two
|
|
1204
1302
|
// implementations of the same judgement start disagreeing.
|
|
@@ -1211,8 +1309,19 @@ export async function takeCensus(root, opts) {
|
|
|
1211
1309
|
* itself. See `isLibrary`.
|
|
1212
1310
|
*/
|
|
1213
1311
|
const library = isLibrary(scoped);
|
|
1312
|
+
/**
|
|
1313
|
+
* O VEREDITO É DE UMA LINHA, NÃO DE UM NOME - o quarto sítio da mesma lei.
|
|
1314
|
+
*
|
|
1315
|
+
* `crosswalk` já julga linha a linha e pula quem tem `from`: o `Tooltip` do `recharts` sai dele
|
|
1316
|
+
* SEM veredito, que é o certo. Mas o mapa era por NOME, então o veredito do `Tooltip` DELE -
|
|
1317
|
+
* `exclusive`, um componente que ele escreveu - era colado também na linha do recharts. Medido em
|
|
1318
|
+
* 10/08: `recharts` e `@base-ui/react` chegavam ao censo como componentes exclusivos dele.
|
|
1319
|
+
*
|
|
1320
|
+
* A chave é nome+origem, que é a mesma identidade que o censo passou a carregar.
|
|
1321
|
+
*/
|
|
1322
|
+
const idOf = (c) => `${c.name}\u0000${c.origin ?? ""}`;
|
|
1214
1323
|
const verdicts = new Map(crosswalk(merged, { library }).map((r) => [
|
|
1215
|
-
r.component
|
|
1324
|
+
idOf(r.component),
|
|
1216
1325
|
{ bucket: r.bucket, canonical: r.canonical, because: r.because },
|
|
1217
1326
|
]));
|
|
1218
1327
|
if (usedThere.length > 0) {
|
|
@@ -1515,7 +1624,7 @@ export async function takeCensus(root, opts) {
|
|
|
1515
1624
|
}
|
|
1516
1625
|
const components = merged.map((c) => ({
|
|
1517
1626
|
...c,
|
|
1518
|
-
...(verdicts.get(c
|
|
1627
|
+
...(verdicts.get(idOf(c)) ?? {}),
|
|
1519
1628
|
...(laws.has(c.name) ? { laws: laws.get(c.name) } : {}),
|
|
1520
1629
|
...(runtimeOf.has(c.name) ? { runtime: runtimeOf.get(c.name) } : {}),
|
|
1521
1630
|
...(companionsOf.has(c.name)
|
|
@@ -2341,10 +2450,31 @@ function sayReach(c) {
|
|
|
2341
2450
|
* shadow one of their own names. `declared` is a DEFINITION of theirs, which is what makes
|
|
2342
2451
|
* this a tie-break rather than a preference.
|
|
2343
2452
|
*/
|
|
2453
|
+
/**
|
|
2454
|
+
* O DESEMPATE QUE DEIXOU DE SER NECESSÁRIO - e que virou uma reivindicação falsa.
|
|
2455
|
+
*
|
|
2456
|
+
* Ele nasceu quando uma linha era um NOME: o `Pill` deles fazia
|
|
2457
|
+
* `import { Toggle } from "@base-ui/react/toggle"`, e esse nome colidia com o `Toggle` que eles
|
|
2458
|
+
* escreveram uma pasta ao lado - a linha saía carregando `from: "@base-ui/react/toggle"`, e `from` é
|
|
2459
|
+
* o que faz o crosswalk pular um componente. O Toggle DELES sumia do sistema inteiro (test50,
|
|
2460
|
+
* 04/08). Apagar o `from` era a única saída, porque não havia duas linhas para escolher.
|
|
2461
|
+
*
|
|
2462
|
+
* Agora há: a origem entra na chave, então o `Toggle` deles e o do `@base-ui/react` são duas linhas.
|
|
2463
|
+
* Continuar apagando o `from` da linha de terceiro faz a esteira reivindicar o componente ALHEIO -
|
|
2464
|
+
* medido em 10/08 no repo do dono: o `Tooltip` do `recharts` e o `Toggle` do `@base-ui/react`
|
|
2465
|
+
* chegavam ao censo como `exclusive`, ou seja, como componentes que ele teria escrito. É exatamente
|
|
2466
|
+
* o caso que a lei 13 nomeia.
|
|
2467
|
+
*
|
|
2468
|
+
* A regra passa a olhar a ORIGEM: um `from` só se apaga quando não há origem para distinguir as
|
|
2469
|
+
* duas - o mundo antigo, e o único em que o desempate ainda é honesto.
|
|
2470
|
+
*/
|
|
2344
2471
|
export function declaredWins(component, declared) {
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2472
|
+
if (!component.from || !declared)
|
|
2473
|
+
return component;
|
|
2474
|
+
/** Com origem, a linha dele existe à parte e esta aqui é de quem a exportou. */
|
|
2475
|
+
if (component.origin)
|
|
2476
|
+
return component;
|
|
2477
|
+
return { ...component, from: undefined };
|
|
2348
2478
|
}
|
|
2349
2479
|
function rootPackage(tag, sketch) {
|
|
2350
2480
|
if (!tag || !/^[A-Z]/.test(tag))
|
|
@@ -235,8 +235,19 @@ function importedNames(source, internal = []) {
|
|
|
235
235
|
if (!part || part === "*")
|
|
236
236
|
continue;
|
|
237
237
|
const local = (part.split(/\s+as\s+/).pop() ?? "").trim();
|
|
238
|
+
/**
|
|
239
|
+
* O ESPECIFICADOR VIAJA MESMO QUANDO É DE DENTRO - e `own` vira uma resposta à parte.
|
|
240
|
+
*
|
|
241
|
+
* `OWN` era um balde só para TODO caminho interno, então o `Button` da biblioteca dele e o
|
|
242
|
+
* `Button` do Chakra re-exportado atrás do alias `@/` eram a mesma linha. Medido no repo do
|
|
243
|
+
* dono em 10/08: `Button` chega de 10 alvos internos diferentes, 6 deles dentro dos apps, e a
|
|
244
|
+
* união deles escreveu seis leis - `enlarge`, `on`, `hover`, `click`, `asChild`, `onlyBorder` -
|
|
245
|
+
* sobre um componente que não tem nenhuma dessas props.
|
|
246
|
+
*
|
|
247
|
+
* A lei 13 diz que a origem decide. "De dentro" não é uma origem, é uma vizinhança.
|
|
248
|
+
*/
|
|
238
249
|
if (/^[A-Z]/.test(local))
|
|
239
|
-
out.set(local,
|
|
250
|
+
out.set(local, { spec, own });
|
|
240
251
|
}
|
|
241
252
|
}
|
|
242
253
|
return out;
|
|
@@ -333,7 +344,7 @@ internal = []) {
|
|
|
333
344
|
* causa do `own: true` valer em 7 de 128: uma linha que mistura duas origens nunca tem TODAS
|
|
334
345
|
* as origens de dentro.
|
|
335
346
|
*/
|
|
336
|
-
const key = `${name}\u0000${owner ?? ""}`;
|
|
347
|
+
const key = `${name}\u0000${owner?.spec ?? ""}`;
|
|
337
348
|
let hit = tally.get(key);
|
|
338
349
|
if (!hit) {
|
|
339
350
|
hit = {
|
|
@@ -341,14 +352,18 @@ internal = []) {
|
|
|
341
352
|
files: new Set(),
|
|
342
353
|
props: new Map(),
|
|
343
354
|
propFiles: new Map(),
|
|
344
|
-
...(owner && owner
|
|
355
|
+
...(owner && !owner.own ? { from: owner.spec } : {}),
|
|
345
356
|
origins: new Set(),
|
|
346
357
|
};
|
|
347
358
|
tally.set(key, hit);
|
|
348
359
|
}
|
|
349
|
-
/**
|
|
360
|
+
/**
|
|
361
|
+
* A ORIGEM AGORA ESTÁ INTEIRA NA CHAVE, então esta linha tem uma só. `origins` continua
|
|
362
|
+
* existindo porque é ele que separa "veio de um lugar que eu sei ler" de "não veio de lugar
|
|
363
|
+
* nenhum" - e é a segunda que a lei 13 manda não atribuir a ninguém.
|
|
364
|
+
*/
|
|
350
365
|
if (owner)
|
|
351
|
-
hit.origins.add(owner);
|
|
366
|
+
hit.origins.add(owner.own ? OWN : owner.spec);
|
|
352
367
|
hit.count += 1;
|
|
353
368
|
hit.files.add(file);
|
|
354
369
|
LITERAL_PROP.lastIndex = 0;
|
|
@@ -393,6 +408,14 @@ export function tallyToInventory(tally, max = 80) {
|
|
|
393
408
|
.map(([key, v]) => ({
|
|
394
409
|
/** A chave carrega a origem para separar as linhas - o nome é a primeira metade dela. */
|
|
395
410
|
name: key.split("\u0000")[0],
|
|
411
|
+
/**
|
|
412
|
+
* E A SEGUNDA METADE VIAJA, que é o que permite a quem lê perguntar QUAL. Sem isto o censo
|
|
413
|
+
* separava as linhas e devolvia só o nome - foi exatamente assim que a evidência de uso voltou
|
|
414
|
+
* a casar por NOME um passo depois desta função, em `runImport`.
|
|
415
|
+
*/
|
|
416
|
+
...(key.slice(key.indexOf("\u0000") + 1)
|
|
417
|
+
? { origin: key.slice(key.indexOf("\u0000") + 1) }
|
|
418
|
+
: {}),
|
|
396
419
|
...(v.from ? { from: v.from } : {}),
|
|
397
420
|
/** Só dele quando TODA aparição veio de dentro - ver `origins` e `OWN`. */
|
|
398
421
|
...(v.origins.size > 0 && [...v.origins].every((o) => o === OWN)
|
|
@@ -60,8 +60,36 @@ export function checkContracts(used, documents) {
|
|
|
60
60
|
}
|
|
61
61
|
if (axes.size === 0)
|
|
62
62
|
return [];
|
|
63
|
+
/**
|
|
64
|
+
* E O NOME QUE CHEGA DE MAIS DE UM LUGAR DE DENTRO NÃO SE COBRA DE NINGUÉM.
|
|
65
|
+
*
|
|
66
|
+
* A terceira forma da mesma lei, e a que faltava. `own` responde "veio de dentro do projeto", que
|
|
67
|
+
* é uma VIZINHANÇA e não uma origem: um `Button` do Chakra re-exportado atrás do alias `@/` é tão
|
|
68
|
+
* "de dentro" quanto o da biblioteca dele.
|
|
69
|
+
*
|
|
70
|
+
* Medido no repo do dono em 10/08, no `apps/web-dashboard`: `Button` chega de DEZ lugares, cinco
|
|
71
|
+
* deles de dentro - `@frontend-hub/ui` (34 arquivos), `@/components/ui/_legacy/_chakra-ui/button`
|
|
72
|
+
* (25), `@/components/ui/_legacy/_general/Button` (19), `@/components/ui/Button` (3) e
|
|
73
|
+
* `../Button` (1). A ÚNICA acusação que o doctor fazia contra o sistema dele era
|
|
74
|
+
* `variant="outline"`, que é do Chakra: as cinco variantes que o Button DELE recebe estão todas
|
|
75
|
+
* entre as nove que ele declara.
|
|
76
|
+
*
|
|
77
|
+
* Uma acusação falsa custa mais que uma acusação perdida: ela ensina a pessoa a não acreditar na
|
|
78
|
+
* próxima. Enquanto a identidade não se divide de verdade, o mínimo honesto é a esteira SABER que
|
|
79
|
+
* é ambíguo e calar sobre esse nome.
|
|
80
|
+
*/
|
|
81
|
+
const insideOrigins = new Map();
|
|
82
|
+
for (const c of used) {
|
|
83
|
+
if (!c.own)
|
|
84
|
+
continue;
|
|
85
|
+
const seen = insideOrigins.get(c.name) ?? new Set();
|
|
86
|
+
seen.add(c.origin ?? "");
|
|
87
|
+
insideOrigins.set(c.name, seen);
|
|
88
|
+
}
|
|
63
89
|
const out = [];
|
|
64
90
|
for (const c of used) {
|
|
91
|
+
if ((insideOrigins.get(c.name)?.size ?? 0) > 1)
|
|
92
|
+
continue;
|
|
65
93
|
// A third party's component answers to its own package, not to this system.
|
|
66
94
|
if (c.from)
|
|
67
95
|
continue;
|
package/package.json
CHANGED