multiclone 0.0.0-stage → 0.2.0
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 +78 -2
- package/agents/section-builder.md +37 -0
- package/commands/multiclone.md +15 -0
- package/dist/adapters/cli.js +129 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/adapters/cliArgs.js +63 -0
- package/dist/adapters/cliArgs.js.map +1 -0
- package/dist/adapters/mcp.js +83 -0
- package/dist/adapters/mcp.js.map +1 -0
- package/dist/analyze/analyze.js +85 -0
- package/dist/analyze/analyze.js.map +1 -0
- package/dist/analyze/animations.js +340 -0
- package/dist/analyze/animations.js.map +1 -0
- package/dist/analyze/ast.js +182 -0
- package/dist/analyze/ast.js.map +1 -0
- package/dist/analyze/chunks.js +160 -0
- package/dist/analyze/chunks.js.map +1 -0
- package/dist/analyze/jobs/code.js +117 -0
- package/dist/analyze/jobs/code.js.map +1 -0
- package/dist/analyze/jobs/sections.js +356 -0
- package/dist/analyze/jobs/sections.js.map +1 -0
- package/dist/analyze/pretty.js +20 -0
- package/dist/analyze/pretty.js.map +1 -0
- package/dist/analyze/report.js +101 -0
- package/dist/analyze/report.js.map +1 -0
- package/dist/analyze/worker.js +71 -0
- package/dist/analyze/worker.js.map +1 -0
- package/dist/capture/capture.js +340 -0
- package/dist/capture/capture.js.map +1 -0
- package/dist/capture/collectors/a11y.js +92 -0
- package/dist/capture/collectors/a11y.js.map +1 -0
- package/dist/capture/collectors/animations.js +113 -0
- package/dist/capture/collectors/animations.js.map +1 -0
- package/dist/capture/collectors/breakpoints.js +31 -0
- package/dist/capture/collectors/breakpoints.js.map +1 -0
- package/dist/capture/collectors/consent.js +39 -0
- package/dist/capture/collectors/consent.js.map +1 -0
- package/dist/capture/collectors/coverage.js +121 -0
- package/dist/capture/collectors/coverage.js.map +1 -0
- package/dist/capture/collectors/dom.js +16 -0
- package/dist/capture/collectors/dom.js.map +1 -0
- package/dist/capture/collectors/fonts.js +154 -0
- package/dist/capture/collectors/fonts.js.map +1 -0
- package/dist/capture/collectors/frames.js +93 -0
- package/dist/capture/collectors/frames.js.map +1 -0
- package/dist/capture/collectors/index.js +61 -0
- package/dist/capture/collectors/index.js.map +1 -0
- package/dist/capture/collectors/interactions.js +207 -0
- package/dist/capture/collectors/interactions.js.map +1 -0
- package/dist/capture/collectors/intro.js +84 -0
- package/dist/capture/collectors/intro.js.map +1 -0
- package/dist/capture/collectors/listeners.js +84 -0
- package/dist/capture/collectors/listeners.js.map +1 -0
- package/dist/capture/collectors/motion.js +91 -0
- package/dist/capture/collectors/motion.js.map +1 -0
- package/dist/capture/collectors/network.js +288 -0
- package/dist/capture/collectors/network.js.map +1 -0
- package/dist/capture/collectors/probes.js +34 -0
- package/dist/capture/collectors/probes.js.map +1 -0
- package/dist/capture/collectors/runtime.js +38 -0
- package/dist/capture/collectors/runtime.js.map +1 -0
- package/dist/capture/collectors/scripts.js +98 -0
- package/dist/capture/collectors/scripts.js.map +1 -0
- package/dist/capture/collectors/sections.js +17 -0
- package/dist/capture/collectors/sections.js.map +1 -0
- package/dist/capture/collectors/shots.js +58 -0
- package/dist/capture/collectors/shots.js.map +1 -0
- package/dist/capture/collectors/snapshot.js +47 -0
- package/dist/capture/collectors/snapshot.js.map +1 -0
- package/dist/capture/collectors/sourcemaps.js +153 -0
- package/dist/capture/collectors/sourcemaps.js.map +1 -0
- package/dist/capture/collectors/storage.js +72 -0
- package/dist/capture/collectors/storage.js.map +1 -0
- package/dist/capture/context.js +40 -0
- package/dist/capture/context.js.map +1 -0
- package/dist/capture/hooks/candidates.js +104 -0
- package/dist/capture/hooks/candidates.js.map +1 -0
- package/dist/capture/hooks/consent.js +82 -0
- package/dist/capture/hooks/consent.js.map +1 -0
- package/dist/capture/hooks/recorders.js +507 -0
- package/dist/capture/hooks/recorders.js.map +1 -0
- package/dist/capture/hooks/sections.js +62 -0
- package/dist/capture/hooks/sections.js.map +1 -0
- package/dist/capture/hooks/styles.js +86 -0
- package/dist/capture/hooks/styles.js.map +1 -0
- package/dist/capture/probes.js +491 -0
- package/dist/capture/probes.js.map +1 -0
- package/dist/capture/report.js +115 -0
- package/dist/capture/report.js.map +1 -0
- package/dist/compare/compare.js +391 -0
- package/dist/compare/compare.js.map +1 -0
- package/dist/compare/image.js +105 -0
- package/dist/compare/image.js.map +1 -0
- package/dist/compare/probes.js +129 -0
- package/dist/compare/probes.js.map +1 -0
- package/dist/compare/report.js +99 -0
- package/dist/compare/report.js.map +1 -0
- package/dist/compare/session.js +139 -0
- package/dist/compare/session.js.map +1 -0
- package/dist/compare/shoot.js +62 -0
- package/dist/compare/shoot.js.map +1 -0
- package/dist/contracts/catalog.js +29 -0
- package/dist/contracts/catalog.js.map +1 -0
- package/dist/contracts/context.js +19 -0
- package/dist/contracts/context.js.map +1 -0
- package/dist/contracts/fields.js +16 -0
- package/dist/contracts/fields.js.map +1 -0
- package/dist/contracts/tools/analyze.js +38 -0
- package/dist/contracts/tools/analyze.js.map +1 -0
- package/dist/contracts/tools/capture.js +87 -0
- package/dist/contracts/tools/capture.js.map +1 -0
- package/dist/contracts/tools/compare.js +142 -0
- package/dist/contracts/tools/compare.js.map +1 -0
- package/dist/contracts/tools/doctor.js +23 -0
- package/dist/contracts/tools/doctor.js.map +1 -0
- package/dist/contracts/tools/inspect.js +41 -0
- package/dist/contracts/tools/inspect.js.map +1 -0
- package/dist/contracts/tools/method.js +60 -0
- package/dist/contracts/tools/method.js.map +1 -0
- package/dist/contracts/tools/mirror.js +53 -0
- package/dist/contracts/tools/mirror.js.map +1 -0
- package/dist/contracts/tools/project.js +61 -0
- package/dist/contracts/tools/project.js.map +1 -0
- package/dist/contracts/tools/session.js +195 -0
- package/dist/contracts/tools/session.js.map +1 -0
- package/dist/contracts/types.js +20 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/core/cdp.js +146 -0
- package/dist/core/cdp.js.map +1 -0
- package/dist/core/chrome.js +185 -0
- package/dist/core/chrome.js.map +1 -0
- package/dist/core/files.js +31 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/inpage.js +24 -0
- package/dist/core/inpage.js.map +1 -0
- package/dist/core/log.js +10 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/page.js +269 -0
- package/dist/core/page.js.map +1 -0
- package/dist/doctor.js +37 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain/breakpoints.js +47 -0
- package/dist/domain/breakpoints.js.map +1 -0
- package/dist/domain/budget.js +38 -0
- package/dist/domain/budget.js.map +1 -0
- package/dist/domain/compare.js +138 -0
- package/dist/domain/compare.js.map +1 -0
- package/dist/domain/coverage.js +96 -0
- package/dist/domain/coverage.js.map +1 -0
- package/dist/domain/motion.js +142 -0
- package/dist/domain/motion.js.map +1 -0
- package/dist/domain/paths.js +55 -0
- package/dist/domain/paths.js.map +1 -0
- package/dist/domain/result.js +38 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/domain/routes.js +160 -0
- package/dist/domain/routes.js.map +1 -0
- package/dist/domain/sections.js +94 -0
- package/dist/domain/sections.js.map +1 -0
- package/dist/domain/snapshot.js +268 -0
- package/dist/domain/snapshot.js.map +1 -0
- package/dist/domain/sourcemap.js +95 -0
- package/dist/domain/sourcemap.js.map +1 -0
- package/dist/domain/stack.js +342 -0
- package/dist/domain/stack.js.map +1 -0
- package/dist/domain/tokens.js +183 -0
- package/dist/domain/tokens.js.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/viewports.js +45 -0
- package/dist/domain/viewports.js.map +1 -0
- package/dist/mirror/rewrite.js +56 -0
- package/dist/mirror/rewrite.js.map +1 -0
- package/dist/mirror/server.js +191 -0
- package/dist/mirror/server.js.map +1 -0
- package/dist/mirror/store.js +86 -0
- package/dist/mirror/store.js.map +1 -0
- package/dist/project/assets.js +69 -0
- package/dist/project/assets.js.map +1 -0
- package/dist/project/draft.js +860 -0
- package/dist/project/draft.js.map +1 -0
- package/dist/project/method.js +154 -0
- package/dist/project/method.js.map +1 -0
- package/dist/project/scaffold.js +142 -0
- package/dist/project/scaffold.js.map +1 -0
- package/dist/session/discover.js +53 -0
- package/dist/session/discover.js.map +1 -0
- package/dist/session/proc.js +113 -0
- package/dist/session/proc.js.map +1 -0
- package/dist/session/progress.js +83 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/session.js +450 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/state.js +47 -0
- package/dist/session/state.js.map +1 -0
- package/dist/store/inspect.js +212 -0
- package/dist/store/inspect.js.map +1 -0
- package/dist/store/run.js +112 -0
- package/dist/store/run.js.map +1 -0
- package/dist/store/summary.js +69 -0
- package/dist/store/summary.js.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install.sh +29 -0
- package/package.json +67 -4
- package/skills/multiclone/SKILL.md +123 -0
- package/skills/multiclone/references/capture-format.md +73 -0
- package/skills/multiclone/references/fidelity.md +54 -0
- package/skills/multiclone/references/quality.md +47 -0
- package/skills/multiclone/references/stacks.md +156 -0
- package/templates/react-vite/.prettierignore +5 -0
- package/templates/react-vite/.prettierrc.json +6 -0
- package/templates/react-vite/eslint.config.js +38 -0
- package/templates/react-vite/gitignore +4 -0
- package/templates/react-vite/index.html +12 -0
- package/templates/react-vite/package.json +36 -0
- package/templates/react-vite/src/app/App.tsx +15 -0
- package/templates/react-vite/src/app/Page.tsx +11 -0
- package/templates/react-vite/src/app/routes.ts +7 -0
- package/templates/react-vite/src/components/README.md +7 -0
- package/templates/react-vite/src/content/README.md +2 -0
- package/templates/react-vite/src/hooks/useActiveSection.ts +37 -0
- package/templates/react-vite/src/hooks/useInView.ts +45 -0
- package/templates/react-vite/src/hooks/useMediaQuery.ts +15 -0
- package/templates/react-vite/src/lib/cn.ts +4 -0
- package/templates/react-vite/src/lib/math.ts +21 -0
- package/templates/react-vite/src/lib/mc.ts +13 -0
- package/templates/react-vite/src/lib/media.ts +4 -0
- package/templates/react-vite/src/main.tsx +13 -0
- package/templates/react-vite/src/providers/SmoothScroll.tsx +24 -0
- package/templates/react-vite/src/styles/base.css +42 -0
- package/templates/react-vite/src/styles/draft.css +1 -0
- package/templates/react-vite/src/styles/fonts.css +1 -0
- package/templates/react-vite/src/styles/index.css +4 -0
- package/templates/react-vite/src/styles/tokens.css +3 -0
- package/templates/react-vite/src/vite-env.d.ts +1 -0
- package/templates/react-vite/tsconfig.app.json +29 -0
- package/templates/react-vite/tsconfig.json +4 -0
- package/templates/react-vite/tsconfig.node.json +19 -0
- package/templates/react-vite/vite.config.ts +37 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const key = (scriptId, fn, range) => `${scriptId}|${fn.functionName}|${String(range.startOffset)}|${String(range.endOffset)}`;
|
|
2
|
+
/**
|
|
3
|
+
* Ranges executed more often during an action than during an idle window of the same length.
|
|
4
|
+
* Precise coverage counts are cumulative since start, so both snapshots are deltas against the
|
|
5
|
+
* snapshot taken before them; pass those per-window counts here.
|
|
6
|
+
*/
|
|
7
|
+
export function hotRanges(idle, action, options = {}) {
|
|
8
|
+
const minDelta = options.minDelta ?? 1;
|
|
9
|
+
const baseline = new Map();
|
|
10
|
+
for (const script of idle) {
|
|
11
|
+
for (const fn of script.functions) {
|
|
12
|
+
for (const range of fn.ranges)
|
|
13
|
+
baseline.set(key(script.scriptId, fn, range), range.count);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const script of action) {
|
|
18
|
+
for (const fn of script.functions) {
|
|
19
|
+
// The first range of a function is its whole body; nested block ranges refine it.
|
|
20
|
+
for (const range of fn.ranges) {
|
|
21
|
+
const delta = range.count - (baseline.get(key(script.scriptId, fn, range)) ?? 0);
|
|
22
|
+
if (delta < minDelta)
|
|
23
|
+
continue;
|
|
24
|
+
out.push({
|
|
25
|
+
scriptId: script.scriptId,
|
|
26
|
+
url: script.url,
|
|
27
|
+
functionName: fn.functionName,
|
|
28
|
+
start: range.startOffset,
|
|
29
|
+
end: range.endOffset,
|
|
30
|
+
delta,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return mergeNested(out)
|
|
36
|
+
.sort((a, b) => b.delta - a.delta || a.url.localeCompare(b.url) || a.start - b.start)
|
|
37
|
+
.slice(0, options.maxRanges ?? 400);
|
|
38
|
+
}
|
|
39
|
+
/** Drops ranges fully contained in another hot range of the same script (keep the function body). */
|
|
40
|
+
function mergeNested(ranges) {
|
|
41
|
+
const byScript = new Map();
|
|
42
|
+
for (const range of ranges) {
|
|
43
|
+
const list = byScript.get(range.scriptId) ?? [];
|
|
44
|
+
list.push(range);
|
|
45
|
+
byScript.set(range.scriptId, list);
|
|
46
|
+
}
|
|
47
|
+
const kept = [];
|
|
48
|
+
for (const list of byScript.values()) {
|
|
49
|
+
const sorted = [...list].sort((a, b) => a.start - b.start || b.end - a.end);
|
|
50
|
+
let outer;
|
|
51
|
+
for (const range of sorted) {
|
|
52
|
+
if (outer && range.start >= outer.start && range.end <= outer.end)
|
|
53
|
+
continue;
|
|
54
|
+
kept.push(range);
|
|
55
|
+
outer = range;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return kept;
|
|
59
|
+
}
|
|
60
|
+
/** Subtracts the counts of `before` from `after` (both cumulative snapshots). */
|
|
61
|
+
export function coverageDelta(before, after) {
|
|
62
|
+
const previous = new Map();
|
|
63
|
+
for (const script of before) {
|
|
64
|
+
for (const fn of script.functions) {
|
|
65
|
+
for (const range of fn.ranges)
|
|
66
|
+
previous.set(key(script.scriptId, fn, range), range.count);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return after.map((script) => ({
|
|
70
|
+
scriptId: script.scriptId,
|
|
71
|
+
url: script.url,
|
|
72
|
+
functions: script.functions.map((fn) => ({
|
|
73
|
+
functionName: fn.functionName,
|
|
74
|
+
isBlockCoverage: fn.isBlockCoverage,
|
|
75
|
+
ranges: fn.ranges.map((range) => ({
|
|
76
|
+
startOffset: range.startOffset,
|
|
77
|
+
endOffset: range.endOffset,
|
|
78
|
+
count: Math.max(0, range.count - (previous.get(key(script.scriptId, fn, range)) ?? 0)),
|
|
79
|
+
})),
|
|
80
|
+
})),
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
/** Code excerpts for hot ranges, clipped and annotated with offsets into the script file. */
|
|
84
|
+
export function renderHotCode(ranges, sourceFor, maxChars = 6000) {
|
|
85
|
+
const parts = [];
|
|
86
|
+
for (const range of ranges) {
|
|
87
|
+
const source = sourceFor(range.scriptId);
|
|
88
|
+
if (!source)
|
|
89
|
+
continue;
|
|
90
|
+
const body = source.text.slice(range.start, Math.min(range.end, range.start + maxChars));
|
|
91
|
+
const clipped = range.end - range.start > maxChars ? '\n/* … clipped … */' : '';
|
|
92
|
+
parts.push(`/* ${range.functionName || '(anonymous)'} ×${String(range.delta)} — ${source.file ?? range.url} [${String(range.start)}, ${String(range.end)}) */\n${body}${clipped}\n`);
|
|
93
|
+
}
|
|
94
|
+
return parts.join('\n');
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/domain/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/** Properties sampled per element. Order is the order of `MotionSample.values`. */
|
|
2
|
+
export const MOTION_PROPS = [
|
|
3
|
+
'transform',
|
|
4
|
+
'translate',
|
|
5
|
+
'rotate',
|
|
6
|
+
'scale',
|
|
7
|
+
'opacity',
|
|
8
|
+
'clip-path',
|
|
9
|
+
'filter',
|
|
10
|
+
'width',
|
|
11
|
+
'height',
|
|
12
|
+
'top',
|
|
13
|
+
'left',
|
|
14
|
+
'color',
|
|
15
|
+
'background-color',
|
|
16
|
+
'border-radius',
|
|
17
|
+
'text',
|
|
18
|
+
];
|
|
19
|
+
/** Deterministic short id for a track, derived from its path (FNV-1a). */
|
|
20
|
+
export function trackId(path) {
|
|
21
|
+
let hash = 0x811c9dc5;
|
|
22
|
+
for (let index = 0; index < path.length; index++) {
|
|
23
|
+
hash ^= path.charCodeAt(index);
|
|
24
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
25
|
+
}
|
|
26
|
+
return `t${hash.toString(36).padStart(7, '0')}`;
|
|
27
|
+
}
|
|
28
|
+
function sameValues(a, b) {
|
|
29
|
+
if (a?.length !== b?.length || !a || !b)
|
|
30
|
+
return false;
|
|
31
|
+
return a.every((value, index) => value === b[index]);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Adjacent sampled offsets whose values differ for any tracked element and whose gap is wider
|
|
35
|
+
* than `minGap`: where adaptive sampling should take a midpoint.
|
|
36
|
+
*/
|
|
37
|
+
export function refinementTargets(rounds, minGap, maxTargets = 60) {
|
|
38
|
+
const sorted = [...rounds].sort((a, b) => a.y - b.y);
|
|
39
|
+
const scored = [];
|
|
40
|
+
for (let index = 1; index < sorted.length; index++) {
|
|
41
|
+
const before = sorted[index - 1];
|
|
42
|
+
const after = sorted[index];
|
|
43
|
+
if (!before || !after || after.y - before.y <= minGap)
|
|
44
|
+
continue;
|
|
45
|
+
let changed = 0;
|
|
46
|
+
const byIndex = new Map(after.samples.map((sample) => [sample.index, sample.values]));
|
|
47
|
+
for (const sample of before.samples) {
|
|
48
|
+
if (!sameValues(sample.values, byIndex.get(sample.index)))
|
|
49
|
+
changed++;
|
|
50
|
+
}
|
|
51
|
+
const vars = before.vars ?? {};
|
|
52
|
+
const nextVars = after.vars ?? {};
|
|
53
|
+
for (const key of new Set([...Object.keys(vars), ...Object.keys(nextVars)])) {
|
|
54
|
+
if (vars[key] !== nextVars[key])
|
|
55
|
+
changed++;
|
|
56
|
+
}
|
|
57
|
+
if (changed)
|
|
58
|
+
scored.push({ y: Math.round((before.y + after.y) / 2), changed });
|
|
59
|
+
}
|
|
60
|
+
return scored
|
|
61
|
+
.sort((a, b) => b.changed - a.changed || a.y - b.y)
|
|
62
|
+
.slice(0, maxTargets)
|
|
63
|
+
.map((item) => item.y)
|
|
64
|
+
.sort((a, b) => a - b);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Turns raw per-scroll samples into tracks for elements whose style changed with scroll. Each
|
|
68
|
+
* property keeps only the offsets where it changed. `idle` marks elements that also changed with
|
|
69
|
+
* no scroll at all (time-based loops); those are excluded unless they also differ by offset.
|
|
70
|
+
*/
|
|
71
|
+
export function buildMotionTracks(meta, rounds, options = {}) {
|
|
72
|
+
const limit = options.limit ?? 300;
|
|
73
|
+
const sorted = [...rounds].sort((a, b) => a.y - b.y);
|
|
74
|
+
const tracks = [];
|
|
75
|
+
meta.forEach((info, index) => {
|
|
76
|
+
const curves = {};
|
|
77
|
+
let changes = 0;
|
|
78
|
+
MOTION_PROPS.forEach((prop, k) => {
|
|
79
|
+
const points = [];
|
|
80
|
+
let previous;
|
|
81
|
+
for (const round of sorted) {
|
|
82
|
+
const value = round.samples.find((sample) => sample.index === index)?.values[k];
|
|
83
|
+
if (value === undefined)
|
|
84
|
+
continue;
|
|
85
|
+
if (previous === undefined || value !== previous) {
|
|
86
|
+
points.push([round.y, value]);
|
|
87
|
+
previous = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (points.length > 1) {
|
|
91
|
+
curves[prop] = points;
|
|
92
|
+
changes += points.length - 1;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
if (!changes)
|
|
96
|
+
return;
|
|
97
|
+
tracks.push({
|
|
98
|
+
id: trackId(info.path),
|
|
99
|
+
path: info.path,
|
|
100
|
+
tag: info.tag,
|
|
101
|
+
top: info.top,
|
|
102
|
+
height: info.height,
|
|
103
|
+
range: [
|
|
104
|
+
Math.min(...Object.values(curves).map((points) => points[1]?.[0] ?? Infinity)),
|
|
105
|
+
Math.max(...Object.values(curves).map((points) => points.at(-1)?.[0] ?? 0)),
|
|
106
|
+
],
|
|
107
|
+
timeBased: options.idleChanging?.has(index) ?? false,
|
|
108
|
+
curves,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
return tracks
|
|
112
|
+
.sort((a, b) => changeCount(b) - changeCount(a) || a.path.localeCompare(b.path))
|
|
113
|
+
.slice(0, limit);
|
|
114
|
+
}
|
|
115
|
+
export function changeCount(track) {
|
|
116
|
+
return Object.values(track.curves).reduce((sum, points) => sum + (points?.length ?? 1) - 1, 0);
|
|
117
|
+
}
|
|
118
|
+
/** Root CSS variables whose value differs between offsets, with the change points. */
|
|
119
|
+
export function buildVariableTracks(rounds) {
|
|
120
|
+
const sorted = [...rounds].sort((a, b) => a.y - b.y);
|
|
121
|
+
const keys = new Set(sorted.flatMap((round) => Object.keys(round.vars ?? {})));
|
|
122
|
+
const out = {};
|
|
123
|
+
for (const key of [...keys].sort()) {
|
|
124
|
+
const points = [];
|
|
125
|
+
let previous;
|
|
126
|
+
for (const round of sorted) {
|
|
127
|
+
const value = round.vars?.[key];
|
|
128
|
+
if (value === undefined || value === previous)
|
|
129
|
+
continue;
|
|
130
|
+
points.push([round.y, value]);
|
|
131
|
+
previous = value;
|
|
132
|
+
}
|
|
133
|
+
if (points.length > 1)
|
|
134
|
+
out[key] = points;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
/** Linear interpolation of the numbers inside a CSS value; non-numeric parts must match. */
|
|
139
|
+
export function numbersIn(value) {
|
|
140
|
+
return [...value.matchAll(/-?\d*\.?\d+(?:e-?\d+)?/gi)].map((match) => Number(match[0]));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=motion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"motion.js","sourceRoot":"","sources":["../../src/domain/motion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** `#hero > div:nth-of-type(2) > h1`; shadow boundaries are joined with ` >>> `. */
|
|
2
|
+
export function stablePathOf(node, access) {
|
|
3
|
+
const generated = /\d{4,}|^:r|^radix-|^headlessui-|^[a-f0-9]{8,}$|^ember\d|^react-aria/i;
|
|
4
|
+
const scopes = [];
|
|
5
|
+
let current = node;
|
|
6
|
+
let parts = [];
|
|
7
|
+
let guard = 0;
|
|
8
|
+
while (current !== null && guard++ < 400) {
|
|
9
|
+
const tag = access.tag(current).toLowerCase();
|
|
10
|
+
if (tag === 'html' || tag === 'body') {
|
|
11
|
+
parts.unshift(tag);
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
const id = access.id(current);
|
|
15
|
+
if (id && !generated.test(id) && /^[A-Za-z][\w-]*$/.test(id) && access.uniqueId(current, id)) {
|
|
16
|
+
parts.unshift(`#${id}`);
|
|
17
|
+
const host = topHost(current, access);
|
|
18
|
+
if (host === null)
|
|
19
|
+
break;
|
|
20
|
+
scopes.unshift(parts.join(' > '));
|
|
21
|
+
parts = [];
|
|
22
|
+
current = host;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const same = access
|
|
26
|
+
.siblings(current)
|
|
27
|
+
.filter((sibling) => access.tag(sibling) === access.tag(current));
|
|
28
|
+
parts.unshift(same.length > 1 ? `${tag}:nth-of-type(${String(same.indexOf(current) + 1)})` : tag);
|
|
29
|
+
const parent = access.parent(current);
|
|
30
|
+
if (parent === null) {
|
|
31
|
+
const host = access.shadowHost(current);
|
|
32
|
+
if (host === null)
|
|
33
|
+
break;
|
|
34
|
+
scopes.unshift(parts.join(' > '));
|
|
35
|
+
parts = [];
|
|
36
|
+
current = host;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
current = parent;
|
|
40
|
+
}
|
|
41
|
+
scopes.unshift(parts.join(' > '));
|
|
42
|
+
return scopes.filter(Boolean).join(' >>> ');
|
|
43
|
+
function topHost(start, acc) {
|
|
44
|
+
let walk = start;
|
|
45
|
+
let steps = 0;
|
|
46
|
+
while (walk !== null && steps++ < 400) {
|
|
47
|
+
const up = acc.parent(walk);
|
|
48
|
+
if (up === null)
|
|
49
|
+
return acc.shadowHost(walk);
|
|
50
|
+
walk = up;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/domain/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const ok = (value) => ({ ok: true, value });
|
|
2
|
+
export const err = (error) => ({ ok: false, error });
|
|
3
|
+
export const ERROR_TAGS = [
|
|
4
|
+
'invalid-input',
|
|
5
|
+
'chrome-missing',
|
|
6
|
+
'chrome-launch',
|
|
7
|
+
'navigation',
|
|
8
|
+
'timeout',
|
|
9
|
+
'aborted',
|
|
10
|
+
'cdp',
|
|
11
|
+
'budget',
|
|
12
|
+
'not-found',
|
|
13
|
+
'worker',
|
|
14
|
+
'io',
|
|
15
|
+
];
|
|
16
|
+
export const mcError = (tag, message, hint) => hint === undefined ? { tag, message } : { tag, message, hint };
|
|
17
|
+
/** Thrown form of an McError, for code paths where a Result can't flow (deep I/O, workers). */
|
|
18
|
+
export class TaggedError extends Error {
|
|
19
|
+
error;
|
|
20
|
+
constructor(error) {
|
|
21
|
+
super(error.hint === undefined ? error.message : `${error.message} (${error.hint})`);
|
|
22
|
+
this.error = error;
|
|
23
|
+
this.name = `McError[${error.tag}]`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function unwrap(result) {
|
|
27
|
+
if (result.ok)
|
|
28
|
+
return result.value;
|
|
29
|
+
throw new TaggedError(result.error);
|
|
30
|
+
}
|
|
31
|
+
export function toMcError(error) {
|
|
32
|
+
if (error instanceof TaggedError)
|
|
33
|
+
return error.error;
|
|
34
|
+
if (error instanceof Error && error.name === 'AbortError')
|
|
35
|
+
return mcError('aborted', error.message);
|
|
36
|
+
return mcError('io', error instanceof Error ? error.message : String(error));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/domain/result.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,EAAE,GAAG,CAAI,KAAQ,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,GAAG,GAAG,CAAI,KAAQ,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,eAAe;IACf,gBAAgB;IAChB,eAAe;IACf,YAAY;IACZ,SAAS;IACT,SAAS;IACT,KAAK;IACL,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,IAAI;CACI,CAAC;AASX,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAa,EAAE,OAAe,EAAE,IAAa,EAAW,EAAE,CAChF,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAEjE,+FAA+F;AAC/F,MAAM,OAAO,WAAY,SAAQ,KAAK;IACf;IAArB,YAAqB,KAAc;QACjC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QADlE,UAAK,GAAL,KAAK,CAAS;QAEjC,IAAI,CAAC,IAAI,GAAG,WAAW,KAAK,CAAC,GAAG,GAAG,CAAC;IACtC,CAAC;CACF;AAED,MAAM,UAAU,MAAM,CAAI,MAAiB;IACzC,IAAI,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IACnC,MAAM,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,KAAK,YAAY,WAAW;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IACrD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QACvD,OAAO,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC,IAAI,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/** Path segment formats turned into typed parameters (REA's api-surface rules, plus slugs by variance). */
|
|
2
|
+
export const ROUTE_RULES = ['numeric', 'uuid', 'hex', 'iso-date', 'token'];
|
|
3
|
+
export function segmentRule(value) {
|
|
4
|
+
if (/^[0-9]+$/.test(value))
|
|
5
|
+
return 'numeric';
|
|
6
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value))
|
|
7
|
+
return 'uuid';
|
|
8
|
+
if (/^[0-9a-f]{24,}$/i.test(value))
|
|
9
|
+
return 'hex';
|
|
10
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
11
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
12
|
+
if (Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value)
|
|
13
|
+
return 'iso-date';
|
|
14
|
+
}
|
|
15
|
+
// Opaque ids: long mixed letters+digits without separators (base62/base64url).
|
|
16
|
+
if (value.length >= 16 &&
|
|
17
|
+
/^[A-Za-z0-9_-]+$/.test(value) &&
|
|
18
|
+
/\d/.test(value) &&
|
|
19
|
+
/[A-Za-z]/.test(value))
|
|
20
|
+
return 'token';
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
/** True for responses that look like data APIs rather than documents or static assets. */
|
|
24
|
+
export function isApiRequest(request) {
|
|
25
|
+
if (/^(Fetch|XHR|EventSource|WebSocket)$/.test(request.resourceType))
|
|
26
|
+
return true;
|
|
27
|
+
return (/json|graphql|x-protobuf|grpc|ndjson|event-stream/.test(request.mimeType) &&
|
|
28
|
+
request.resourceType !== 'Document');
|
|
29
|
+
}
|
|
30
|
+
const pathSegments = (path) => path.split('/').slice(1);
|
|
31
|
+
/**
|
|
32
|
+
* Groups API requests into route templates. Format rules apply per segment; then, among routes
|
|
33
|
+
* with the same method, origin, segment count and all-but-one equal literal segments, a segment
|
|
34
|
+
* whose value varies across 3+ requests becomes a `{slug}` parameter (sibling variance).
|
|
35
|
+
*/
|
|
36
|
+
export function buildApiRoutes(requests) {
|
|
37
|
+
const drafts = new Map();
|
|
38
|
+
requests.forEach((request, entry) => {
|
|
39
|
+
if (!isApiRequest(request))
|
|
40
|
+
return;
|
|
41
|
+
let url;
|
|
42
|
+
try {
|
|
43
|
+
url = new URL(request.url);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const segments = pathSegments(url.pathname);
|
|
49
|
+
const params = new Map();
|
|
50
|
+
const literal = segments.map((segment, index) => {
|
|
51
|
+
const rule = segmentRule(decodeURIComponent(segment));
|
|
52
|
+
if (rule === null)
|
|
53
|
+
return segment;
|
|
54
|
+
params.set(index, rule);
|
|
55
|
+
return `{${rule}}`;
|
|
56
|
+
});
|
|
57
|
+
const key = `${request.method} ${url.origin}/${literal.join('/')}`;
|
|
58
|
+
const draft = drafts.get(key) ?? {
|
|
59
|
+
method: request.method,
|
|
60
|
+
origin: url.origin,
|
|
61
|
+
segments: literal,
|
|
62
|
+
params,
|
|
63
|
+
query: new Set(),
|
|
64
|
+
statuses: new Set(),
|
|
65
|
+
mimeTypes: new Set(),
|
|
66
|
+
examples: [],
|
|
67
|
+
};
|
|
68
|
+
for (const name of url.searchParams.keys())
|
|
69
|
+
draft.query.add(name);
|
|
70
|
+
draft.statuses.add(request.status);
|
|
71
|
+
if (request.mimeType)
|
|
72
|
+
draft.mimeTypes.add(request.mimeType);
|
|
73
|
+
draft.examples.push({ url: request.url, entry });
|
|
74
|
+
drafts.set(key, draft);
|
|
75
|
+
});
|
|
76
|
+
// Sibling variance: merge drafts differing in exactly one literal segment.
|
|
77
|
+
const groups = new Map();
|
|
78
|
+
for (const draft of drafts.values()) {
|
|
79
|
+
for (let index = 0; index < draft.segments.length; index++) {
|
|
80
|
+
if (draft.params.has(index))
|
|
81
|
+
continue;
|
|
82
|
+
const shape = [...draft.segments];
|
|
83
|
+
shape[index] = '*';
|
|
84
|
+
const key = `${draft.method} ${draft.origin} ${String(index)} ${shape.join('/')}`;
|
|
85
|
+
const list = groups.get(key) ?? [];
|
|
86
|
+
list.push(draft);
|
|
87
|
+
groups.set(key, list);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const merged = new Set();
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const [key, list] of [...groups].sort(([a], [b]) => a.localeCompare(b))) {
|
|
93
|
+
const fresh = list.filter((draft) => !merged.has(draft));
|
|
94
|
+
if (fresh.length < 3)
|
|
95
|
+
continue;
|
|
96
|
+
const index = Number(key.split(' ')[2]);
|
|
97
|
+
const first = fresh[0];
|
|
98
|
+
if (!first)
|
|
99
|
+
continue;
|
|
100
|
+
const segments = [...first.segments];
|
|
101
|
+
segments[index] = '{slug}';
|
|
102
|
+
const params = new Map(first.params);
|
|
103
|
+
params.set(index, 'slug');
|
|
104
|
+
const combined = {
|
|
105
|
+
method: first.method,
|
|
106
|
+
origin: first.origin,
|
|
107
|
+
segments,
|
|
108
|
+
params,
|
|
109
|
+
query: new Set(fresh.flatMap((draft) => [...draft.query])),
|
|
110
|
+
statuses: new Set(fresh.flatMap((draft) => [...draft.statuses])),
|
|
111
|
+
mimeTypes: new Set(fresh.flatMap((draft) => [...draft.mimeTypes])),
|
|
112
|
+
examples: fresh.flatMap((draft) => draft.examples),
|
|
113
|
+
};
|
|
114
|
+
for (const draft of fresh)
|
|
115
|
+
merged.add(draft);
|
|
116
|
+
out.push(combined);
|
|
117
|
+
}
|
|
118
|
+
for (const draft of drafts.values())
|
|
119
|
+
if (!merged.has(draft))
|
|
120
|
+
out.push(draft);
|
|
121
|
+
return out
|
|
122
|
+
.map((draft) => ({
|
|
123
|
+
method: draft.method,
|
|
124
|
+
origin: draft.origin,
|
|
125
|
+
template: `/${draft.segments.join('/')}`,
|
|
126
|
+
params: [...draft.params]
|
|
127
|
+
.map(([index, rule]) => ({ index, rule }))
|
|
128
|
+
.sort((a, b) => a.index - b.index),
|
|
129
|
+
query: [...draft.query].sort(),
|
|
130
|
+
statuses: [...draft.statuses].sort((a, b) => a - b),
|
|
131
|
+
mimeTypes: [...draft.mimeTypes].sort(),
|
|
132
|
+
examples: draft.examples.slice(0, 20),
|
|
133
|
+
}))
|
|
134
|
+
.sort((a, b) => a.origin.localeCompare(b.origin) ||
|
|
135
|
+
a.template.localeCompare(b.template) ||
|
|
136
|
+
a.method.localeCompare(b.method));
|
|
137
|
+
}
|
|
138
|
+
/** Does a concrete path match a template? Returns the parameter values, or null. */
|
|
139
|
+
export function matchRoute(template, path) {
|
|
140
|
+
const want = pathSegments(template);
|
|
141
|
+
const have = pathSegments(path);
|
|
142
|
+
if (want.length !== have.length)
|
|
143
|
+
return null;
|
|
144
|
+
const params = {};
|
|
145
|
+
for (let index = 0; index < want.length; index++) {
|
|
146
|
+
const expected = want[index] ?? '';
|
|
147
|
+
const actual = have[index] ?? '';
|
|
148
|
+
const param = /^\{([\w-]+)\}$/.exec(expected);
|
|
149
|
+
if (param) {
|
|
150
|
+
const rule = param[1] ?? 'slug';
|
|
151
|
+
if (rule !== 'slug' && segmentRule(decodeURIComponent(actual)) !== rule)
|
|
152
|
+
return null;
|
|
153
|
+
params[`${String(index)}:${rule}`] = actual;
|
|
154
|
+
}
|
|
155
|
+
else if (expected !== actual)
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return params;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/domain/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const slugify = (value) => value
|
|
2
|
+
.toLowerCase()
|
|
3
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
4
|
+
.replace(/^-|-$/g, '')
|
|
5
|
+
.slice(0, 40) || 'section';
|
|
6
|
+
/**
|
|
7
|
+
* Matches sections of the primary viewport to the others: same path first, then same label,
|
|
8
|
+
* then the closest relative vertical position. Unmatched sections on other viewports are kept as
|
|
9
|
+
* their own entries, ordered by relative position.
|
|
10
|
+
*/
|
|
11
|
+
export function matchSections(byViewport, heights, primary) {
|
|
12
|
+
const base = byViewport.get(primary) ?? [];
|
|
13
|
+
const rel = (viewport, section) => section.top / Math.max(1, heights.get(viewport) ?? section.bottom);
|
|
14
|
+
const groups = base.map((section) => ({
|
|
15
|
+
label: section.label,
|
|
16
|
+
anchor: rel(primary, section),
|
|
17
|
+
perViewport: { [primary]: section },
|
|
18
|
+
}));
|
|
19
|
+
for (const [viewport, sections] of [...byViewport].sort(([a], [b]) => a.localeCompare(b))) {
|
|
20
|
+
if (viewport === primary)
|
|
21
|
+
continue;
|
|
22
|
+
const free = new Set(groups.map((_, index) => index));
|
|
23
|
+
for (const section of sections) {
|
|
24
|
+
let pick = [...free].find((index) => groups[index]?.perViewport[primary]?.path === section.path);
|
|
25
|
+
pick ??= [...free].find((index) => groups[index]?.label === section.label);
|
|
26
|
+
if (pick === undefined) {
|
|
27
|
+
let best = Infinity;
|
|
28
|
+
for (const index of free) {
|
|
29
|
+
const group = groups[index];
|
|
30
|
+
if (!group)
|
|
31
|
+
continue;
|
|
32
|
+
const distance = Math.abs(group.anchor - rel(viewport, section));
|
|
33
|
+
if (distance < best && distance < 0.08) {
|
|
34
|
+
best = distance;
|
|
35
|
+
pick = index;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const group = pick === undefined ? undefined : groups[pick];
|
|
40
|
+
if (pick !== undefined && group) {
|
|
41
|
+
group.perViewport[viewport] = section;
|
|
42
|
+
free.delete(pick);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
groups.push({
|
|
46
|
+
label: section.label,
|
|
47
|
+
anchor: rel(viewport, section),
|
|
48
|
+
perViewport: { [viewport]: section },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
groups.sort((a, b) => a.anchor - b.anchor);
|
|
54
|
+
const used = new Map();
|
|
55
|
+
return groups.map((group, order) => {
|
|
56
|
+
const slug = slugify(group.label);
|
|
57
|
+
const count = used.get(slug) ?? 0;
|
|
58
|
+
used.set(slug, count + 1);
|
|
59
|
+
return {
|
|
60
|
+
id: `${String(order + 1).padStart(2, '0')}-${count ? `${slug}-${String(count + 1)}` : slug}`,
|
|
61
|
+
label: group.label,
|
|
62
|
+
order,
|
|
63
|
+
perViewport: group.perViewport,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** True when [top, bottom] overlaps the section by at least half of the smaller of the two. */
|
|
68
|
+
export function overlapsSection(top, bottom, section) {
|
|
69
|
+
const overlap = Math.min(bottom, section.bottom) - Math.max(top, section.top);
|
|
70
|
+
if (overlap <= 0)
|
|
71
|
+
return false;
|
|
72
|
+
const smaller = Math.max(1, Math.min(bottom - top, section.bottom - section.top));
|
|
73
|
+
return overlap / smaller >= 0.5;
|
|
74
|
+
}
|
|
75
|
+
/** Section whose range contains the most of [top, bottom], or null. */
|
|
76
|
+
export function sectionFor(sections, top, bottom) {
|
|
77
|
+
let best = null;
|
|
78
|
+
let bestOverlap = 0;
|
|
79
|
+
for (const section of sections) {
|
|
80
|
+
const overlap = Math.min(bottom, section.bottom) - Math.max(top, section.top);
|
|
81
|
+
if (overlap > bestOverlap) {
|
|
82
|
+
bestOverlap = overlap;
|
|
83
|
+
best = section;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return best;
|
|
87
|
+
}
|
|
88
|
+
/** True when `path` is the section path or lies inside it (path prefix with a separator). */
|
|
89
|
+
export function pathWithin(path, sectionPath) {
|
|
90
|
+
return (path === sectionPath ||
|
|
91
|
+
path.startsWith(`${sectionPath} > `) ||
|
|
92
|
+
path.startsWith(`${sectionPath} >>> `));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=sections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/domain/sections.ts"],"names":[],"mappings":"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"}
|