synthesisui 0.16.375 → 0.16.377

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.
@@ -132,6 +132,58 @@ export function planFix(d, read) {
132
132
  continue;
133
133
  const idx = f.line - 1;
134
134
  const current = body[idx];
135
+ /**
136
+ * A DECLARAÇÃO DE UM TOKEN NÃO É UM USO DELE - e trocar ali APAGA o token do app inteiro.
137
+ *
138
+ * O QUE ACONTECIA: `--color-brand-blue: #4f46e5;` é onde o token NASCE. O scan vê o literal, o
139
+ * sistema tem um nome para aquele valor - o próprio `--color-brand-blue` -, e a troca escrevia
140
+ * `--color-brand-blue: var(--color-brand-blue)`. Isso é um ciclo de custom property, e a regra do
141
+ * CSS é dura: a propriedade fica inválida no elemento E em todos os descendentes. Como esses
142
+ * tokens moram em `:root`, o app inteiro perde a cor.
143
+ *
144
+ * MEDIDO em 05/09, sobre uma cópia do repositório do dono: **26 declarações** viraram
145
+ * auto-referência numa passada. E cada uma delas é o destino de dezenas de trocas que o mesmo
146
+ * comando acabou de fazer - o conserto apagava aquilo que ele mesmo tinha acabado de apontar.
147
+ *
148
+ * É A MESMA FAMÍLIA DO CICLO DOS EASINGS que o dono encontrou em 04/09, e desta vez produzida
149
+ * pelo nosso comando de conserto. Sem erro no console: o navegador simplesmente descarta.
150
+ *
151
+ * A REGRA É ESTREITA DE PROPÓSITO. Apontar um token DELE para outro token DELE
152
+ * (`--brand-hover: #4f46e5` -> `var(--color-brand-blue)`) continua valendo e é bom. Só a
153
+ * auto-referência é fatal, e só ela é recusada.
154
+ *
155
+ * É GERAL: toda folha declara token com valor literal - 149 no repositório dele, 180 no
156
+ * frontend-hub.
157
+ */
158
+ /**
159
+ * SEM ÂNCORA NO INÍCIO DA LINHA - e a âncora era um buraco de verdade.
160
+ *
161
+ * A primeira versão deste guard casava `^\s*--nome:`, o que só enxerga CSS formatado com uma
162
+ * declaração por linha. Numa folha minificada a linha inteira é
163
+ * `.pulse-page{--violet:#6755ff;--green:#79e39e;background:#080a10}` - a declaração não começa a
164
+ * linha, o guard não a via, e o ciclo passaria batido exatamente onde ninguém vai reler o diff.
165
+ *
166
+ * Medido no repositório do dono: `apps/landing/app/styles/pulse.css` é assim, e ele declara
167
+ * `--violet` e `--green` no meio de uma linha. Naquele repositório o ciclo não chega a nascer
168
+ * porque nenhum daqueles nomes coincide com um token do sistema - mas isso é sorte da população,
169
+ * não proteção.
170
+ *
171
+ * Percorre TODAS as declarações da linha e recusa a que se apontaria para si mesma. As outras
172
+ * seguem trocáveis: numa linha minificada, um `background:#fbfaf6` ao lado de um `--violet:...`
173
+ * continua sendo um uso legítimo.
174
+ */
175
+ const declaring = [
176
+ ...(current ?? "").matchAll(/(--[a-z0-9-]+)\s*:\s*([^;}]*)/gi),
177
+ ].find(([, , value]) => value?.includes(f.literal));
178
+ if (declaring && declaring[1] === name) {
179
+ skipped.push({
180
+ file: f.file,
181
+ line: f.line,
182
+ literal: f.literal,
183
+ because: "self-reference",
184
+ });
185
+ continue;
186
+ }
135
187
  const swapped = current === undefined ? null : swap(current, f.literal, name);
136
188
  if (swapped === null) {
137
189
  /**
@@ -211,6 +263,8 @@ export function describeFix(result, dry) {
211
263
  const moved = skipped.filter((s) => s.because === "moved").length;
212
264
  /** O valor veio de forma abreviada - ver `not-written` em `planFix`. */
213
265
  const notWritten = skipped.filter((s) => s.because === "not-written").length;
266
+ /** A linha declara o próprio token - ver `self-reference` em `planFix`. */
267
+ const selfRef = skipped.filter((s) => s.because === "self-reference").length;
214
268
  const coincidence = skipped.filter((s) => s.because === "cross-family").length;
215
269
  const unread = skipped.filter((s) => s.because === "unreadable").length;
216
270
  const decisions = skipped.filter((s) => s.because === "no-token").length;
@@ -229,7 +283,13 @@ export function describeFix(result, dry) {
229
283
  */
230
284
  notWritten > 0
231
285
  ? `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.");
286
+ : /**
287
+ * E quando tudo o que havia eram as linhas onde os tokens nascem, "Nothing to apply."
288
+ * sozinho manda a pessoa procurar um defeito. O comando passou por ali de propósito.
289
+ */
290
+ selfRef > 0
291
+ ? `Nothing to apply. ${selfRef === 1 ? "The one finding is" : `All ${selfRef} findings are`} on the line where the token itself is declared - replacing there would point it at itself, and the browser would drop it.`
292
+ : "Nothing to apply.");
233
293
  return lines;
234
294
  }
235
295
  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"}.`);
@@ -269,6 +329,12 @@ export function describeFix(result, dry) {
269
329
  * mudado: 13 de 13 eram `duration-300` e afins. Mandar rodar de novo não muda nada, e mandar
270
330
  * alguém procurar uma edição que ela não fez é pior que calar.
271
331
  */
332
+ /**
333
+ * DITO, e não calado: é a linha onde o token NASCE, e a pessoa precisa saber que o comando passou
334
+ * por ali de propósito - senão ela procura por que aquele valor não foi trocado.
335
+ */
336
+ if (selfRef > 0)
337
+ lines.push(` ${selfRef} ${selfRef === 1 ? "is" : "are"} the line where the token itself is declared - replacing there would point it at itself and the browser would drop it. Left alone.`);
272
338
  if (notWritten > 0)
273
339
  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.`);
274
340
  if (moved > 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.375",
3
+ "version": "0.16.377",
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": {