ushman-characterize 0.4.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/AGENTS.md +110 -0
- package/CHANGELOG.md +41 -0
- package/LICENSE.md +21 -0
- package/README.md +193 -0
- package/bin/ushman-characterize +19 -0
- package/dist/babel-config.d.ts +7 -0
- package/dist/babel-config.d.ts.map +1 -0
- package/dist/babel-config.js +17 -0
- package/dist/capture-server.d.ts +31 -0
- package/dist/capture-server.d.ts.map +1 -0
- package/dist/capture-server.js +199 -0
- package/dist/capture.d.ts +97 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +620 -0
- package/dist/cli/logger.d.ts +7 -0
- package/dist/cli/logger.d.ts.map +1 -0
- package/dist/cli/logger.js +14 -0
- package/dist/cli/parse-flags.d.ts +8 -0
- package/dist/cli/parse-flags.d.ts.map +1 -0
- package/dist/cli/parse-flags.js +60 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +439 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +19 -0
- package/dist/dedupe-contract.d.ts +26 -0
- package/dist/dedupe-contract.d.ts.map +1 -0
- package/dist/dedupe-contract.js +12 -0
- package/dist/default-export.d.ts +6 -0
- package/dist/default-export.d.ts.map +1 -0
- package/dist/default-export.js +52 -0
- package/dist/format-contract.d.ts +25 -0
- package/dist/format-contract.d.ts.map +1 -0
- package/dist/format-contract.js +96 -0
- package/dist/function-utils.d.ts +6 -0
- package/dist/function-utils.d.ts.map +1 -0
- package/dist/function-utils.js +22 -0
- package/dist/generate-replay.d.ts +18 -0
- package/dist/generate-replay.d.ts.map +1 -0
- package/dist/generate-replay.js +158 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/instrument.d.ts +39 -0
- package/dist/instrument.d.ts.map +1 -0
- package/dist/instrument.js +605 -0
- package/dist/ledger.d.ts +19 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +50 -0
- package/dist/puppeteer-harness.d.ts +74 -0
- package/dist/puppeteer-harness.d.ts.map +1 -0
- package/dist/puppeteer-harness.js +248 -0
- package/dist/purity-classifier.d.ts +28 -0
- package/dist/purity-classifier.d.ts.map +1 -0
- package/dist/purity-classifier.js +363 -0
- package/dist/rebind.d.ts +26 -0
- package/dist/rebind.d.ts.map +1 -0
- package/dist/rebind.js +356 -0
- package/dist/replay-report.d.ts +18 -0
- package/dist/replay-report.d.ts.map +1 -0
- package/dist/replay-report.js +12 -0
- package/dist/scene.d.ts +24 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +235 -0
- package/dist/schema-types.d.ts +40 -0
- package/dist/schema-types.d.ts.map +1 -0
- package/dist/schema-types.js +32 -0
- package/dist/seed-scaffolds.d.ts +31 -0
- package/dist/seed-scaffolds.d.ts.map +1 -0
- package/dist/seed-scaffolds.js +96 -0
- package/dist/shared.d.ts +36 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +390 -0
- package/dist/state-dag.d.ts +5 -0
- package/dist/state-dag.d.ts.map +1 -0
- package/dist/state-dag.js +27 -0
- package/dist/stub-pure.d.ts +57 -0
- package/dist/stub-pure.d.ts.map +1 -0
- package/dist/stub-pure.js +987 -0
- package/dist/time.d.ts +3 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +10 -0
- package/dist/trace-format.d.ts +24 -0
- package/dist/trace-format.d.ts.map +1 -0
- package/dist/trace-format.js +213 -0
- package/dist/trace-serializer.d.ts +94 -0
- package/dist/trace-serializer.d.ts.map +1 -0
- package/dist/trace-serializer.js +607 -0
- package/dist/tracer-runtime.d.ts +25 -0
- package/dist/tracer-runtime.d.ts.map +1 -0
- package/dist/tracer-runtime.js +291 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/workspace-paths.d.ts +64 -0
- package/dist/workspace-paths.d.ts.map +1 -0
- package/dist/workspace-paths.js +288 -0
- package/package.json +86 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
type BrowserLike = {
|
|
2
|
+
readonly close: () => Promise<void>;
|
|
3
|
+
readonly newPage: () => Promise<BrowserPage>;
|
|
4
|
+
readonly pages: () => Promise<BrowserPage[]>;
|
|
5
|
+
};
|
|
6
|
+
type PuppeteerModule = {
|
|
7
|
+
readonly launch: (options: Record<string, unknown>) => Promise<BrowserLike>;
|
|
8
|
+
};
|
|
9
|
+
export type BrowserRequest = {
|
|
10
|
+
readonly continue: () => Promise<unknown>;
|
|
11
|
+
readonly respond: (response: {
|
|
12
|
+
readonly body: string;
|
|
13
|
+
readonly contentType: string;
|
|
14
|
+
readonly status: number;
|
|
15
|
+
}) => Promise<unknown>;
|
|
16
|
+
readonly url: () => string;
|
|
17
|
+
};
|
|
18
|
+
export type BrowserPage = {
|
|
19
|
+
readonly click: (selector: string) => Promise<unknown>;
|
|
20
|
+
readonly close: () => Promise<unknown>;
|
|
21
|
+
readonly evaluate: <T>(fn: (...args: never[]) => Promise<T> | T, ...args: unknown[]) => Promise<T>;
|
|
22
|
+
readonly evaluateOnNewDocument: (script: string) => Promise<unknown>;
|
|
23
|
+
readonly goto: (url: string, options?: {
|
|
24
|
+
readonly waitUntil?: string;
|
|
25
|
+
}) => Promise<unknown>;
|
|
26
|
+
readonly off?: (event: 'request', handler: (request: BrowserRequest) => void) => void;
|
|
27
|
+
readonly on: (event: 'request', handler: (request: BrowserRequest) => void) => void;
|
|
28
|
+
readonly setRequestInterception: (enabled: boolean) => Promise<unknown>;
|
|
29
|
+
readonly url?: () => string;
|
|
30
|
+
readonly waitForNetworkIdle?: (options: {
|
|
31
|
+
readonly idleTime: number;
|
|
32
|
+
readonly timeout: number;
|
|
33
|
+
}) => Promise<unknown>;
|
|
34
|
+
};
|
|
35
|
+
export type HarnessLaunchOptions = {
|
|
36
|
+
readonly deterministicPreboot?: boolean;
|
|
37
|
+
readonly replaceDateConstructor?: boolean;
|
|
38
|
+
readonly seed?: string;
|
|
39
|
+
readonly viewport: {
|
|
40
|
+
readonly height: number;
|
|
41
|
+
readonly width: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export type PuppeteerPageHandle = {
|
|
45
|
+
readonly close: () => Promise<void>;
|
|
46
|
+
readonly goto: (url: string) => Promise<void>;
|
|
47
|
+
readonly page: BrowserPage;
|
|
48
|
+
readonly tickFrame: (msPerFrame?: number) => Promise<void>;
|
|
49
|
+
};
|
|
50
|
+
export type PuppeteerHarness = {
|
|
51
|
+
readonly close: () => Promise<void>;
|
|
52
|
+
readonly launch: (options: HarnessLaunchOptions) => Promise<PuppeteerPageHandle>;
|
|
53
|
+
};
|
|
54
|
+
export declare const safeEvaluate: <T>(page: BrowserPage, label: string, fn: (...args: never[]) => Promise<T> | T, ...args: unknown[]) => Promise<T>;
|
|
55
|
+
export declare const createPuppeteerHarness: ({ executablePath, headless, moduleLoader, }?: {
|
|
56
|
+
readonly executablePath?: string;
|
|
57
|
+
readonly headless?: boolean;
|
|
58
|
+
readonly moduleLoader?: () => Promise<PuppeteerModule>;
|
|
59
|
+
}) => PuppeteerHarness;
|
|
60
|
+
export declare const __testOnly: {
|
|
61
|
+
buildChromeFlags: (viewport: {
|
|
62
|
+
readonly height: number;
|
|
63
|
+
readonly width: number;
|
|
64
|
+
}) => string[];
|
|
65
|
+
buildPrebootScript: ({ clockStartMs, replaceDateConstructor, seed, }: {
|
|
66
|
+
readonly clockStartMs: number;
|
|
67
|
+
readonly replaceDateConstructor?: boolean;
|
|
68
|
+
readonly seed: string;
|
|
69
|
+
}) => string;
|
|
70
|
+
isContextDestroyedError: (error: unknown) => boolean;
|
|
71
|
+
waitForSpaSettle: (page: BrowserPage) => Promise<void>;
|
|
72
|
+
};
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=puppeteer-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"puppeteer-harness.d.ts","sourceRoot":"","sources":["../src/puppeteer-harness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
const FAKE_CLOCK_START_MS = Date.UTC(2026, 0, 1, 0, 0, 0);
|
|
10
|
+
const buildChromeFlags = (viewport) => [
|
|
11
|
+
'--headless=new',
|
|
12
|
+
'--no-sandbox',
|
|
13
|
+
'--disable-dev-shm-usage',
|
|
14
|
+
'--hide-scrollbars',
|
|
15
|
+
'--mute-audio',
|
|
16
|
+
'--disable-background-timer-throttling',
|
|
17
|
+
'--disable-backgrounding-occluded-windows',
|
|
18
|
+
'--disable-renderer-backgrounding',
|
|
19
|
+
`--window-size=${viewport.width},${viewport.height}`,
|
|
20
|
+
];
|
|
21
|
+
const buildPrebootScript = ({ clockStartMs, replaceDateConstructor = false, seed, }) => `(function preboot(seed, clockStartMs, replaceDateConstructor) {
|
|
22
|
+
var g = globalThis;
|
|
23
|
+
if (g.__ushmanPreboot) { return; }
|
|
24
|
+
function hash(str) {
|
|
25
|
+
var h1 = 0xdeadbeef ^ 0, h2 = 0x41c6ce57 ^ 0;
|
|
26
|
+
for (var i = 0; i < str.length; i++) {
|
|
27
|
+
var ch = str.charCodeAt(i);
|
|
28
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
29
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
30
|
+
}
|
|
31
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
32
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
33
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)) / 4503599627370496;
|
|
34
|
+
}
|
|
35
|
+
function prng() {
|
|
36
|
+
prngState = (prngState * 16807) % 2147483647;
|
|
37
|
+
if (prngState === 0) { prngState = 1; }
|
|
38
|
+
return (prngState - 1) / 2147483646;
|
|
39
|
+
}
|
|
40
|
+
var fakeNowMs = clockStartMs;
|
|
41
|
+
var timerId = 1;
|
|
42
|
+
var pendingTimers = {};
|
|
43
|
+
var realPerfNow = performance.now.bind(performance);
|
|
44
|
+
var realtimePerfStartMs = realPerfNow();
|
|
45
|
+
var realRandom = Math.random;
|
|
46
|
+
var realDate = Date;
|
|
47
|
+
var realDateNow = Date.now;
|
|
48
|
+
var prngState = Math.floor(hash(seed) * 2147483646) + 1;
|
|
49
|
+
Math.random = function () { return prng(); };
|
|
50
|
+
Date.now = function () { return fakeNowMs; };
|
|
51
|
+
if (replaceDateConstructor) {
|
|
52
|
+
var FakeDate = function () {
|
|
53
|
+
var args = Array.prototype.slice.call(arguments);
|
|
54
|
+
if (!(this instanceof FakeDate)) {
|
|
55
|
+
return new realDate(fakeNowMs).toString();
|
|
56
|
+
}
|
|
57
|
+
if (args.length === 0) {
|
|
58
|
+
return Reflect.construct(realDate, [fakeNowMs], FakeDate);
|
|
59
|
+
}
|
|
60
|
+
return Reflect.construct(realDate, args, FakeDate);
|
|
61
|
+
};
|
|
62
|
+
FakeDate.now = function () { return fakeNowMs; };
|
|
63
|
+
FakeDate.parse = realDate.parse.bind(realDate);
|
|
64
|
+
FakeDate.UTC = realDate.UTC.bind(realDate);
|
|
65
|
+
FakeDate.prototype = realDate.prototype;
|
|
66
|
+
Object.setPrototypeOf(FakeDate, realDate);
|
|
67
|
+
g.Date = FakeDate;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
performance.now = function () { return fakeNowMs - clockStartMs; };
|
|
71
|
+
} catch {}
|
|
72
|
+
g.requestAnimationFrame = function (cb) {
|
|
73
|
+
var id = timerId++;
|
|
74
|
+
pendingTimers[id] = { fn: cb, fireAtMs: fakeNowMs + 16, repeatMs: null, raf: true };
|
|
75
|
+
return id;
|
|
76
|
+
};
|
|
77
|
+
g.cancelAnimationFrame = function (id) { delete pendingTimers[id]; };
|
|
78
|
+
g.setTimeout = function (fn, ms) {
|
|
79
|
+
var args = Array.prototype.slice.call(arguments, 2);
|
|
80
|
+
var id = timerId++;
|
|
81
|
+
pendingTimers[id] = { args: args, fireAtMs: fakeNowMs + (ms || 0), fn: fn, repeatMs: null, raf: false };
|
|
82
|
+
return id;
|
|
83
|
+
};
|
|
84
|
+
g.clearTimeout = function (id) { delete pendingTimers[id]; };
|
|
85
|
+
g.setInterval = function (fn, ms) {
|
|
86
|
+
var args = Array.prototype.slice.call(arguments, 2);
|
|
87
|
+
var intervalMs = ms || 0;
|
|
88
|
+
var id = timerId++;
|
|
89
|
+
pendingTimers[id] = { args: args, fireAtMs: fakeNowMs + intervalMs, fn: fn, repeatMs: intervalMs, raf: false };
|
|
90
|
+
return id;
|
|
91
|
+
};
|
|
92
|
+
g.clearInterval = function (id) { delete pendingTimers[id]; };
|
|
93
|
+
if (g.crypto) {
|
|
94
|
+
var uuidCounter = 0;
|
|
95
|
+
g.crypto.randomUUID = function () {
|
|
96
|
+
uuidCounter++;
|
|
97
|
+
var hex = uuidCounter.toString(16).padStart(12, '0');
|
|
98
|
+
return '00000000-0000-4000-8000-' + hex;
|
|
99
|
+
};
|
|
100
|
+
g.crypto.getRandomValues = function (typedArray) {
|
|
101
|
+
for (var i = 0; i < typedArray.length; i++) {
|
|
102
|
+
typedArray[i] = Math.floor(prng() * 256);
|
|
103
|
+
}
|
|
104
|
+
return typedArray;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function tick(msPerFrame) {
|
|
108
|
+
fakeNowMs += (msPerFrame || 16);
|
|
109
|
+
var ready = [];
|
|
110
|
+
for (var id in pendingTimers) {
|
|
111
|
+
if (pendingTimers[id].fireAtMs <= fakeNowMs) {
|
|
112
|
+
ready.push(pendingTimers[id]);
|
|
113
|
+
if (pendingTimers[id].repeatMs === null) {
|
|
114
|
+
delete pendingTimers[id];
|
|
115
|
+
} else {
|
|
116
|
+
pendingTimers[id].fireAtMs += pendingTimers[id].repeatMs;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (var j = 0; j < ready.length; j++) {
|
|
121
|
+
var timer = ready[j];
|
|
122
|
+
try {
|
|
123
|
+
if (timer.raf) {
|
|
124
|
+
timer.fn(fakeNowMs - clockStartMs);
|
|
125
|
+
} else if (typeof timer.fn === 'function') {
|
|
126
|
+
timer.fn.apply(undefined, timer.args || []);
|
|
127
|
+
}
|
|
128
|
+
} catch {}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
g.__ushmanPreboot = {
|
|
132
|
+
__realDate: realDate,
|
|
133
|
+
__realDateNow: realDateNow,
|
|
134
|
+
__realPerfNow: realPerfNow,
|
|
135
|
+
__realRandom: realRandom,
|
|
136
|
+
tick: tick,
|
|
137
|
+
};
|
|
138
|
+
})(${JSON.stringify(seed)}, ${JSON.stringify(clockStartMs)}, ${JSON.stringify(replaceDateConstructor)});`;
|
|
139
|
+
const waitForSpaSettle = async (page) => {
|
|
140
|
+
try {
|
|
141
|
+
await page.waitForNetworkIdle?.({ idleTime: 500, timeout: 8_000 });
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// fall through
|
|
145
|
+
}
|
|
146
|
+
for (let index = 0; index < 5; index += 1) {
|
|
147
|
+
try {
|
|
148
|
+
await page.evaluate(() => document.readyState);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
153
|
+
if (!/Execution context was destroyed/i.test(message)) {
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const isContextDestroyedError = (error) => {
|
|
161
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
162
|
+
return /Execution context was destroyed/i.test(message);
|
|
163
|
+
};
|
|
164
|
+
const loadPuppeteer = async () => {
|
|
165
|
+
const specifier = 'puppeteer';
|
|
166
|
+
const imported = (await import(__rewriteRelativeImportExtension(specifier)));
|
|
167
|
+
const resolved = (imported.default ?? imported);
|
|
168
|
+
if (typeof resolved.launch !== 'function') {
|
|
169
|
+
throw new Error('The installed puppeteer package does not expose launch().');
|
|
170
|
+
}
|
|
171
|
+
return resolved;
|
|
172
|
+
};
|
|
173
|
+
export const safeEvaluate = async (page, label, fn, ...args) => {
|
|
174
|
+
let lastError = null;
|
|
175
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
176
|
+
try {
|
|
177
|
+
return await page.evaluate(fn, ...args);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
lastError = error;
|
|
181
|
+
if (!isContextDestroyedError(error)) {
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
await waitForSpaSettle(page);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
188
|
+
throw new Error(`[${label}] ${message}`);
|
|
189
|
+
};
|
|
190
|
+
export const createPuppeteerHarness = ({ executablePath, headless = true, moduleLoader = loadPuppeteer, } = {}) => {
|
|
191
|
+
let browser = null;
|
|
192
|
+
return {
|
|
193
|
+
async close() {
|
|
194
|
+
if (!browser) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
await browser.close();
|
|
198
|
+
browser = null;
|
|
199
|
+
},
|
|
200
|
+
async launch(options) {
|
|
201
|
+
if (!browser) {
|
|
202
|
+
const puppeteer = await moduleLoader();
|
|
203
|
+
browser = await puppeteer.launch({
|
|
204
|
+
...(executablePath ? { executablePath } : {}),
|
|
205
|
+
args: buildChromeFlags(options.viewport),
|
|
206
|
+
defaultViewport: {
|
|
207
|
+
height: options.viewport.height,
|
|
208
|
+
width: options.viewport.width,
|
|
209
|
+
},
|
|
210
|
+
headless,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const existingPages = await browser.pages();
|
|
214
|
+
const reusablePage = existingPages.find((entry) => entry.url?.() === 'about:blank');
|
|
215
|
+
const page = reusablePage ?? (await browser.newPage());
|
|
216
|
+
if (options.deterministicPreboot !== false) {
|
|
217
|
+
await page.evaluateOnNewDocument(buildPrebootScript({
|
|
218
|
+
clockStartMs: FAKE_CLOCK_START_MS,
|
|
219
|
+
replaceDateConstructor: options.replaceDateConstructor ?? false,
|
|
220
|
+
seed: options.seed ?? 'ushman-characterize',
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
close: async () => {
|
|
225
|
+
await page.close();
|
|
226
|
+
},
|
|
227
|
+
goto: async (url) => {
|
|
228
|
+
await page.goto(url, { waitUntil: 'load' });
|
|
229
|
+
await waitForSpaSettle(page);
|
|
230
|
+
},
|
|
231
|
+
page,
|
|
232
|
+
tickFrame: async (msPerFrame = 16) => {
|
|
233
|
+
await safeEvaluate(page, 'tickFrame', (frameDuration) => {
|
|
234
|
+
const preboot = globalThis
|
|
235
|
+
.__ushmanPreboot;
|
|
236
|
+
preboot?.tick?.(frameDuration);
|
|
237
|
+
}, msPerFrame);
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
export const __testOnly = {
|
|
244
|
+
buildChromeFlags,
|
|
245
|
+
buildPrebootScript,
|
|
246
|
+
isContextDestroyedError,
|
|
247
|
+
waitForSpaSettle,
|
|
248
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type BundleAst } from './shared.ts';
|
|
2
|
+
export type ImpureReason = 'async-or-generator' | 'calls-denied-global' | 'reads-denied-global' | 'reads-mutable-outer-binding' | 'throws-non-error' | 'writes-outer-binding';
|
|
3
|
+
export type PureFunctionInfo = {
|
|
4
|
+
readonly arity: number;
|
|
5
|
+
readonly bindingName: string;
|
|
6
|
+
readonly kind: 'function';
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly parameterNames: readonly string[];
|
|
9
|
+
};
|
|
10
|
+
export type ImpureFunctionInfo = {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly reason: ImpureReason;
|
|
13
|
+
};
|
|
14
|
+
export type PureClassificationResult = {
|
|
15
|
+
readonly impureFunctions: readonly ImpureFunctionInfo[];
|
|
16
|
+
readonly pureFunctions: readonly PureFunctionInfo[];
|
|
17
|
+
readonly skippedForTracing: readonly string[];
|
|
18
|
+
readonly totalTopLevelFunctions: number;
|
|
19
|
+
};
|
|
20
|
+
export declare const classifyPureTopLevelFunctionsFromBundle: (bundle: BundleAst) => PureClassificationResult;
|
|
21
|
+
/**
|
|
22
|
+
* Classify top-level function declarations into conservative pure/impure buckets.
|
|
23
|
+
*/
|
|
24
|
+
export declare const classifyPureTopLevelFunctions: ({ source, sourcePath, }: {
|
|
25
|
+
readonly source: string;
|
|
26
|
+
readonly sourcePath: string;
|
|
27
|
+
}) => PureClassificationResult;
|
|
28
|
+
//# sourceMappingURL=purity-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purity-classifier.d.ts","sourceRoot":"","sources":["../src/purity-classifier.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,aAAa,CAAC;AAE7D,MAAM,MAAM,YAAY,GAClB,oBAAoB,GACpB,qBAAqB,GACrB,qBAAqB,GACrB,6BAA6B,GAC7B,kBAAkB,GAClB,sBAAsB,CAAC;AAE7B,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACnC,QAAQ,CAAC,eAAe,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxD,QAAQ,CAAC,aAAa,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpD,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CAC3C,CAAC;AAqZF,eAAO,MAAM,uCAAuC,GAAI,QAAQ,SAAS,KAAG,wBAoD3E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,GAAI,yBAG3C;IACC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC/B,KAAG,wBAMC,CAAC"}
|