synthesisui 0.16.377 → 0.16.379
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/align.js +47 -2
- package/dist/commands/doctor.js +13 -1
- package/dist/doctor/scan.js +113 -1
- package/dist/install-marks.js +17 -2
- package/package.json +1 -1
package/dist/commands/align.js
CHANGED
|
@@ -154,10 +154,55 @@ opts = {}) {
|
|
|
154
154
|
* medido em 11/08, 12 de 36 componentes têm árvore diferente entre o leitor de 07/08 e o de hoje.
|
|
155
155
|
*/
|
|
156
156
|
const measuredBy = await censusMeasuredBy(root);
|
|
157
|
-
|
|
157
|
+
/**
|
|
158
|
+
* A RÉGUA QUE DIZ "VOCÊ ESTÁ ATRÁS" MORA DENTRO DA VERSÃO QUE ESTÁ ATRÁS - e por isso o silêncio
|
|
159
|
+
* daqui nunca significou que estava tudo em dia.
|
|
160
|
+
*
|
|
161
|
+
* O QUE ACONTECIA, medido em 05/09 no repositório do dono: o `connect` prega a versão do dia em
|
|
162
|
+
* que rodou, e os hooks dele chamam `synthesisui@0.16.370` LITERAL. Abrindo o tarball publicado
|
|
163
|
+
* daquela versão, `READER_SINCE = "0.16.367"`. O censo dele foi medido pela 0.16.376, e o leitor
|
|
164
|
+
* de hoje mudou na 0.16.378. Ele ESTÁ atrás - e a comparação acima, feita com a régua congelada de
|
|
165
|
+
* 0.16.367, responde que não: `isOlderCli("0.16.376", "0.16.367")` é falso, e este check cala.
|
|
166
|
+
*
|
|
167
|
+
* É a armadilha inteira: quem prega uma versão passa a medir a própria defasagem com a régua do
|
|
168
|
+
* dia em que pregou. O aviso só existe na versão que ele não tem, e um check que cala lê como
|
|
169
|
+
* "está em dia" - "ausência de evidência não é evidência", agora com a nossa assinatura.
|
|
170
|
+
*
|
|
171
|
+
* O SINAL QUE FUNCIONA OFFLINE, e é o que fecha a porta em vez de vigiá-la: comparar as duas
|
|
172
|
+
* coisas que este processo JÁ conhece. Se o CLI que está rodando é mais velho que o CLI que
|
|
173
|
+
* MEDIU, então ele está julgando uma medição feita por uma versão que sabe mais do que ele - e
|
|
174
|
+
* nada que ele afirme sobre estar em dia pode ser verdade. Ele não precisa saber o que veio
|
|
175
|
+
* depois; ele só precisa saber que veio.
|
|
176
|
+
*
|
|
177
|
+
* É GERAL e não depende de rede: o `align` não faz uma única chamada HTTP, de propósito, e
|
|
178
|
+
* continua sem fazer. As duas versões estão em disco - uma é a que está executando, a outra está
|
|
179
|
+
* carimbada no censo.
|
|
180
|
+
*/
|
|
181
|
+
if (measuredBy && cli && isOlderCli(cli, measuredBy))
|
|
182
|
+
out.push({
|
|
183
|
+
/**
|
|
184
|
+
* A FRASE NÃO CITA UMA FRASE QUE A TELA NÃO IMPRIME.
|
|
185
|
+
*
|
|
186
|
+
* A primeira redação dizia que o *"you are up to date"* deste check não é uma resposta - e
|
|
187
|
+
* este comando nunca escreve essa linha. Ele CALA quando não encontra desalinho, e é o
|
|
188
|
+
* silêncio que era falso. Citar uma frase inexistente manda a pessoa procurar na tela algo
|
|
189
|
+
* que não está lá, que é o defeito de 08/08 outra vez em escala menor.
|
|
190
|
+
*/
|
|
191
|
+
says: `this check is running on CLI ${cli}, and the measurement in this repo was read by ${measuredBy} - a newer one. It cannot see what changed in the readers after ${cli}, so its silence about the measurement being current is not an answer. ${cli} is the version pinned the day \`connect\` last ran here.`,
|
|
192
|
+
run: "npx synthesisui@latest connect",
|
|
193
|
+
});
|
|
194
|
+
else if (behind(measuredBy, cli, READER_SINCE))
|
|
158
195
|
out.push({
|
|
159
196
|
says: `the measurement stored in this repo was read by an older reader, so what the platform knows about your components is what that reader could see. A re-measure is the only thing that reaches it - the fix lives on this machine, not on the server.`,
|
|
160
|
-
|
|
197
|
+
/**
|
|
198
|
+
* `connect` VEM PRIMEIRO, e a plataforma já dizia isso enquanto esta linha dizia outra coisa.
|
|
199
|
+
*
|
|
200
|
+
* `readerBehind` em `apps/web/src/lib/ds/reader-behind.ts` devolve os DOIS passos, com o
|
|
201
|
+
* motivo escrito: sem o `connect`, o `sync` pode medir com o leitor velho, reenviar o mesmo
|
|
202
|
+
* censo, e ensinar que sincronizar não adianta - "o pior resultado possível de todos". Esta
|
|
203
|
+
* linha mandava só `sync`, e é ela que roda na máquina dele a cada sessão.
|
|
204
|
+
*/
|
|
205
|
+
run: "npx synthesisui@latest connect && npx synthesisui sync",
|
|
161
206
|
});
|
|
162
207
|
/**
|
|
163
208
|
* O ESCOPO, que é o desalinho mais caro e o mais silencioso: sem ele o `sync` mede o repo inteiro
|
package/dist/commands/doctor.js
CHANGED
|
@@ -890,7 +890,19 @@ export async function doctor(opts) {
|
|
|
890
890
|
* "not drift" era a nossa palavra para o motivo, e ela não diz o motivo. As duas razões reais
|
|
891
891
|
* cabem na linha: ou nenhum token poderia segurar aquele valor, ou ele já vem de um.
|
|
892
892
|
*/
|
|
893
|
-
|
|
893
|
+
/**
|
|
894
|
+
* E EM 05/09 ELAS VIRARAM TRÊS, senão esta linha volta a esconder metade.
|
|
895
|
+
*
|
|
896
|
+
* Os dois motivos novos não cabem em nenhum dos dois antigos: um token PODERIA segurar aquele
|
|
897
|
+
* valor, e é justamente por isso que escrevê-lo ali destrói. Uma cor dentro do e-mail que o app
|
|
898
|
+
* monta como texto, ou dentro de um hex escrito numa frase da página, não é pintada pela folha
|
|
899
|
+
* do app - `var()` não resolve num cliente de e-mail, e uma frase não é pintura nenhuma.
|
|
900
|
+
*
|
|
901
|
+
* Esta é a linha que o cliente lê SEM `--verbose`, e ela é o resumo inteiro para quem não pede
|
|
902
|
+
* detalhe. Sem a terceira metade, 61 valores no repositório dele saem da conta sob um motivo
|
|
903
|
+
* que não é o deles.
|
|
904
|
+
*/
|
|
905
|
+
console.log(body(`${plural(asideTotal, "value")} left out of the count - a token could never hold them, they already come from one, or the page never paints them` +
|
|
894
906
|
(skippedProjects.length > 0
|
|
895
907
|
? `, and ${plural(skippedProjects.length, "nested project")} that speak their own systems`
|
|
896
908
|
: "") +
|
package/dist/doctor/scan.js
CHANGED
|
@@ -269,6 +269,97 @@ function fallbackSpans(line, table) {
|
|
|
269
269
|
}
|
|
270
270
|
return out;
|
|
271
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* ONDE A CASCATA DO APP NÃO ALCANÇA - e trocar por `var()` ali APAGA a cor.
|
|
274
|
+
*
|
|
275
|
+
* O QUE ACONTECIA: `apps/web/lib/email.ts` monta o e-mail de login como TEXTO, e o `--fix` trocou
|
|
276
|
+
* `background:#6366f1` por `background:var(--color-brand-indigo)` no botão "Sign in". Aquele HTML é
|
|
277
|
+
* entregue a um cliente de e-mail, onde o `:root` do app não existe: a custom property não resolve,
|
|
278
|
+
* a declaração fica inválida, e o `background` volta para `transparent`. O botão de entrar some
|
|
279
|
+
* sobre um card quase preto - e é a PRIMEIRA tela que um usuário novo vê.
|
|
280
|
+
*
|
|
281
|
+
* É A MESMA FAMÍLIA DE `RENDERS_IMAGE`, que já recusa o arquivo que desenha para uma imagem pelo
|
|
282
|
+
* mesmo motivo declarado: "where CSS variables do not exist". Faltava a metade que sai como HTML.
|
|
283
|
+
*
|
|
284
|
+
* O SINAL É DA LINGUAGEM, NÃO DO REPOSITÓRIO: em `.ts`/`.tsx`/`.js`/`.jsx`, `style="..."` com uma
|
|
285
|
+
* declaração dentro NÃO é JSX - o React tipa `style` como objeto (`style={{}}`). Um atributo HTML
|
|
286
|
+
* escrito com aspas só existe ali dentro de uma string, isto é, marcação montada como texto: um
|
|
287
|
+
* e-mail, um PDF, um `srcdoc`, um sanitizador. Nenhum deles herda a folha do app.
|
|
288
|
+
*
|
|
289
|
+
* `.vue` e `.svelte` ficam FORA de propósito: neles `style="..."` é atributo de template real, o
|
|
290
|
+
* elemento é do app, e a cascata alcança. Recusar ali cegaria o produto para dois frameworks
|
|
291
|
+
* inteiros.
|
|
292
|
+
*
|
|
293
|
+
* MEDIDO em 05/09, em 4 escopos: `codelevel-monorepo` 7 linhas (`apps/web/lib/email.ts`, 2 delas já
|
|
294
|
+
* trocadas pelo `--fix` no repositório dele) · `frontend-hub/packages/ui` 3 linhas
|
|
295
|
+
* (`SignalUI/.../Sanitize.ts`, que remonta HTML de editor de texto) · `synthesisui-hub/apps/web`
|
|
296
|
+
* 18 linhas (`src/lib/email.ts` - o nosso próprio produto tem a forma) · `frontend-hub/apps/web-
|
|
297
|
+
* dashboard` 0. Três de quatro: a forma é geral, não é peculiaridade de um repositório.
|
|
298
|
+
*/
|
|
299
|
+
const HTML_STYLE_ATTR = /style\s*=\s*"([^"]*)"/g;
|
|
300
|
+
/** Só onde `style="..."` não pode ser um elemento do app - ver `HTML_STYLE_ATTR`. */
|
|
301
|
+
const ASSEMBLES_MARKUP = /\.(?:tsx?|jsx?|mjs|cjs)$/i;
|
|
302
|
+
function markupTextSpans(file, line) {
|
|
303
|
+
if (!ASSEMBLES_MARKUP.test(file))
|
|
304
|
+
return [];
|
|
305
|
+
const out = [];
|
|
306
|
+
for (const m of line.matchAll(HTML_STYLE_ATTR)) {
|
|
307
|
+
if (!m[1].includes(":"))
|
|
308
|
+
continue;
|
|
309
|
+
const start = (m.index ?? 0) + m[0].indexOf('"') + 1;
|
|
310
|
+
out.push([start, start + m[1].length]);
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* O QUE A PÁGINA DIZ NÃO É O QUE ELA PINTA - e o `--fix` reescreveu uma frase.
|
|
316
|
+
*
|
|
317
|
+
* O QUE ACONTECIA: a landing dele demonstra a própria ferramenta num terminal falso, e a frase era
|
|
318
|
+
* `#6b6b78 is already --color-ink-500`. O scanner viu um hex, o sistema nomeia aquele valor, e a
|
|
319
|
+
* troca deixou `var(--color-ink-500) is already --color-ink-500` - uma tautologia, na frase que
|
|
320
|
+
* anuncia o que o produto faz. Não foi estilo mudado: foi CONTEÚDO.
|
|
321
|
+
*
|
|
322
|
+
* A LEI JÁ EXISTIA e esta é a borda dela - `fix` muda VALOR, nunca FORMA. Um literal em posição de
|
|
323
|
+
* conteúdo não é nem valor nem forma: é texto que uma pessoa lê.
|
|
324
|
+
*
|
|
325
|
+
* A REGIÃO É DERIVADA DA MARCAÇÃO, não de nome de arquivo: entre um `>` e o `<` seguinte está o que
|
|
326
|
+
* o elemento mostra. E dentro dela o literal ainda precisa estar CRU - `{x > 1 ? "#fff" : "#000"}`
|
|
327
|
+
* põe valores numa região que se parece com conteúdo, e as aspas são o que os separa de uma frase.
|
|
328
|
+
*
|
|
329
|
+
* UMA EXPRESSÃO NÃO É UMA FRASE, e esta borda custou um achado real. `<style>{`...`}</style>` é a
|
|
330
|
+
* folha que o app injeta de verdade: a cascata ALCANÇA, `var()` resolve, e o `120ms` escrito ali é
|
|
331
|
+
* deriva como qualquer outra. Medido em `apps/web/src/components/dashboard/live-specimen.tsx`, o
|
|
332
|
+
* guard sem esta borda derrubava 24 achados para 23. O sinal é da linguagem: uma chave logo depois
|
|
333
|
+
* do `>` abre uma expressão JSX, e o que vem dentro dela é código.
|
|
334
|
+
*
|
|
335
|
+
* `<style>html,body{...}</style>` DENTRO DE UMA STRING continua sendo conteúdo - lá a chave não
|
|
336
|
+
* encosta no `>`, e o documento é outro (um `srcdoc` de iframe, medido no `frontend-hub`), onde a
|
|
337
|
+
* folha do app também não chega.
|
|
338
|
+
*
|
|
339
|
+
* MEDIDO em 05/09, em 4 escopos: `codelevel-monorepo` 1 (a frase da landing) · `frontend-hub/apps/
|
|
340
|
+
* web-dashboard` 1 (o CSS do iframe) · `synthesisui-hub/apps/web` 14, entre elas a nossa PRÓPRIA
|
|
341
|
+
* demonstração na home, `<Line tone="ok">#2563eb -> --ds-color-semantic-info</Line>` · `frontend-
|
|
342
|
+
* hub/packages/ui` 0. O preço de errar é o produto reescrevendo a página de vendas de quem o
|
|
343
|
+
* instalou - inclusive a nossa.
|
|
344
|
+
*/
|
|
345
|
+
function contentSpans(line) {
|
|
346
|
+
const out = [];
|
|
347
|
+
let open = line.indexOf(">");
|
|
348
|
+
while (open !== -1) {
|
|
349
|
+
const close = line.indexOf("<", open + 1);
|
|
350
|
+
if (close === -1)
|
|
351
|
+
break;
|
|
352
|
+
if (close > open + 1 && line[open + 1] !== "{")
|
|
353
|
+
out.push([open + 1, close]);
|
|
354
|
+
open = line.indexOf(">", close + 1);
|
|
355
|
+
}
|
|
356
|
+
return out;
|
|
357
|
+
}
|
|
358
|
+
/** Um valor entre aspas é um valor, mesmo numa região de conteúdo. */
|
|
359
|
+
function quotedAt(line, col, len) {
|
|
360
|
+
const q = /["'`]/;
|
|
361
|
+
return q.test(line[col - 1] ?? "") || q.test(line[col + len] ?? "");
|
|
362
|
+
}
|
|
272
363
|
/**
|
|
273
364
|
* The line that DEFINES a token is not a line that drifted from it.
|
|
274
365
|
*
|
|
@@ -403,6 +494,12 @@ function scanCore(file, source, table) {
|
|
|
403
494
|
// shadow) is one decision, so it is reported once.
|
|
404
495
|
const spans = fallbackSpans(line, table);
|
|
405
496
|
const inFallback = (at) => spans.some(([a, b]) => at >= a && at <= b);
|
|
497
|
+
/** Ver `markupTextSpans`: HTML montado como texto sai do alcance da folha do app. */
|
|
498
|
+
const markup = markupTextSpans(file, line);
|
|
499
|
+
const inMarkup = (at) => markup.some(([a, b]) => at >= a && at <= b);
|
|
500
|
+
/** Ver `contentSpans`: entre `>` e `<` está o que o elemento MOSTRA. */
|
|
501
|
+
const content = contentSpans(line);
|
|
502
|
+
const inContent = (at) => content.some(([a, b]) => at >= a && at <= b);
|
|
406
503
|
const seen = new Set();
|
|
407
504
|
// NOT named `at`: that is the line number in this scope, and shadowing it
|
|
408
505
|
// put column positions into the report as line numbers.
|
|
@@ -413,6 +510,14 @@ function scanCore(file, source, table) {
|
|
|
413
510
|
setAside("a token's own fallback");
|
|
414
511
|
return;
|
|
415
512
|
}
|
|
513
|
+
if (col >= 0 && inMarkup(col)) {
|
|
514
|
+
setAside("markup assembled as text, where the app's variables do not reach");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (col >= 0 && inContent(col) && !quotedAt(line, col, literal.length)) {
|
|
518
|
+
setAside("text the page shows, not a value it paints");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
416
521
|
const key = `${kind}:${literal}`;
|
|
417
522
|
if (seen.has(key))
|
|
418
523
|
return;
|
|
@@ -475,7 +580,14 @@ function scanCore(file, source, table) {
|
|
|
475
580
|
// A stack already reading from the system is the point, not a problem.
|
|
476
581
|
if (stack.startsWith("var("))
|
|
477
582
|
continue;
|
|
478
|
-
|
|
583
|
+
/**
|
|
584
|
+
* A COLUNA VIAJA AQUI TAMBÉM - sem ela os guards por posição são cegos para uma família.
|
|
585
|
+
*
|
|
586
|
+
* `font` era o único `push` sem coluna, então um `font-family` dentro de um `style="..."` de
|
|
587
|
+
* e-mail passava pelos dois guards novos e pelo de fallback. Um valor não deixa de estar fora
|
|
588
|
+
* do alcance da folha por ser uma pilha de fontes.
|
|
589
|
+
*/
|
|
590
|
+
push("font", stack, (m.index ?? 0) + m[0].indexOf(stack));
|
|
479
591
|
}
|
|
480
592
|
for (const m of line.matchAll(MOTION_PROP)) {
|
|
481
593
|
const value = m[1];
|
package/dist/install-marks.js
CHANGED
|
@@ -242,7 +242,15 @@ export const MATERIALISER_SINCE = "0.16.370";
|
|
|
242
242
|
* `line 12 oklch(...) -> --color-mint-500`. Um hook pinado antes desta versão aconselha OUTRA
|
|
243
243
|
* coisa - nada -, que é a régua desta marca.
|
|
244
244
|
*/
|
|
245
|
-
|
|
245
|
+
/**
|
|
246
|
+
* 0.16.367 -> 0.16.378 em 05/09: o hook parava de cobrar onde o conselho DESTRÓI. Ele lê `scanSource`
|
|
247
|
+
* direto, então um hook pinado antes olha `style="background:#6366f1"` dentro do e-mail de login que
|
|
248
|
+
* o app monta como texto e manda escrever `var(--color-brand-indigo)` - no cliente de e-mail a
|
|
249
|
+
* custom property não resolve, a declaração fica inválida e o botão "Sign in" perde o fundo. E olha
|
|
250
|
+
* `#6b6b78 is already --color-ink-500` numa frase da landing e manda tokenizar TEXTO. Um hook
|
|
251
|
+
* pinado antes desta versão aconselha OUTRA coisa, que é a régua desta marca.
|
|
252
|
+
*/
|
|
253
|
+
export const CHECKER_SINCE = "0.16.378";
|
|
246
254
|
/**
|
|
247
255
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
248
256
|
*
|
|
@@ -665,7 +673,14 @@ export const CHECKER_SINCE = "0.16.367";
|
|
|
665
673
|
* `codelevel-ui` e 23 no `frontend-hub`, e ZERO no `observed` das três populações. Um censo tirado
|
|
666
674
|
* antes disto não tem aqueles valores na régua, e só um `sync` os traz.
|
|
667
675
|
*/
|
|
668
|
-
|
|
676
|
+
/**
|
|
677
|
+
* 0.16.367 -> 0.16.378 em 05/09: o censo produzido MUDA. O `import` roda `scanSource` sobre cada
|
|
678
|
+
* arquivo e passa os relatórios por `diagnose`, então duas formas que nunca foram valor de design
|
|
679
|
+
* saem do `observed`: marcação montada como texto (o e-mail, o sanitizador de editor) e literal em
|
|
680
|
+
* posição de conteúdo. Um censo medido antes desta versão conta como deriva o que a folha do app
|
|
681
|
+
* nem alcança - e o número do cliente é a promessa.
|
|
682
|
+
*/
|
|
683
|
+
export const READER_SINCE = "0.16.378";
|
|
669
684
|
/**
|
|
670
685
|
* O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
|
|
671
686
|
*
|
package/package.json
CHANGED