synthesisui 0.16.346 → 0.16.348

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.
@@ -202,7 +202,17 @@ function declarations(body) {
202
202
  */
203
203
  let flat = body;
204
204
  for (let guard = 0; guard < 12; guard++) {
205
- const next = flat.replace(/\{[^{}]*\}/g, "");
205
+ /**
206
+ * O CABEÇALHO SAI JUNTO COM O BLOCO, e não depois - senão ele fica grudado na declaração
207
+ * seguinte e come a declaração inteira. Tirando só `{ … }`, o corpo de
208
+ *
209
+ * .panel { color: red; &:hover { color: blue; } padding: 24px; }
210
+ *
211
+ * virava `color: red; &:hover padding: 24px;`, e o pedaço do meio tem `:` no `:hover`:
212
+ * a propriedade lida era `&` e o `padding` do cartão dele MORRIA - a decisão estava no
213
+ * código, contada como interpretada, e não chegava à receita.
214
+ */
215
+ const next = flat.replace(/[^;{}]*\{[^{}]*\}/g, "");
206
216
  if (next === flat)
207
217
  break;
208
218
  flat = next;
@@ -197,6 +197,48 @@ function backtick(source, from) {
197
197
  * contagem: um global com regra de CLASSE é forma que nenhum leitor cobre hoje - 399 declarações
198
198
  * no repo dele, e a única lacuna que estava calada em vez de declarada (04/08).
199
199
  */
200
+ /**
201
+ * O SELETOR DE UMA DECLARAÇÃO, resolvido contra os blocos que a contêm.
202
+ *
203
+ * O QUE O CLIENTE GANHA: uma declaração que ele escreveu dentro de `&:hover` chega aqui como
204
+ * `.card:hover` - o nome inteiro, o mesmo que o navegador aplica. Sem isto ela chegava como
205
+ * `&:hover`, e um `&` sem pai não tem a quem se ligar: nenhum leitor deste lado ou do outro
206
+ * consegue dizer de que elemento aquela decisão é.
207
+ *
208
+ * UMA AT-RULE É CONTEXTO, NUNCA PAI. `@media (…) { .card { padding } }` é uma decisão do `.card`
209
+ * sob uma condição, e não de um elemento chamado `@media`. A at-rule só responde pelo seletor
210
+ * quando não há nenhum dentro dela - que é como `@utility text-grad { … }` do Tailwind 4 e o
211
+ * `0%` de um `@keyframes` seguem chegando exatamente como chegavam.
212
+ */
213
+ function selectorOf(open) {
214
+ let selector = "";
215
+ let atRule = "";
216
+ for (const block of open) {
217
+ if (!block)
218
+ continue;
219
+ if (block.startsWith("@")) {
220
+ if (!selector)
221
+ atRule = block;
222
+ continue;
223
+ }
224
+ selector = selector ? resolveNesting(block, selector) : block;
225
+ }
226
+ return selector || atRule;
227
+ }
228
+ /**
229
+ * O `&` DO FILHO TROCADO PELO PAI, e o filho sem `&` pendurado como descendente - as duas
230
+ * regras do CSS aninhado. Uma lista de pais vira `:is(a, b)`, que é o que o próprio CSS faz:
231
+ * escrever `a, b:hover` diria outra coisa, e diria errado.
232
+ */
233
+ function resolveNesting(child, parent) {
234
+ const base = parent.includes(",") ? `:is(${parent})` : parent;
235
+ return child
236
+ .split(",")
237
+ .map((part) => part.trim())
238
+ .filter(Boolean)
239
+ .map((part) => part.includes("&") ? part.replaceAll("&", base) : `${base} ${part}`)
240
+ .join(", ");
241
+ }
200
242
  export function fragmentsOfStylesheet(file, css,
201
243
  /**
202
244
  * COMO ESTA FOLHA CHEGA NO BUILD DELES, e isso vem do GRAFO DE IMPORTS e nunca do nome do
@@ -212,31 +254,54 @@ export function fragmentsOfStylesheet(file, css,
212
254
  */
213
255
  kind) {
214
256
  const out = [];
215
- let selector = "";
257
+ /**
258
+ * OS BLOCOS ABERTOS, E NÃO O ÚLTIMO SELETOR VISTO.
259
+ *
260
+ * O QUE O CLIENTE VIVIA COM UMA VARIÁVEL SÓ: depois de um bloco aninhado, TODA declaração que
261
+ * vinha a seguir ficava com o seletor do bloco que já tinha fechado. No `.card { color: red;
262
+ * &:hover { color: blue } padding: 8px }`, o `padding` dele era registrado como sendo do
263
+ * `:hover` - uma decisão de repouso lida como decisão de estado. Medido no repositório vivo em
264
+ * 01/09, sobre 724 folhas e 19 374 declarações: **440 (2,3%) ficavam com o seletor de um bloco
265
+ * já fechado, e 942 (4,9%) saíam com um `&` que não tinha pai a que se referir**.
266
+ */
267
+ const open = [];
216
268
  for (const [i, raw] of css.split("\n").entries()) {
217
269
  const line = raw.replace(/\/\*.*?\*\//g, "");
218
270
  for (const piece of line.matchAll(PIECES)) {
219
271
  const text = (piece[1] ?? "").trim();
220
272
  if (piece[2] === "{") {
221
- selector = text;
273
+ open.push(text);
222
274
  continue;
223
275
  }
276
+ /**
277
+ * O BLOCO SÓ FECHA DEPOIS QUE A DECLARAÇÃO DELE FOI LIDA. `.a { color: red }` numa linha
278
+ * só termina a declaração no `}`, sem `;` - desempilhar antes de ler perdia a última
279
+ * declaração de todo bloco escrito assim. Medido no repositório vivo quando aconteceu:
280
+ * 19 declarações a menos no censo do `frontend-hub`, num conserto que só devia mexer em
281
+ * QUAL seletor cada uma tem.
282
+ */
283
+ const closes = piece[2] === "}";
224
284
  /**
225
285
  * Sem terminador não há declaração: `padding: 8px` no fim de uma linha pode ser a primeira
226
286
  * metade de um valor que continua na próxima.
227
287
  */
228
- if (!piece[2] || !text)
288
+ if (!piece[2] || !text) {
289
+ if (closes)
290
+ open.pop();
229
291
  continue;
292
+ }
230
293
  const m = DECLARATION.exec(text);
231
- if (!m)
232
- continue;
233
294
  /**
234
295
  * UM TOKEN NÃO É UM FRAGMENTO DE COMPONENTE. `--color-ocean-500: #…` é a paleta, e ela tem
235
296
  * o seu próprio caminho e o seu próprio relatório; contá-la aqui inflaria o total com o que
236
297
  * já está coberto em outro lugar.
237
298
  */
238
- if (m[1].startsWith("--"))
299
+ if (!m || m[1].startsWith("--")) {
300
+ if (closes)
301
+ open.pop();
239
302
  continue;
303
+ }
304
+ const selector = selectorOf(open);
240
305
  out.push({
241
306
  shape: "css",
242
307
  file,
@@ -249,6 +314,8 @@ kind) {
249
314
  ? { reason: "sheet-not-imported" }
250
315
  : {}),
251
316
  });
317
+ if (closes)
318
+ open.pop();
252
319
  }
253
320
  }
254
321
  return out;
@@ -302,6 +369,24 @@ const STRUCTURE = new Set([
302
369
  function targetClass(text) {
303
370
  const brace = text.indexOf("{");
304
371
  const selector = brace === -1 ? text : text.slice(0, brace);
372
+ /**
373
+ * `@utility x` É A CLASSE `.x` - ela é a forma do Tailwind 4 de declarar um utilitário, e não
374
+ * traz o ponto que este casamento procura.
375
+ *
376
+ * O QUE ELE VIA SEM ISTO: a declaração CHEGAVA ao componente e o relatório dizia que não. O
377
+ * `readGlobalClasses` lê `@utility` desde 24/08 e a entrega no look de quem veste a classe -
378
+ * medido em 01/09 pela cadeia real, o `Scene` recebe `perspective: 900px` da `@utility
379
+ * scene-3d`. Mas o julgamento procurava um ponto no seletor, não achava, e mandava as mesmas
380
+ * declarações para o ledger como forma sem leitor. No censo do `codelevel`: **68 declarações
381
+ * em 22 utilities anunciadas como não interpretadas**, com as duas que um componente veste
382
+ * (`scene-3d` no `Scene`, `stage-3d` no `Stage`) já dentro da receita dele.
383
+ *
384
+ * Um número que acusa lacuna onde não há custa o mesmo que um que a esconde: manda alguém
385
+ * consertar o que não está quebrado. Quase custou um leitor inteiro escrito duas vezes.
386
+ */
387
+ const utility = /^@utility\s+([a-z][\w-]*)/i.exec(selector.trim())?.[1];
388
+ if (utility)
389
+ return utility;
305
390
  for (const group of selector.split(",")) {
306
391
  const classes = group.match(/\.[A-Za-z][\w-]*/g);
307
392
  /** Sem o ponto: o nome que `globalClasses` indexa. */
@@ -532,7 +532,7 @@ export const CHECKER_SINCE = "0.16.308";
532
532
  * si, o campo fica ausente, e ausente ali continua sendo a resposta certa - o `codelevel-ui` dá
533
533
  * 0 de 0 contra 145 arquivos de página do `frontend-hub`.
534
534
  */
535
- export const READER_SINCE = "0.16.346";
535
+ export const READER_SINCE = "0.16.348";
536
536
  /**
537
537
  * O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
538
538
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.346",
3
+ "version": "0.16.348",
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": {