synthesisui 0.16.286 → 0.16.290
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/anatomy-read.js +20 -5
- package/dist/commands/add.js +25 -0
- package/dist/commands/component.js +65 -3
- package/dist/commands/import.js +92 -16
- package/dist/doctor/broken-refs.js +15 -1
- package/dist/doctor/component-gate.js +59 -2
- package/dist/doctor/css-modules.js +77 -47
- package/dist/doctor/definitions-scan.js +59 -3
- package/dist/doctor/transcribe.js +9 -51
- package/dist/doctor/variant-read.js +31 -5
- package/dist/global-wear.js +44 -0
- package/dist/install-marks.js +2 -2
- package/dist/namespace-pairs.js +80 -0
- package/dist/not-expressed.js +76 -0
- package/dist/repo-state.js +9 -0
- package/dist/their-tongue.js +47 -0
- package/dist/their-vars.js +10 -3
- package/dist/token-ref.js +93 -0
- package/package.json +1 -1
package/dist/repo-state.js
CHANGED
|
@@ -63,6 +63,15 @@ export async function repoStateOf(projectRoot, slug, cli) {
|
|
|
63
63
|
const payload = {
|
|
64
64
|
...(typeof lock?.version === "number" ? { installed: lock.version } : {}),
|
|
65
65
|
...(lock?.adopted === true ? { adopted: true } : {}),
|
|
66
|
+
/**
|
|
67
|
+
* O MAPA, do `.lock` - ver `RepoStatePayload.tokenMap`.
|
|
68
|
+
*
|
|
69
|
+
* Lido e não recalculado: o cruzamento é caro (varre as folhas dele e o build) e já foi feito
|
|
70
|
+
* pelo `add`, que é quem tinha o payload em mãos. Aqui ele só viaja.
|
|
71
|
+
*/
|
|
72
|
+
...(lock?.tokenMap && lock.tokenMap.length > 0
|
|
73
|
+
? { tokenMap: lock.tokenMap }
|
|
74
|
+
: {}),
|
|
66
75
|
cli,
|
|
67
76
|
...(doctor?.at ? { doctorAt: doctor.at } : {}),
|
|
68
77
|
...(typeof doctor?.phantoms === "number"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** `var(--ds-x)` e `var(--ds-x, fallback)` - o que a folha compilada escreve. */
|
|
2
|
+
const OUR_VAR = /var\(\s*(--ds-[a-zA-Z0-9_-]+)\s*(?:,([^()]*))?\)/g;
|
|
3
|
+
export function inTheirTongue(css, tongue) {
|
|
4
|
+
let named = 0;
|
|
5
|
+
let inlined = 0;
|
|
6
|
+
const left = new Set();
|
|
7
|
+
const out = css.replace(OUR_VAR, (whole, name, fallback) => {
|
|
8
|
+
const theirName = tongue.names.get(name);
|
|
9
|
+
if (theirName) {
|
|
10
|
+
named += 1;
|
|
11
|
+
/**
|
|
12
|
+
* O FALLBACK NÃO VIAJA. `var(--x, #valor)` sobreviveria a um rename DELE pintando o valor
|
|
13
|
+
* velho - a plataforma decidindo por cima da decisão dele. Se ele renomear, quebra, e o
|
|
14
|
+
* `doctor` diz qual (dono, 22/08).
|
|
15
|
+
*/
|
|
16
|
+
return `var(${theirName})`;
|
|
17
|
+
}
|
|
18
|
+
const value = tongue.values.get(name);
|
|
19
|
+
if (value) {
|
|
20
|
+
inlined += 1;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
left.add(name);
|
|
24
|
+
return fallback ? whole : whole;
|
|
25
|
+
});
|
|
26
|
+
return { css: out, named, inlined, left: [...left].sort() };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* O VOCABULÁRIO DESTE REPOSITÓRIO, montado do que o `add` já deixou na pasta.
|
|
30
|
+
*
|
|
31
|
+
* `map` vem do `.lock` (`tokenMap`) e é o que a máquina dele descobriu; `declared` vem do
|
|
32
|
+
* `tokens.css` instalado, que é onde cada variável nossa tem o valor compilado. Nenhuma medição
|
|
33
|
+
* nova: as duas coisas já estão no disco.
|
|
34
|
+
*/
|
|
35
|
+
export function tongueOf(map, installedCss) {
|
|
36
|
+
const names = new Map(map.map((p) => [p.ours, p.theirs]));
|
|
37
|
+
const values = new Map();
|
|
38
|
+
for (const m of installedCss.matchAll(/^\s*(--ds-[a-zA-Z0-9_-]+)\s*:\s*([^;]+);/gm)) {
|
|
39
|
+
const value = m[2].trim();
|
|
40
|
+
/** Uma linha que aponta para outra variável não é um valor - seguir a cadeia é do navegador. */
|
|
41
|
+
if (value.includes("var("))
|
|
42
|
+
continue;
|
|
43
|
+
if (!values.has(m[1]))
|
|
44
|
+
values.set(m[1], value);
|
|
45
|
+
}
|
|
46
|
+
return { names, values };
|
|
47
|
+
}
|
package/dist/their-vars.js
CHANGED
|
@@ -95,12 +95,18 @@ export async function resolvableVars(root) {
|
|
|
95
95
|
* ou `null` quando não há build - e aí nada é reescrito.
|
|
96
96
|
*/
|
|
97
97
|
export function pointAtTheirNames(css, theirs, resolvable) {
|
|
98
|
+
/**
|
|
99
|
+
* SEM BUILD, SEM MAPA - a mesma regra da reescrita, e pelo mesmo motivo: um repositório que nunca
|
|
100
|
+
* buildou não tem como provar o que resolve, e um par afirmado sem prova é pior que par nenhum.
|
|
101
|
+
*/
|
|
98
102
|
if (!resolvable || theirs.byName.size === 0)
|
|
99
|
-
return { css, pointed: 0, pruned: 0 };
|
|
103
|
+
return { css, pointed: 0, pruned: 0, pairs: [] };
|
|
100
104
|
const ours = buildTable({ css, source: "installed" });
|
|
101
105
|
const alias = theirNames(ours, theirs);
|
|
102
106
|
let pointed = 0;
|
|
103
107
|
let pruned = 0;
|
|
108
|
+
/** Ver `PointedAt.pairs`: o mapa sai do mesmo casamento que reescreve a linha. */
|
|
109
|
+
const pairs = [];
|
|
104
110
|
const out = css.replace(/^(\s*)(--ds-[a-zA-Z0-9_-]+)(\s*:\s*)([^;]+);/gm, (line, indent, name, sep, value) => {
|
|
105
111
|
/** Uma linha que já aponta para outra variável não é uma cópia de valor. */
|
|
106
112
|
if (value.includes("var("))
|
|
@@ -116,9 +122,10 @@ export function pointAtTheirNames(css, theirs, resolvable) {
|
|
|
116
122
|
return line;
|
|
117
123
|
}
|
|
118
124
|
pointed += 1;
|
|
125
|
+
pairs.push({ ours: name, theirs: theirName, value: value.trim() });
|
|
119
126
|
return `${indent}${name}${sep}var(${theirName});`;
|
|
120
127
|
});
|
|
121
|
-
return { css: out, pointed, pruned };
|
|
128
|
+
return { css: out, pointed, pruned, pairs };
|
|
122
129
|
}
|
|
123
130
|
/**
|
|
124
131
|
* O PREFIXO DA NOSSA VARIÁVEL -> A FAMÍLIA, e a chave que `theirNames` devolve é `<família>:<valor>`.
|
|
@@ -142,7 +149,7 @@ const FAMILY_KIND = {
|
|
|
142
149
|
export async function pointTokensAtTheirNames(root, payload) {
|
|
143
150
|
const css = payload.artifacts["tokens.css"] ?? "";
|
|
144
151
|
if (!css)
|
|
145
|
-
return { css, pointed: 0, pruned: 0 };
|
|
152
|
+
return { css, pointed: 0, pruned: 0, pairs: [] };
|
|
146
153
|
const [theirs, resolvable] = await Promise.all([
|
|
147
154
|
harvestTheirCss(root),
|
|
148
155
|
resolvableVars(root),
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O NOME QUE UM TOKEN DELE TEM DENTRO DO DOCUMENTO - uma regra, num lugar só.
|
|
3
|
+
*
|
|
4
|
+
* O QUE O CLIENTE GANHA: mudar um valor no Studio repinta o componente que o usa. Um ref liga os
|
|
5
|
+
* dois; um `var()` literal não liga nada - ele renderiza certo hoje e fica órfão da edição.
|
|
6
|
+
*
|
|
7
|
+
* ESTA FUNÇÃO EXISTIA DUAS VEZES, em `transcribe.ts` e em `css-modules.ts`, e as duas divergiam: a
|
|
8
|
+
* segunda não conhecia `--font-*`, então a família de fonte dele virava referência quando lida de uma
|
|
9
|
+
* classe e `var()` quando lida de uma folha - a mesma decisão dele com dois destinos, dependendo de
|
|
10
|
+
* onde a esteira olhou. Gêmeo não declarado sempre acaba assim.
|
|
11
|
+
*
|
|
12
|
+
* E O GRADIENTE ERA DECIDIDO PELO NOME. A regra reconhecia `--gradient-*`; o cliente escreveu
|
|
13
|
+
* `--grad-cool`. O escritor da plataforma reconhece pelo VALOR - `linear-gradient(…)` - e guarda em
|
|
14
|
+
* `foundations.gradients.grad-cool`, então o token TINHA casa no documento e a classe que o usa
|
|
15
|
+
* apontava para o vazio. É a lei 13 aplicada a token: a origem decide, e aqui a origem é o valor.
|
|
16
|
+
*
|
|
17
|
+
* Medido: `--grad-*` são 5 no `codelevel-ui`, `--gradient-*` são 3 no `frontend-hub`, e as duas
|
|
18
|
+
* grafias passam a chegar onde o documento as guarda.
|
|
19
|
+
*/
|
|
20
|
+
export function tokenRefFor(name,
|
|
21
|
+
/**
|
|
22
|
+
* O que cada token DELE vale. O mapa é o que permite reconhecer um gradiente pela forma em vez do
|
|
23
|
+
* nome; vazio, a decisão volta a ser só pelo nome, que é o comportamento de quem não tem o valor
|
|
24
|
+
* em mãos.
|
|
25
|
+
*/
|
|
26
|
+
declared) {
|
|
27
|
+
const bare = name.replace(/^--/, "");
|
|
28
|
+
if (bare.startsWith("color-"))
|
|
29
|
+
return refFor(bare.slice("color-".length));
|
|
30
|
+
if (bare.startsWith("radius-"))
|
|
31
|
+
return `{radius.${bare.slice(7)}}`;
|
|
32
|
+
if (bare.startsWith("spacing-"))
|
|
33
|
+
return `{spacing.${bare.slice(8)}}`;
|
|
34
|
+
if (bare.startsWith("shadow-"))
|
|
35
|
+
return `{shadow.${bare.slice(7)}}`;
|
|
36
|
+
// `--gradient-ui` e `--background-image-gradient-ui` são um token em duas grafias - o namespace de
|
|
37
|
+
// utility do Tailwind v4 embrulha o primeiro. Os dois chegam a `{gradients.ui}`.
|
|
38
|
+
if (bare.startsWith("background-image-gradient-")) {
|
|
39
|
+
return `{gradients.${bare.slice("background-image-gradient-".length)}}`;
|
|
40
|
+
}
|
|
41
|
+
if (bare.startsWith("gradient-"))
|
|
42
|
+
return `{gradients.${bare.slice(9)}}`;
|
|
43
|
+
if (bare.startsWith("text-")) {
|
|
44
|
+
/**
|
|
45
|
+
* O TOKEN COMPANHEIRO. O Tailwind v4 escreve "a altura de linha DE text-body-s" como
|
|
46
|
+
* `--text-body-s--line-height` - um duplo hífen dentro de um nome. Lido como nome de passo ele
|
|
47
|
+
* produzia `{typography.scale.body-s--line-height.fontSize}`, cujo duplo hífen nenhuma gramática
|
|
48
|
+
* de ref aceita, e a receita inteira era RECUSADA na validação (test13, 01/08). O sufixo nomeia a
|
|
49
|
+
* propriedade; o meio nomeia o passo.
|
|
50
|
+
*/
|
|
51
|
+
const companion = /^text-(.+?)--(line-height|letter-spacing|font-weight)$/.exec(bare);
|
|
52
|
+
if (companion) {
|
|
53
|
+
const prop = {
|
|
54
|
+
"line-height": "lineHeight",
|
|
55
|
+
"letter-spacing": "letterSpacing",
|
|
56
|
+
"font-weight": "weight",
|
|
57
|
+
}[companion[2]];
|
|
58
|
+
return `{typography.scale.${companion[1]}.${prop}}`;
|
|
59
|
+
}
|
|
60
|
+
// Qualquer outro duplo hífen é um nome que esta gramática não segura - o `var()` literal ainda
|
|
61
|
+
// resolve contra a folha dele, e um ref inválido não ajuda ninguém.
|
|
62
|
+
if (bare.slice(5).includes("--"))
|
|
63
|
+
return `var(${name})`;
|
|
64
|
+
return `{typography.scale.${bare.slice(5)}.fontSize}`;
|
|
65
|
+
}
|
|
66
|
+
if (bare.startsWith("font-"))
|
|
67
|
+
return `{typography.families.${bare.slice(5)}}`;
|
|
68
|
+
/**
|
|
69
|
+
* O GRADIENTE PELA FORMA DO VALOR, e é a última pergunta e não a primeira.
|
|
70
|
+
*
|
|
71
|
+
* Os namespaces acima são vocabulário conhecido e ganham deste teste - `--color-brand` que valha um
|
|
72
|
+
* `linear-gradient` continua sendo cor pelo nome que ele deu. Aqui embaixo estão os nomes que a
|
|
73
|
+
* gente NÃO modela, e é onde `--grad-cool` cai. A chave é o nome dele inteiro, que é exatamente o
|
|
74
|
+
* que `gradientsFromCensus` guarda no documento.
|
|
75
|
+
*/
|
|
76
|
+
const value = declared.get(name);
|
|
77
|
+
if (value && /\b(?:linear|radial|conic)-gradient\(/.test(value)) {
|
|
78
|
+
return `{gradients.${bare}}`;
|
|
79
|
+
}
|
|
80
|
+
// Um namespace que não modelamos. O `var()` literal continua sendo CSS correto contra a folha
|
|
81
|
+
// dele, e inventar um ref apontaria para nada.
|
|
82
|
+
return `var(${name})`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* `ocean-500` → `{color.ocean.500}`. O passo é o número final; o que vem antes é a família, hífens
|
|
86
|
+
* intactos, porque `royal-blue-500` é uma família chamada `royal-blue`.
|
|
87
|
+
*/
|
|
88
|
+
function refFor(name) {
|
|
89
|
+
const m = /^(.*)-(\d{2,4})$/.exec(name);
|
|
90
|
+
if (!m)
|
|
91
|
+
return `{color.${name}}`;
|
|
92
|
+
return `{color.${m[1]}.${m[2]}}`;
|
|
93
|
+
}
|
package/package.json
CHANGED