synthesisui 0.16.135 → 0.16.136
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/import.js
CHANGED
|
@@ -13,7 +13,7 @@ import { describeGate, gateComponent, groupSkips, SCREENS_FOR_SYSTEM, } from "..
|
|
|
13
13
|
import { emptyTally, internalSpecifiers, scanComponentsInto, tallyToInventory, } from "../doctor/components-scan.js";
|
|
14
14
|
import { countShape, describeCoverage, summarizeCoverage, } from "../doctor/coverage.js";
|
|
15
15
|
import { crosswalk, floorSize, isLibrary, observedRules, useLiveCatalogue, } from "../doctor/crosswalk.js";
|
|
16
|
-
import { keyframeOffsets, moduleImports, readModuleCss, readModuleUsage, transcribeModule, } from "../doctor/css-modules.js";
|
|
16
|
+
import { keyframeOffsets, moduleImports, partialCandidates, readModuleCss, readModuleUsage, sheetImports, transcribeModule, } from "../doctor/css-modules.js";
|
|
17
17
|
import { dataContract } from "../doctor/data-contract.js";
|
|
18
18
|
import { reconcile, scanDefinitions, } from "../doctor/definitions-scan.js";
|
|
19
19
|
import { fragmentsOfSource, fragmentsOfStylesheet, judgeFragments, } from "../doctor/fragments.js";
|
|
@@ -128,6 +128,48 @@ async function siblingProjects(root) {
|
|
|
128
128
|
* this" - could not be said, and we ended up rediscovering by colour distance
|
|
129
129
|
* what their stylesheet had spelled out all along.
|
|
130
130
|
*/
|
|
131
|
+
/**
|
|
132
|
+
* UMA FOLHA E TUDO O QUE ELA TRAZ PARA DENTRO DE SI, na ordem em que o sass compila.
|
|
133
|
+
*
|
|
134
|
+
* Uma partial (`_darkMode.scss`) nunca é compilada sozinha: ela entra em quem a importa, e portanto
|
|
135
|
+
* herda o escopo de quem a importa. Ler o `.module.scss` sem seguir os `@import` dele deixava de
|
|
136
|
+
* fora 1 400 declarações (91% de tudo o que a esteira chamava de "CSS global sem leitor") - e elas
|
|
137
|
+
* são, no build dele, as faces light e dark de classes que o componente JÁ veste (medido, 05/08).
|
|
138
|
+
*
|
|
139
|
+
* Devolve o CSS concatenado e os arquivos que entraram, porque o ledger precisa saber que a partial
|
|
140
|
+
* pertence a um componente admitido - senão ela continua contabilizada como forma sem leitor, e o
|
|
141
|
+
* relatório passa a discordar da receita.
|
|
142
|
+
*/
|
|
143
|
+
async function sheetWithImports(path, seen = new Set(), depth = 0) {
|
|
144
|
+
if (depth > 6 || seen.has(path))
|
|
145
|
+
return { css: "", files: [] };
|
|
146
|
+
seen.add(path);
|
|
147
|
+
const body = await readFile(path, "utf8").catch(() => "");
|
|
148
|
+
if (!body)
|
|
149
|
+
return { css: "", files: [] };
|
|
150
|
+
let css = "";
|
|
151
|
+
const files = [path];
|
|
152
|
+
/**
|
|
153
|
+
* O IMPORTADO VEM ANTES, que é a ordem do sass: quem importa sobrescreve o que importou. Inverter
|
|
154
|
+
* isto faria a face dark de uma partial vencer a base do próprio module.
|
|
155
|
+
*/
|
|
156
|
+
for (const spec of sheetImports(body)) {
|
|
157
|
+
for (const candidate of partialCandidates(spec)) {
|
|
158
|
+
const child = join(dirname(path), candidate);
|
|
159
|
+
const nested = await sheetWithImports(child, seen, depth + 1);
|
|
160
|
+
if (nested.css || nested.files.length > 1 || (await exists(child))) {
|
|
161
|
+
css += nested.css;
|
|
162
|
+
files.push(...nested.files);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { css: `${css}\n${body}`, files };
|
|
168
|
+
}
|
|
169
|
+
/** Existe no disco - o candidato de partial que o sass acharia primeiro. */
|
|
170
|
+
async function exists(path) {
|
|
171
|
+
return await readFile(path, "utf8").then(() => true, () => false);
|
|
172
|
+
}
|
|
131
173
|
async function harvestOwnCss(root,
|
|
132
174
|
/**
|
|
133
175
|
* O LEDGER TAMBÉM COME AQUI, e por um motivo de promessa: este é o único laço que vê TODO
|
|
@@ -139,17 +181,40 @@ async function harvestOwnCss(root,
|
|
|
139
181
|
* não admitido é um motivo, não um desaparecimento.
|
|
140
182
|
*/
|
|
141
183
|
into) {
|
|
142
|
-
|
|
184
|
+
/**
|
|
185
|
+
* DOIS PASSES, porque o escopo de uma folha está no GRAFO e não no nome dela.
|
|
186
|
+
*
|
|
187
|
+
* O primeiro junta tudo; o segundo julga cada folha sabendo quem importa quem. Um pass só
|
|
188
|
+
* decidia por `/\.module\./` e chamava de "CSS global sem leitor" 1 400 declarações que o build
|
|
189
|
+
* deles compila dentro de um module (medido, 05/08).
|
|
190
|
+
*/
|
|
191
|
+
const sheets = [];
|
|
143
192
|
for await (const file of walkAll([root])) {
|
|
144
193
|
if (!/\.(css|scss|sass|less)$/i.test(file))
|
|
145
194
|
continue;
|
|
146
195
|
const body = await readFile(file, "utf8").catch(() => "");
|
|
196
|
+
sheets.push({ file, body });
|
|
197
|
+
}
|
|
198
|
+
/** Todo caminho que alguma folha importa, resolvido como o sass resolveria. */
|
|
199
|
+
const imported = new Set();
|
|
200
|
+
for (const sheet of sheets)
|
|
201
|
+
for (const spec of sheetImports(sheet.body))
|
|
202
|
+
for (const candidate of partialCandidates(spec))
|
|
203
|
+
imported.add(join(dirname(sheet.file), candidate));
|
|
204
|
+
let css = "";
|
|
205
|
+
for (const { file, body } of sheets) {
|
|
147
206
|
css += `\n${body}`;
|
|
148
|
-
if (into
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
207
|
+
if (!into || !body)
|
|
208
|
+
continue;
|
|
209
|
+
const partial = basename(file).startsWith("_");
|
|
210
|
+
into.push({
|
|
211
|
+
file: relative(root, file),
|
|
212
|
+
fragments: fragmentsOfStylesheet(relative(root, file), body, /\.module\./.test(file) || (partial && imported.has(file))
|
|
213
|
+
? "scoped"
|
|
214
|
+
: partial
|
|
215
|
+
? "dead"
|
|
216
|
+
: "global"),
|
|
217
|
+
});
|
|
153
218
|
}
|
|
154
219
|
return css;
|
|
155
220
|
}
|
|
@@ -564,7 +629,13 @@ export async function takeCensus(root, opts) {
|
|
|
564
629
|
let fromModule = null;
|
|
565
630
|
for (const mod of modules) {
|
|
566
631
|
const cssPath = join(dirname(file), mod.specifier);
|
|
567
|
-
|
|
632
|
+
/**
|
|
633
|
+
* O MODULE E AS PARTIALS QUE ELE IMPORTA, que no build dele são um arquivo só. Ler apenas
|
|
634
|
+
* o `.module.scss` deixava 1 400 declarações fora - as faces light e dark de classes que
|
|
635
|
+
* o componente já veste, escritas em `_lightMode.scss`/`_darkMode.scss` ao lado.
|
|
636
|
+
*/
|
|
637
|
+
const sheet = await sheetWithImports(cssPath);
|
|
638
|
+
const moduleCss = sheet.css.trim();
|
|
568
639
|
if (!moduleCss)
|
|
569
640
|
continue;
|
|
570
641
|
const usage = readModuleUsage(src, mod.local);
|
|
@@ -574,8 +645,14 @@ export async function takeCensus(root, opts) {
|
|
|
574
645
|
* ESTE MODULE PERTENCE A UM COMPONENTE ADMITIDO - o único fato que este laço tem e o
|
|
575
646
|
* ledger precisa. Os fragmentos dele vêm do `harvestOwnCss`, que vê todos os arquivos
|
|
576
647
|
* de estilo e não só os de componente aceito.
|
|
648
|
+
*
|
|
649
|
+
* A PARTIAL ENTRA JUNTO: ela é parte deste module, então o veredito dela é o mesmo. Sem
|
|
650
|
+
* isto o relatório continuaria chamando de "forma sem leitor" exatamente o que a receita
|
|
651
|
+
* acabou de ler - relatório e receita discordando, que é o defeito que o ledger existe
|
|
652
|
+
* para não ter.
|
|
577
653
|
*/
|
|
578
|
-
|
|
654
|
+
for (const part of sheet.files)
|
|
655
|
+
admittedStyles.add(relative(root, part));
|
|
579
656
|
const readModule = transcribeModule(readModuleCss(moduleCss), usage, declaredValues);
|
|
580
657
|
if (readModule.read === 0)
|
|
581
658
|
continue;
|
|
@@ -335,6 +335,50 @@ export function moduleImports(source) {
|
|
|
335
335
|
specifier: m[2],
|
|
336
336
|
}));
|
|
337
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* `@import "./_darkMode"`, `@use "./_lightMode.scss"` - o que uma folha traz para dentro de si.
|
|
340
|
+
*
|
|
341
|
+
* UMA PARTIAL NÃO É UMA FOLHA. Um arquivo `_nome.scss` nunca é compilado sozinho - o sass o
|
|
342
|
+
* compila DENTRO de quem o importa, e por isso o escopo dele é o de quem importa. No app do dono,
|
|
343
|
+
* 122 das 138 folhas "globais" são partials e 120 delas são importadas por um `.module.scss` do
|
|
344
|
+
* mesmo diretório: 1 400 declarações (91%) que a esteira classificava como CSS global sem leitor
|
|
345
|
+
* são, no build dele, regras de module - hasheadas e escopadas ao componente (medido, 05/08).
|
|
346
|
+
*
|
|
347
|
+
* Decidir escopo por NOME DE ARQUIVO (`/\.module\./`) é a lei 14 um nível abaixo: a resposta está
|
|
348
|
+
* no grafo de imports, não na string do caminho.
|
|
349
|
+
*/
|
|
350
|
+
const SHEET_IMPORT = /@(?:import|use|forward)\s+["']([^"']+)["']/g;
|
|
351
|
+
export function sheetImports(css) {
|
|
352
|
+
SHEET_IMPORT.lastIndex = 0;
|
|
353
|
+
return ([...stripCssComments(css).matchAll(SHEET_IMPORT)]
|
|
354
|
+
.map((m) => m[1].trim())
|
|
355
|
+
/**
|
|
356
|
+
* Só o que é relativo. `@use "sass:math"` e um pacote do node_modules não carregam decisão de
|
|
357
|
+
* aparência deles, e seguir esses caminhos é como um leitor de CSS vira um resolvedor de
|
|
358
|
+
* módulos pela metade.
|
|
359
|
+
*/
|
|
360
|
+
.filter((spec) => spec.startsWith(".") || !spec.includes(":"))
|
|
361
|
+
.filter((spec) => !spec.startsWith("~") && !spec.startsWith("url(")));
|
|
362
|
+
}
|
|
363
|
+
/** `./_darkMode` → os nomes de arquivo que o sass tentaria, na ordem em que ele tenta. */
|
|
364
|
+
export function partialCandidates(specifier) {
|
|
365
|
+
const clean = specifier.replace(/^\.\//, "");
|
|
366
|
+
const slash = clean.lastIndexOf("/");
|
|
367
|
+
const dir = slash === -1 ? "" : `${clean.slice(0, slash)}/`;
|
|
368
|
+
const base = slash === -1 ? clean : clean.slice(slash + 1);
|
|
369
|
+
if (/\.(css|scss|sass|less)$/.test(base))
|
|
370
|
+
return base.startsWith("_")
|
|
371
|
+
? [`${dir}${base}`]
|
|
372
|
+
: [`${dir}${base}`, `${dir}_${base}`];
|
|
373
|
+
const stem = base.startsWith("_") ? base : `_${base}`;
|
|
374
|
+
return [
|
|
375
|
+
`${dir}${base}.scss`,
|
|
376
|
+
`${dir}${stem}.scss`,
|
|
377
|
+
`${dir}${base}.sass`,
|
|
378
|
+
`${dir}${stem}.sass`,
|
|
379
|
+
`${dir}${base}.css`,
|
|
380
|
+
];
|
|
381
|
+
}
|
|
338
382
|
/**
|
|
339
383
|
* A generic in type position, not an element.
|
|
340
384
|
*
|
package/dist/doctor/fragments.js
CHANGED
|
@@ -110,7 +110,20 @@ export function fragmentsOfSource(file, source) {
|
|
|
110
110
|
* contagem: um global com regra de CLASSE é forma que nenhum leitor cobre hoje - 399 declarações
|
|
111
111
|
* no repo dele, e a única lacuna que estava calada em vez de declarada (04/08).
|
|
112
112
|
*/
|
|
113
|
-
export function fragmentsOfStylesheet(file, css,
|
|
113
|
+
export function fragmentsOfStylesheet(file, css,
|
|
114
|
+
/**
|
|
115
|
+
* COMO ESTA FOLHA CHEGA NO BUILD DELES, e isso vem do GRAFO DE IMPORTS e nunca do nome do
|
|
116
|
+
* arquivo. Uma partial (`_darkMode.scss`) é compilada dentro de quem a importa e herda o escopo
|
|
117
|
+
* dele: 122 das 138 folhas "globais" do app dele são partials, e 120 entram num `.module.scss`
|
|
118
|
+
* ao lado (medido, 05/08).
|
|
119
|
+
*
|
|
120
|
+
* scoped module, ou partial de um module: o veredito é do componente dono, e
|
|
121
|
+
* `judgeFragments` o dá olhando se o escopo o admitiu
|
|
122
|
+
* global uma folha que o código importa: forma que nenhum leitor cobre hoje
|
|
123
|
+
* dead partial que ninguém importa: o build deles não a compila, e ela não
|
|
124
|
+
* pinta nada - aqui, nem lá
|
|
125
|
+
*/
|
|
126
|
+
kind) {
|
|
114
127
|
const out = [];
|
|
115
128
|
let selector = "";
|
|
116
129
|
for (const [i, raw] of css.split("\n").entries()) {
|
|
@@ -143,7 +156,11 @@ export function fragmentsOfStylesheet(file, css, scoped) {
|
|
|
143
156
|
line: i + 1,
|
|
144
157
|
text: `${selector ? `${selector} ` : ""}{ ${m[1]}: ${m[2].trim()} }`,
|
|
145
158
|
read: false,
|
|
146
|
-
...(
|
|
159
|
+
...(kind === "global"
|
|
160
|
+
? { reason: "shape-not-read" }
|
|
161
|
+
: kind === "dead"
|
|
162
|
+
? { reason: "sheet-not-imported" }
|
|
163
|
+
: {}),
|
|
147
164
|
});
|
|
148
165
|
}
|
|
149
166
|
}
|
|
@@ -84,7 +84,14 @@ function whereOf(shape, reason) {
|
|
|
84
84
|
module: null,
|
|
85
85
|
work: reason === "component-not-admitted"
|
|
86
86
|
? "the gate refused the component: these styles exist and no recipe claims them. Changing that means moving the GATE - a decision about the vitrine, not a reader to write"
|
|
87
|
-
:
|
|
87
|
+
: reason === "sheet-not-imported"
|
|
88
|
+
? /**
|
|
89
|
+
* NÃO É LACUNA NOSSA NEM DELES-QUE-A-GENTE-CONSERTA: é um arquivo que o build deles
|
|
90
|
+
* não compila. Cair na frase de runtime dizia que o valor é montado em tempo de
|
|
91
|
+
* execução, o que é falso e mandaria alguém procurar o que não existe.
|
|
92
|
+
*/
|
|
93
|
+
"a sass partial no stylesheet imports: their own build never compiles it, so it paints nothing today - here or in their app. Deleting it is their call, not a reader to write"
|
|
94
|
+
: "the value is assembled at render time and is not in the source at any level - there is nothing to read",
|
|
88
95
|
};
|
|
89
96
|
}
|
|
90
97
|
}
|
|
@@ -54,6 +54,7 @@ const BECAUSE = {
|
|
|
54
54
|
"value-not-read": "the shape is read and this value is not - a utility or property outside the scales this project declares",
|
|
55
55
|
computed: "the value is assembled at render time, so it is not in the source at any level and there is nothing to read",
|
|
56
56
|
"component-not-admitted": "read, and it belongs to a component this scope does not admit into the system - the styles exist and no recipe claims them",
|
|
57
|
+
"sheet-not-imported": "this is a sass partial and no stylesheet imports it, so your own build never compiles it - it paints nothing today, here or anywhere",
|
|
57
58
|
};
|
|
58
59
|
/**
|
|
59
60
|
* O ledger de uma varredura, a partir dos fragmentos vistos.
|
package/package.json
CHANGED