synthesisui 0.16.380 → 0.16.381
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.
- package/dist/doctor/fragments.js +84 -5
- package/dist/install-marks.js +1 -1
- package/package.json +1 -1
package/dist/doctor/fragments.js
CHANGED
|
@@ -22,8 +22,28 @@ const CLASS_LITERAL = /className=(?:"([^"]{0,400})"|\{\s*"([^"]{0,400})"\s*\})/g
|
|
|
22
22
|
const CLASS_TEMPLATE = /className=\{\s*`([^`]{0,400})`\s*\}/g;
|
|
23
23
|
/** `className={algo}` sem literal nenhum: não existe na fonte. */
|
|
24
24
|
const CLASS_RUNTIME = /className=\{\s*([A-Za-z_$][\w$.[\]]{0,60})\s*\}/g;
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* A ABERTURA de `cn("…", …)` e amigos - o FIM sai por parêntese balanceado, e não por regex.
|
|
27
|
+
*
|
|
28
|
+
* O QUE ACONTECIA: o corpo era `([^)]{0,600})`, que para no PRIMEIRO `)`. Basta uma chamada aninhada
|
|
29
|
+
* - `cn("flex", buttonVariants({ size }), "p-4")` - para tudo o que vem depois dela desaparecer da
|
|
30
|
+
* conta. Não é o teto de 600: é o parêntese.
|
|
31
|
+
*
|
|
32
|
+
* MEDIDO EM TRÊS POPULAÇÕES (05/09, classes que o coletor não via por causa do corte):
|
|
33
|
+
*
|
|
34
|
+
* codelevel/packages/ui 21 de 33 chamadas truncadas de 83
|
|
35
|
+
* frontend-hub/packages/ui 41 de 17 chamadas truncadas de 78
|
|
36
|
+
* frontend-hub/apps/web-dashboard 1 de 1 chamada truncada de 47
|
|
37
|
+
*
|
|
38
|
+
* E o que sumia não era resto: `shadow-[0_10px_30px_-10px_rgba(…)]`, `data-[starting-style]:…`,
|
|
39
|
+
* `bg-[var(--color-lightgray-300)]` - as classes mais ricas do repositório, que são exatamente as
|
|
40
|
+
* que o cliente quer ver contadas. Num ledger cuja promessa é que nada é descartado em silêncio,
|
|
41
|
+
* elas não eram lidas E não eram "não lidas": não existiam.
|
|
42
|
+
*
|
|
43
|
+
* É O MESMO PRECEDENTE do `sx` e do `styled` três blocos abaixo, e pela mesma razão: um regex com
|
|
44
|
+
* teto escolhe a formatação do arquivo de outra pessoa.
|
|
45
|
+
*/
|
|
46
|
+
const CALL_OPEN = /\b(?:cn|clsx|classNames|cx|twMerge|twJoin|classcat)\(/g;
|
|
27
47
|
const STRING_IN_CALL = /"([^"]{0,300})"|'([^']{0,300})'/g;
|
|
28
48
|
/** `style={{ … }}`. */
|
|
29
49
|
const INLINE = /style=\{\{([^}]{0,400})\}\}/g;
|
|
@@ -72,6 +92,7 @@ const MODULE_REF = /\$\{\s*[A-Za-z_$][\w$]*\.[A-Za-z_$][\w$]*\s*\}/g;
|
|
|
72
92
|
*
|
|
73
93
|
* status === "success" ? "bg-success-500" : ... "success" é OPERANDO da comparação
|
|
74
94
|
* // ... to prevent the "short width" issue "short width" está num COMENTÁRIO
|
|
95
|
+
* cn(iconVariants({ animation: … : "none" }), …) "none" é ARGUMENTO de outra chamada
|
|
75
96
|
*
|
|
76
97
|
* MEDIDO EM 11/08 no repo real, sobre as 26 declarações que o censo listava como `value-not-read`:
|
|
77
98
|
*
|
|
@@ -93,6 +114,38 @@ function blankComments(body) {
|
|
|
93
114
|
function isComparedTo(body, index) {
|
|
94
115
|
return /(?:===|!==|==|!=)\s*$/.test(body.slice(0, index));
|
|
95
116
|
}
|
|
117
|
+
/** Um utilitário de classe abrindo parêntese, para saber QUEM abriu a chamada mais interna. */
|
|
118
|
+
const OPENS_A_CLASS_CALL = /\b(?:cn|clsx|classNames|cx|twMerge|twJoin|classcat)\($/;
|
|
119
|
+
/**
|
|
120
|
+
* O LITERAL É ARGUMENTO DE OUTRA CHAMADA, e argumento de outra chamada não é classe.
|
|
121
|
+
*
|
|
122
|
+
* `cn(iconVariants({ animation: shouldAnimate ? animation : "none" }), className)` põe `"none"`
|
|
123
|
+
* dentro do `cn`, mas ele não veste nada: é o valor que a função de variantes recebe para escolher a
|
|
124
|
+
* classe. A esteira listava `none` como uma classe que não conseguiu ler, e o cliente ia procurar no
|
|
125
|
+
* código dele um estilo que ele nunca escreveu - o mesmo custo do operando de `===` logo acima.
|
|
126
|
+
*
|
|
127
|
+
* MEDIDO EM TRÊS POPULAÇÕES (05/09, sobre os literais que já passam pelos dois guards anteriores):
|
|
128
|
+
*
|
|
129
|
+
* codelevel/packages/ui 3 de 83 `"none"` em Card, Icon, Typography
|
|
130
|
+
* frontend-hub/packages/ui 0 de 123
|
|
131
|
+
* frontend-hub/apps/web-dashboard 0 de 68
|
|
132
|
+
*
|
|
133
|
+
* QUEM ABRIU A CHAMADA DECIDE, e não o simples fato de haver uma. Um utilitário de classe aninhado
|
|
134
|
+
* (`cn(clsx("flex"))`) continua vestindo, e o que está dentro dele É classe - sem esta metade, o
|
|
135
|
+
* conserto de um falso positivo criaria um falso negativo. Nas três populações essa forma dá N=0
|
|
136
|
+
* hoje; ela está aqui porque aninhar utilitário é forma de qualquer projeto, e o `CALL_LITERAL` só
|
|
137
|
+
* casa a chamada de fora.
|
|
138
|
+
*/
|
|
139
|
+
function isArgumentOfAnotherCall(body, index) {
|
|
140
|
+
const open = [];
|
|
141
|
+
for (let i = 0; i < index; i++) {
|
|
142
|
+
if (body[i] === "(")
|
|
143
|
+
open.push(!OPENS_A_CLASS_CALL.test(body.slice(0, i + 1)));
|
|
144
|
+
else if (body[i] === ")")
|
|
145
|
+
open.pop();
|
|
146
|
+
}
|
|
147
|
+
return open[open.length - 1] === true;
|
|
148
|
+
}
|
|
96
149
|
export function fragmentsOfSource(file, source) {
|
|
97
150
|
const out = [];
|
|
98
151
|
const at = (index) => source.slice(0, index).split("\n").length;
|
|
@@ -127,15 +180,28 @@ export function fragmentsOfSource(file, source) {
|
|
|
127
180
|
* OS LITERAIS DENTRO DE UMA CHAMADA. `cn("flex p-4", cond && "gap-2")` tem dois, e os dois são
|
|
128
181
|
* classe escrita à mão - a forma mais comum do repo dele (113 arquivos).
|
|
129
182
|
*/
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
183
|
+
/**
|
|
184
|
+
* SÓ A CHAMADA MAIS EXTERNA - senão um utilitário aninhado conta os literais dele duas vezes.
|
|
185
|
+
*
|
|
186
|
+
* Enquanto o corpo parava no primeiro `)`, um `clsx(` dentro de um `cn(` era uma segunda match e
|
|
187
|
+
* ninguém percebia. Com o corpo inteiro, o de fora já cobre o de dentro.
|
|
188
|
+
*/
|
|
189
|
+
let until = 0;
|
|
190
|
+
for (const call of source.matchAll(CALL_OPEN)) {
|
|
191
|
+
const from = (call.index ?? 0) + call[0].length;
|
|
192
|
+
if (from < until)
|
|
193
|
+
continue;
|
|
194
|
+
until = closingParen(source, from);
|
|
195
|
+
const body = blankComments(source.slice(from, until));
|
|
196
|
+
const base = from;
|
|
133
197
|
for (const s of body.matchAll(STRING_IN_CALL)) {
|
|
134
198
|
const text = s[1] ?? s[2] ?? "";
|
|
135
199
|
if (!LOOKS_LIKE_CLASS.test(text))
|
|
136
200
|
continue;
|
|
137
201
|
if (isComparedTo(body, s.index ?? 0))
|
|
138
202
|
continue;
|
|
203
|
+
if (isArgumentOfAnotherCall(body, s.index ?? 0))
|
|
204
|
+
continue;
|
|
139
205
|
push("class", base + (s.index ?? 0), text);
|
|
140
206
|
}
|
|
141
207
|
}
|
|
@@ -151,6 +217,19 @@ export function fragmentsOfSource(file, source) {
|
|
|
151
217
|
}
|
|
152
218
|
return out;
|
|
153
219
|
}
|
|
220
|
+
/** O fim da chamada aberta em `from`, contando parênteses. Sem fechamento, o fim do arquivo. */
|
|
221
|
+
function closingParen(source, from) {
|
|
222
|
+
let depth = 1;
|
|
223
|
+
let i = from;
|
|
224
|
+
while (i < source.length && depth > 0) {
|
|
225
|
+
if (source[i] === "(")
|
|
226
|
+
depth += 1;
|
|
227
|
+
else if (source[i] === ")")
|
|
228
|
+
depth -= 1;
|
|
229
|
+
i += 1;
|
|
230
|
+
}
|
|
231
|
+
return depth === 0 ? i - 1 : source.length;
|
|
232
|
+
}
|
|
154
233
|
/** O fim de um objeto aberto com duas chaves - `sx={{ … }}` fecha em duas. */
|
|
155
234
|
function balanced(source, from, close) {
|
|
156
235
|
let depth = 2;
|
package/dist/install-marks.js
CHANGED
|
@@ -680,7 +680,7 @@ export const CHECKER_SINCE = "0.16.378";
|
|
|
680
680
|
* posição de conteúdo. Um censo medido antes desta versão conta como deriva o que a folha do app
|
|
681
681
|
* nem alcança - e o número do cliente é a promessa.
|
|
682
682
|
*/
|
|
683
|
-
export const READER_SINCE = "0.16.
|
|
683
|
+
export const READER_SINCE = "0.16.381";
|
|
684
684
|
/**
|
|
685
685
|
* O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
|
|
686
686
|
*
|
package/package.json
CHANGED