youiyoux 0.1.17 → 0.1.19
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/chunks/{chunk-TW24A5TT.js → chunk-2F2HM7FE.js} +6 -6
- package/dist/chunks/{chunk-XHJQOWD4.js → chunk-4BQPCZLL.js} +1 -1
- package/dist/chunks/{chunk-I6HDWG3U.js → chunk-5D7PLY7A.js} +1 -1
- package/dist/chunks/{chunk-CKH54UT6.js → chunk-75LXBAYB.js} +245 -36
- package/dist/chunks/{chunk-2HRV3FFX.js → chunk-AFEQZT2N.js} +2 -2
- package/dist/chunks/{chunk-BMBXZG7W.js → chunk-DHZDMZXE.js} +64 -23
- package/dist/chunks/{chunk-CLYYS6VI.js → chunk-M56633DV.js} +8 -1
- package/dist/chunks/{chunk-W3ZCAAXH.js → chunk-NG73FB4O.js} +4 -4
- package/dist/chunks/{chunk-COJJZPVD.js → chunk-OE4RYJOS.js} +3 -3
- package/dist/chunks/{chunk-G5BKBWEQ.js → chunk-SLAQGAAP.js} +1 -1
- package/dist/chunks/{chunk-Q77GHEZ5.js → chunk-UJMXSTUF.js} +2 -2
- package/dist/chunks/{figma-auth-O7YTQOAD.js → figma-auth-A2SAMRLF.js} +1 -1
- package/dist/chunks/{ingest-XSUSELVB.js → ingest-X4MIF5F6.js} +7 -7
- package/dist/chunks/{src-X34V5MHP.js → src-AXF5XUQE.js} +5 -1
- package/dist/chunks/{src-COKDT2AL.js → src-DFXQLHEP.js} +2 -2
- package/dist/chunks/{src-CWTSWOK4.js → src-HBKEBCH6.js} +2 -2
- package/dist/chunks/{src-WSHA347Z.js → src-LGHUKRL2.js} +7 -7
- package/dist/chunks/{src-RMQQPWAD.js → src-Q3ZJHEUQ.js} +3 -3
- package/dist/chunks/{src-3F2YGGDW.js → src-ULAQV67E.js} +3 -3
- package/dist/chunks/{src-O535ZT77.js → src-UXXYZOQ5.js} +2 -2
- package/dist/chunks/{src-HKWBBHA4.js → src-VSWKGVFT.js} +4 -4
- package/dist/hub-previews.js +6 -6
- package/dist/hub-server.js +3 -3
- package/dist/hub-snapshot.js +1 -1
- package/dist/schema/youi.inventory.schema.json +34 -0
- package/dist/youi.js +8 -8
- package/dist/youiyoux.js +8 -8
- package/package.json +4 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire as __youiRequire } from "node:module"; import { dirname as __youiDir } from "node:path"; import { fileURLToPath as __youiPath } from "node:url"; const require = __youiRequire(import.meta.url); const __youiDirname = __youiDir(__youiPath(import.meta.url));
|
|
2
2
|
import {
|
|
3
3
|
loadProject
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-75LXBAYB.js";
|
|
5
5
|
import {
|
|
6
6
|
shortHash
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-M56633DV.js";
|
|
8
8
|
|
|
9
9
|
// ../cli/src/ui.ts
|
|
10
10
|
import * as util from "node:util";
|
|
@@ -57,7 +57,7 @@ import { homedir, userInfo } from "node:os";
|
|
|
57
57
|
import { join, resolve } from "node:path";
|
|
58
58
|
async function swapImpact(candidate, family) {
|
|
59
59
|
try {
|
|
60
|
-
const { discoverIndexPath, sharedStore } = await import("./src-
|
|
60
|
+
const { discoverIndexPath, sharedStore } = await import("./src-ULAQV67E.js");
|
|
61
61
|
const path = discoverIndexPath();
|
|
62
62
|
if (!process.env.DATABASE_URL && !existsSync(path)) return null;
|
|
63
63
|
const impact = await (await sharedStore(path, process.env, { readOnly: true })).swapImpact(candidate, family);
|
|
@@ -68,7 +68,7 @@ async function swapImpact(candidate, family) {
|
|
|
68
68
|
}
|
|
69
69
|
async function libraryLicence(id) {
|
|
70
70
|
try {
|
|
71
|
-
const { discoverCacheDir, findListing } = await import("./src-
|
|
71
|
+
const { discoverCacheDir, findListing } = await import("./src-ULAQV67E.js");
|
|
72
72
|
const { entry } = await findListing(discoverCacheDir(void 0, process.env), id);
|
|
73
73
|
return entry.id === id ? entry.license : null;
|
|
74
74
|
} catch {
|
|
@@ -79,11 +79,11 @@ function workflowStateDir(project, state) {
|
|
|
79
79
|
return resolve(state ?? join(homedir(), ".youi", "workflow", shortHash(`${project.repo.root}\0${project.root}`)));
|
|
80
80
|
}
|
|
81
81
|
async function ingest(link) {
|
|
82
|
-
const { readLink } = await import("./ingest-
|
|
82
|
+
const { readLink } = await import("./ingest-X4MIF5F6.js");
|
|
83
83
|
return readLink(link, { allowLocal: false });
|
|
84
84
|
}
|
|
85
85
|
async function startRuleEditor(options) {
|
|
86
|
-
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-
|
|
86
|
+
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-VSWKGVFT.js");
|
|
87
87
|
const projectRoot = resolve(options.project);
|
|
88
88
|
const load = { ...options.config ? { configPath: resolve(options.config) } : {}, ...options.design ? { designRoot: resolve(options.design) } : {}, ...options.root ? { productRoot: resolve(options.root) } : {} };
|
|
89
89
|
const project = await loadProject(projectRoot, load);
|
|
@@ -18,11 +18,12 @@ import {
|
|
|
18
18
|
sameColor,
|
|
19
19
|
splitTopLevel,
|
|
20
20
|
tailwindTheme
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-4BQPCZLL.js";
|
|
22
22
|
import {
|
|
23
23
|
AST_GREP_LANGUAGES,
|
|
24
24
|
BUILT_IN_CHECKS,
|
|
25
25
|
ComponentContract,
|
|
26
|
+
GLOB_SYNTAX,
|
|
26
27
|
INVENTORY_ROLES,
|
|
27
28
|
ProjectConfig,
|
|
28
29
|
RouteConfig,
|
|
@@ -51,7 +52,7 @@ import {
|
|
|
51
52
|
toPosix,
|
|
52
53
|
unifiedDiff,
|
|
53
54
|
writeFileAtomic
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-M56633DV.js";
|
|
55
56
|
|
|
56
57
|
// ../scanner/src/parse.ts
|
|
57
58
|
import { Lang, parseAsync } from "@ast-grep/napi";
|
|
@@ -1113,8 +1114,8 @@ function clusterShapes(shapes, linkage = "complete", tolerance = DEFAULT_TOLERAN
|
|
|
1113
1114
|
}
|
|
1114
1115
|
|
|
1115
1116
|
// ../scanner/src/inventory/theme.ts
|
|
1116
|
-
import { readFile as readFile2 } from "node:fs/promises";
|
|
1117
|
-
import { join as join4 } from "node:path";
|
|
1117
|
+
import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
|
|
1118
|
+
import { dirname as dirname4, join as join4 } from "node:path";
|
|
1118
1119
|
import { Lang as Lang3, parseAsync as parseAsync2 } from "@ast-grep/napi";
|
|
1119
1120
|
var ROOT_FONT_SIZE = 16;
|
|
1120
1121
|
var PILL = 9999;
|
|
@@ -1222,12 +1223,14 @@ var Theme = class {
|
|
|
1222
1223
|
warnings;
|
|
1223
1224
|
/** Project declarations only: excludes implicit Tailwind defaults. */
|
|
1224
1225
|
declared;
|
|
1226
|
+
forms;
|
|
1225
1227
|
vars;
|
|
1226
|
-
constructor(vars, tailwind, warnings, declared = /* @__PURE__ */ new Map()) {
|
|
1228
|
+
constructor(vars, tailwind, warnings, declared = /* @__PURE__ */ new Map(), forms = null) {
|
|
1227
1229
|
this.vars = vars;
|
|
1228
1230
|
this.declared = declared;
|
|
1229
1231
|
this.tailwind = tailwind;
|
|
1230
1232
|
this.warnings = warnings;
|
|
1233
|
+
this.forms = forms;
|
|
1231
1234
|
}
|
|
1232
1235
|
variable(name) {
|
|
1233
1236
|
return this.vars.get(name);
|
|
@@ -1274,6 +1277,68 @@ function literal(node2) {
|
|
|
1274
1277
|
function pairsOf(object) {
|
|
1275
1278
|
return object.children().filter((c) => c.kind() === "pair" || c.kind() === "spread_element" || c.kind() === "method_definition" || c.kind() === "shorthand_property_identifier").map((node2) => ({ key: node2.kind() === "pair" ? keyText(node2.field("key")) : null, value: node2.kind() === "pair" ? node2.field("value") : null, node: node2 }));
|
|
1276
1279
|
}
|
|
1280
|
+
var FORMS = "@tailwindcss/forms";
|
|
1281
|
+
var formsMode = (text) => /strategy\s*:\s*["']?class/.test(text.slice(text.indexOf(FORMS))) ? "class" : "base";
|
|
1282
|
+
async function formsPluginOf(root, sheets, configFile) {
|
|
1283
|
+
for (const sheet of sheets) {
|
|
1284
|
+
const at = sheet.source.search(/@plugin\s+["']@tailwindcss\/forms["']/);
|
|
1285
|
+
if (at >= 0) return formsMode(sheet.source.slice(at, at + 200));
|
|
1286
|
+
}
|
|
1287
|
+
const configSource = configFile ? await readFile2(join4(root, configFile), "utf8").catch(() => null) : null;
|
|
1288
|
+
const texts = configSource ? [configSource, ...await presetSources(root, configSource)] : [];
|
|
1289
|
+
const found = texts.find((t) => t.includes(FORMS));
|
|
1290
|
+
if (found) return formsMode(found);
|
|
1291
|
+
for (let dir = root, up = 0; up < 6; dir = dirname4(dir), up++) {
|
|
1292
|
+
const pkg = await readFile2(join4(dir, "package.json"), "utf8").catch(() => null);
|
|
1293
|
+
if (pkg?.includes(`"${FORMS}"`)) return "unknown";
|
|
1294
|
+
if (await readFile2(join4(dir, ".git", "HEAD"), "utf8").then(() => true, () => false)) break;
|
|
1295
|
+
if (dirname4(dir) === dir) break;
|
|
1296
|
+
}
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
|
1299
|
+
async function presetSources(root, config) {
|
|
1300
|
+
const sources = [];
|
|
1301
|
+
const specifiers = [...config.matchAll(/(?:from\s+|require\()\s*["']([^"']+)["']/g)].map((m) => m[1]).filter((s) => !s.startsWith("tailwindcss") && s !== FORMS);
|
|
1302
|
+
const read = async (base) => {
|
|
1303
|
+
for (const ext of ["", ".ts", ".js", ".mjs", ".cjs", ".mts", "/tailwind.config.ts", "/tailwind.config.js", "/index.ts", "/index.js"]) {
|
|
1304
|
+
const text = await readFile2(base + ext, "utf8").catch(() => null);
|
|
1305
|
+
if (text !== null) return text;
|
|
1306
|
+
}
|
|
1307
|
+
return null;
|
|
1308
|
+
};
|
|
1309
|
+
for (const specifier of specifiers.slice(0, 10)) {
|
|
1310
|
+
if (specifier.startsWith(".")) {
|
|
1311
|
+
const text = await read(join4(root, specifier));
|
|
1312
|
+
if (text) sources.push(text);
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
const parts = specifier.split("/");
|
|
1316
|
+
const name = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
1317
|
+
const rest = parts.slice(specifier.startsWith("@") ? 2 : 1).join("/");
|
|
1318
|
+
for (let dir = root, up = 0; up < 6; dir = dirname4(dir), up++) {
|
|
1319
|
+
let found = null;
|
|
1320
|
+
for (const folder of ["packages", "libs", "config", "tooling"]) {
|
|
1321
|
+
for (const entry of await readdir2(join4(dir, folder)).catch(() => [])) {
|
|
1322
|
+
const pkg = await readFile2(join4(dir, folder, entry, "package.json"), "utf8").catch(() => null);
|
|
1323
|
+
let named2 = null;
|
|
1324
|
+
try {
|
|
1325
|
+
named2 = pkg ? JSON.parse(pkg).name : null;
|
|
1326
|
+
} catch {
|
|
1327
|
+
named2 = null;
|
|
1328
|
+
}
|
|
1329
|
+
if (named2 === name) found = join4(dir, folder, entry);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
if (found) {
|
|
1333
|
+
const text = await read(rest ? join4(found, rest) : found);
|
|
1334
|
+
if (text) sources.push(text);
|
|
1335
|
+
break;
|
|
1336
|
+
}
|
|
1337
|
+
if (dirname4(dir) === dir) break;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
return sources;
|
|
1341
|
+
}
|
|
1277
1342
|
async function readTailwindConfig(root) {
|
|
1278
1343
|
const vars = /* @__PURE__ */ new Map();
|
|
1279
1344
|
const warnings = [];
|
|
@@ -1344,7 +1409,7 @@ async function buildTheme(root, sheets, usesTailwindPackage) {
|
|
|
1344
1409
|
}
|
|
1345
1410
|
}
|
|
1346
1411
|
}
|
|
1347
|
-
return new Theme(vars, version, config.warnings, declared);
|
|
1412
|
+
return new Theme(vars, version, config.warnings, declared, version ? await formsPluginOf(root, sheets, config.file) : null);
|
|
1348
1413
|
}
|
|
1349
1414
|
|
|
1350
1415
|
// ../scanner/src/inventory/style.ts
|
|
@@ -1361,9 +1426,12 @@ var StyleAccumulator = class {
|
|
|
1361
1426
|
states = [];
|
|
1362
1427
|
preflight;
|
|
1363
1428
|
tag;
|
|
1364
|
-
|
|
1429
|
+
/** A form control whose unstyled padding a plugin may set, unread: unknown, never 0. */
|
|
1430
|
+
unsetUnknown;
|
|
1431
|
+
constructor(tag, preflight, unsetUnknown = false) {
|
|
1365
1432
|
this.tag = tag;
|
|
1366
1433
|
this.preflight = preflight;
|
|
1434
|
+
this.unsetUnknown = unsetUnknown;
|
|
1367
1435
|
}
|
|
1368
1436
|
/** Whether any declaration applied at all; an element nothing styles has no known padding or radius. */
|
|
1369
1437
|
touched = false;
|
|
@@ -1393,7 +1461,7 @@ var StyleAccumulator = class {
|
|
|
1393
1461
|
}
|
|
1394
1462
|
finish() {
|
|
1395
1463
|
const derived = [];
|
|
1396
|
-
const zero = this.touched && (this.preflight || !FORM_CONTROLS.has(this.tag ?? "")) ? 0 : null;
|
|
1464
|
+
const zero = this.touched && !this.unsetUnknown && (this.preflight || !FORM_CONTROLS.has(this.tag ?? "")) ? 0 : null;
|
|
1397
1465
|
const axis = (a, b) => {
|
|
1398
1466
|
const x = this.known(a);
|
|
1399
1467
|
const y = this.known(b);
|
|
@@ -1700,8 +1768,20 @@ function applyDeclaration(style, declaration, theme, selector) {
|
|
|
1700
1768
|
if (PADDING_SIDES[declaration.property]) for (const prop of PADDING_SIDES[declaration.property]) set(prop, length(value));
|
|
1701
1769
|
}
|
|
1702
1770
|
}
|
|
1771
|
+
var FORMS_CONTROLS = /* @__PURE__ */ new Set(["input", "select", "textarea"]);
|
|
1703
1772
|
function resolveClasses(classes, tag, theme, rules) {
|
|
1704
|
-
const
|
|
1773
|
+
const forms = FORMS_CONTROLS.has(tag ?? "") ? theme.forms === "base" || theme.forms === "class" && classes.some((c) => /^form-(?:input|select|textarea|multiselect)$/.test(c)) ? "styled" : theme.forms === "unknown" ? "unknown" : null : null;
|
|
1774
|
+
const style = new StyleAccumulator(tag, false, forms === "unknown");
|
|
1775
|
+
if (forms === "styled") {
|
|
1776
|
+
style.set("paddingTop", 8);
|
|
1777
|
+
style.set("paddingBottom", 8);
|
|
1778
|
+
style.set("paddingLeft", 12);
|
|
1779
|
+
style.set("paddingRight", tag === "select" ? 40 : 12);
|
|
1780
|
+
style.set("fontSize", 16);
|
|
1781
|
+
style.set("lineHeight", 24);
|
|
1782
|
+
style.set("border", 1);
|
|
1783
|
+
style.set("radius", 0);
|
|
1784
|
+
}
|
|
1705
1785
|
rules.apply(style, classes, theme);
|
|
1706
1786
|
let tailwindClasses = 0;
|
|
1707
1787
|
if (theme.tailwind) {
|
|
@@ -2108,6 +2188,12 @@ function expoRoute(file, appDir) {
|
|
|
2108
2188
|
}
|
|
2109
2189
|
function routeEntries(files, config) {
|
|
2110
2190
|
const entries = /* @__PURE__ */ new Map();
|
|
2191
|
+
const exact = /* @__PURE__ */ new Map();
|
|
2192
|
+
const globs = [];
|
|
2193
|
+
for (const m of config.strategy === "map" ? config.map : []) {
|
|
2194
|
+
if (GLOB_SYNTAX.test(m.file)) globs.push(m);
|
|
2195
|
+
else exact.set(m.file, [...exact.get(m.file) ?? [], ...m.routes]);
|
|
2196
|
+
}
|
|
2111
2197
|
for (const file of files) {
|
|
2112
2198
|
if (matchesAny(file, config.shell)) {
|
|
2113
2199
|
entries.set(file, { routes: [SHELL_ROUTE], shell: true });
|
|
@@ -2123,7 +2209,7 @@ function routeEntries(files, config) {
|
|
|
2123
2209
|
}
|
|
2124
2210
|
}
|
|
2125
2211
|
if (config.strategy === "map") {
|
|
2126
|
-
const routes =
|
|
2212
|
+
const routes = [...exact.get(file) ?? [], ...globs.filter((m) => matchesAny(file, [m.file])).flatMap((m) => m.routes)];
|
|
2127
2213
|
if (routes.length > 0) entries.set(file, { routes: [...new Set(routes)], shell: false });
|
|
2128
2214
|
}
|
|
2129
2215
|
}
|
|
@@ -3925,7 +4011,7 @@ function ruleRows(project) {
|
|
|
3925
4011
|
// ../scanner/src/watch.ts
|
|
3926
4012
|
import { existsSync, mkdtempSync, rmSync, watch, writeFileSync } from "node:fs";
|
|
3927
4013
|
import { tmpdir } from "node:os";
|
|
3928
|
-
import { dirname as
|
|
4014
|
+
import { dirname as dirname5, join as join8, relative as relative3, resolve as resolve4, sep } from "node:path";
|
|
3929
4015
|
var DEFAULT_DEBOUNCE_MS = 120;
|
|
3930
4016
|
var LIVE_TIMEOUT_MS = 1e4;
|
|
3931
4017
|
var PROBE_INTERVAL_MS = 50;
|
|
@@ -4028,8 +4114,8 @@ var ProjectWatcher = class _ProjectWatcher {
|
|
|
4028
4114
|
for (const w of this.watchers) w.close();
|
|
4029
4115
|
const { root, config, repo, system } = project;
|
|
4030
4116
|
const sourceDirs = covering(config.include.map((g) => resolve4(root, staticBase(g))).filter((d) => existsSync(d)));
|
|
4031
|
-
const definitionDirs = covering([
|
|
4032
|
-
const topLevel = [.../* @__PURE__ */ new Set([repo.root,
|
|
4117
|
+
const definitionDirs = covering([dirname5(system.config.tokens), system.config.components, system.config.rules, ...system.config.design ? [dirname5(system.config.design)] : []].map((p) => resolve4(repo.root, p)).filter((d) => existsSync(d) && d !== repo.root));
|
|
4118
|
+
const topLevel = [.../* @__PURE__ */ new Set([repo.root, dirname5(this.configFile), root])];
|
|
4033
4119
|
this.watchers = [
|
|
4034
4120
|
...sourceDirs.map((dir) => watch2(dir, { recursive: true }, (_event, name) => name && this.sourceChanged(project, join8(dir, name.toString())))),
|
|
4035
4121
|
...definitionDirs.map((dir) => watch2(dir, { recursive: true }, () => this.definitionsChanged())),
|
|
@@ -4041,7 +4127,7 @@ var ProjectWatcher = class _ProjectWatcher {
|
|
|
4041
4127
|
watchConfigOnly() {
|
|
4042
4128
|
const watch2 = this.options.watch ?? defaultWatch;
|
|
4043
4129
|
for (const w of this.watchers) w.close();
|
|
4044
|
-
this.watchers = [watch2(
|
|
4130
|
+
this.watchers = [watch2(dirname5(this.configFile), { recursive: true }, () => this.definitionsChanged())];
|
|
4045
4131
|
for (const w of this.watchers) w.on("error", (error) => this.watcherFailed(error));
|
|
4046
4132
|
void this.whenLive();
|
|
4047
4133
|
}
|
|
@@ -4257,21 +4343,22 @@ function readTemplate(source, offset) {
|
|
|
4257
4343
|
}
|
|
4258
4344
|
const parent = stack.at(-1);
|
|
4259
4345
|
if (parent && parent.firstChild === null) parent.firstChild = tag;
|
|
4346
|
+
const inside = parent ? parent.at : null;
|
|
4260
4347
|
const lower = tag.toLowerCase();
|
|
4261
4348
|
if (RAW_TEXT.has(lower) && !selfClosing) {
|
|
4262
4349
|
const close = source.indexOf(`</${lower}`, j);
|
|
4263
4350
|
const end = close < 0 ? source.length : close;
|
|
4264
4351
|
if (lower === "style") styles.push({ css: source.slice(j, end), line: positionAt(starts, j).line });
|
|
4265
|
-
found.push({ tag, index: i, attributes: attributes2, opened: null, text: null });
|
|
4352
|
+
found.push({ tag, index: i, attributes: attributes2, opened: null, text: null, parent: inside });
|
|
4266
4353
|
i = close < 0 ? source.length : source.indexOf(">", close) + 1 || source.length;
|
|
4267
4354
|
continue;
|
|
4268
4355
|
}
|
|
4269
|
-
const opened = selfClosing ? null : { tag, index: i, firstChild: null };
|
|
4356
|
+
const opened = selfClosing ? null : { tag, index: i, firstChild: null, at: found.length };
|
|
4270
4357
|
if (opened) stack.push(opened);
|
|
4271
|
-
found.push({ tag, index: i, attributes: attributes2, opened, text: opened ? textAt(source, j) : null });
|
|
4358
|
+
found.push({ tag, index: i, attributes: attributes2, opened, text: opened ? textAt(source, j) : null, parent: inside });
|
|
4272
4359
|
i = j;
|
|
4273
4360
|
}
|
|
4274
|
-
const tags = found.map(({ tag, index, attributes: attributes2, opened, text }) => ({ tag, ...positionAt(starts, index), attributes: attributes2, firstChild: opened?.firstChild ?? null, text }));
|
|
4361
|
+
const tags = found.map(({ tag, index, attributes: attributes2, opened, text, parent }) => ({ tag, ...positionAt(starts, index), attributes: attributes2, firstChild: opened?.firstChild ?? null, text, parent }));
|
|
4275
4362
|
return { tags, styles, problems };
|
|
4276
4363
|
}
|
|
4277
4364
|
function frontmatterOf(source) {
|
|
@@ -4744,6 +4831,23 @@ async function pathAliases(root, tsconfig) {
|
|
|
4744
4831
|
}
|
|
4745
4832
|
}
|
|
4746
4833
|
var position2 = (node2) => ({ line: node2.range().start.line + 1, column: node2.range().start.column + 1 });
|
|
4834
|
+
var COPY_OVERLAP = 0.6;
|
|
4835
|
+
var markupToken = (tag, classes) => classes.length > 0 ? `${tag}.${[...new Set(classes)].sort().join(".")}` : tag;
|
|
4836
|
+
function overlap2(a, b) {
|
|
4837
|
+
const shared = [...a].filter((t) => b.has(t)).length;
|
|
4838
|
+
return shared / (a.size + b.size - shared || 1);
|
|
4839
|
+
}
|
|
4840
|
+
function jsxMarkup(element) {
|
|
4841
|
+
const tag = element.field("name")?.text();
|
|
4842
|
+
if (!tag || !/^[a-z]/.test(tag)) return null;
|
|
4843
|
+
const container = element.kind() === "jsx_opening_element" ? element.parent() : null;
|
|
4844
|
+
const inside = /* @__PURE__ */ new Set();
|
|
4845
|
+
for (const child of container?.findAll({ rule: { any: [{ kind: "jsx_opening_element" }, { kind: "jsx_self_closing_element" }] } }) ?? []) {
|
|
4846
|
+
if (child.id() === element.id()) continue;
|
|
4847
|
+
inside.add(markupToken(child.field("name")?.text() ?? "", classValueOf(jsxClassAttribute(child)).certain));
|
|
4848
|
+
}
|
|
4849
|
+
return { tag, classes: [...new Set(classValueOf(jsxClassAttribute(element)).certain)].sort(), inside };
|
|
4850
|
+
}
|
|
4747
4851
|
var pascal = (text) => text.split(/[^A-Za-z0-9]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join("");
|
|
4748
4852
|
var packageOf = (specifier) => specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
4749
4853
|
var literalOf2 = (value) => value && "literal" in value ? String(value.literal) : null;
|
|
@@ -4807,6 +4911,11 @@ var ProjectPass = class {
|
|
|
4807
4911
|
target;
|
|
4808
4912
|
modules = /* @__PURE__ */ new Map();
|
|
4809
4913
|
astro = /* @__PURE__ */ new Map();
|
|
4914
|
+
/** Shaped plain classes not named for an element: members only once a look of a known role uses them (settleProvisional). */
|
|
4915
|
+
provisional = /* @__PURE__ */ new Set();
|
|
4916
|
+
/** A React definition's root element, for inlineCopies. */
|
|
4917
|
+
reactRoots = /* @__PURE__ */ new Map();
|
|
4918
|
+
copies = [];
|
|
4810
4919
|
sheets = [];
|
|
4811
4920
|
failed = [];
|
|
4812
4921
|
definitions = /* @__PURE__ */ new Map();
|
|
@@ -4902,7 +5011,7 @@ var ProjectPass = class {
|
|
|
4902
5011
|
const shaped = rule.declarations.some((d) => SHAPE_PROPERTIES.test(d.property));
|
|
4903
5012
|
for (const selector of splitTopLevel(prelude, ",")) {
|
|
4904
5013
|
const match = /^\.([a-z][a-z0-9]*(?:-[a-z0-9]+)*)(?:--([a-z0-9-]+))?$/.exec(selector.trim());
|
|
4905
|
-
if (!match
|
|
5014
|
+
if (!match) continue;
|
|
4906
5015
|
const [, name, modifier] = match;
|
|
4907
5016
|
const entry = plain2.get(name) ?? { line: rule.declarations[0]?.line ?? 1, modifiers: /* @__PURE__ */ new Set(), shaped: false };
|
|
4908
5017
|
if (modifier) entry.modifiers.add(modifier);
|
|
@@ -4924,7 +5033,12 @@ var ProjectPass = class {
|
|
|
4924
5033
|
prefixes.push(prefix);
|
|
4925
5034
|
for (const block of names) found.push({ name: block, role: roleOfBlock(block, prefix), ...blocks.get(block) });
|
|
4926
5035
|
}
|
|
4927
|
-
for (const [name, entry] of plain2)
|
|
5036
|
+
for (const [name, entry] of plain2) {
|
|
5037
|
+
if (!entry.shaped || found.some((f) => f.name === name)) continue;
|
|
5038
|
+
const role = roleOfClass(name);
|
|
5039
|
+
if (!role) this.provisional.add(name);
|
|
5040
|
+
found.push({ name, role, line: entry.line, modifiers: entry.modifiers });
|
|
5041
|
+
}
|
|
4928
5042
|
if (found.length === 0) continue;
|
|
4929
5043
|
const members = [];
|
|
4930
5044
|
for (const { name, role, line: line2, modifiers } of found.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -4938,10 +5052,36 @@ var ProjectPass = class {
|
|
|
4938
5052
|
this.kits.push({ id: kit, project: this.id, kind: "class-kit", path: sheet.file, ...prefixes.length === 1 ? { prefix: prefixes[0] } : {}, members });
|
|
4939
5053
|
}
|
|
4940
5054
|
}
|
|
5055
|
+
/**
|
|
5056
|
+
* Keep a provisional class only when it styles an element of a known role, with that role (the
|
|
5057
|
+
* one most of its looks have); drop the rest, so a layout class never counts as a component.
|
|
5058
|
+
*/
|
|
5059
|
+
settleProvisional() {
|
|
5060
|
+
for (const name of this.provisional) {
|
|
5061
|
+
const definition = this.blocks.get(name);
|
|
5062
|
+
if (!definition) continue;
|
|
5063
|
+
const roles = this.looks.filter((l) => l.definition === definition.entry.id).map((l) => l.role);
|
|
5064
|
+
const kit = this.kits.find((k) => k.id === definition.entry.kit);
|
|
5065
|
+
if (roles.length === 0) {
|
|
5066
|
+
this.definitions.delete(definition.entry.id);
|
|
5067
|
+
this.blocks.delete(name);
|
|
5068
|
+
if (kit) kit.members = kit.members.filter((m) => m.name !== definition.entry.name);
|
|
5069
|
+
continue;
|
|
5070
|
+
}
|
|
5071
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5072
|
+
for (const r of roles) counts.set(r, (counts.get(r) ?? 0) + 1);
|
|
5073
|
+
const role = [...counts].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))[0][0];
|
|
5074
|
+
definition.entry.role = role;
|
|
5075
|
+
const member = kit?.members.find((m) => m.name === definition.entry.name);
|
|
5076
|
+
if (member) member.role = role;
|
|
5077
|
+
}
|
|
5078
|
+
this.provisional.clear();
|
|
5079
|
+
for (let i = this.kits.length - 1; i >= 0; i--) if (this.kits[i].members.length === 0) this.kits.splice(i, 1);
|
|
5080
|
+
}
|
|
4941
5081
|
/* ---------------------------------------------------------- definitions */
|
|
4942
5082
|
kitOfClasses(classes) {
|
|
4943
5083
|
for (const name of classes) {
|
|
4944
|
-
const block = this.blocks.get(name);
|
|
5084
|
+
const block = this.provisional.has(name) ? void 0 : this.blocks.get(name);
|
|
4945
5085
|
if (block) return block.entry.kit;
|
|
4946
5086
|
}
|
|
4947
5087
|
return null;
|
|
@@ -5031,6 +5171,7 @@ var ProjectPass = class {
|
|
|
5031
5171
|
}
|
|
5032
5172
|
const range = declaration.node.range();
|
|
5033
5173
|
this.definitions.set(`${module.file}#${entry.name}`, { entry: def, recipe: found?.recipe ?? null, range: { start: range.start.index, end: range.end.index }, rootId: found?.root.id() ?? null });
|
|
5174
|
+
if (found) this.reactRoots.set(def.id, found.root);
|
|
5034
5175
|
}
|
|
5035
5176
|
}
|
|
5036
5177
|
for (const folder of [...cvaFolders].sort()) {
|
|
@@ -5066,6 +5207,70 @@ var ProjectPass = class {
|
|
|
5066
5207
|
this.definitions.set(`${file}#default`, { entry, recipe, range: null, rootId: root ? root.line * 1e5 + root.column : null });
|
|
5067
5208
|
}
|
|
5068
5209
|
}
|
|
5210
|
+
/* -------------------------------------------------------- inline copies */
|
|
5211
|
+
/**
|
|
5212
|
+
* Elements that write out a component's markup instead of rendering it: in another file, the
|
|
5213
|
+
* component's root tag with at least its root classes, and inside it at least COPY_OVERLAP of the
|
|
5214
|
+
* same elements (each a tag with its classes). A component whose root has no class, or holds
|
|
5215
|
+
* fewer than two elements, has no markup distinct enough to recognise.
|
|
5216
|
+
*/
|
|
5217
|
+
async inlineCopies() {
|
|
5218
|
+
const components = [];
|
|
5219
|
+
for (const definition of this.definitions.values()) {
|
|
5220
|
+
const { entry } = definition;
|
|
5221
|
+
if (entry.kind === "react") {
|
|
5222
|
+
const root = this.reactRoots.get(entry.id);
|
|
5223
|
+
const markup = root ? jsxMarkup(root) : null;
|
|
5224
|
+
if (markup) components.push({ id: entry.id, file: entry.file, markup });
|
|
5225
|
+
} else if (entry.kind === "astro") {
|
|
5226
|
+
const astro = this.astro.get(entry.file);
|
|
5227
|
+
const top = astro?.tags.flatMap((t, i) => t.parent === null && !["style", "script", "slot", "fragment"].includes(t.tag.toLowerCase()) ? [i] : []) ?? [];
|
|
5228
|
+
const at = top.length === 1 && /^[a-z]/.test(astro.tags[top[0]].tag) ? top[0] : -1;
|
|
5229
|
+
const markup = astro && at >= 0 ? await this.astroMarkup(astro, at) : null;
|
|
5230
|
+
if (markup) components.push({ id: entry.id, file: entry.file, markup });
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
const usable = components.filter((c) => c.markup.classes.length > 0 && c.markup.inside.size >= 2);
|
|
5234
|
+
if (usable.length === 0) return;
|
|
5235
|
+
const byTag = /* @__PURE__ */ new Map();
|
|
5236
|
+
for (const c of usable) byTag.set(c.markup.tag, [...byTag.get(c.markup.tag) ?? [], c]);
|
|
5237
|
+
const consider = (file, at, tag, classes, markup) => {
|
|
5238
|
+
const candidates = (byTag.get(tag) ?? []).filter((c) => c.file !== file && c.markup.classes.every((k) => classes.includes(k)));
|
|
5239
|
+
if (candidates.length === 0) return;
|
|
5240
|
+
return (async () => {
|
|
5241
|
+
const found = await markup();
|
|
5242
|
+
if (!found) return;
|
|
5243
|
+
const best = candidates.map((c) => ({ c, score: overlap2(c.markup.inside, found.inside) })).filter((m) => m.score >= COPY_OVERLAP).sort((a, b) => b.score - a.score)[0];
|
|
5244
|
+
if (best) this.copies.push({ project: this.id, component: best.c.id, file, ...at });
|
|
5245
|
+
})();
|
|
5246
|
+
};
|
|
5247
|
+
for (const module of this.sortedModules()) {
|
|
5248
|
+
if (module.lang !== "tsx") continue;
|
|
5249
|
+
for (const element of module.root.root().findAll({ rule: { any: [{ kind: "jsx_opening_element" }, { kind: "jsx_self_closing_element" }] } })) {
|
|
5250
|
+
const tag = element.field("name")?.text() ?? "";
|
|
5251
|
+
if (!/^[a-z]/.test(tag)) continue;
|
|
5252
|
+
await consider(module.file, position2(element), tag, classValueOf(jsxClassAttribute(element)).certain, () => jsxMarkup(element));
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
for (const [file, astro] of [...this.astro].sort(([a], [b]) => a.localeCompare(b))) {
|
|
5256
|
+
for (let i = 0; i < astro.tags.length; i++) {
|
|
5257
|
+
const tag = astro.tags[i];
|
|
5258
|
+
if (!/^[a-z]/.test(tag.tag)) continue;
|
|
5259
|
+
await consider(file, { line: tag.line, column: tag.column }, tag.tag, (await this.templateClasses(tag)).certain, () => this.astroMarkup(astro, i));
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
async astroMarkup(astro, at) {
|
|
5264
|
+
const root = astro.tags[at];
|
|
5265
|
+
if (!root) return null;
|
|
5266
|
+
const inside = /* @__PURE__ */ new Set();
|
|
5267
|
+
for (let j = at + 1; j < astro.tags.length; j++) {
|
|
5268
|
+
let up = astro.tags[j].parent;
|
|
5269
|
+
while (up !== null && up !== at) up = astro.tags[up].parent;
|
|
5270
|
+
if (up === at) inside.add(markupToken(astro.tags[j].tag, (await this.templateClasses(astro.tags[j])).certain));
|
|
5271
|
+
}
|
|
5272
|
+
return { tag: root.tag, classes: [...new Set((await this.templateClasses(root)).certain)].sort(), inside };
|
|
5273
|
+
}
|
|
5069
5274
|
/* ------------------------------------------------------------------ looks */
|
|
5070
5275
|
addLook(input) {
|
|
5071
5276
|
const resolved = resolveClasses(input.classes, input.rootTag, this.theme, this.rulesFor(input.file));
|
|
@@ -5173,7 +5378,8 @@ var ProjectPass = class {
|
|
|
5173
5378
|
}
|
|
5174
5379
|
intrinsicLook(file, at, tag, props, site, inside, label) {
|
|
5175
5380
|
let role = roleOfIntrinsic(tag, props);
|
|
5176
|
-
const
|
|
5381
|
+
const named2 = site.certain.filter((c) => this.blocks.has(c));
|
|
5382
|
+
const block = this.blocks.get(named2.find((c) => !this.provisional.has(c)) ?? named2[0] ?? "") ?? null;
|
|
5177
5383
|
role ??= block?.entry.role ?? null;
|
|
5178
5384
|
if (!role || role === inside) return;
|
|
5179
5385
|
const recipe = { kind: "class", tag, classes: [...new Set(site.certain)], label: /^(?:input|img|hr|br)$/.test(tag) ? null : label };
|
|
@@ -5409,8 +5615,10 @@ async function readProject(target, options = {}) {
|
|
|
5409
5615
|
pass.classKits();
|
|
5410
5616
|
await pass.reactDefinitions();
|
|
5411
5617
|
await pass.astroDefinitions();
|
|
5618
|
+
await pass.inlineCopies();
|
|
5412
5619
|
await pass.collectLooks();
|
|
5413
5620
|
await pass.storyLooks();
|
|
5621
|
+
pass.settleProvisional();
|
|
5414
5622
|
return pass;
|
|
5415
5623
|
}
|
|
5416
5624
|
async function collectProject(target, options = {}) {
|
|
@@ -5419,7 +5627,7 @@ async function collectProject(target, options = {}) {
|
|
|
5419
5627
|
const definitions = [...pass.definitions.values()].map((d) => d.entry).sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.name.localeCompare(b.name));
|
|
5420
5628
|
const primitives = [...pass.primitives].map(([pkg, p]) => ({ package: pkg, project: target.id, exports: [...p.exports].sort(), count: p.count, sites: p.sites.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.column - b.column) })).sort((a, b) => a.package.localeCompare(b.package));
|
|
5421
5629
|
const looks = pass.looks.sort(byPosition);
|
|
5422
|
-
return { id: target.id, target, commit: git3.commit, failed: pass.failed.sort((a, b) => a.file.localeCompare(b.file)), warnings: pass.theme.warnings, definitions, kits: pass.kits.sort((a, b) => a.id.localeCompare(b.id)), primitives, looks, kitImports: pass.kitImports, stories: pass.stories };
|
|
5630
|
+
return { id: target.id, target, commit: git3.commit, failed: pass.failed.sort((a, b) => a.file.localeCompare(b.file)), warnings: pass.theme.warnings, definitions, kits: pass.kits.sort((a, b) => a.id.localeCompare(b.id)), primitives, looks, kitImports: pass.kitImports, stories: pass.stories, copies: pass.copies.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.column - b.column) };
|
|
5423
5631
|
}
|
|
5424
5632
|
|
|
5425
5633
|
// ../scanner/src/inventory/target.ts
|
|
@@ -5641,6 +5849,7 @@ async function buildInventory(dirs, options = {}) {
|
|
|
5641
5849
|
looks: allLooks,
|
|
5642
5850
|
families,
|
|
5643
5851
|
flags: flagsOf(projects),
|
|
5852
|
+
copies: projects.flatMap((p) => p.copies),
|
|
5644
5853
|
summary: {
|
|
5645
5854
|
looks: uses.length,
|
|
5646
5855
|
clustered: uses.filter((l) => l.family !== null).length,
|
|
@@ -5919,7 +6128,7 @@ import { rmSync as rmSync2 } from "node:fs";
|
|
|
5919
6128
|
import { createHash as createHash2 } from "node:crypto";
|
|
5920
6129
|
import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
5921
6130
|
import { homedir as homedir2 } from "node:os";
|
|
5922
|
-
import { dirname as
|
|
6131
|
+
import { dirname as dirname6, join as join13 } from "node:path";
|
|
5923
6132
|
var SPECIMEN_FORMAT = "youiyoux.specimens/5";
|
|
5924
6133
|
var newStats = () => ({ tailwindCompiles: 0, bundles: 0, hits: 0, misses: 0 });
|
|
5925
6134
|
function defaultCacheDir(env = process.env) {
|
|
@@ -5961,7 +6170,7 @@ function specimenKey(root, commit, files, recipes) {
|
|
|
5961
6170
|
return hash.digest("hex").slice(0, 24);
|
|
5962
6171
|
}
|
|
5963
6172
|
function writeJsonAtomic(file, value) {
|
|
5964
|
-
mkdirSync(
|
|
6173
|
+
mkdirSync(dirname6(file), { recursive: true });
|
|
5965
6174
|
writeFileSync2(`${file}.${process.pid}.tmp`, JSON.stringify(value));
|
|
5966
6175
|
renameSync(`${file}.${process.pid}.tmp`, file);
|
|
5967
6176
|
}
|
|
@@ -5995,7 +6204,7 @@ var SpecimenCache = class {
|
|
|
5995
6204
|
// ../scanner/src/specimens/css.ts
|
|
5996
6205
|
import { createRequire as createRequire2 } from "node:module";
|
|
5997
6206
|
import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
5998
|
-
import { basename as basename3, dirname as
|
|
6207
|
+
import { basename as basename3, dirname as dirname7, extname, join as join14, posix as posix5, resolve as resolve6 } from "node:path";
|
|
5999
6208
|
import { Worker } from "node:worker_threads";
|
|
6000
6209
|
var SCHEMES = ["light", "dark"];
|
|
6001
6210
|
var TAILWIND_TIMEOUT_MS = 3e4;
|
|
@@ -6030,7 +6239,7 @@ var isFile = (path) => {
|
|
|
6030
6239
|
function resolveSheet(root, from, specifier, aliases) {
|
|
6031
6240
|
let rel = null;
|
|
6032
6241
|
if (specifier.startsWith(".") && !within(root, from)) {
|
|
6033
|
-
const target = resolve6(
|
|
6242
|
+
const target = resolve6(dirname7(from), specifier);
|
|
6034
6243
|
if (!inPackage(target)) return { refused: `"${specifier}" leaves the package ${displayPath(root, from)}` };
|
|
6035
6244
|
return existsSync3(target) ? { path: target } : null;
|
|
6036
6245
|
}
|
|
@@ -7356,7 +7565,7 @@ async function projectTheme(root) {
|
|
|
7356
7565
|
|
|
7357
7566
|
// ../scanner/src/specimens/preview-bundle.ts
|
|
7358
7567
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
7359
|
-
import { basename as basename4, dirname as
|
|
7568
|
+
import { basename as basename4, dirname as dirname8, isAbsolute as isAbsolute3, join as join17, resolve as resolve9, sep as sep2 } from "node:path";
|
|
7360
7569
|
var NAMESPACE2 = "youi-preview";
|
|
7361
7570
|
var GUARDED2 = "youiPreviewGuarded";
|
|
7362
7571
|
var ENTRY2 = "youi-preview.js";
|
|
@@ -7592,7 +7801,7 @@ async function bundlePreview(job, options = {}) {
|
|
|
7592
7801
|
const at = args.importer.lastIndexOf(`${sep2}node_modules${sep2}`) + `${sep2}node_modules${sep2}`.length;
|
|
7593
7802
|
const rest = args.importer.slice(at).split(sep2);
|
|
7594
7803
|
const base = args.importer.slice(0, at) + rest.slice(0, rest[0].startsWith("@") ? 2 : 1).join(sep2);
|
|
7595
|
-
const target = resolve9(
|
|
7804
|
+
const target = resolve9(dirname8(args.importer), args.path);
|
|
7596
7805
|
if (target.startsWith(base + sep2)) return void 0;
|
|
7597
7806
|
}
|
|
7598
7807
|
const again = (path, resolveDir) => build.resolve(path, { importer: args.importer, resolveDir, kind: args.kind, pluginData: { [GUARDED2]: true }, with: args.with });
|
|
@@ -7769,7 +7978,7 @@ import { execFile as execFile3 } from "node:child_process";
|
|
|
7769
7978
|
import { createHash as createHash3 } from "node:crypto";
|
|
7770
7979
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync6, rmSync as rmSync3, statSync as statSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7771
7980
|
import { createRequire as createRequire3 } from "node:module";
|
|
7772
|
-
import { dirname as
|
|
7981
|
+
import { dirname as dirname9, extname as extname2, isAbsolute as isAbsolute4, join as join18, relative as relative5 } from "node:path";
|
|
7773
7982
|
import { promisify as promisify3 } from "node:util";
|
|
7774
7983
|
var SHOTS_FORMAT = "youiyoux.shots/4";
|
|
7775
7984
|
var SHOT_WIDTHS = [1280, 390];
|
|
@@ -7928,7 +8137,7 @@ var Eyes = class {
|
|
|
7928
8137
|
}
|
|
7929
8138
|
async open() {
|
|
7930
8139
|
if (this.browser) return this.browser;
|
|
7931
|
-
const { launchBrowser } = await import("./src-
|
|
8140
|
+
const { launchBrowser } = await import("./src-DFXQLHEP.js");
|
|
7932
8141
|
try {
|
|
7933
8142
|
this.browser = await launchBrowser(this.options.executablePath, { purpose: { what: "youiyoux render", command: "youiyoux render" }, ...this.options.download === false ? { download: false } : {}, ...this.options.log ? { log: this.options.log } : {} });
|
|
7934
8143
|
} catch (error) {
|
|
@@ -8133,7 +8342,7 @@ async function renderShots(rootDir, targets, options = {}) {
|
|
|
8133
8342
|
for (const key of [join18(root, file), join18(rootDir, file)]) overlay.set(key, contents);
|
|
8134
8343
|
if (contents !== null) {
|
|
8135
8344
|
const copy = join18(baseSources, file);
|
|
8136
|
-
mkdirSync2(
|
|
8345
|
+
mkdirSync2(dirname9(copy), { recursive: true });
|
|
8137
8346
|
writeFileSync4(copy, contents);
|
|
8138
8347
|
}
|
|
8139
8348
|
}
|
|
@@ -8257,7 +8466,7 @@ function shotsText(report, again = (t) => `run youiyoux render${t ? ` ${t}` : ""
|
|
|
8257
8466
|
const moved = c.diff.shots.filter((d) => d.changed > 0);
|
|
8258
8467
|
lines.push(moved.length === 0 ? ` before/after against ${c.diff.base}: no visible change` : ` before/after against ${c.diff.base}: pixels changed ${moved.map((d) => `${percent(d.changed)} in ${d.scheme} ${d.width}`).join(", ")}`);
|
|
8259
8468
|
for (const d of moved) lines.push(` diff ${d.scheme} ${d.width}: ${d.diff}`);
|
|
8260
|
-
if (c.diff.shots[0]) lines.push(` before images: ${
|
|
8469
|
+
if (c.diff.shots[0]) lines.push(` before images: ${dirname9(c.diff.shots[0].before)}`);
|
|
8261
8470
|
} else lines.push(` before/after: ${c.diff.none}`);
|
|
8262
8471
|
if (c.a11y.length === 0) lines.push(" accessibility: no issues axe can find (WCAG 2.2 A and AA, both schemes and widths)");
|
|
8263
8472
|
else {
|
|
@@ -8652,7 +8861,7 @@ import { randomBytes } from "node:crypto";
|
|
|
8652
8861
|
import { existsSync as existsSync7, realpathSync as realpathSync2 } from "node:fs";
|
|
8653
8862
|
import { chmod, mkdir as mkdir2, rename as rename3, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
8654
8863
|
import { homedir as homedir3 } from "node:os";
|
|
8655
|
-
import { basename as basename5, dirname as
|
|
8864
|
+
import { basename as basename5, dirname as dirname10, join as join20 } from "node:path";
|
|
8656
8865
|
import { chromium } from "playwright-core";
|
|
8657
8866
|
function sessionFile(root, env = process.env) {
|
|
8658
8867
|
let real = root;
|
|
@@ -8670,8 +8879,8 @@ function chosenSession(root, named2, env = process.env) {
|
|
|
8670
8879
|
return existsSync7(file) ? { file, saved: true } : null;
|
|
8671
8880
|
}
|
|
8672
8881
|
async function writePrivate(file, content) {
|
|
8673
|
-
await mkdir2(
|
|
8674
|
-
const temp = join20(
|
|
8882
|
+
await mkdir2(dirname10(file), { recursive: true, mode: 448 });
|
|
8883
|
+
const temp = join20(dirname10(file), `.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
|
|
8675
8884
|
try {
|
|
8676
8885
|
await writeFile2(temp, content, { encoding: "utf8", mode: 384 });
|
|
8677
8886
|
await chmod(temp, 384);
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
loadPackage,
|
|
5
5
|
readTryIndex,
|
|
6
6
|
send
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NG73FB4O.js";
|
|
8
8
|
import {
|
|
9
9
|
writeFileAtomic
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-M56633DV.js";
|
|
11
11
|
|
|
12
12
|
// ../../apps/web/scripts/discover-thumbs.ts
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|