synthesisui 0.16.374 → 0.16.375

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.
@@ -51,6 +51,8 @@ export function planFix(d, read) {
51
51
  const next = new Map();
52
52
  /** Linhas por arquivo, mutadas em memória: dois achados no mesmo arquivo compõem. */
53
53
  const lines = new Map();
54
+ /** A mesma chave, congelada antes da primeira troca - ver o skip de `not-written`. */
55
+ const originals = new Map();
54
56
  /**
55
57
  * DE BAIXO PARA CIMA no arquivo não é necessário - a troca não muda a contagem de linhas - mas a
56
58
  * ORDEM por arquivo é, para dois achados na mesma linha não se atropelarem: o segundo procura o seu
@@ -119,6 +121,11 @@ export function planFix(d, read) {
119
121
  continue;
120
122
  }
121
123
  lines.set(f.file, raw.split("\n"));
124
+ /**
125
+ * A LINHA COMO ELA ESTAVA ANTES DE QUALQUER TROCA DESTA RODADA - e é ela que separa dois
126
+ * skips que hoje se dizem com a mesma frase. Ver o bloco de `swapped === null`.
127
+ */
128
+ originals.set(f.file, raw.split("\n"));
122
129
  }
123
130
  const body = lines.get(f.file);
124
131
  if (!body)
