synthesisui 0.16.282 → 0.16.284
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/add.js +26 -1
- package/dist/commands/doctor.js +20 -0
- package/dist/guide.js +21 -1
- package/dist/install-marks.js +1 -1
- package/dist/their-vars.js +200 -0
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -10,6 +10,7 @@ import { body as line, section, snippet } from "../output.js";
|
|
|
10
10
|
import { fetchDesignSystem } from "../registry.js";
|
|
11
11
|
import { describeFiltered, ruleApplies, rulesForProject, } from "../rule-filter.js";
|
|
12
12
|
import { detectStack } from "../stack.js";
|
|
13
|
+
import { pointTokensAtTheirNames } from "../their-vars.js";
|
|
13
14
|
/**
|
|
14
15
|
* QUAL METADE DESTA PASTA UM TIME COMMITA.
|
|
15
16
|
*
|
|
@@ -193,9 +194,18 @@ export async function add(slug, opts) {
|
|
|
193
194
|
// know what was active before, to report install vs update vs switch
|
|
194
195
|
const prev = await readRootLock(rootLockPath);
|
|
195
196
|
await mkdir(versionDir, { recursive: true });
|
|
197
|
+
/**
|
|
198
|
+
* O VOCABULÁRIO DELE, LIDO NESTA MÁQUINA - ver `their-vars.ts`, e é por isso que isto acontece
|
|
199
|
+
* aqui e não no compilador: a pergunta *"esta variável existe NESTE repositório?"* só tem resposta
|
|
200
|
+
* onde o repositório está.
|
|
201
|
+
*
|
|
202
|
+
* Falha calada de propósito: um repositório sem folha de estilo, ou sem build, devolve o que veio
|
|
203
|
+
* do servidor. A folha nunca fica pior do que estava.
|
|
204
|
+
*/
|
|
205
|
+
const theirVars = await pointTokensAtTheirNames(projectRoot, payload);
|
|
196
206
|
// 1. server artifacts (tokens.css, theme.css, …) → pinned version folder
|
|
197
207
|
for (const [filename, content] of Object.entries(payload.artifacts)) {
|
|
198
|
-
await writeFile(join(versionDir, filename), content, "utf8");
|
|
208
|
+
await writeFile(join(versionDir, filename), filename === "tokens.css" ? theirVars.css : content, "utf8");
|
|
199
209
|
}
|
|
200
210
|
// 2. canonical source of truth
|
|
201
211
|
await writeFile(join(versionDir, "design-system.json"), `${JSON.stringify(payload.document, null, 2)}\n`, "utf8");
|
|
@@ -250,6 +260,14 @@ export async function add(slug, opts) {
|
|
|
250
260
|
/** Ver `RegistryPayload.compiler`: é o que faz um conserto de CSS chegar a um install. */
|
|
251
261
|
...(payload.compiler != null ? { compiler: payload.compiler } : {}),
|
|
252
262
|
...(payload.rulesStamp ? { rules: payload.rulesStamp } : {}),
|
|
263
|
+
/**
|
|
264
|
+
* QUANTAS LINHAS DESTA FOLHA APONTAM PARA UMA VARIÁVEL DELE - ver `their-vars.ts`.
|
|
265
|
+
*
|
|
266
|
+
* Sem isto, o `tokens.css` de dois repositórios do mesmo sistema seria diferente e nada diria por
|
|
267
|
+
* quê. O número é o rastro: o `doctor` sabe que aquelas linhas dependem do vocabulário DESTE
|
|
268
|
+
* repositório, e é ele que avisa quando uma delas deixa de resolver.
|
|
269
|
+
*/
|
|
270
|
+
...(theirVars.pointed > 0 ? { theirVars: theirVars.pointed } : {}),
|
|
253
271
|
...(scope ? { scope } : {}),
|
|
254
272
|
...(systems.length > 0 ? { scopes: systems } : {}),
|
|
255
273
|
...(usage.length > 0 ? { usage } : {}),
|
|
@@ -371,6 +389,13 @@ export async function add(slug, opts) {
|
|
|
371
389
|
"GUIDE.md",
|
|
372
390
|
];
|
|
373
391
|
console.log(` v${v}/: ${files.join(", ")}`);
|
|
392
|
+
/**
|
|
393
|
+
* A FOLHA NÃO É A QUE O SERVIDOR COMPILOU, e calar isso é o pior dos dois mundos: o cliente vê um
|
|
394
|
+
* `var(--color-ink-500)` num arquivo "gerenciado pelo synthesisui" e não tem como saber de onde
|
|
395
|
+
* veio. Dito assim, ele lê a linha como o que ela é - o sistema seguindo o vocabulário dele.
|
|
396
|
+
*/
|
|
397
|
+
if (theirVars.pointed > 0)
|
|
398
|
+
console.log(` ${theirVars.pointed} value${theirVars.pointed === 1 ? "" : "s"} in tokens.css now point at the name YOUR code already gives ${theirVars.pointed === 1 ? "it" : "them"} - change yours and the system follows${theirVars.pruned > 0 ? `; ${theirVars.pruned} matched but your build does not emit ${theirVars.pruned === 1 ? "that name" : "those names"}, so ${theirVars.pruned === 1 ? "it keeps" : "they keep"} the value` : ""}`);
|
|
374
399
|
/**
|
|
375
400
|
* O QUE O AGENTE VAI LER, e por qual porta - nomear o arquivo quando a porta é uma ferramenta
|
|
376
401
|
* mandaria alguém procurar um caminho que não existe mais.
|
package/dist/commands/doctor.js
CHANGED
|
@@ -20,6 +20,7 @@ import { groupRole } from "../group-role.js";
|
|
|
20
20
|
import { actingSlug, describeScope, measuredScope, scopePaths, } from "../measured-scope.js";
|
|
21
21
|
import { body, paint, section, snippet } from "../output.js";
|
|
22
22
|
import { resolveDeps } from "../stack.js";
|
|
23
|
+
import { danglingTheirVars } from "../their-vars.js";
|
|
23
24
|
/**
|
|
24
25
|
* `synthesisui doctor` - the check nobody else ships.
|
|
25
26
|
*
|
|
@@ -891,6 +892,25 @@ export async function doctor(opts) {
|
|
|
891
892
|
}
|
|
892
893
|
console.log(body("The exact snippets are in the output of `init`."));
|
|
893
894
|
}
|
|
895
|
+
/**
|
|
896
|
+
* A FOLHA APONTA PARA O VOCABULÁRIO DELE, E UM NOME SUMIU - ver `their-vars.ts`.
|
|
897
|
+
*
|
|
898
|
+
* O `add` reescreve `--ds-color-ink-500: #6b6b78` como `var(--color-ink-500)` quando o repositório
|
|
899
|
+
* já nomeia aquele valor, para não existirem duas fontes da verdade. Não há fallback, por decisão:
|
|
900
|
+
* uma cópia do valor sobreviveria a um rename DELE pintando o valor velho, que é a plataforma
|
|
901
|
+
* decidindo por cima da decisão dele.
|
|
902
|
+
*
|
|
903
|
+
* O preço é que um rename apaga a cor, e este é o único lugar que conhece as duas pontas. Sem esta
|
|
904
|
+
* linha ele veria um componente sem cor e nada explicaria de onde veio.
|
|
905
|
+
*/
|
|
906
|
+
const dangling = danglingTheirVars(await readFile(join(root, "_synthesisui", "ds", table.slug ?? "", "tokens.css"), "utf8").catch(() => ""), installed.theirs);
|
|
907
|
+
if (dangling.length > 0) {
|
|
908
|
+
console.log("");
|
|
909
|
+
console.log(body(`${dangling.length} line${dangling.length === 1 ? "" : "s"} of this system point at ${dangling.length === 1 ? "a variable" : "variables"} your code no longer declares, so ${dangling.length === 1 ? "that value" : "those values"} paint nothing:`));
|
|
910
|
+
for (const { ours, theirs: name } of dangling.slice(0, 6))
|
|
911
|
+
console.log(body(` ${ours} → ${name}`));
|
|
912
|
+
console.log(body("Rename it back, or run `npx synthesisui add <slug>` to re-point the sheet at what you have now."));
|
|
913
|
+
}
|
|
894
914
|
/**
|
|
895
915
|
* E AQUI O RELATÓRIO PARA, quando a fiação está vermelha: uma instrução, e nada mais.
|
|
896
916
|
*
|
package/dist/guide.js
CHANGED
|
@@ -262,6 +262,23 @@ export function buildGuide(payload) {
|
|
|
262
262
|
const { document: doc, slug, name, version } = payload;
|
|
263
263
|
const { meta, foundations, motion, components } = doc;
|
|
264
264
|
const semanticRoles = Object.keys(foundations.color.semantic);
|
|
265
|
+
/**
|
|
266
|
+
* O NOME QUE ELE DÁ AO PAPEL, quando o documento sabe qual é - `semanticNames`.
|
|
267
|
+
*
|
|
268
|
+
* O guia listava `info, faint, muted, scrim, accent, border, canvas, danger, raised, overlay,
|
|
269
|
+
* primary, success, surface, warning` e chamava isso de vocabulário do sistema DELE. Nenhuma dessas
|
|
270
|
+
* palavras está no código dele: `canvas` é `paper`, `primary` é `brand-blue`, `danger` é
|
|
271
|
+
* `feedback-error`. Este arquivo é o que o agente dele LÊ antes de escrever, então a nossa língua
|
|
272
|
+
* aqui vira o código dele.
|
|
273
|
+
*
|
|
274
|
+
* A missão de 16/08 tirou o nosso identificador das telas e da saída de texto do CLI; o guia é
|
|
275
|
+
* artefato e escapou da varredura. Medido em 22/08 no `codelevel-ui`: 14 papéis listados, 12 com
|
|
276
|
+
* nome dele guardado no documento e nenhum aparecendo.
|
|
277
|
+
*
|
|
278
|
+
* Sem `semanticNames` o papel sai como está - é o caso de um sistema que NASCEU aqui, e aí o nome
|
|
279
|
+
* é nosso mesmo.
|
|
280
|
+
*/
|
|
281
|
+
const theirRole = (role) => foundations.color.semanticNames?.[role] ?? role;
|
|
265
282
|
/**
|
|
266
283
|
* AS CORES QUE ELE NOMEIA POR PROPÓSITO, no arquivo que o agente lê primeiro.
|
|
267
284
|
*
|
|
@@ -679,7 +696,10 @@ ${hasTailwind
|
|
|
679
696
|
The token names below are the source vocabulary - every utility derives from them.`
|
|
680
697
|
: ""}
|
|
681
698
|
- **Always use semantic tokens**, never raw values nor primitives directly.
|
|
682
|
-
Color: \`var(--ds-color-semantic-<role>)\`${hasTailwind ? " (utility: `bg-<role>`/`text-<role>`)" : ""}. The roles are: ${list(semanticRoles)
|
|
699
|
+
Color: \`var(--ds-color-semantic-<role>)\`${hasTailwind ? " (utility: `bg-<role>`/`text-<role>`)" : ""}. The roles are: ${list(semanticRoles.map((r) => {
|
|
700
|
+
const theirs = theirRole(r);
|
|
701
|
+
return theirs === r ? r : `${r} (${theirs} in your code)`;
|
|
702
|
+
}))}.
|
|
683
703
|
- Primitives (\`--ds-color-<palette>-<step>\`) exist but should **not** be referenced directly -
|
|
684
704
|
they feed the semantic roles.${namedColours.length > 0
|
|
685
705
|
? `\n- **Yours by name** → \`var(--ds-color-<name>)\`: ${namedColours.length} colour${namedColours.length === 1 ? "" : "s"} your code names by PURPOSE rather than by step, so no scale could hold ${namedColours.length === 1 ? "it" : "them"} - ${list(namedColours.slice(0, 8))}${namedColours.length > 8 ? ", …" : ""}. These are yours: reach for them when the purpose matches, and prefer a semantic role when it does not.`
|
package/dist/install-marks.js
CHANGED
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
* é sempre o bump deste PR - nunca o número que o `package.json` já carrega, porque alguém pode
|
|
129
129
|
* publicar no meio.
|
|
130
130
|
*/
|
|
131
|
-
export const MATERIALISER_SINCE = "0.16.
|
|
131
|
+
export const MATERIALISER_SINCE = "0.16.284";
|
|
132
132
|
/**
|
|
133
133
|
* A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
|
|
134
134
|
*
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { theirNames } from "./doctor/their-names.js";
|
|
4
|
+
import { buildTable, normalizeValue, } from "./doctor/tokens.js";
|
|
5
|
+
/**
|
|
6
|
+
* A FOLHA APONTA PARA O NOME QUE O CÓDIGO DELE JÁ DÁ AO VALOR.
|
|
7
|
+
*
|
|
8
|
+
* O QUE O CLIENTE VÊ. O `tokens.css` que a gente instala declara `--ds-color-ink-500: #6b6b78` num
|
|
9
|
+
* repositório que declara `--color-ink-500: #6b6b78` desde antes da gente existir. Mesmo valor,
|
|
10
|
+
* mesma palavra, prefixo nosso - e duas fontes da verdade. Ele muda a dele e a nossa fica congelada
|
|
11
|
+
* no valor que a gente copiou. Medido em 22/08 no `codelevel-monorepo`: 78 de 161 declarações.
|
|
12
|
+
*
|
|
13
|
+
* Depois disto a nossa linha vira `--ds-color-ink-500: var(--color-ink-500)`, e a cor do sistema
|
|
14
|
+
* segue a decisão dele sem a gente reescrever nada no arquivo dele.
|
|
15
|
+
*
|
|
16
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
17
|
+
* POR QUE ISTO MORA NO CLI E NÃO NO COMPILADOR, que é onde eu ia colocar.
|
|
18
|
+
*
|
|
19
|
+
* O mesmo `compileDesignSystemCss` serve DOIS consumidores: o `tokens.css` que vai para a pasta dele
|
|
20
|
+
* e o Canvas do Studio, onde a folha de estilo dele não existe. Apontar para `var(--color-ink-500)`
|
|
21
|
+
* lá dentro apagaria a cor do nosso próprio preview - e apagaria também em todo projeto de DESTINO,
|
|
22
|
+
* que é o caso que `orphan-var.ts` já descreve: *"no projeto de origem isso nunca aparece, porque o
|
|
23
|
+
* globals.css dele ainda está lá"*.
|
|
24
|
+
*
|
|
25
|
+
* A informação que decide - *"esta variável existe NESTE repositório?"* - só existe na máquina dele.
|
|
26
|
+
* Rodando aqui, o projeto de destino se resolve sozinho: nada casa, nada é reescrito.
|
|
27
|
+
*
|
|
28
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
29
|
+
* O QUE PROTEGE, e cada guarda saiu de uma medição.
|
|
30
|
+
*
|
|
31
|
+
* o BUILD é a autoridade o Tailwind PODA `@theme` que nenhuma utility usa. Medido nos 19
|
|
32
|
+
* arquivos CSS que o build dele produziu: 7 das 78 declarações somem.
|
|
33
|
+
* Apontar para uma podada não deixa a cor errada - apaga a cor.
|
|
34
|
+
* (as 29 cores dele sobreviveram; a poda pegou só `--animate-*`)
|
|
35
|
+
* sem build, sem reescrita um repositório que nunca buildou não tem como provar o que resolve,
|
|
36
|
+
* e chutar aqui é o oposto do objetivo. A folha fica como veio e o
|
|
37
|
+
* comando DIZ que ficou.
|
|
38
|
+
* a categoria fecha `theirNames` recusa comprimento cru: `24px` pode ser raio ou
|
|
39
|
+
* espaçamento no vocabulário dele, e escolher errado escreve um token
|
|
40
|
+
* de tipo num `border-radius`.
|
|
41
|
+
* nada de fallback `var(--x, #6b6b78)` sobreviveria a um rename DELE pintando o valor
|
|
42
|
+
* velho - a plataforma decidindo por cima da decisão dele. Se ele
|
|
43
|
+
* renomear, quebra, e o `doctor` diz qual (dono, 22/08: *"a gente não
|
|
44
|
+
* pode ser invasivo... mas tem que ser capaz de identificar"*).
|
|
45
|
+
*/
|
|
46
|
+
/** Onde um build costuma deixar o CSS que o navegador realmente recebe. */
|
|
47
|
+
const BUILD_DIRS = [".next", "dist", "build", "out", "storybook-static"];
|
|
48
|
+
async function* cssUnder(dir) {
|
|
49
|
+
for (const entry of await readdir(dir, { withFileTypes: true }).catch(() => [])) {
|
|
50
|
+
const path = join(dir, entry.name);
|
|
51
|
+
if (entry.isDirectory())
|
|
52
|
+
yield* cssUnder(path);
|
|
53
|
+
else if (entry.name.endsWith(".css"))
|
|
54
|
+
yield path;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* AS VARIÁVEIS QUE O BUILD DELE REALMENTE EMITE - a autoridade sobre o que resolve no navegador.
|
|
59
|
+
*
|
|
60
|
+
* `null` quando não há build nenhum, e null significa *não sei*, não *nenhuma*. Quem chama trata os
|
|
61
|
+
* dois de forma oposta.
|
|
62
|
+
*/
|
|
63
|
+
export async function resolvableVars(root) {
|
|
64
|
+
const out = new Set();
|
|
65
|
+
let found = false;
|
|
66
|
+
for (const dir of BUILD_DIRS) {
|
|
67
|
+
for await (const file of cssUnder(join(root, dir))) {
|
|
68
|
+
found = true;
|
|
69
|
+
const css = await readFile(file, "utf8").catch(() => "");
|
|
70
|
+
for (const m of css.matchAll(/(--[a-zA-Z0-9_-]+)\s*:/g))
|
|
71
|
+
out.add(m[1]);
|
|
72
|
+
}
|
|
73
|
+
/** Monorepo: o build mora dentro de cada app, não na raiz. */
|
|
74
|
+
for (const group of ["apps", "packages"]) {
|
|
75
|
+
for (const entry of await readdir(join(root, group), {
|
|
76
|
+
withFileTypes: true,
|
|
77
|
+
}).catch(() => [])) {
|
|
78
|
+
if (!entry.isDirectory())
|
|
79
|
+
continue;
|
|
80
|
+
for await (const file of cssUnder(join(root, group, entry.name, dir))) {
|
|
81
|
+
found = true;
|
|
82
|
+
const css = await readFile(file, "utf8").catch(() => "");
|
|
83
|
+
for (const m of css.matchAll(/(--[a-zA-Z0-9_-]+)\s*:/g))
|
|
84
|
+
out.add(m[1]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return found ? out : null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* REESCREVE A FOLHA, e só as linhas que passam nos dois portões.
|
|
93
|
+
*
|
|
94
|
+
* `theirs` é a tabela do repositório dele (`harvestOwnTokens`); `resolvable` é o que o build emite,
|
|
95
|
+
* ou `null` quando não há build - e aí nada é reescrito.
|
|
96
|
+
*/
|
|
97
|
+
export function pointAtTheirNames(css, theirs, resolvable) {
|
|
98
|
+
if (!resolvable || theirs.byName.size === 0)
|
|
99
|
+
return { css, pointed: 0, pruned: 0 };
|
|
100
|
+
const ours = buildTable({ css, source: "installed" });
|
|
101
|
+
const alias = theirNames(ours, theirs);
|
|
102
|
+
let pointed = 0;
|
|
103
|
+
let pruned = 0;
|
|
104
|
+
const out = css.replace(/^(\s*)(--ds-[a-zA-Z0-9_-]+)(\s*:\s*)([^;]+);/gm, (line, indent, name, sep, value) => {
|
|
105
|
+
/** Uma linha que já aponta para outra variável não é uma cópia de valor. */
|
|
106
|
+
if (value.includes("var("))
|
|
107
|
+
return line;
|
|
108
|
+
const kind = Object.entries(FAMILY_KIND).find(([prefix]) => name.startsWith(prefix))?.[1];
|
|
109
|
+
if (!kind)
|
|
110
|
+
return line;
|
|
111
|
+
const theirName = alias.get(`${kind}:${normalizeValue(value.trim(), ours.rootPx)}`);
|
|
112
|
+
if (!theirName || theirName === name)
|
|
113
|
+
return line;
|
|
114
|
+
if (!resolvable.has(theirName)) {
|
|
115
|
+
pruned += 1;
|
|
116
|
+
return line;
|
|
117
|
+
}
|
|
118
|
+
pointed += 1;
|
|
119
|
+
return `${indent}${name}${sep}var(${theirName});`;
|
|
120
|
+
});
|
|
121
|
+
return { css: out, pointed, pruned };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* O PREFIXO DA NOSSA VARIÁVEL -> A FAMÍLIA, e a chave que `theirNames` devolve é `<família>:<valor>`.
|
|
125
|
+
*
|
|
126
|
+
* Comprimento cru fica de fora por decisão de `their-names.ts`, e a razão é a mesma aqui: `24px` pode
|
|
127
|
+
* ser raio ou espaçamento no vocabulário dele.
|
|
128
|
+
*/
|
|
129
|
+
const FAMILY_KIND = {
|
|
130
|
+
"--ds-color-": "color",
|
|
131
|
+
"--ds-shadow-": "shadow",
|
|
132
|
+
"--ds-typography-families-": "font",
|
|
133
|
+
"--ds-motion-durations-": "motion",
|
|
134
|
+
"--ds-motion-easings-": "motion",
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* A JORNADA INTEIRA, num chamador só - varrer, medir o build, reescrever.
|
|
138
|
+
*
|
|
139
|
+
* Recebe o payload em vez do CSS solto porque um argumento opcional a menos é uma chamada pela
|
|
140
|
+
* metade a menos: quem chama não tem como esquecer de passar a folha certa.
|
|
141
|
+
*/
|
|
142
|
+
export async function pointTokensAtTheirNames(root, payload) {
|
|
143
|
+
const css = payload.artifacts["tokens.css"] ?? "";
|
|
144
|
+
if (!css)
|
|
145
|
+
return { css, pointed: 0, pruned: 0 };
|
|
146
|
+
const [theirs, resolvable] = await Promise.all([
|
|
147
|
+
harvestTheirCss(root),
|
|
148
|
+
resolvableVars(root),
|
|
149
|
+
]);
|
|
150
|
+
return pointAtTheirNames(css, theirs, resolvable);
|
|
151
|
+
}
|
|
152
|
+
/** As folhas de estilo DELE, e nenhuma da nossa pasta. Gêmeo de `harvestOwnTokens` no doctor. */
|
|
153
|
+
async function harvestTheirCss(root) {
|
|
154
|
+
const skip = new Set([
|
|
155
|
+
"node_modules",
|
|
156
|
+
".git",
|
|
157
|
+
"dist",
|
|
158
|
+
".next",
|
|
159
|
+
"build",
|
|
160
|
+
"out",
|
|
161
|
+
"_synthesisui",
|
|
162
|
+
]);
|
|
163
|
+
let css = "";
|
|
164
|
+
const walk = async (dir) => {
|
|
165
|
+
for (const entry of await readdir(dir, { withFileTypes: true }).catch(() => [])) {
|
|
166
|
+
if (skip.has(entry.name) || entry.name.startsWith("."))
|
|
167
|
+
continue;
|
|
168
|
+
const path = join(dir, entry.name);
|
|
169
|
+
if (entry.isDirectory())
|
|
170
|
+
await walk(path);
|
|
171
|
+
else if (/\.(css|scss|sass|less)$/i.test(entry.name))
|
|
172
|
+
css += `\n${await readFile(path, "utf8").catch(() => "")}`;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
await walk(root);
|
|
176
|
+
return buildTable({ css, source: "yours" });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* AS LINHAS QUE APONTAM PARA UM NOME DELE QUE NÃO EXISTE MAIS.
|
|
180
|
+
*
|
|
181
|
+
* O dono decidiu a política em 22/08, e ela é o oposto de defensiva: *"só fazer o design dele quebrar
|
|
182
|
+
* e ele mesmo acaba consertando. A gente não pode ser invasivo... mas tem que ser capaz de, se o
|
|
183
|
+
* usuário precisar, corrigir, ou pelo menos identificar o problema."*
|
|
184
|
+
*
|
|
185
|
+
* Então não existe fallback. Se ele renomeia `--color-ink-500`, a cor some - e este é o único lugar
|
|
186
|
+
* que sabe dizer POR QUÊ, porque só ele conhece as duas pontas: a folha que a gente instalou e o
|
|
187
|
+
* vocabulário que o repositório declara hoje.
|
|
188
|
+
*/
|
|
189
|
+
export function danglingTheirVars(installedCss, theirs) {
|
|
190
|
+
const out = [];
|
|
191
|
+
for (const m of installedCss.matchAll(/(--ds-[a-zA-Z0-9_-]+)\s*:\s*var\(\s*(--[a-zA-Z0-9_-]+)\s*\)\s*;/g)) {
|
|
192
|
+
const target = m[2];
|
|
193
|
+
/** Uma referência à nossa própria folha resolve nela mesma - não é dependência do repo dele. */
|
|
194
|
+
if (target.startsWith("--ds-"))
|
|
195
|
+
continue;
|
|
196
|
+
if (!theirs.byName.has(target))
|
|
197
|
+
out.push({ ours: m[1], theirs: target });
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
package/package.json
CHANGED