synthesisui 0.16.404 → 0.16.405

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.
@@ -72,6 +72,82 @@ function attributeExpressions(source) {
72
72
  }
73
73
  return out;
74
74
  }
75
+ /**
76
+ * A DECLARAÇÃO DE UMA CONST QUE O ATRIBUTO USA - o salto que faltava, e a mesma regra do atributo.
77
+ *
78
+ * O QUE FICAVA DE FORA, e estava declarado no contrato com o número: a tabela de variantes mora
79
+ * numa const separada e chega ao atributo por VARIÁVEL. O caso real, medido no `frontend-hub`:
80
+ *
81
+ * ```
82
+ * const buttonVariants = cva("… rounded-[var(--radius-md)] …", { variants: { … } });
83
+ * …
84
+ * className={twUtils.cn(buttonVariants({ variant, size, className }))}
85
+ * ```
86
+ *
87
+ * As classes estão na declaração, não no atributo - então o leitor de 08/09, que já colhia toda
88
+ * string DENTRO da expressão, via `buttonVariants(...)` e não via nenhuma classe. Medido nas duas
89
+ * árvores: **4 + 41** declarações `cva(` e **0 + 85** `tv(`.
90
+ *
91
+ * A REGRA CONTINUA SENDO A MESMA, um salto adiante: o atributo diz quais identificadores importam,
92
+ * e a declaração daqueles identificadores é lida no mesmo arquivo. Nada aqui conhece `cva`, `tv` ou
93
+ * `cn` - o próximo cliente escreve a tabela dele num objeto pelado, e cai na mesma regra.
94
+ *
95
+ * E O ERRO CONTINUA CAINDO PARA O LADO SEGURO: uma const que não é classe - um rótulo, uma
96
+ * mensagem - entrega palavras que o `@theme` não declara, então elas somem na peneira final. O
97
+ * cabeçalho deste módulo diz que entre errar cobrando e errar calando, cobrar é o erro que a pessoa
98
+ * percebe.
99
+ */
100
+ function declarationsBehind(source, exprs) {
101
+ /**
102
+ * TODO IDENTIFICADOR DA EXPRESSÃO, e não só os que ela CHAMA.
103
+ *
104
+ * A primeira versão pegava `nome(`, e o objeto pelado - `pick(byTone, tone)` - passa a tabela
105
+ * como ARGUMENTO. O que decide é o atributo mencionar o identificador; se ele é chamado ou
106
+ * passado é sintaxe, e sintaxe é o que muda de projeto para projeto.
107
+ */
108
+ const names = new Set();
109
+ for (const expr of exprs)
110
+ for (const m of expr.matchAll(/\b([A-Za-z_$][\w$]*)\b/g))
111
+ names.add(m[1]);
112
+ if (names.size === 0)
113
+ return [];
114
+ const out = [];
115
+ for (const name of names) {
116
+ /** `const <nome> = ` - e o valor vai até a linha que fecha no MESMO nível de indentação. */
117
+ const at = source.search(new RegExp(`\\b(?:const|let|var)\\s+${name}\\s*=`));
118
+ if (at < 0)
119
+ continue;
120
+ let depth = 0;
121
+ let i = source.indexOf("=", at);
122
+ let quote = null;
123
+ let started = false;
124
+ for (; i < source.length; i += 1) {
125
+ const c = source[i];
126
+ if (quote) {
127
+ if (c === "\\")
128
+ i += 1;
129
+ else if (c === quote)
130
+ quote = null;
131
+ continue;
132
+ }
133
+ if (c === '"' || c === "'" || c === "`")
134
+ quote = c;
135
+ else if (c === "(" || c === "{" || c === "[") {
136
+ depth += 1;
137
+ started = true;
138
+ }
139
+ else if (c === ")" || c === "}" || c === "]") {
140
+ depth -= 1;
141
+ if (started && depth <= 0)
142
+ break;
143
+ }
144
+ else if (c === ";" && !started)
145
+ break;
146
+ }
147
+ out.push(source.slice(at, i + 1));
148
+ }
149
+ return out;
150
+ }
75
151
  /** As classes escritas no código - `hover:animate-shimmer` conta como `animate-shimmer`. */
76
152
  function classesIn(source) {
77
153
  const out = new Set();
@@ -89,9 +165,16 @@ function classesIn(source) {
89
165
  * E TODA STRING DENTRO DA EXPRESSÃO - ver `attributeExpressions`. As três formas de escrever uma
90
166
  * string em JS/TS, porque quem escolhe a aspa é o formatador dele, não a gente.
91
167
  */
92
- for (const expr of attributeExpressions(source))
93
- for (const lit of expr.matchAll(/"([^"]*)"|'([^']*)'|`([^`]*)`/g))
168
+ const exprs = attributeExpressions(source);
169
+ const strings = (text) => {
170
+ for (const lit of text.matchAll(/"([^"]*)"|'([^']*)'|`([^`]*)`/g))
94
171
  collect(lit[1] ?? lit[2] ?? lit[3] ?? "");
172
+ };
173
+ for (const expr of exprs)
174
+ strings(expr);
175
+ /** E a declaração de quem o atributo chama - ver `declarationsBehind`. */
176
+ for (const decl of declarationsBehind(source, exprs))
177
+ strings(decl);
95
178
  return out;
96
179
  }
97
180
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.404",
3
+ "version": "0.16.405",
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": {