@@ -127,12 +134,38 @@ export function planFix(d, read) {
127
134
  const current = body[idx];
128
135
  const swapped = current === undefined ? null : swap(current, f.literal, name);
129
136
  if (swapped === null) {
130
- /** O arquivo mudou desde a medição, ou o literal já foi trocado por outro achado. */
137
+ /**
138
+ * DOIS MOTIVOS DIFERENTES, E A TELA DIZIA UM SÓ - e o que ela dizia era falso quase sempre.
139
+ *
140
+ * O QUE O DONO VIU em 05/09: *"13 lines changed since the scan and were left alone - run it
141
+ * again"*, num repositório onde ele não tinha editado nada. Medido: **13 de 13** eram classe
142
+ * utilitária. A linha era `"transition-all duration-300 ease-[var(--ease-out-soft)]"`, o scan
143
+ * derivou `300ms` de `duration-300` - corretamente -, e o `swap` procura o texto `300ms`, que
144
+ * nunca esteve escrito ali. `grep 300ms` no arquivo devolve zero.
145
+ *
146
+ * O comentário que estava aqui já sabia disso: *"o arquivo mudou desde a medição, OU o literal
147
+ * já foi trocado por outro achado"*. A frase impressa contava só o primeiro caso, e mandava
148
+ * rodar de novo - o que não muda nada, porque nada mudou.
149
+ *
150
+ * A LINHA ORIGINAL DESEMPATA. Sem o literal nela, o valor veio de forma abreviada e trocá-lo é
151
+ * outra reescrita (`duration-[var(--duration-base)]`), não uma troca de literal. Com o literal
152
+ * nela, alguma coisa mexeu na linha depois - e aí rodar de novo é o conselho certo.
153
+ *
154
+ * É GERAL: `duration-*` é Tailwind puro - 15 arquivos no repositório dele, 37 no frontend-hub.
155
+ */
156
+ /**
157
+ * A LINHA SUMIU É OUTRA COISA - e é `moved` de verdade: um arquivo que encolheu desde a
158
+ * medição mudou, e rodar de novo é o conselho certo. `not-written` só quando a linha ESTÁ lá
159
+ * e o valor não está escrito nela.
160
+ */
161
+ const before = originals.get(f.file)?.[idx];
131
162
  skipped.push({
132
163
  file: f.file,
133
164
  line: f.line,
134
165
  literal: f.literal,
135
- because: "moved",
166
+ because: before === undefined || before.includes(f.literal)
167
+ ? "moved"
168
+ : "not-written",
136
169
  });
137
170
  continue;
138
171
  }
@@ -176,6 +209,8 @@ export async function readerFor(root, files) {
176
209
  export function describeFix(result, dry) {
177
210
  const { applied, skipped } = result;
178
211
  const moved = skipped.filter((s) => s.because === "moved").length;
212
+ /** O valor veio de forma abreviada - ver `not-written` em `planFix`. */
213
+ const notWritten = skipped.filter((s) => s.because === "not-written").length;
179
214
  const coincidence = skipped.filter((s) => s.because === "cross-family").length;
180
215
  const unread = skipped.filter((s) => s.because === "unreadable").length;
181
216
  const decisions = skipped.filter((s) => s.because === "no-token").length;
@@ -187,23 +222,55 @@ export function describeFix(result, dry) {
187
222
  ? `Nothing to apply. All ${decisions} findings are values your system has no name for - those are design decisions, not fixes.`
188
223
  : relative > 0
189
224
  ? `Nothing to apply. All ${relative} findings are lengths in \`em\`, which follow the element's font size - swapping them can move the layout, so that call is yours.`
190
- : "Nothing to apply.");
225
+ : /**
226
+ * E QUANDO NADA É APLICÁVEL, O MOTIVO SAI AQUI TAMBÉM - senão a saída inteira é
227
+ * "Nothing to apply." e a pessoa não tem como saber que o valor existe, tem nome, e só
228
+ * não está escrito como texto.
229
+ */
230
+ notWritten > 0
231
+ ? `Nothing to apply. All ${notWritten} findings are written as a shorthand - a utility class like \`duration-300\` carries the value in its name, so there is no literal on the line to replace. Changing them is a different rewrite.`
232
+ : "Nothing to apply.");
191
233
  return lines;
192
234
  }
193
235
  lines.push(`${dry ? "Would replace" : "Replaced"} ${applied.length} hand-written value${applied.length === 1 ? "" : "s"} with the token your system already has, across ${result.files} file${result.files === 1 ? "" : "s"}.`);
194
236
  const byToken = new Map();
195
237
  for (const a of applied)
196
238
  byToken.set(a.token, (byToken.get(a.token) ?? 0) + 1);
197
- for (const [token, n] of [...byToken.entries()]
198
- .sort((a, b) => b[1] - a[1])
199
- .slice(0, 6))
239
+ const ranked = [...byToken.entries()].sort((a, b) => b[1] - a[1]);
240
+ const SHOWN = 6;
241
+ for (const [token, n] of ranked.slice(0, SHOWN))
200
242
  lines.push(` var(${token}) · ${n} time${n === 1 ? "" : "s"}`);
243
+ /**
244
+ * O QUE O CORTE ESCONDEU, DITO - e é a mesma lei que a linha abaixo já obedece.
245
+ *
246
+ * O QUE O DONO VIU em 05/09: `Would replace 143 ... across 20 files` e seis linhas somando 81. As
247
+ * outras 62 ocorrências não apareciam em lugar nenhum, e ele aprovaria a escrita sem saber que
248
+ * existiam.
249
+ *
250
+ * O comentário três linhas abaixo já enuncia a regra - *"DITO SEMPRE QUE ACONTECE, senão o número
251
+ * some da conta sem explicação"* -, aplicada ao `relative` e ao `moved` e não ao próprio corte
252
+ * desta lista. Terceira vez nesta família num dia: o `gaps` (#1327) e a tela de admin (#1304).
253
+ */
254
+ const rest = ranked.slice(SHOWN);
255
+ if (rest.length > 0) {
256
+ const restUses = rest.reduce((n, [, uses]) => n + uses, 0);
257
+ lines.push(` and ${restUses} more across ${rest.length} other token${rest.length === 1 ? "" : "s"}, not listed here`);
258
+ }
201
259
  /**
202
260
  * DITO SEMPRE QUE ACONTECE - senão o número de "trocado" some da conta sem explicação, e a pessoa
203
261
  * conclui que o comando falhou onde ele se recusou de propósito.
204
262
  */
205
263
  if (relative > 0)
206
264
  lines.push(` ${relative} more ${relative === 1 ? "is a length" : "are lengths"} in \`em\`, which follow the element's font size - your system names the same number, but the pixel may differ. Left for you to decide.`);
265
+ /**
266
+ * O VALOR QUE NÃO ESTÁ ESCRITO - a frase que substituiu uma afirmação falsa sobre o repositório.
267
+ *
268
+ * Isto saía como *"N lines changed since the scan - run it again"*, e na tela do dono nada tinha
269
+ * mudado: 13 de 13 eram `duration-300` e afins. Mandar rodar de novo não muda nada, e mandar
270
+ * alguém procurar uma edição que ela não fez é pior que calar.
271
+ */
272
+ if (notWritten > 0)
273
+ lines.push(` ${notWritten} more ${notWritten === 1 ? "is" : "are"} written as a shorthand - a utility class like \`duration-300\` carries the value in its name, so there is no literal on the line to replace. Changing ${notWritten === 1 ? "it" : "those"} is a different rewrite. Left alone.`);
207
274
  if (moved > 0)
208
275
  lines.push(`${moved} line${moved === 1 ? "" : "s"} changed since the scan and ${moved === 1 ? "was" : "were"} left alone - run it again.`);
209
276
  if (coincidence > 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.374",
3
+ "version": "0.16.375",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {