synthesisui 0.16.328 → 0.16.329

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.
@@ -2253,14 +2253,103 @@ export function rootClasses(source, name) {
2253
2253
  if (end === -1)
2254
2254
  return [];
2255
2255
  const tag = source.slice(open, end);
2256
- const at = tag.search(/className\s*=/);
2257
- if (at === -1)
2256
+ /**
2257
+ * O `className` DO PRÓPRIO ELEMENTO, e não o primeiro que aparece no texto.
2258
+ *
2259
+ * ═══ O DEFEITO, medido em 28/08 ═══
2260
+ *
2261
+ * Era `tag.search(/className\s*=/)` seguido de casar todo literal de string até o fim da tag.
2262
+ * Numa tag de abertura que carrega JSX dentro de uma prop, o primeiro `className=` do texto é o
2263
+ * daquele JSX aninhado - e as classes dele eram atribuídas à RAIZ.
2264
+ *
2265
+ * <ReactMarkdown components={{ p: (props) => <p className={"py-2 " + className} /> }}>
2266
+ *
2267
+ * A raiz ali não escreve classe nenhuma, e o leitor lhe dava `py-2` - junto com pedaços de código
2268
+ * (`}`, `/>`, `...props`) que a varredura de literais recolhia pelo caminho.
2269
+ *
2270
+ * A consequência VISÍVEL, medida: o contrato `editions-performance-list` chegava com
2271
+ * `animation: var(--animate-spin)` na raiz. O giro é de um spinner que vive dentro de uma prop, e
2272
+ * a receita dizia que o componente inteiro gira.
2273
+ *
2274
+ * ═══ A PROPRIEDADE ═══
2275
+ *
2276
+ * Uma classe só pode ser atribuída a um elemento se AQUELE elemento a escreveu. Classe de JSX
2277
+ * aninhado em prop, callback, render prop ou objeto não pertence à raiz.
2278
+ *
2279
+ * A regra é ESTRUTURAL e não tem exceção por nome: nada aqui conhece `components`, `ReactMarkdown`
2280
+ * ou qualquer exemplar. O atributo do elemento é o que está em profundidade ZERO dentro da tag de
2281
+ * abertura, e é só ele que é lido.
2282
+ *
2283
+ * E o VALOR também é delimitado, não varrido até o fim: um `className="a"` seguido de
2284
+ * `onClick={() => <span className="b"/>}` dava `a b` antes, porque a varredura ia até o `>`.
2285
+ */
2286
+ const own = ownClassNameExpr(tag);
2287
+ if (own == null)
2258
2288
  return [];
2259
2289
  // Every string literal inside the className expression. Template literals and
2260
2290
  // computed values are skipped on purpose: a class we cannot see in full is a
2261
2291
  // class we would be guessing at.
2262
- const expr = tag.slice(at);
2263
- return [...expr.matchAll(/["']([^"']+)["']/g)]
2292
+ return [...own.matchAll(/["']([^"']+)["']/g)]
2264
2293
  .flatMap((m) => m[1].split(/\s+/))
2265
2294
  .filter((c) => c.length > 0 && !c.includes("${"));
2266
2295
  }
2296
+ /**
2297
+ * A EXPRESSÃO do `className` que é atributo DIRETO desta tag de abertura, ou `null`.
2298
+ *
2299
+ * Duas travas, e as duas nasceram medidas:
2300
+ *
2301
+ * PROFUNDIDADE ZERO um `className` dentro de `{...}`, `(...)` ou `[...]` é de outro elemento -
2302
+ * objeto de prop, callback, render prop, JSX passado como prop.
2303
+ * FRONTEIRA DE PALAVRA `wrapperClassName=` não é `className=`. O regex antigo casava dentro dele,
2304
+ * e a classe de um wrapper virava classe da raiz.
2305
+ *
2306
+ * O valor é DELIMITADO: a string entre aspas, ou o bloco `{...}` balanceado. Ler até o fim da tag
2307
+ * misturaria o atributo com tudo que vem depois dele.
2308
+ */
2309
+ function ownClassNameExpr(tag) {
2310
+ let depth = 0;
2311
+ for (let i = 0; i < tag.length; i++) {
2312
+ const ch = tag[i];
2313
+ if (ch === "{" || ch === "(" || ch === "[") {
2314
+ depth += 1;
2315
+ continue;
2316
+ }
2317
+ if (ch === "}" || ch === ")" || ch === "]") {
2318
+ depth -= 1;
2319
+ continue;
2320
+ }
2321
+ if (depth !== 0 || !tag.startsWith("className", i))
2322
+ continue;
2323
+ /** Atributo é palavra inteira: o que vem antes tem que ser separador, nunca letra. */
2324
+ const before = i > 0 ? tag[i - 1] : " ";
2325
+ if (/[A-Za-z0-9_$]/.test(before))
2326
+ continue;
2327
+ let j = i + "className".length;
2328
+ while (j < tag.length && /\s/.test(tag[j]))
2329
+ j += 1;
2330
+ if (tag[j] !== "=")
2331
+ continue;
2332
+ j += 1;
2333
+ while (j < tag.length && /\s/.test(tag[j]))
2334
+ j += 1;
2335
+ const quote = tag[j];
2336
+ if (quote === '"' || quote === "'") {
2337
+ const close = tag.indexOf(quote, j + 1);
2338
+ return close === -1 ? tag.slice(j) : tag.slice(j, close + 1);
2339
+ }
2340
+ if (tag[j] !== "{")
2341
+ return "";
2342
+ let d = 0;
2343
+ for (let k = j; k < tag.length; k++) {
2344
+ if (tag[k] === "{")
2345
+ d += 1;
2346
+ else if (tag[k] === "}") {
2347
+ d -= 1;
2348
+ if (d === 0)
2349
+ return tag.slice(j, k + 1);
2350
+ }
2351
+ }
2352
+ return tag.slice(j);
2353
+ }
2354
+ return null;
2355
+ }
@@ -360,8 +360,14 @@ export const CHECKER_SINCE = "0.16.308";
360
360
  * estado legado e o deriver volta a deduzir por posição, que é o defeito. Medido no app real: 8
