youiyoux 0.1.0 → 0.1.3
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/README.md +24 -14
- package/dist/chunks/{chunk-FUB7B3VK.js → chunk-74KBRI2H.js} +1 -1
- package/dist/chunks/{chunk-ZLRFD5JI.js → chunk-C3TSTYP7.js} +68 -7
- package/dist/chunks/{chunk-3ZHGONNA.js → chunk-L5BV4PI7.js} +399 -37
- package/dist/chunks/{src-7ENJHYG4.js → chunk-OIHNEGWH.js} +278 -78
- package/dist/chunks/{chunk-UXLATKEQ.js → chunk-RTOTNSOV.js} +484 -141
- package/dist/chunks/{chunk-UHPK62Q5.js → chunk-UEB6MJDX.js} +75 -10
- package/dist/chunks/{src-VEHGMKYV.js → src-DS43LCRA.js} +2 -2
- package/dist/chunks/src-U5NTDPUX.js +148 -0
- package/dist/chunks/{src-WQWYJ6IQ.js → src-YGEZCUAO.js} +48 -6
- package/dist/chunks/{src-4KFNL3MY.js → src-YUC5PIDK.js} +6 -2
- package/dist/chunks/{src-B742AYFC.js → src-ZS76UD7E.js} +30 -2
- package/dist/schema/youi.request.schema.json +229 -0
- package/dist/youi.js +5 -5
- package/dist/youiyoux.js +5 -5
- package/package.json +10 -12
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
unifiedDiff,
|
|
46
46
|
validateTokenSets,
|
|
47
47
|
writeFileAtomic
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-C3TSTYP7.js";
|
|
49
49
|
import {
|
|
50
50
|
__commonJS,
|
|
51
51
|
__toESM
|
|
@@ -8183,7 +8183,7 @@ async function bundle(sources, { req, parse: userParse, yamlToMomoa }) {
|
|
|
8183
8183
|
};
|
|
8184
8184
|
const originalSourceLength = sources.length;
|
|
8185
8185
|
const origin = sources[0].filename;
|
|
8186
|
-
let
|
|
8186
|
+
let document2 = {};
|
|
8187
8187
|
for (let i = 0; i < sources.length; i++) {
|
|
8188
8188
|
const resolved = {
|
|
8189
8189
|
...sources[i],
|
|
@@ -8195,8 +8195,8 @@ async function bundle(sources, { req, parse: userParse, yamlToMomoa }) {
|
|
|
8195
8195
|
if (typeof resolved.src !== "string") {
|
|
8196
8196
|
resolved.src = print(resolved.document, { indent: 2 });
|
|
8197
8197
|
}
|
|
8198
|
-
if (!
|
|
8199
|
-
|
|
8198
|
+
if (!document2.type) {
|
|
8199
|
+
document2 = resolved.document;
|
|
8200
8200
|
}
|
|
8201
8201
|
cache[sources[i].filename.href] = resolved;
|
|
8202
8202
|
await traverseAsync(resolved.document, {
|
|
@@ -8222,9 +8222,9 @@ async function bundle(sources, { req, parse: userParse, yamlToMomoa }) {
|
|
|
8222
8222
|
});
|
|
8223
8223
|
if (i > 0) {
|
|
8224
8224
|
if (i < originalSourceLength) {
|
|
8225
|
-
|
|
8225
|
+
document2 = mergeDocuments([document2, resolved.document]);
|
|
8226
8226
|
} else {
|
|
8227
|
-
let $defs = getObjMember(
|
|
8227
|
+
let $defs = getObjMember(document2.body, "$defs");
|
|
8228
8228
|
if (!$defs) {
|
|
8229
8229
|
const $defsMember = {
|
|
8230
8230
|
type: "Member",
|
|
@@ -8233,7 +8233,7 @@ async function bundle(sources, { req, parse: userParse, yamlToMomoa }) {
|
|
|
8233
8233
|
loc: VIRTUAL_LOC
|
|
8234
8234
|
};
|
|
8235
8235
|
$defs = $defsMember.value;
|
|
8236
|
-
|
|
8236
|
+
document2.body.members.push($defsMember);
|
|
8237
8237
|
}
|
|
8238
8238
|
$defs.members.push({
|
|
8239
8239
|
type: "Member",
|
|
@@ -8245,7 +8245,7 @@ async function bundle(sources, { req, parse: userParse, yamlToMomoa }) {
|
|
|
8245
8245
|
}
|
|
8246
8246
|
}
|
|
8247
8247
|
return {
|
|
8248
|
-
document,
|
|
8248
|
+
document: document2,
|
|
8249
8249
|
sources: cache
|
|
8250
8250
|
};
|
|
8251
8251
|
}
|
|
@@ -10855,10 +10855,10 @@ function processTokens(rootSource, { config, logger, sourceByFilename, resolveAl
|
|
|
10855
10855
|
}
|
|
10856
10856
|
|
|
10857
10857
|
// ../../node_modules/.pnpm/@terrazzo+parser@2.7.1_yaml-to-momoa@0.1.0/node_modules/@terrazzo/parser/dist/resolver/normalize.js
|
|
10858
|
-
async function normalizeResolver(
|
|
10858
|
+
async function normalizeResolver(document2, { logger, filename, req, src, yamlToMomoa }) {
|
|
10859
10859
|
const resolverBundle = await bundle([{ filename, src }], { req, yamlToMomoa });
|
|
10860
10860
|
const resolverSource = evaluate(resolverBundle.document);
|
|
10861
|
-
replaceNode(
|
|
10861
|
+
replaceNode(document2, resolverBundle.document);
|
|
10862
10862
|
for (const set2 of Object.values(resolverSource.sets ?? {})) {
|
|
10863
10863
|
for (const source of set2.sources) {
|
|
10864
10864
|
resolvePartials(source, { resolver: resolverSource, logger });
|
|
@@ -10883,7 +10883,7 @@ async function normalizeResolver(document, { logger, filename, req, src, yamlToM
|
|
|
10883
10883
|
resolutionOrder: resolverSource.resolutionOrder,
|
|
10884
10884
|
_source: {
|
|
10885
10885
|
filename,
|
|
10886
|
-
document
|
|
10886
|
+
document: document2
|
|
10887
10887
|
}
|
|
10888
10888
|
};
|
|
10889
10889
|
}
|
|
@@ -11311,12 +11311,12 @@ async function loadResolver(inputs, { config, logger, req, yamlToMomoa }) {
|
|
|
11311
11311
|
label: "init"
|
|
11312
11312
|
};
|
|
11313
11313
|
for (const input of inputs) {
|
|
11314
|
-
let
|
|
11314
|
+
let document2;
|
|
11315
11315
|
if (typeof input.src === "string") {
|
|
11316
11316
|
if (maybeRawJSON(input.src)) {
|
|
11317
|
-
|
|
11317
|
+
document2 = toMomoa(input.src);
|
|
11318
11318
|
} else if (yamlToMomoa) {
|
|
11319
|
-
|
|
11319
|
+
document2 = yamlToMomoa(input.src);
|
|
11320
11320
|
} else {
|
|
11321
11321
|
logger.error({
|
|
11322
11322
|
...entry,
|
|
@@ -11329,14 +11329,14 @@ async function loadResolver(inputs, { config, logger, req, yamlToMomoa }) {
|
|
|
11329
11329
|
});
|
|
11330
11330
|
}
|
|
11331
11331
|
} else if (input.src && typeof input.src === "object") {
|
|
11332
|
-
|
|
11332
|
+
document2 = toMomoa(JSON.stringify(input.src, void 0, 2));
|
|
11333
11333
|
} else {
|
|
11334
11334
|
logger.error({
|
|
11335
11335
|
...entry,
|
|
11336
11336
|
message: `Could not parse ${input.filename}. Is this valid JSON or YAML?`
|
|
11337
11337
|
});
|
|
11338
11338
|
}
|
|
11339
|
-
if (!
|
|
11339
|
+
if (!document2 || !isLikelyResolver(document2)) {
|
|
11340
11340
|
continue;
|
|
11341
11341
|
}
|
|
11342
11342
|
if (inputs.length > 1) {
|
|
@@ -11345,7 +11345,7 @@ async function loadResolver(inputs, { config, logger, req, yamlToMomoa }) {
|
|
|
11345
11345
|
message: `Resolver must be the only input, found ${inputs.length} sources.`
|
|
11346
11346
|
});
|
|
11347
11347
|
}
|
|
11348
|
-
resolverDoc =
|
|
11348
|
+
resolverDoc = document2;
|
|
11349
11349
|
break;
|
|
11350
11350
|
}
|
|
11351
11351
|
let resolver;
|
|
@@ -11629,7 +11629,7 @@ function simpleFlatten(tokens, { logger }) {
|
|
|
11629
11629
|
async function loadSources(inputs, { config, logger, req, continueOnError, yamlToMomoa, resolveAliases: resolveAliases3 = true, transform: transform2 }) {
|
|
11630
11630
|
const entry = { group: "parser", label: "init" };
|
|
11631
11631
|
const firstLoad = performance.now();
|
|
11632
|
-
let
|
|
11632
|
+
let document2 = {};
|
|
11633
11633
|
const sources = inputs.map((input, i) => ({
|
|
11634
11634
|
...input,
|
|
11635
11635
|
document: {},
|
|
@@ -11643,7 +11643,7 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
11643
11643
|
parse: transform2 ? transformer(transform2) : void 0,
|
|
11644
11644
|
yamlToMomoa
|
|
11645
11645
|
});
|
|
11646
|
-
|
|
11646
|
+
document2 = result.document;
|
|
11647
11647
|
sourceByFilename = result.sources;
|
|
11648
11648
|
for (const [filename, source] of Object.entries(result.sources)) {
|
|
11649
11649
|
const i = sources.findIndex((s) => s.filename.href === filename);
|
|
@@ -11670,8 +11670,8 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
11670
11670
|
logger.debug({ ...entry, message: `JSON loaded`, timing: performance.now() - firstLoad });
|
|
11671
11671
|
const rootSource = {
|
|
11672
11672
|
filename: sources[0].filename,
|
|
11673
|
-
document,
|
|
11674
|
-
src: print(
|
|
11673
|
+
document: document2,
|
|
11674
|
+
src: print(document2, { indent: 2 }).replaceAll(String.raw`\/`, "/")
|
|
11675
11675
|
};
|
|
11676
11676
|
return {
|
|
11677
11677
|
tokens: processTokens(rootSource, {
|
|
@@ -11686,17 +11686,17 @@ async function loadSources(inputs, { config, logger, req, continueOnError, yamlT
|
|
|
11686
11686
|
}
|
|
11687
11687
|
function transformer(transform2) {
|
|
11688
11688
|
return async (src, filename) => {
|
|
11689
|
-
let
|
|
11689
|
+
let document2 = toMomoa(src);
|
|
11690
11690
|
let lastPath = "#/";
|
|
11691
11691
|
let last$type;
|
|
11692
11692
|
if (transform2.root) {
|
|
11693
|
-
const result = transform2.root(
|
|
11693
|
+
const result = transform2.root(document2, { filename, parent: void 0, path: [] });
|
|
11694
11694
|
if (result) {
|
|
11695
|
-
|
|
11695
|
+
document2 = result;
|
|
11696
11696
|
}
|
|
11697
11697
|
}
|
|
11698
|
-
const isResolver = isLikelyResolver(
|
|
11699
|
-
traverse(
|
|
11698
|
+
const isResolver = isLikelyResolver(document2);
|
|
11699
|
+
traverse(document2, {
|
|
11700
11700
|
enter(node2, parent, rawPath) {
|
|
11701
11701
|
const path = isResolver ? filterResolverPaths(rawPath) : rawPath;
|
|
11702
11702
|
if (node2.type !== "Object" || path.length === 0) {
|
|
@@ -11729,7 +11729,7 @@ function transformer(transform2) {
|
|
|
11729
11729
|
}
|
|
11730
11730
|
}
|
|
11731
11731
|
});
|
|
11732
|
-
return
|
|
11732
|
+
return document2;
|
|
11733
11733
|
};
|
|
11734
11734
|
}
|
|
11735
11735
|
|
|
@@ -13213,8 +13213,8 @@ function refs(sources, inline) {
|
|
|
13213
13213
|
return [];
|
|
13214
13214
|
});
|
|
13215
13215
|
}
|
|
13216
|
-
function resolverLayout(
|
|
13217
|
-
const doc =
|
|
13216
|
+
function resolverLayout(document2, themeModifier) {
|
|
13217
|
+
const doc = document2 ?? {};
|
|
13218
13218
|
const inline = { count: 0 };
|
|
13219
13219
|
const order = (doc.resolutionOrder ?? []).map((entry) => /^#\/sets\/(.+)$/.exec(String(entry?.$ref ?? ""))?.[1]).filter((name) => name !== void 0);
|
|
13220
13220
|
const setNames = order.length > 0 ? order : Object.keys(doc.sets ?? {});
|
|
@@ -13588,13 +13588,13 @@ var YOUI_TYPES = /* @__PURE__ */ new Set(["spring", "focusRing"]);
|
|
|
13588
13588
|
async function validateSets(repoRoot, system, resolverText) {
|
|
13589
13589
|
const resolverFile = join2(repoRoot, system.tokens);
|
|
13590
13590
|
const where2 = (file) => toPosix(relative(repoRoot, file));
|
|
13591
|
-
let
|
|
13591
|
+
let document2;
|
|
13592
13592
|
try {
|
|
13593
|
-
|
|
13593
|
+
document2 = JSON.parse(resolverText);
|
|
13594
13594
|
} catch (error) {
|
|
13595
13595
|
throw new DefinitionError(where2(resolverFile), [`not valid JSON: ${error instanceof Error ? error.message : String(error)}`]);
|
|
13596
13596
|
}
|
|
13597
|
-
const files = resolverLayout(
|
|
13597
|
+
const files = resolverLayout(document2, system.themeModifier).files.map((ref) => join2(dirname2(resolverFile), ref));
|
|
13598
13598
|
const sources = await Promise.all(
|
|
13599
13599
|
files.map(async (file) => {
|
|
13600
13600
|
try {
|
|
@@ -15902,8 +15902,8 @@ var ExportOrigins = class {
|
|
|
15902
15902
|
const found = binding ? await follow(binding.specifier, binding.imported) : null;
|
|
15903
15903
|
if (!found) return null;
|
|
15904
15904
|
const change = this.changes.get(found.old);
|
|
15905
|
-
const
|
|
15906
|
-
return { ...found, next: found.next === null ? null :
|
|
15905
|
+
const rename2 = change.renameBarrels || this.elements.isOwned(file) || this.elements.implementationFiles.has(file);
|
|
15906
|
+
return { ...found, next: found.next === null ? null : rename2 && name === found.old ? change.to : name };
|
|
15907
15907
|
}
|
|
15908
15908
|
for (const specifier of module.starExports) {
|
|
15909
15909
|
const found = await follow(specifier, name);
|
|
@@ -20749,7 +20749,7 @@ function composeOf(itemName, exports, label) {
|
|
|
20749
20749
|
const main = components.find((e) => e === PASCAL(itemName)) ?? components[0];
|
|
20750
20750
|
if (!main) return null;
|
|
20751
20751
|
const has = (suffix) => components.includes(`${main}${suffix}`) ? `${main}${suffix}` : null;
|
|
20752
|
-
const [input, list, item, group, trigger, content, header, title, description, footer] = ["Input", "List", "Item", "Group", "Trigger", "Content", "Header", "Title", "Description", "Footer"].map(has);
|
|
20752
|
+
const [input, list, item, group, trigger, content, header, title, description, footer, menu] = ["Input", "List", "Item", "Group", "Trigger", "Content", "Header", "Title", "Description", "Footer", "Menu"].map(has);
|
|
20753
20753
|
if (list && item) {
|
|
20754
20754
|
const items = ["Calendar", "Search emoji", "Calculator"].map((text) => node(item, {}, [text]));
|
|
20755
20755
|
return node(main, { style: { minWidth: 220 } }, [...input ? [node(input, { placeholder: "Type a command or search\u2026" })] : [], node(list, {}, group ? [node(group, { heading: "Suggestions" }, items)] : items)]);
|
|
@@ -20761,6 +20761,15 @@ function composeOf(itemName, exports, label) {
|
|
|
20761
20761
|
node(content, { value: "password" }, ["Change your password here."])
|
|
20762
20762
|
]);
|
|
20763
20763
|
}
|
|
20764
|
+
if (menu && trigger) {
|
|
20765
|
+
return node(main, {}, ["File", "Edit", "View"].map((text) => node(menu, {}, [node(trigger, {}, [text]), ...content && item ? [node(content, {}, [node(item, {}, ["New tab"])])] : []])));
|
|
20766
|
+
}
|
|
20767
|
+
if (item && trigger && content) {
|
|
20768
|
+
return node(main, { type: "single", collapsible: true, defaultValue: "item-1", style: { width: 320 } }, [
|
|
20769
|
+
node(item, { value: "item-1" }, [node(trigger, {}, ["Is it accessible?"]), node(content, {}, ["Yes, with your tokens."])]),
|
|
20770
|
+
node(item, { value: "item-2" }, [node(trigger, {}, ["Is it styled?"]), node(content, {}, ["In your theme."])])
|
|
20771
|
+
]);
|
|
20772
|
+
}
|
|
20764
20773
|
if (trigger && content) {
|
|
20765
20774
|
const head = header ? [node(header, {}, [...title ? [node(title, {}, [label])] : [], ...description ? [node(description, {}, ["A preview of this part in your theme."])] : []])] : [...title ? [node(title, {}, [label])] : []];
|
|
20766
20775
|
return node(main, { open: true }, [node(trigger, {}, [`Open ${label}`]), node(content, {}, head.length ? head : [label])]);
|
|
@@ -21014,6 +21023,7 @@ async function bundlePreview(job, options = {}) {
|
|
|
21014
21023
|
if (message.startsWith("esbuild timed out")) return { error: `bundling took over ${limitOf(timeoutMs)} and was stopped` };
|
|
21015
21024
|
return { error: `it did not bundle: ${message}` };
|
|
21016
21025
|
}
|
|
21026
|
+
if (refusals.size > 0) return { error: [...refusals][0] };
|
|
21017
21027
|
if (radix.size > 0) notes.add(`radix-ui is not installed: its ${[...radix.keys()].sort().join(", ")} ${radix.size === 1 ? "comes" : "come"} from ${[...new Set(radix.values())].sort().join(", ")}`);
|
|
21018
21028
|
if (fromHub.size > 0) notes.add(`${[...fromHub].sort().join(", ")}: not installed in your project, so the hub's own ${fromHub.size === 1 ? "copy draws it" : "copies draw them"}`);
|
|
21019
21029
|
const inputs = [];
|
|
@@ -21269,7 +21279,7 @@ var Eyes = class {
|
|
|
21269
21279
|
}
|
|
21270
21280
|
async open() {
|
|
21271
21281
|
if (this.browser) return this.browser;
|
|
21272
|
-
const { launchBrowser } = await import("./src-
|
|
21282
|
+
const { launchBrowser } = await import("./src-DS43LCRA.js");
|
|
21273
21283
|
try {
|
|
21274
21284
|
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 } : {} });
|
|
21275
21285
|
} catch (error) {
|
|
@@ -21625,6 +21635,344 @@ function shotsText(report, again = (t) => `run youiyoux render${t ? ` ${t}` : ""
|
|
|
21625
21635
|
return lines.join("\n");
|
|
21626
21636
|
}
|
|
21627
21637
|
|
|
21638
|
+
// ../scanner/src/screens/capture.ts
|
|
21639
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
21640
|
+
import { rename, writeFile } from "node:fs/promises";
|
|
21641
|
+
import { join as join19 } from "node:path";
|
|
21642
|
+
|
|
21643
|
+
// ../scanner/src/screens/locate.ts
|
|
21644
|
+
import { realpathSync } from "node:fs";
|
|
21645
|
+
import { posix as posix7 } from "node:path";
|
|
21646
|
+
var MAX_PLACES = 4e3;
|
|
21647
|
+
function locateInPage(limit, maxFrames = 6) {
|
|
21648
|
+
const size = { width: document.documentElement.scrollWidth, height: document.documentElement.scrollHeight };
|
|
21649
|
+
const roots = [];
|
|
21650
|
+
for (const element of document.querySelectorAll("*")) {
|
|
21651
|
+
const key = Object.keys(element).find((k) => k.startsWith("__reactContainer$"));
|
|
21652
|
+
if (!key) continue;
|
|
21653
|
+
const container = element[key];
|
|
21654
|
+
roots.push(container.stateNode?.current ?? container);
|
|
21655
|
+
}
|
|
21656
|
+
if (roots.length === 0) return { react: false, dev: false, size, places: [], capped: false };
|
|
21657
|
+
const COMPONENT = /* @__PURE__ */ new Set([0, 1, 11, 14, 15]);
|
|
21658
|
+
const nameOf = (type2) => {
|
|
21659
|
+
const t = type2;
|
|
21660
|
+
return t?.displayName || t?.name || t?.render?.displayName || t?.render?.name || t?.type?.displayName || t?.type?.name || null;
|
|
21661
|
+
};
|
|
21662
|
+
const INTERNAL = /\/node_modules\/|\/\.vite\/deps\/|\/_next\/static\/chunks\/(?:framework|main|webpack)|react-dom|jsx-dev-runtime|jsx-runtime/;
|
|
21663
|
+
const framesOf = (stack) => {
|
|
21664
|
+
const frames = [];
|
|
21665
|
+
for (const text of (stack ?? "").split("\n").slice(1)) {
|
|
21666
|
+
if (/react[-_]stack[-_]bottom[-_]frame/.test(text)) break;
|
|
21667
|
+
const match = /((?:https?|file):\/\/[^\s()]+?):(\d+):(\d+)\)?\s*$/.exec(text);
|
|
21668
|
+
if (!match || INTERNAL.test(match[1])) continue;
|
|
21669
|
+
frames.push({ url: match[1], line: Number(match[2]), column: Number(match[3]) });
|
|
21670
|
+
if (frames.length >= maxFrames) break;
|
|
21671
|
+
}
|
|
21672
|
+
return frames;
|
|
21673
|
+
};
|
|
21674
|
+
const boxOf = (fiber) => {
|
|
21675
|
+
let left = Infinity;
|
|
21676
|
+
let top = Infinity;
|
|
21677
|
+
let right = -Infinity;
|
|
21678
|
+
let bottom = -Infinity;
|
|
21679
|
+
const walk = (first) => {
|
|
21680
|
+
for (let node2 = first; node2; node2 = node2.sibling) {
|
|
21681
|
+
if (node2.tag === 5) {
|
|
21682
|
+
const rect = node2.stateNode?.getBoundingClientRect?.();
|
|
21683
|
+
if (rect && rect.width > 0 && rect.height > 0) {
|
|
21684
|
+
left = Math.min(left, rect.left);
|
|
21685
|
+
top = Math.min(top, rect.top);
|
|
21686
|
+
right = Math.max(right, rect.right);
|
|
21687
|
+
bottom = Math.max(bottom, rect.bottom);
|
|
21688
|
+
}
|
|
21689
|
+
} else if (node2.tag !== 6) walk(node2.child);
|
|
21690
|
+
}
|
|
21691
|
+
};
|
|
21692
|
+
walk(fiber.child);
|
|
21693
|
+
if (!Number.isFinite(left)) return null;
|
|
21694
|
+
return { x: Math.round(left + scrollX), y: Math.round(top + scrollY), width: Math.round(right - left), height: Math.round(bottom - top) };
|
|
21695
|
+
};
|
|
21696
|
+
const places = [];
|
|
21697
|
+
let dev = false;
|
|
21698
|
+
let capped = false;
|
|
21699
|
+
const visit = (fiber, depth) => {
|
|
21700
|
+
for (let node2 = fiber; node2; node2 = node2.sibling) {
|
|
21701
|
+
let inner = depth;
|
|
21702
|
+
if (COMPONENT.has(node2.tag)) {
|
|
21703
|
+
if (node2._debugStack) dev = true;
|
|
21704
|
+
const box = boxOf(node2);
|
|
21705
|
+
const name = nameOf(node2.type);
|
|
21706
|
+
if (box && name) {
|
|
21707
|
+
if (places.length >= limit) {
|
|
21708
|
+
capped = true;
|
|
21709
|
+
return;
|
|
21710
|
+
}
|
|
21711
|
+
places.push({ name, owner: nameOf(node2._debugOwner?.type), frames: framesOf(node2._debugStack?.stack), box, depth });
|
|
21712
|
+
}
|
|
21713
|
+
inner = depth + 1;
|
|
21714
|
+
}
|
|
21715
|
+
visit(node2.child, inner);
|
|
21716
|
+
if (capped) return;
|
|
21717
|
+
}
|
|
21718
|
+
};
|
|
21719
|
+
for (const root of roots) visit(root.child, 0);
|
|
21720
|
+
return { react: true, dev, size, places, capped };
|
|
21721
|
+
}
|
|
21722
|
+
var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
21723
|
+
var DIGIT = new Map([...BASE64].map((c, i) => [c, i]));
|
|
21724
|
+
function decodeMap(map) {
|
|
21725
|
+
if (!Array.isArray(map.sources) || typeof map.mappings !== "string") return null;
|
|
21726
|
+
const root = typeof map.sourceRoot === "string" && map.sourceRoot ? map.sourceRoot.replace(/\/?$/, "/") : "";
|
|
21727
|
+
const sources = map.sources.map((s) => typeof s === "string" ? `${root}${s}` : "");
|
|
21728
|
+
const lines = [];
|
|
21729
|
+
let source = 0;
|
|
21730
|
+
let line2 = 0;
|
|
21731
|
+
let column = 0;
|
|
21732
|
+
for (const text of map.mappings.split(";")) {
|
|
21733
|
+
const segments = [];
|
|
21734
|
+
let generated = 0;
|
|
21735
|
+
for (const part2 of text.split(",")) {
|
|
21736
|
+
if (!part2) continue;
|
|
21737
|
+
const values = [];
|
|
21738
|
+
let value = 0;
|
|
21739
|
+
let shift = 0;
|
|
21740
|
+
for (const char of part2) {
|
|
21741
|
+
const digit = DIGIT.get(char);
|
|
21742
|
+
if (digit === void 0) return null;
|
|
21743
|
+
value += (digit & 31) << shift;
|
|
21744
|
+
if (digit & 32) shift += 5;
|
|
21745
|
+
else {
|
|
21746
|
+
values.push(value & 1 ? -(value >>> 1) : value >>> 1);
|
|
21747
|
+
value = 0;
|
|
21748
|
+
shift = 0;
|
|
21749
|
+
}
|
|
21750
|
+
}
|
|
21751
|
+
generated += values[0] ?? 0;
|
|
21752
|
+
if (values.length >= 4) {
|
|
21753
|
+
source += values[1];
|
|
21754
|
+
line2 += values[2];
|
|
21755
|
+
column += values[3];
|
|
21756
|
+
segments.push([generated, source, line2, column]);
|
|
21757
|
+
}
|
|
21758
|
+
}
|
|
21759
|
+
lines.push(segments);
|
|
21760
|
+
}
|
|
21761
|
+
return { sources, lines };
|
|
21762
|
+
}
|
|
21763
|
+
function originalPosition(map, line2, column) {
|
|
21764
|
+
const segments = map.lines[line2 - 1];
|
|
21765
|
+
if (!segments?.length) return null;
|
|
21766
|
+
let found = null;
|
|
21767
|
+
for (const segment of segments) {
|
|
21768
|
+
if (segment[0] > column - 1) break;
|
|
21769
|
+
found = segment;
|
|
21770
|
+
}
|
|
21771
|
+
found ??= segments[0];
|
|
21772
|
+
const source = map.sources[found[1]];
|
|
21773
|
+
return source === void 0 ? null : { source, line: found[2] + 1, column: found[3] + 1 };
|
|
21774
|
+
}
|
|
21775
|
+
async function sourceMapOf(url, text, fetchText) {
|
|
21776
|
+
const at = text.lastIndexOf("sourceMappingURL=");
|
|
21777
|
+
if (at < 0 || !/\/\/[#@]\s*$/.test(text.slice(Math.max(0, at - 8), at))) return null;
|
|
21778
|
+
const target = text.slice(at + "sourceMappingURL=".length).split(/\s/, 1)[0];
|
|
21779
|
+
if (!target) return null;
|
|
21780
|
+
let json;
|
|
21781
|
+
if (target.startsWith("data:")) {
|
|
21782
|
+
const at2 = target.indexOf(",");
|
|
21783
|
+
const payload = target.slice(at2 + 1);
|
|
21784
|
+
json = /;base64/.test(target.slice(0, at2)) ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
|
|
21785
|
+
} else json = await fetchText(new URL(target, url).href);
|
|
21786
|
+
if (!json) return null;
|
|
21787
|
+
try {
|
|
21788
|
+
return decodeMap(JSON.parse(json));
|
|
21789
|
+
} catch {
|
|
21790
|
+
return null;
|
|
21791
|
+
}
|
|
21792
|
+
}
|
|
21793
|
+
function projectPath(source, moduleUrl, root) {
|
|
21794
|
+
let path;
|
|
21795
|
+
const webpack = /^webpack:\/\/[^/]*\/(.*)$/.exec(source);
|
|
21796
|
+
if (webpack) path = `/${webpack[1].replace(/^\.\//, "")}`;
|
|
21797
|
+
else if (/^[a-z]+:\/\//i.test(source) && !source.startsWith("file://")) path = new URL(source).pathname;
|
|
21798
|
+
else if (source.startsWith("file://")) path = new URL(source).pathname;
|
|
21799
|
+
else if (source.startsWith("/")) path = source;
|
|
21800
|
+
else path = new URL(source, moduleUrl).pathname;
|
|
21801
|
+
path = decodeURIComponent(path).replace(/^\/@fs\//, "/");
|
|
21802
|
+
for (const base of root ? /* @__PURE__ */ new Set([root, realOrSelf(root)]) : []) {
|
|
21803
|
+
const prefix = base.replace(/\\/g, "/").replace(/\/?$/, "/");
|
|
21804
|
+
if (path.startsWith(prefix)) return posix7.normalize(path.slice(prefix.length));
|
|
21805
|
+
}
|
|
21806
|
+
if (/^\/(?:Users|home|private|var|tmp|opt|mnt|[A-Za-z]:)\//.test(path)) return null;
|
|
21807
|
+
const relative6 = posix7.normalize(path.replace(/^\/+/, ""));
|
|
21808
|
+
return relative6.startsWith("..") || relative6 === "." ? null : relative6;
|
|
21809
|
+
}
|
|
21810
|
+
function realOrSelf(path) {
|
|
21811
|
+
try {
|
|
21812
|
+
return realpathSync(path);
|
|
21813
|
+
} catch {
|
|
21814
|
+
return path;
|
|
21815
|
+
}
|
|
21816
|
+
}
|
|
21817
|
+
async function resolvePlaces(raw, fetchText, root = null) {
|
|
21818
|
+
const maps = /* @__PURE__ */ new Map();
|
|
21819
|
+
const mapFor = (url) => {
|
|
21820
|
+
const module = url.replace(/[?#].*$/, "");
|
|
21821
|
+
let found = maps.get(module);
|
|
21822
|
+
if (!found) {
|
|
21823
|
+
found = fetchText(url).then((text) => text === null ? null : sourceMapOf(url, text, fetchText), () => null);
|
|
21824
|
+
maps.set(module, found);
|
|
21825
|
+
}
|
|
21826
|
+
return found;
|
|
21827
|
+
};
|
|
21828
|
+
return Promise.all(
|
|
21829
|
+
raw.map(async (place) => {
|
|
21830
|
+
const base = { name: place.name, owner: place.owner, box: place.box, depth: place.depth };
|
|
21831
|
+
for (const frame of place.frames) {
|
|
21832
|
+
const map = await mapFor(frame.url);
|
|
21833
|
+
const original = map ? originalPosition(map, frame.line, frame.column) : null;
|
|
21834
|
+
if (!original) continue;
|
|
21835
|
+
if (/(?:^|\/)node_modules\/|^webpack\/|^\(webpack\)/.test(original.source)) continue;
|
|
21836
|
+
const file = projectPath(original.source, frame.url, root);
|
|
21837
|
+
if (file) return { ...base, file, line: original.line, column: original.column };
|
|
21838
|
+
}
|
|
21839
|
+
const unmapped = place.frames[0];
|
|
21840
|
+
return { ...base, file: unmapped ? projectPath(unmapped.url.replace(/[?#].*$/, ""), unmapped.url, null) : null, line: null, column: null };
|
|
21841
|
+
})
|
|
21842
|
+
);
|
|
21843
|
+
}
|
|
21844
|
+
|
|
21845
|
+
// ../scanner/src/screens/capture.ts
|
|
21846
|
+
var SCREENS_SCHEMA = "youiyoux.screens/v1";
|
|
21847
|
+
var PLACES_SCHEMA = "youiyoux.places/v1";
|
|
21848
|
+
var SCHEMES2 = ["light", "dark"];
|
|
21849
|
+
var PICTURE_SCALE = 2;
|
|
21850
|
+
var FULL_SCALE = PICTURE_SCALE;
|
|
21851
|
+
var THUMB_SCALE = 0.5;
|
|
21852
|
+
var SETTLE_MS = 1200;
|
|
21853
|
+
var NAVIGATION_TIMEOUT_MS = 3e4;
|
|
21854
|
+
var MAX_VIEWPORTS = 6;
|
|
21855
|
+
var WEBP_QUALITY = 0.9;
|
|
21856
|
+
function screenSlug(route) {
|
|
21857
|
+
if (route === "*") return "app-shell";
|
|
21858
|
+
if (route === "?") return "unrouted";
|
|
21859
|
+
return route.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "root";
|
|
21860
|
+
}
|
|
21861
|
+
function readScreensSpec(dir) {
|
|
21862
|
+
const file = join19(dir, "screens.json");
|
|
21863
|
+
let value;
|
|
21864
|
+
try {
|
|
21865
|
+
value = JSON.parse(readFileSync7(file, "utf8"));
|
|
21866
|
+
} catch (error) {
|
|
21867
|
+
throw new Error(`cannot read ${file}: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}`);
|
|
21868
|
+
}
|
|
21869
|
+
const valid = value.schema === SCREENS_SCHEMA && typeof value.project === "string" && typeof value.source === "string" && typeof value.viewport?.width === "number" && typeof value.viewport.height === "number" && Array.isArray(value.screens) && value.screens.every((s) => typeof s?.route === "string" && typeof s.path === "string");
|
|
21870
|
+
if (!valid) throw new Error(`${file} is not a ${SCREENS_SCHEMA} document: it needs project, source, viewport { width, height } and screens [{ route, path }]`);
|
|
21871
|
+
const slugs = /* @__PURE__ */ new Map();
|
|
21872
|
+
for (const { route } of value.screens) {
|
|
21873
|
+
const slug2 = screenSlug(route);
|
|
21874
|
+
if (slugs.has(slug2)) throw new Error(`${file}: routes ${slugs.get(slug2)} and ${route} would share the file name ${slug2}`);
|
|
21875
|
+
slugs.set(slug2, route);
|
|
21876
|
+
}
|
|
21877
|
+
return value;
|
|
21878
|
+
}
|
|
21879
|
+
async function writeBytes(file, bytes) {
|
|
21880
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
21881
|
+
await writeFile(temporary, bytes);
|
|
21882
|
+
await rename(temporary, file);
|
|
21883
|
+
}
|
|
21884
|
+
async function encode(page, png, scale) {
|
|
21885
|
+
const url = await page.evaluate(
|
|
21886
|
+
async ({ data, scale: scale2, quality }) => {
|
|
21887
|
+
const image = new Image();
|
|
21888
|
+
image.src = `data:image/png;base64,${data}`;
|
|
21889
|
+
await image.decode();
|
|
21890
|
+
const canvas = document.createElement("canvas");
|
|
21891
|
+
canvas.width = Math.max(1, Math.round(image.naturalWidth * scale2));
|
|
21892
|
+
canvas.height = Math.max(1, Math.round(image.naturalHeight * scale2));
|
|
21893
|
+
const context = canvas.getContext("2d");
|
|
21894
|
+
context.imageSmoothingQuality = "high";
|
|
21895
|
+
context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
21896
|
+
return canvas.toDataURL("image/webp", quality);
|
|
21897
|
+
},
|
|
21898
|
+
{ data: png.toString("base64"), scale, quality: WEBP_QUALITY }
|
|
21899
|
+
);
|
|
21900
|
+
if (!url.startsWith("data:image/webp;base64,")) throw new Error("this Chromium cannot encode WebP");
|
|
21901
|
+
return Buffer.from(url.slice("data:image/webp;base64,".length), "base64");
|
|
21902
|
+
}
|
|
21903
|
+
var sentence = (error) => (error instanceof Error ? error.message : String(error)).split("\n")[0].replace(/\.$/, "");
|
|
21904
|
+
async function captureScreens(dir, options) {
|
|
21905
|
+
const spec = readScreensSpec(dir);
|
|
21906
|
+
const unknown = (options.routes ?? []).filter((route) => !spec.screens.some((s) => s.route === route));
|
|
21907
|
+
if (unknown.length) throw new Error(`${join19(dir, "screens.json")} has no route ${unknown.join(", ")}: it lists ${spec.screens.map((s) => s.route).join(", ")}`);
|
|
21908
|
+
const chosen = options.routes?.length ? spec.screens.filter((s) => options.routes.includes(s.route)) : spec.screens;
|
|
21909
|
+
const log = options.log ?? (() => void 0);
|
|
21910
|
+
const { width, height } = spec.viewport;
|
|
21911
|
+
const results = /* @__PURE__ */ new Map();
|
|
21912
|
+
let dev = false;
|
|
21913
|
+
let react = false;
|
|
21914
|
+
for (const scheme of SCHEMES2) {
|
|
21915
|
+
const context = await options.browser.newContext({ viewport: { width, height }, deviceScaleFactor: FULL_SCALE, colorScheme: scheme, reducedMotion: "reduce", ...options.storageState ? { storageState: options.storageState } : {} });
|
|
21916
|
+
try {
|
|
21917
|
+
const page = await context.newPage();
|
|
21918
|
+
const encoder = await context.newPage();
|
|
21919
|
+
for (const screen of chosen) {
|
|
21920
|
+
const slug2 = screenSlug(screen.route);
|
|
21921
|
+
if (results.get(screen.route)?.error) continue;
|
|
21922
|
+
try {
|
|
21923
|
+
const target = new URL(screen.path, options.base).href;
|
|
21924
|
+
await page.goto(target, { waitUntil: "load", timeout: NAVIGATION_TIMEOUT_MS });
|
|
21925
|
+
await page.evaluate(() => document.fonts?.ready.then(() => void 0));
|
|
21926
|
+
await page.waitForTimeout(SETTLE_MS);
|
|
21927
|
+
let located = scheme === "light" ? await page.evaluate(locateInPage, MAX_PLACES) : null;
|
|
21928
|
+
if (located && !located.react) {
|
|
21929
|
+
await page.waitForLoadState("load");
|
|
21930
|
+
await page.waitForTimeout(SETTLE_MS * 2);
|
|
21931
|
+
located = await page.evaluate(locateInPage, MAX_PLACES);
|
|
21932
|
+
}
|
|
21933
|
+
const pageHeight = located?.size.height ?? await page.evaluate(() => document.documentElement.scrollHeight);
|
|
21934
|
+
const clip = { x: 0, y: 0, width, height: Math.min(Math.max(pageHeight, height), height * MAX_VIEWPORTS) };
|
|
21935
|
+
const png = await page.screenshot({ fullPage: true, clip });
|
|
21936
|
+
await writeBytes(join19(dir, `${slug2}.${scheme}.webp`), await encode(encoder, png, 1));
|
|
21937
|
+
await writeBytes(join19(dir, `${slug2}.${scheme}.thumb.webp`), await encode(encoder, png, THUMB_SCALE / FULL_SCALE));
|
|
21938
|
+
if (located) {
|
|
21939
|
+
react ||= located.react;
|
|
21940
|
+
dev ||= located.dev;
|
|
21941
|
+
const places = await resolvePlaces(located.places, async (url) => {
|
|
21942
|
+
const response = await fetch(url).catch(() => null);
|
|
21943
|
+
return response?.ok ? response.text() : null;
|
|
21944
|
+
}, options.root ?? null);
|
|
21945
|
+
const file = { schema: PLACES_SCHEMA, route: screen.route, path: screen.path, viewport: spec.viewport, size: { width, height: clip.height }, dev: located.dev, capped: located.capped, places: places.filter((p3) => p3.box.y < clip.height) };
|
|
21946
|
+
await writeFileAtomic(join19(dir, `${slug2}.places.json`), `${JSON.stringify(file)}
|
|
21947
|
+
`);
|
|
21948
|
+
results.set(screen.route, { placed: file.places.length, lined: file.places.filter((p3) => p3.line !== null).length, error: null });
|
|
21949
|
+
}
|
|
21950
|
+
log(`${screen.route} (${scheme}) \u2192 ${slug2}.${scheme}.webp${located ? `, ${results.get(screen.route).placed} components placed` : ""}`);
|
|
21951
|
+
} catch (error) {
|
|
21952
|
+
results.set(screen.route, { placed: 0, lined: 0, error: `${sentence(error)} (${screen.path})` });
|
|
21953
|
+
log(`${screen.route} (${scheme}): ${sentence(error)}`);
|
|
21954
|
+
}
|
|
21955
|
+
}
|
|
21956
|
+
} finally {
|
|
21957
|
+
await context.close();
|
|
21958
|
+
}
|
|
21959
|
+
}
|
|
21960
|
+
const now = (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
21961
|
+
if (chosen === spec.screens) await writeFileAtomic(join19(dir, "screens.json"), `${JSON.stringify({ ...spec, capturedAt: now }, null, 2)}
|
|
21962
|
+
`);
|
|
21963
|
+
const screens = chosen.map((s) => ({ route: s.route, path: s.path, ...results.get(s.route) ?? { placed: 0, lined: 0, error: "not captured" } }));
|
|
21964
|
+
return { dir, project: spec.project, screens, production: react && !dev, noReact: !react && screens.some((s) => !s.error) };
|
|
21965
|
+
}
|
|
21966
|
+
function captureText(report) {
|
|
21967
|
+
const ok = report.screens.filter((s) => !s.error);
|
|
21968
|
+
const lines = [`${ok.length} of ${report.screens.length} screens of ${report.project} captured \u2192 ${report.dir}`];
|
|
21969
|
+
for (const s of report.screens) lines.push(s.error ? ` \u2716 ${s.route}: ${s.error}` : ` \u2713 ${s.route}: ${s.placed} components placed, ${s.lined} with their line`);
|
|
21970
|
+
if (report.noReact) lines.push("No React on these pages, so nothing is placed: the pictures are kept without places.");
|
|
21971
|
+
else if (report.production) lines.push("These pages are a production build: components are placed but have no lines. Run the app in development (vite, next dev) and capture again.");
|
|
21972
|
+
lines.push(ok.length ? "Next: youiyoux ui --project <dir> shows them on the Screens page, each component selectable." : "Next: start the app, check --base, and capture again.");
|
|
21973
|
+
return lines.join("\n");
|
|
21974
|
+
}
|
|
21975
|
+
|
|
21628
21976
|
export {
|
|
21629
21977
|
parseCssColor,
|
|
21630
21978
|
resolverLayout,
|
|
@@ -21793,5 +22141,19 @@ export {
|
|
|
21793
22141
|
compareA11yIssues,
|
|
21794
22142
|
renderShots,
|
|
21795
22143
|
shotsNext,
|
|
21796
|
-
shotsText
|
|
22144
|
+
shotsText,
|
|
22145
|
+
MAX_PLACES,
|
|
22146
|
+
locateInPage,
|
|
22147
|
+
decodeMap,
|
|
22148
|
+
originalPosition,
|
|
22149
|
+
sourceMapOf,
|
|
22150
|
+
projectPath,
|
|
22151
|
+
resolvePlaces,
|
|
22152
|
+
SCREENS_SCHEMA,
|
|
22153
|
+
PLACES_SCHEMA,
|
|
22154
|
+
PICTURE_SCALE,
|
|
22155
|
+
screenSlug,
|
|
22156
|
+
readScreensSpec,
|
|
22157
|
+
captureScreens,
|
|
22158
|
+
captureText
|
|
21797
22159
|
};
|