synthesisui 0.16.295 → 0.16.297
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 +32 -0
- package/dist/runtime-vars.js +102 -0
- package/package.json +1 -1
package/dist/commands/import.js
CHANGED
|
@@ -47,6 +47,7 @@ import { body, paint, section } from "../output.js";
|
|
|
47
47
|
import { outsideScope } from "../outside-scope.js";
|
|
48
48
|
import { phase, startProgress } from "../progress.js";
|
|
49
49
|
import { repoStateOf } from "../repo-state.js";
|
|
50
|
+
import { runtimeDeclaredVars, runtimeDeclaredVarsIn } from "../runtime-vars.js";
|
|
50
51
|
import { detectStack, resolveDeps, stackVersions } from "../stack.js";
|
|
51
52
|
import { placeInWorkspace } from "../workspace-place.js";
|
|
52
53
|
import { add } from "./add.js";
|
|
@@ -1934,6 +1935,37 @@ export async function takeCensus(root, opts) {
|
|
|
1934
1935
|
for (const m of css.matchAll(/(--[a-zA-Z0-9_-]+)\s*:/g)) {
|
|
1935
1936
|
declaredNames.add(m[1]);
|
|
1936
1937
|
}
|
|
1938
|
+
/**
|
|
1939
|
+
* E O QUE ELE DECLARA FORA DO CSS - ver `runtimeDeclaredVars`.
|
|
1940
|
+
*
|
|
1941
|
+
* `next/font` gera a variável em tempo de execução, então uma varredura de folhas `.css` não a
|
|
1942
|
+
* enxerga e o relatório acusava as quatro fontes do repositório dele de "não resolvem para nada".
|
|
1943
|
+
* Medido em 24/08: 4 das 6 variáveis reportadas como mortas estavam vivas, e o agente teve que se
|
|
1944
|
+
* desdizer na frente do cliente.
|
|
1945
|
+
*/
|
|
1946
|
+
for (const name of runtimeDeclaredVars(sources))
|
|
1947
|
+
declaredNames.add(name);
|
|
1948
|
+
/**
|
|
1949
|
+
* E FORA DO ESCOPO TAMBÉM - senão o conserto acima não alcança um monorepo.
|
|
1950
|
+
*
|
|
1951
|
+
* Com um escopo estreitado este `root` É a pasta do escopo, então `sources` tem o escopo e mais
|
|
1952
|
+
* nada. As fontes deste repositório são declaradas nos apps e CONSUMIDAS dentro da biblioteca - a
|
|
1953
|
+
* divisão que o próprio Next recomenda, e não um acidente de organização.
|
|
1954
|
+
*
|
|
1955
|
+
* MEDIDO: com o leitor acima já publicado, a segunda corrida ainda reportou as quatro fontes como
|
|
1956
|
+
* mortas. A promessa escrita acima é *"a name is only broken if NOTHING declares it, anywhere"*, e
|
|
1957
|
+
* "anywhere" tem que incluir os roots que a pessoa nomeou em uso.
|
|
1958
|
+
*/
|
|
1959
|
+
const usageRoots = (opts?.usage ?? []).map((u) => u.path);
|
|
1960
|
+
if (usageRoots.length > 0) {
|
|
1961
|
+
const outside = await runtimeDeclaredVarsIn(usageRoots, {
|
|
1962
|
+
readdir: (p) => readdir(p, { withFileTypes: true, encoding: "utf8" }),
|
|
1963
|
+
readFile: (p) => readFile(p, "utf8"),
|
|
1964
|
+
join,
|
|
1965
|
+
});
|
|
1966
|
+
for (const name of outside)
|
|
1967
|
+
declaredNames.add(name);
|
|
1968
|
+
}
|
|
1937
1969
|
/**
|
|
1938
1970
|
* HOW SOMEBODY CALLS THE COMPONENT THEY ALREADY HAVE.
|
|
1939
1971
|
*
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AS VARIÁVEIS QUE O CÓDIGO DELE DECLARA FORA DO CSS - e sem elas a plataforma acusa o repositório
|
|
3
|
+
* dele de um defeito que não existe.
|
|
4
|
+
*
|
|
5
|
+
* O QUE O CLIENTE VIA, medido numa corrida real em 24/08 contra o `codelevel`:
|
|
6
|
+
*
|
|
7
|
+
* "6 var() que não resolvem para nada: --font-ds-display, --font-ds-body,
|
|
8
|
+
* --font-ds-mono, --font-ds-serif, --ring-circ, --ring-target"
|
|
9
|
+
*
|
|
10
|
+
* Quatro das seis resolvem. Elas são declaradas por `next/font`, que gera a variável em tempo de
|
|
11
|
+
* execução e a injeta pelo `className` - o inventário de declarações lia só folhas `.css`, então
|
|
12
|
+
* para ele aquilo não existia. O agente teve que se desdizer na frente do cliente no MESMO
|
|
13
|
+
* fechamento, e uma afirmação errada custa mais confiança que a lacuna que ela tentava reportar.
|
|
14
|
+
*
|
|
15
|
+
* O ALCANCE, medido no mesmo repositório: 27 arquivos usam `next/font`, declarando 8 variáveis.
|
|
16
|
+
* Não é caso de borda - é a forma recomendada de carregar fonte em Next, e o nosso próprio
|
|
17
|
+
* `fonts.ts` a ESCREVE para o cliente. Sabíamos escrever a forma e não sabíamos lê-la.
|
|
18
|
+
*
|
|
19
|
+
* POR QUE O IMPORT PRECISA DO ARQUIVO, e não só do padrão: `variable: "--x"` é texto comum o
|
|
20
|
+
* bastante para aparecer em CSS-in-JS e em objetos de configuração de qualquer biblioteca. Contar
|
|
21
|
+
* aquilo como declaração em todo lugar trocaria um falso positivo por um falso negativo - a
|
|
22
|
+
* plataforma deixaria de avisar sobre uma variável genuinamente morta. Então a regra é a origem, e
|
|
23
|
+
* não o nome: só vale num arquivo que importa de `next/font`, que é o pacote cujo contrato promete
|
|
24
|
+
* a declaração.
|
|
25
|
+
*/
|
|
26
|
+
/** Um arquivo importa de `next/font`? É a origem que autoriza a leitura abaixo. */
|
|
27
|
+
const IMPORTS_NEXT_FONT = /from\s+["']next\/font(?:\/[a-z]+)?["']/;
|
|
28
|
+
/**
|
|
29
|
+
* O CAMPO DO CONTRATO. `next/font` aceita `variable` em `Inter({...})` e em `localFont({...})`, e nos
|
|
30
|
+
* dois casos a promessa é a mesma: a classe devolvida declara essa variável no elemento.
|
|
31
|
+
*/
|
|
32
|
+
const VARIABLE_FIELD = /\bvariable\s*:\s*["'](--[a-zA-Z0-9_-]+)["']/g;
|
|
33
|
+
/**
|
|
34
|
+
* Os nomes que os arquivos dele declaram em tempo de execução, e que nenhuma folha `.css` carrega.
|
|
35
|
+
*
|
|
36
|
+
* Devolve um `Set` porque é assim que o inventário de declarações do import é consultado - a
|
|
37
|
+
* intenção é somar a ele, nunca substituí-lo: uma variável pode ser declarada nos dois lugares, e
|
|
38
|
+
* duas fontes que concordam não são um conflito.
|
|
39
|
+
*/
|
|
40
|
+
export function runtimeDeclaredVars(sources) {
|
|
41
|
+
const out = new Set();
|
|
42
|
+
for (const { source } of sources) {
|
|
43
|
+
if (!IMPORTS_NEXT_FONT.test(source))
|
|
44
|
+
continue;
|
|
45
|
+
for (const m of source.matchAll(VARIABLE_FIELD))
|
|
46
|
+
out.add(m[1]);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* E A DECLARAÇÃO PODE MORAR FORA DO ESCOPO - o caso que o conserto de 24/08 não alcançou.
|
|
52
|
+
*
|
|
53
|
+
* MEDIDO no `codelevel` na segunda corrida, já com o leitor acima publicado: as quatro fontes
|
|
54
|
+
* CONTINUARAM sendo reportadas como mortas. A causa não era o leitor - era o que chega nele.
|
|
55
|
+
*
|
|
56
|
+
* `--scope packages/ui` faz o `root` do censo ser a pasta do escopo, então a varredura vê
|
|
57
|
+
* `packages/ui` e mais nada. As fontes são declaradas em `apps/landing/app/fonts.ts` e
|
|
58
|
+
* `apps/web/app/fonts.ts`, e USADAS dentro de `packages/ui`. Essa divisão não é acidente de
|
|
59
|
+
* organização: num monorepo, o app carrega a fonte e a biblioteca a consome, e é a forma
|
|
60
|
+
* recomendada pelo próprio Next.
|
|
61
|
+
*
|
|
62
|
+
* O código já promete o contrário do que fazia - *"a name is only broken if NOTHING declares it,
|
|
63
|
+
* anywhere"* está escrito no ponto que monta a lista. "Anywhere" tem que incluir os roots de
|
|
64
|
+
* `--usage`, que a pessoa nomeou justamente para dizer onde o vocabulário é consumido.
|
|
65
|
+
*
|
|
66
|
+
* SÓ LEITURA, e só de arquivos de código: nada aqui escreve, e um root de uso já é lido para
|
|
67
|
+
* evidência - a diferença é que agora ele também pode DECLARAR.
|
|
68
|
+
*/
|
|
69
|
+
export async function runtimeDeclaredVarsIn(roots, read) {
|
|
70
|
+
const out = new Set();
|
|
71
|
+
const seen = new Set();
|
|
72
|
+
const walk = async (dir, depth) => {
|
|
73
|
+
/**
|
|
74
|
+
* O TETO DE PROFUNDIDADE é o que mantém isto barato num monorepo grande. Uma declaração de
|
|
75
|
+
* fonte mora no diretório de app (`app/fonts.ts`, `src/app/fonts.ts`, `styles/fonts.ts`) -
|
|
76
|
+
* quatro níveis cobrem as três formas com folga, e o custo não cresce com o tamanho do repo.
|
|
77
|
+
*/
|
|
78
|
+
if (depth < 0 || seen.has(dir))
|
|
79
|
+
return;
|
|
80
|
+
seen.add(dir);
|
|
81
|
+
const entries = await read.readdir(dir).catch(() => []);
|
|
82
|
+
for (const e of entries) {
|
|
83
|
+
if (e.name.startsWith(".") || e.name === "node_modules")
|
|
84
|
+
continue;
|
|
85
|
+
const full = read.join(dir, e.name);
|
|
86
|
+
if (e.isDirectory()) {
|
|
87
|
+
await walk(full, depth - 1);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!/\.(ts|tsx|js|jsx|mjs)$/i.test(e.name))
|
|
91
|
+
continue;
|
|
92
|
+
const src = await read.readFile(full).catch(() => "");
|
|
93
|
+
if (!src)
|
|
94
|
+
continue;
|
|
95
|
+
for (const name of runtimeDeclaredVars([{ file: full, source: src }]))
|
|
96
|
+
out.add(name);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
for (const r of roots)
|
|
100
|
+
await walk(r, 4);
|
|
101
|
+
return out;
|
|
102
|
+
}
|
package/package.json
CHANGED