361
361
  * componentes que devolvem um Fragment recuperam as classes que hoje caem no vazio, e 386 de 386
362
362
  * looks legados leem exatamente como liam.
363
+ *
364
+ * 0.16.328 -> 0.16.329 em 28/08: `rootClasses` passou a ler só o `className` do PRÓPRIO elemento.
365
+ * Antes ele ancorava no primeiro `className=` do texto da tag de abertura, então a classe de um JSX
366
+ * escrito dentro de uma prop virava classe da raiz - e o `className` da raiz, quando vinha depois,
367
+ * nunca era alcançado. Medido: 1134 componentes, 77 mudaram, e a receita que o cliente recebe muda
368
+ * com eles. Uma medição anterior não produz o conserto, então a marca sobe.
363
369
  */
364
- export const READER_SINCE = "0.16.328";
370
+ export const READER_SINCE = "0.16.329";
365
371
  /**
366
372
  * O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
367
373
  *
@@ -51,6 +51,27 @@ export const CODELEVEL_CENSUS = join(POPULATIONS, "codelevel-ui.census.json");
51
51
  * `signalui` viraram provas apagadas. Ver `fixtures/populations/README.md`.
52
52
  */
53
53
  export const CODELEVEL_LEDGER = join(POPULATIONS, "codelevel-ui.ledger.jsonl");
54
+ /**
55
+ * O MESMO REPOSITÓRIO, MEDIDO DEPOIS - e os dois instantes ficam, porque cada um carrega uma
56
+ * dimensão que o outro não tem.
57
+ *
58
+ * O ledger ao lado é de 26/08, de um CLI que ainda não transportava OCORRÊNCIAS. Este é de 28/08,
59
+ * medido pelo `doctor` 0.16.327 publicado, e carrega `unrepresentedMatches`.
60
+ *
61
+ * POR QUE O ANTIGO NÃO FOI SUBSTITUÍDO. Ele não é evidência velha: ele é a evidência do estado
62
+ * LEGADO, que é onde todo cliente está até sincronizar. Medido ao trocar um pelo outro - a causa
63
+ * `cross-family-suggestion` deixa de nascer da fonte `repo` e passa a nascer de `judged`, e a fonte
64
+ * `repo` some da população inteira. `screen.real` precisa das TRÊS fontes vivas ao mesmo tempo;
65
+ * sobrescrever apagaria uma dimensão para ganhar outra.
66
+ *
67
+ * 26/08 crossFamily 1 · matched 22 · sem o campo recount 11 · judged 1 · repo 1
68
+ * 28/08 crossFamily 1 · matched 22 · 4 ocorrências recount 11 · judged 2 · repo 0
69
+ *
70
+ * INSPECIONADO ANTES DE VERSIONAR (28/08): zero caminhos absolutos, zero `/home/`, zero e-mails,
71
+ * zero credenciais, zero URLs. Ele carrega o que o campo novo promete carregar - caminhos RELATIVOS
72
+ * de origem, com a linha.
73
+ */
74
+ export const CODELEVEL_LEDGER_WITH_OCCURRENCES = join(POPULATIONS, "codelevel-ui.ledger.with-occurrences.jsonl");
54
75
  /**
55
76
  * OS DOIS DOCUMENTOS HISTÓRICOS - a exceção autorizada à regra do derivável (dono, 28/08).
56
77
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.328",
3
+ "version": "0.16.329",
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": {