synthesisui 0.16.396 → 0.16.398
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/commands/component.js +62 -22
- package/dist/commands/doctor.js +88 -1
- package/dist/sheet-needed.js +76 -0
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import { hasInteractiveTemplate, interactiveTemplate, } from "../interactive-tem
|
|
|
8
8
|
import { body, section, snippet } from "../output.js";
|
|
9
9
|
import { findCollision, installedThemeVars, reactMajorOf, readInstalledConvention, readInstalledScheme, } from "../project-facts.js";
|
|
10
10
|
import { fetchComponent, RegistryError } from "../registry.js";
|
|
11
|
+
import { installedThemeCss, whatOnlyTheSheetResolves, } from "../sheet-needed.js";
|
|
11
12
|
import { flavourResolver } from "../styles-flavour.js";
|
|
12
13
|
import { inTheirTongue, projectTongue, sumSpoken, } from "../their-tongue.js";
|
|
13
14
|
import { readCensus, unreadComment, unreadForComponent, } from "../unread-for-component.js";
|
|
@@ -110,6 +111,13 @@ export async function component(slug, name, opts) {
|
|
|
110
111
|
* sai no fim - depois da linha que nomeia o que foi escrito.
|
|
111
112
|
*/
|
|
112
113
|
let spoken = null;
|
|
114
|
+
/**
|
|
115
|
+
* OS BYTES QUE FORAM A DISCO - é sobre ELES que a pergunta "precisa da folha?" se responde.
|
|
116
|
+
*
|
|
117
|
+
* Pela mesma razão que `spoken` é preenchido em cada caminho de escrita: perguntar sobre o
|
|
118
|
+
* recipe, ou sobre o css antes da tradução, seria responder sobre um arquivo que ninguém abriu.
|
|
119
|
+
*/
|
|
120
|
+
let writtenSource = "";
|
|
113
121
|
const artifactsAreTheProduct = opts.artifactsOnly === true || config.target !== "next";
|
|
114
122
|
if (artifactsAreTheProduct) {
|
|
115
123
|
const dir = join(root, "_synthesisui", "ds", slug, "components");
|
|
@@ -119,6 +127,7 @@ export async function component(slug, name, opts) {
|
|
|
119
127
|
const sheet = tongue ? inTheirTongue(res.css, tongue) : null;
|
|
120
128
|
if (sheet)
|
|
121
129
|
spoken = sheet;
|
|
130
|
+
writtenSource = sheet ? sheet.css : res.css;
|
|
122
131
|
await writeFile(join(dir, `${res.name}.css`), `${sheet ? sheet.css : res.css}\n`, "utf8");
|
|
123
132
|
console.log(`✓ ${res.name} → _synthesisui/ds/${slug}/components/${res.name}.{json,css} (${slug} v${res.version})`);
|
|
124
133
|
}
|
|
@@ -287,6 +296,7 @@ export async function component(slug, name, opts) {
|
|
|
287
296
|
];
|
|
288
297
|
for (const f of written)
|
|
289
298
|
await writeFile(join(compDir, f.filename), f.content, "utf8");
|
|
299
|
+
writtenSource = written.map((f) => f.content).join("\n");
|
|
290
300
|
/** O fingerprint do que escrevemos - é o que protege a edição dele no upgrade (T7). */
|
|
291
301
|
await recordWritten(join(root, "_synthesisui", "ds", slug), local, written);
|
|
292
302
|
filenames = written.map((f) => f.filename);
|
|
@@ -335,6 +345,7 @@ export async function component(slug, name, opts) {
|
|
|
335
345
|
}));
|
|
336
346
|
for (const f of written)
|
|
337
347
|
await writeFile(join(compDir, f.filename), f.content, "utf8");
|
|
348
|
+
writtenSource = written.map((f) => f.content).join("\n");
|
|
338
349
|
await recordWritten(join(root, "_synthesisui", "ds", slug), local, written);
|
|
339
350
|
if (flavour === "tailwind")
|
|
340
351
|
await writeCn(root, compDir, slug);
|
|
@@ -368,34 +379,63 @@ export async function component(slug, name, opts) {
|
|
|
368
379
|
`@import "../_synthesisui/ds/${slug}/theme.css";`,
|
|
369
380
|
]
|
|
370
381
|
: [`@import "../_synthesisui/ds/${slug}/tokens.css";`];
|
|
371
|
-
console.log(section(`One-time setup (once per app, for "${slug}")`));
|
|
372
382
|
/**
|
|
373
|
-
*
|
|
383
|
+
* O SETUP SÓ É COBRADO QUANDO ESTE ARQUIVO PRECISA DELE - ver `sheet-needed.ts`.
|
|
384
|
+
*
|
|
385
|
+
* O DEFEITO, apontado pelo dono olhando a própria tela (07/09): o comando terminava dizendo
|
|
386
|
+
* *"No variable in what was just written points at our stylesheet"* e, três linhas abaixo,
|
|
387
|
+
* imprimia **One-time setup** mandando colar dois `@import`. As duas frases não podem ser
|
|
388
|
+
* verdadeiras ao mesmo tempo, e a segunda pedia uma dependência de runtime para um arquivo que
|
|
389
|
+
* não a usa.
|
|
374
390
|
*
|
|
375
|
-
* A
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
* `--
|
|
391
|
+
* A VERSÃO ANTERIOR DESTE BLOCO já tinha visto metade do problema e parou na metade: manteve o
|
|
392
|
+
* setup e acrescentou *"o que estes imports ainda trazem são os utilitários do sistema e o
|
|
393
|
+
* movimento"*. A razão é real - `INV-VOLTA-13` deixa no `@theme` os nomes que só o sistema tem -
|
|
394
|
+
* mas ela era AFIRMADA, nunca medida. No `codelevel` aquele `@theme` declara 50 variáveis, todas
|
|
395
|
+
* `--animate-*` e `--max-width-*`, e o componente gerado não veste nenhuma delas: as duas
|
|
396
|
+
* animações que ele usa são declaradas pelo `globals.css` DELE.
|
|
380
397
|
*
|
|
381
|
-
* Então
|
|
382
|
-
*
|
|
398
|
+
* Então a pergunta passa a ser feita: sobrou variável nossa, ou classe que só o nosso `@theme`
|
|
399
|
+
* gera? Se nenhuma das duas, o arquivo está isolado e o bloco diz isso - com o que o import ainda
|
|
400
|
+
* daria, para a escolha continuar sendo dele.
|
|
383
401
|
*/
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
402
|
+
const need = whatOnlyTheSheetResolves({
|
|
403
|
+
source: writtenSource,
|
|
404
|
+
themeCss: await installedThemeCss(root, slug),
|
|
405
|
+
/** O vocabulário DELE sai da conta - ver `theirNames`. O mapa do `.lock` é a via mais barata. */
|
|
406
|
+
theirNames: tongue?.names ? [...tongue.names.values()] : [],
|
|
407
|
+
});
|
|
408
|
+
if (!need.needed) {
|
|
409
|
+
console.log(section("This file needs nothing else"));
|
|
410
|
+
console.log(body("Every variable and class in it is declared by your own code - no import, no scope"));
|
|
411
|
+
console.log(body("attribute, nothing at runtime. It is yours."));
|
|
387
412
|
console.log("");
|
|
413
|
+
console.log(body(`The system stays what it is here: the reference your agent reads to build ON it.`));
|
|
414
|
+
console.log(body(`If you later want the utilities only its own @theme generates, that is when`));
|
|
415
|
+
console.log(body(`importing earns its place - and \`doctor\` says so.`));
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* E O "USE IT" SAI NOS DOIS CAMINHOS - a primeira versão disto era um `return`, e ela levava
|
|
419
|
+
* junto a única linha que diz COMO importar o componente. Dizer "está isolado" e sonegar o
|
|
420
|
+
* `import { ButtonSample }` troca um defeito por outro.
|
|
421
|
+
*/
|
|
422
|
+
if (need.needed) {
|
|
423
|
+
console.log(section(`One-time setup (once per app, for "${slug}")`));
|
|
424
|
+
console.log(body(need.variables.length > 0
|
|
425
|
+
? `(what still needs the sheet here: ${need.variables.slice(0, 3).join(", ")}${need.variables.length > 3 ? `, +${need.variables.length - 3}` : ""} - your code names no value for ${need.variables.length === 1 ? "it" : "them"})`
|
|
426
|
+
: `(what still needs the sheet here: the ${need.classes.slice(0, 3).join(", ")}${need.classes.length > 3 ? `, +${need.classes.length - 3}` : ""} ${need.classes.length === 1 ? "utility" : "utilities"}, which only this system's @theme generates)`));
|
|
427
|
+
console.log("");
|
|
428
|
+
console.log(body(`1. Import the design system in your GLOBAL stylesheet, e.g. app/globals.css`));
|
|
429
|
+
console.log(body(` (the path is relative to that file - hence the leading ../):`));
|
|
430
|
+
console.log("");
|
|
431
|
+
console.log(snippet(imports));
|
|
432
|
+
console.log("");
|
|
433
|
+
console.log(body(`2. Scope your app: add data-ds="${slug}" to a ROOT element, e.g. app/layout.tsx:`));
|
|
434
|
+
console.log("");
|
|
435
|
+
console.log(snippet([`<body data-ds="${slug}">{children}</body>`]));
|
|
436
|
+
console.log("");
|
|
437
|
+
console.log(body(`(If you haven't installed the system yet, run: synthesisui add ${slug})`));
|
|
388
438
|
}
|
|
389
|
-
console.log(body(`1. Import the design system in your GLOBAL stylesheet, e.g. app/globals.css`));
|
|
390
|
-
console.log(body(` (the path is relative to that file - hence the leading ../):`));
|
|
391
|
-
console.log("");
|
|
392
|
-
console.log(snippet(imports));
|
|
393
|
-
console.log("");
|
|
394
|
-
console.log(body(`2. Scope your app: add data-ds="${slug}" to a ROOT element, e.g. app/layout.tsx:`));
|
|
395
|
-
console.log("");
|
|
396
|
-
console.log(snippet([`<body data-ds="${slug}">{children}</body>`]));
|
|
397
|
-
console.log("");
|
|
398
|
-
console.log(body(`(If you haven't installed the system yet, run: synthesisui add ${slug})`));
|
|
399
439
|
console.log(section("Use it"));
|
|
400
440
|
if (!opts.artifactsOnly && config.target === "next") {
|
|
401
441
|
/**
|
package/dist/commands/doctor.js
CHANGED
|
@@ -22,7 +22,9 @@ import { groupRole } from "../group-role.js";
|
|
|
22
22
|
import { actingSlug, describeScope, measuredScope, scopePaths, } from "../measured-scope.js";
|
|
23
23
|
import { body, paint, section, snippet } from "../output.js";
|
|
24
24
|
import { setupPrompt } from "../setup-prompt.js";
|
|
25
|
+
import { installedThemeCss, whatOnlyTheSheetResolves, } from "../sheet-needed.js";
|
|
25
26
|
import { resolveDeps } from "../stack.js";
|
|
27
|
+
import { projectTongue } from "../their-tongue.js";
|
|
26
28
|
import { danglingTheirVars } from "../their-vars.js";
|
|
27
29
|
/**
|
|
28
30
|
* `synthesisui doctor` - the check nobody else ships.
|
|
@@ -782,6 +784,14 @@ export async function doctor(opts) {
|
|
|
782
784
|
* Nobody debugs from 0%. They conclude the product does not work.
|
|
783
785
|
*/
|
|
784
786
|
const wiring = await readWiring(root, table.slug);
|
|
787
|
+
/**
|
|
788
|
+
* O QUE, NESTE REPOSITÓRIO, SÓ A NOSSA FOLHA RESOLVE - acumulado na varredura QUE JÁ ACONTECE.
|
|
789
|
+
*
|
|
790
|
+
* Uma segunda passada pelo disco para responder isto custaria o dobro num repositório de 178
|
|
791
|
+
* arquivos, e a resposta está no mesmo texto que o scan já tem na mão. Ver `sheet-needed.ts`.
|
|
792
|
+
*/
|
|
793
|
+
const themeCss = table.slug ? await installedThemeCss(root, table.slug) : "";
|
|
794
|
+
let scannedSource = "";
|
|
785
795
|
const skippedProjects = [];
|
|
786
796
|
const tally = emptyTally();
|
|
787
797
|
const internalSpecs = await internalSpecifiers(root);
|
|
@@ -793,6 +803,9 @@ export async function doctor(opts) {
|
|
|
793
803
|
continue;
|
|
794
804
|
const rel = relative(root, file);
|
|
795
805
|
reports.push(scanSource(rel, src, table));
|
|
806
|
+
/** A pasta que a plataforma escreve não conta: ela É a folha, não um consumidor dela. */
|
|
807
|
+
if (!rel.startsWith("_synthesisui"))
|
|
808
|
+
scannedSource += `\n${src}`;
|
|
796
809
|
// Composition, alongside values: the contract check needs to know which
|
|
797
810
|
// elements this file writes and with what options. Stories and tests are
|
|
798
811
|
// excluded for the reason they are excluded everywhere else - they compose
|
|
@@ -967,7 +980,22 @@ export async function doctor(opts) {
|
|
|
967
980
|
* `table.source` é a distinção certa e ela já estava aqui, uma linha abaixo, em `unwired`:
|
|
968
981
|
* `"yours"` e `"adopted"` são o vocabulário dela, e não há duas linhas para ligar.
|
|
969
982
|
*/
|
|
970
|
-
const
|
|
983
|
+
const sheetNeed = whatOnlyTheSheetResolves({
|
|
984
|
+
source: scannedSource,
|
|
985
|
+
themeCss,
|
|
986
|
+
theirNames: installed.theirs.byName.keys(),
|
|
987
|
+
});
|
|
988
|
+
/**
|
|
989
|
+
* BLOQUEADO SÓ QUANDO A FOLHA É NECESSÁRIA - a mesma pergunta que decide `unwired`.
|
|
990
|
+
*
|
|
991
|
+
* Sem esta condição, o comando parava de cobrar a fiação lá em cima e continuava recusando o
|
|
992
|
+
* `--fix` aqui embaixo, fechando com *"esse número fica acionável no momento em que as duas forem
|
|
993
|
+
* verdade"* - duas condições que ele mesmo tinha acabado de deixar de pedir. Um relatório que
|
|
994
|
+
* retira a exigência numa seção e a mantém na outra ensina que nenhuma das duas é para valer.
|
|
995
|
+
*/
|
|
996
|
+
const blocked = table.source === "installed" &&
|
|
997
|
+
sheetNeed.needed &&
|
|
998
|
+
(!wiring.imported || !wiring.scoped);
|
|
971
999
|
/**
|
|
972
1000
|
* QUANTAS DAS DUAS FALTAM - e sem este número três frases mandavam consertar DUAS coisas quando
|
|
973
1001
|
* faltava UMA.
|
|
@@ -983,12 +1011,71 @@ export async function doctor(opts) {
|
|
|
983
1011
|
*/
|
|
984
1012
|
const missingWiring = (wiring.imported ? 0 : 1) + (wiring.scoped ? 0 : 1);
|
|
985
1013
|
const bothMissing = missingWiring === 2;
|
|
1014
|
+
/**
|
|
1015
|
+
* A FIAÇÃO SÓ É COBRADA QUANDO ALGUMA COISA NESTE REPOSITÓRIO PRECISA DELA - ver `sheet-needed.ts`.
|
|
1016
|
+
*
|
|
1017
|
+
* O DEFEITO, apontado pelo dono em 07/09 sobre o próprio repositório: *"por que a gente precisa
|
|
1018
|
+
* desses imports, visto que o design do projeto dele já funciona? criar esse import gera
|
|
1019
|
+
* dependência ao design system, que é coisa que a gente não quer - a gente quer isolar os dois
|
|
1020
|
+
* pontos, sendo que o nosso deve ser apenas uma REFERÊNCIA para que qualquer agente que gera
|
|
1021
|
+
* código saiba como utilizar o design system"*.
|
|
1022
|
+
*
|
|
1023
|
+
* MEDIDO NO `codelevel` no mesmo dia: no repositório inteiro, apenas dois arquivos mencionam
|
|
1024
|
+
* `--ds-*` - um componente que a PLATAFORMA gerou com uma versão anterior à tradução, e a costura
|
|
1025
|
+
* de tipografia que o nosso próprio setup pediu. Zero linhas do código que ELE escreveu. Regerado
|
|
1026
|
+
* com o CLI de hoje, o componente sai com 0 referências à nossa folha, e as duas animações que ele
|
|
1027
|
+
* veste são declaradas pelo `globals.css` dele.
|
|
1028
|
+
*
|
|
1029
|
+
* Ou seja: o comando cobrava uma dependência de runtime que nada naquele repositório usava - e o
|
|
1030
|
+
* produto já promete o contrário em `their-tongue.ts` (*"nenhuma folha nossa precisa existir no
|
|
1031
|
+
* repositório dele"*). As duas metades discordavam porque nenhuma perguntava.
|
|
1032
|
+
*
|
|
1033
|
+
* O ESCOPO (`data-ds`) SEGUE A MESMA REGRA e pelo mesmo motivo: ele existe para a folha aplicar
|
|
1034
|
+
* dentro dele. Sem folha necessária, um atributo na árvore dele é a mesma dependência com outro
|
|
1035
|
+
* nome.
|
|
1036
|
+
*
|
|
1037
|
+
* E QUANDO ALGO PRECISA, tudo continua exatamente como era - inclusive o roteiro para o agente. A
|
|
1038
|
+
* mudança não é deixar de cobrar: é parar de cobrar sem ter perguntado.
|
|
1039
|
+
*/
|
|
986
1040
|
const unwired = table.source === "installed" &&
|
|
1041
|
+
sheetNeed.needed &&
|
|
987
1042
|
(!wiring.imported || !wiring.scoped || fontsPending);
|
|
988
1043
|
if (unwired) {
|
|
989
1044
|
console.log("");
|
|
990
1045
|
console.log(body(`${table.name ?? table.slug} is installed - but this project does not load it yet.`));
|
|
991
1046
|
console.log("");
|
|
1047
|
+
/**
|
|
1048
|
+
* O QUE ESTÁ COBRANDO A FOLHA, POR NOME - senão a exigência lê como uma regra nossa.
|
|
1049
|
+
*
|
|
1050
|
+
* Ela não é: é um efeito do que ESTE repositório escreveu. Medido no `codelevel` (07/09), as
|
|
1051
|
+
* duas coisas que a exigiam eram um componente gerado por uma versão anterior à tradução do CLI
|
|
1052
|
+
* e a costura de tipografia que o nosso próprio setup pediu - nenhuma linha do código dele.
|
|
1053
|
+
* Regerado com o CLI de hoje, o mesmo componente sai com zero referências e a exigência some.
|
|
1054
|
+
*
|
|
1055
|
+
* Sem esta linha, quem lê não tem como saber que a dependência é REMOVÍVEL, e a única saída
|
|
1056
|
+
* visível é aceitar o import.
|
|
1057
|
+
*/
|
|
1058
|
+
/**
|
|
1059
|
+
* E A SAÍDA SÓ É OFERECIDA QUANDO ELA EXISTE - senão o comando manda consertar o que não conserta.
|
|
1060
|
+
*
|
|
1061
|
+
* "re-run `component` and it speaks your own names instead" só é verdade onde há MAPA: onde algum
|
|
1062
|
+
* valor do sistema coincide com um nome que o repositório dele já declara. Sem mapa, a tradução
|
|
1063
|
+
* roda e não tem o que traduzir, regerar devolve o mesmo arquivo, e a folha é o caminho legítimo.
|
|
1064
|
+
*
|
|
1065
|
+
* MEDIDO EM 07/09, validando o binário publicado num `create-next-app` que instalou o
|
|
1066
|
+
* `codelevel`: `.lock` sem `tokenMap`, o componente saiu com 14 linhas `--ds-*`, e esta frase
|
|
1067
|
+
* mandava regerar. No `codelevel-monorepo`, onde o `.lock` tem 33 pares, regerar É a saída - e o
|
|
1068
|
+
* mesmo texto servia os dois. É o defeito que o `CLAUDE.md` registra em primeira pessoa: afirmar
|
|
1069
|
+
* que um comando conserta o que ele não conserta.
|
|
1070
|
+
*/
|
|
1071
|
+
const translatable = (await projectTongue(root, table.slug ?? "")) !== null;
|
|
1072
|
+
const asks = sheetNeed.variables.length > 0
|
|
1073
|
+
? `${sheetNeed.variables.slice(0, 3).join(", ")}${sheetNeed.variables.length > 3 ? `, +${sheetNeed.variables.length - 3} more` : ""}${translatable
|
|
1074
|
+
? ` - re-run \`component\` on whatever writes ${sheetNeed.variables.length === 1 ? "it" : "them"} and it speaks your own names instead`
|
|
1075
|
+
: ` - your code names no value this system also holds, so there is nothing to translate ${sheetNeed.variables.length === 1 ? "it" : "them"} into, and the sheet is the way`}`
|
|
1076
|
+
: `the ${sheetNeed.classes.slice(0, 3).join(", ")}${sheetNeed.classes.length > 3 ? `, +${sheetNeed.classes.length - 3} more` : ""} ${sheetNeed.classes.length === 1 ? "utility" : "utilities"}, which only this system's @theme generates`;
|
|
1077
|
+
console.log(body(` what asks for it: ${asks}`));
|
|
1078
|
+
console.log("");
|
|
992
1079
|
console.log(body(wiring.imported
|
|
993
1080
|
? ` ✓ some stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`
|
|
994
1081
|
: ` ✗ no stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`));
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { TAILWIND_THEME_VARS } from "./tailwind-theme-vars.js";
|
|
4
|
+
/** `--animate-shimmer` no `@theme` -> o nome `shimmer`, que é o que uma classe carrega. */
|
|
5
|
+
function themeNames(themeCss) {
|
|
6
|
+
const out = new Set();
|
|
7
|
+
for (const block of themeCss.matchAll(/@theme[^{]*\{([\s\S]*?)\n\}/g))
|
|
8
|
+
for (const m of block[1].matchAll(/^\s*--([a-z]+)-([a-zA-Z0-9_-]+)\s*:/gm))
|
|
9
|
+
out.add(m[2]);
|
|
10
|
+
return [...out];
|
|
11
|
+
}
|
|
12
|
+
/** As classes escritas no código - `hover:animate-shimmer` conta como `animate-shimmer`. */
|
|
13
|
+
function classesIn(source) {
|
|
14
|
+
const out = new Set();
|
|
15
|
+
for (const m of source.matchAll(/class(?:Name)?=(?:"([^"]*)"|'([^']*)'|\{`([^`]*)`\}|\{"([^"]*)"\})/g)) {
|
|
16
|
+
const body = m[1] ?? m[2] ?? m[3] ?? m[4] ?? "";
|
|
17
|
+
for (const raw of body.split(/\s+/)) {
|
|
18
|
+
if (!raw)
|
|
19
|
+
continue;
|
|
20
|
+
const bare = raw.split(":").pop() ?? raw;
|
|
21
|
+
out.add(bare.replace(/^[!-]/, ""));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* O QUE, NESTE TEXTO, SÓ A FOLHA RESOLVE.
|
|
28
|
+
*
|
|
29
|
+
* Puro de propósito: quem varre o disco é quem chama, e um spec precisa poder afirmar a regra sem
|
|
30
|
+
* um diretório temporário.
|
|
31
|
+
*/
|
|
32
|
+
export function whatOnlyTheSheetResolves(input) {
|
|
33
|
+
const variables = [
|
|
34
|
+
...new Set([...input.source.matchAll(/var\(\s*(--ds-[a-zA-Z0-9_-]+)/g)].map((m) => m[1])),
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* `--animate-shimmer` declarado por ele -> o nome `shimmer` sai da conta.
|
|
38
|
+
*
|
|
39
|
+
* E O QUE O PRÓPRIO TAILWIND DECLARA sai junto, pela mesma razão e pela lista que já existe:
|
|
40
|
+
* `animate-pulse` existe em qualquer projeto que importe o Tailwind, e acusá-la de exigir a nossa
|
|
41
|
+
* folha é o mesmo aviso falso que `TAILWIND_THEME_VARS` foi escrito para acabar. Medido no
|
|
42
|
+
* `codelevel` (07/09): sem esta linha, `animate-pulse` era a ÚNICA coisa sustentando a cobrança
|
|
43
|
+
* do import naquele repositório.
|
|
44
|
+
*/
|
|
45
|
+
const theirs = new Set();
|
|
46
|
+
for (const name of [...TAILWIND_THEME_VARS, ...(input.theirNames ?? [])]) {
|
|
47
|
+
const m = /^--[a-z]+-(.+)$/.exec(name.toLowerCase());
|
|
48
|
+
if (m)
|
|
49
|
+
theirs.add(m[1]);
|
|
50
|
+
}
|
|
51
|
+
const names = themeNames(input.themeCss).filter((n) => !theirs.has(n));
|
|
52
|
+
const written = classesIn(input.source);
|
|
53
|
+
const classes = [
|
|
54
|
+
...new Set([...written].filter((c) => names.some((n) => c === n || c.endsWith(`-${n}`)))),
|
|
55
|
+
];
|
|
56
|
+
return {
|
|
57
|
+
variables,
|
|
58
|
+
classes,
|
|
59
|
+
needed: variables.length > 0 || classes.length > 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** O `theme.css` da versão instalada - a folha da raiz é um re-export de uma linha. */
|
|
63
|
+
export async function installedThemeCss(root, slug) {
|
|
64
|
+
const dir = join(root, "_synthesisui", "ds", slug);
|
|
65
|
+
const lock = await readFile(join(dir, ".lock"), "utf8").catch(() => null);
|
|
66
|
+
let version = 0;
|
|
67
|
+
if (lock) {
|
|
68
|
+
try {
|
|
69
|
+
version = JSON.parse(lock).version ?? 0;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
version = 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return readFile(join(dir, `v${version}`, "theme.css"), "utf8").catch(() => "");
|
|
76
|
+
}
|
package/package.json
CHANGED