ushman-equiv 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 +81 -0
- package/LICENSE.md +21 -0
- package/README.md +201 -0
- package/bin/ushman-equiv +19 -0
- package/dist/analysis-context.d.ts +102 -0
- package/dist/analysis-context.d.ts.map +1 -0
- package/dist/analysis-context.js +708 -0
- package/dist/ast-guards.d.ts +24 -0
- package/dist/ast-guards.d.ts.map +1 -0
- package/dist/ast-guards.js +83 -0
- package/dist/candidate-boot.d.ts +30 -0
- package/dist/candidate-boot.d.ts.map +1 -0
- package/dist/candidate-boot.js +262 -0
- package/dist/canonicalize.d.ts +19 -0
- package/dist/canonicalize.d.ts.map +1 -0
- package/dist/canonicalize.js +525 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +312 -0
- package/dist/equiv-execution-context.d.ts +25 -0
- package/dist/equiv-execution-context.d.ts.map +1 -0
- package/dist/equiv-execution-context.js +82 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/run.d.ts +8 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +129 -0
- package/dist/shared.d.ts +9 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +47 -0
- package/dist/tier-i-import-graph.d.ts +7 -0
- package/dist/tier-i-import-graph.d.ts.map +1 -0
- package/dist/tier-i-import-graph.js +34 -0
- package/dist/tier-l-child-runtime.d.ts +2 -0
- package/dist/tier-l-child-runtime.d.ts.map +1 -0
- package/dist/tier-l-child-runtime.js +62 -0
- package/dist/tier-l-module-load.d.ts +6 -0
- package/dist/tier-l-module-load.d.ts.map +1 -0
- package/dist/tier-l-module-load.js +139 -0
- package/dist/tier-l-stub-source.d.ts +11 -0
- package/dist/tier-l-stub-source.d.ts.map +1 -0
- package/dist/tier-l-stub-source.js +246 -0
- package/dist/tier-r-replay.d.ts +6 -0
- package/dist/tier-r-replay.d.ts.map +1 -0
- package/dist/tier-r-replay.js +382 -0
- package/dist/tier-s-symbol-diff.d.ts +19 -0
- package/dist/tier-s-symbol-diff.d.ts.map +1 -0
- package/dist/tier-s-symbol-diff.js +156 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/workspace.d.ts +63 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +459 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-i-import-graph.d.ts","sourceRoot":"","sources":["../src/tier-i-import-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAgB,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrF,QAAA,MAAM,2BAA2B,GAC7B,SAAS,kBAAkB,EAC3B,SAAS,qBAAqB,KAC/B,OAAO,CAAC,gBAAgB,CA8B1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GACzB,SAAS,kBAAkB,KAC5B,OAAO,CAAC,gBAAgB,CAAwE,CAAC;AAEpG,OAAO,EAAE,2BAA2B,EAAE,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createEquivExecutionContext } from "./equiv-execution-context.js";
|
|
2
|
+
import { displayPath } from "./workspace.js";
|
|
3
|
+
const checkImportGraphWithContext = async (options, context) => {
|
|
4
|
+
const start = Date.now();
|
|
5
|
+
const analysis = await context.getImportGraph(options);
|
|
6
|
+
const missing = analysis.imports.filter((entry) => !entry.resolved);
|
|
7
|
+
const details = [
|
|
8
|
+
...analysis.parseFindings,
|
|
9
|
+
...missing.map((entry) => ({
|
|
10
|
+
evidence: {
|
|
11
|
+
importer: displayPath(options.workspaceRoot, entry.importerPath),
|
|
12
|
+
specifier: entry.specifier,
|
|
13
|
+
},
|
|
14
|
+
message: entry.message ?? `Unresolved import: ${entry.specifier}`,
|
|
15
|
+
path: displayPath(options.workspaceRoot, entry.importerPath),
|
|
16
|
+
})),
|
|
17
|
+
...analysis.warnings,
|
|
18
|
+
];
|
|
19
|
+
const severity = analysis.parseFindings.length > 0 || missing.length > 0
|
|
20
|
+
? 'red'
|
|
21
|
+
: analysis.imports.length === 0 || analysis.warnings.length > 0
|
|
22
|
+
? 'yellow'
|
|
23
|
+
: 'green';
|
|
24
|
+
const resolvedCount = analysis.imports.filter((entry) => entry.resolved).length;
|
|
25
|
+
return {
|
|
26
|
+
details: details.length > 0 ? details : undefined,
|
|
27
|
+
elapsedMs: Date.now() - start,
|
|
28
|
+
severity,
|
|
29
|
+
summary: `imports=${analysis.imports.length}, resolved=${resolvedCount}, missing=${missing.length}`,
|
|
30
|
+
tier: 'I',
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export const checkImportGraph = async (options) => checkImportGraphWithContext(options, createEquivExecutionContext());
|
|
34
|
+
export { checkImportGraphWithContext };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-l-child-runtime.d.ts","sourceRoot":"","sources":["../src/tier-l-child-runtime.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,2BAA2B,GAAI,gBAAgB,MAAM,KAAG,MA4D7D,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createBrowserShimSource, createStubFactorySource, createStubHelperModuleSource, TIER_L_STUB_HELPER_SPECIFIER, } from "./tier-l-stub-source.js";
|
|
2
|
+
const MODULE_LOAD_CONFIG_ENV = 'USHMAN_EQUIV_MODULE_LOAD_CONFIG';
|
|
3
|
+
export const createModuleLoadChildScript = (resultSentinel) => `
|
|
4
|
+
import { registerHooks } from 'node:module';
|
|
5
|
+
import { format } from 'node:util';
|
|
6
|
+
|
|
7
|
+
const config = JSON.parse(process.env.${MODULE_LOAD_CONFIG_ENV} ?? '{}');
|
|
8
|
+
|
|
9
|
+
// registerHooks keeps the loader fully in-process so Tier L does not need to
|
|
10
|
+
// write a temporary loader file to disk before importing the candidate entrypoint.
|
|
11
|
+
const writeConsole = (...args) => {
|
|
12
|
+
process.stderr.write(\`\${format(...args)}\\n\`);
|
|
13
|
+
};
|
|
14
|
+
console.log = writeConsole;
|
|
15
|
+
console.info = writeConsole;
|
|
16
|
+
console.warn = writeConsole;
|
|
17
|
+
console.error = writeConsole;
|
|
18
|
+
console.debug = writeConsole;
|
|
19
|
+
|
|
20
|
+
${createStubFactorySource()}
|
|
21
|
+
|
|
22
|
+
${createBrowserShimSource()}
|
|
23
|
+
|
|
24
|
+
// Keep one helper payload in the child and let each vendor stub import it
|
|
25
|
+
// instead of embedding the full proxy factory into every generated module.
|
|
26
|
+
const stubHelperUrl = \`data:text/javascript;charset=utf-8,\${encodeURIComponent(${JSON.stringify(createStubHelperModuleSource())})}\`;
|
|
27
|
+
const stubModuleUrls = new Map(
|
|
28
|
+
[
|
|
29
|
+
[${JSON.stringify(TIER_L_STUB_HELPER_SPECIFIER)}, stubHelperUrl],
|
|
30
|
+
...Object.entries(config.stubModules ?? {}).map(([specifier, source]) => [
|
|
31
|
+
specifier,
|
|
32
|
+
\`data:text/javascript;charset=utf-8,\${encodeURIComponent(source)}\`,
|
|
33
|
+
]),
|
|
34
|
+
],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
registerHooks({
|
|
38
|
+
resolve(specifier, context, nextResolve) {
|
|
39
|
+
if (stubModuleUrls.has(specifier)) {
|
|
40
|
+
return {
|
|
41
|
+
shortCircuit: true,
|
|
42
|
+
url: stubModuleUrls.get(specifier),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return nextResolve(specifier, context);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
await import(config.entrypointUrl);
|
|
51
|
+
process.stdout.write(${JSON.stringify(resultSentinel)} + JSON.stringify({ loaded: true }) + '\\n');
|
|
52
|
+
} catch (error) {
|
|
53
|
+
process.stdout.write(
|
|
54
|
+
${JSON.stringify(resultSentinel)} +
|
|
55
|
+
JSON.stringify({
|
|
56
|
+
error: error instanceof Error ? (error.stack ?? error.message) : String(error),
|
|
57
|
+
loaded: false,
|
|
58
|
+
}) +
|
|
59
|
+
'\\n',
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
`.trim();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type EquivExecutionContext } from './equiv-execution-context.ts';
|
|
2
|
+
import type { EquivCheckResult, ModuleLoadOptions } from './types.ts';
|
|
3
|
+
declare const checkModuleLoadWithContext: (options: ModuleLoadOptions, context: EquivExecutionContext) => Promise<EquivCheckResult>;
|
|
4
|
+
export declare const checkModuleLoad: (options: ModuleLoadOptions) => Promise<EquivCheckResult>;
|
|
5
|
+
export { checkModuleLoadWithContext };
|
|
6
|
+
//# sourceMappingURL=tier-l-module-load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-l-module-load.d.ts","sourceRoot":"","sources":["../src/tier-l-module-load.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAEvG,OAAO,KAAK,EAAE,gBAAgB,EAAgB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAwIpF,QAAA,MAAM,0BAA0B,GAC5B,SAAS,iBAAiB,EAC1B,SAAS,qBAAqB,KAC/B,OAAO,CAAC,gBAAgB,CAwC1B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,SAAS,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CACrB,CAAC;AAEvE,OAAO,EAAE,0BAA0B,EAAE,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createEquivExecutionContext } from "./equiv-execution-context.js";
|
|
3
|
+
import { captureChildText, readPositiveIntegerEnv } from "./shared.js";
|
|
4
|
+
import { DEFAULT_EQUIV_MODE, displayPath, importMapMatchesSpecifier, toFileImportUrl, } from "./workspace.js";
|
|
5
|
+
import { createModuleLoadChildScript } from "./tier-l-child-runtime.js";
|
|
6
|
+
import { createStubModuleSource } from "./tier-l-stub-source.js";
|
|
7
|
+
const MODULE_LOAD_CHILD_TIMEOUT_MS = readPositiveIntegerEnv('USHMAN_EQUIV_MODULE_LOAD_TIMEOUT_MS', 30_000);
|
|
8
|
+
const MODULE_LOAD_MAX_LOG_BYTES = readPositiveIntegerEnv('USHMAN_EQUIV_MAX_LOG_BYTES', 32 * 1024);
|
|
9
|
+
const RESULT_SENTINEL = '__USHMAN_EQUIV_MODULE_LOAD_RESULT__';
|
|
10
|
+
const parseChildResult = (stdout, stderr) => {
|
|
11
|
+
const sentinelIndex = stdout.lastIndexOf(RESULT_SENTINEL);
|
|
12
|
+
if (sentinelIndex === -1) {
|
|
13
|
+
throw new Error(stderr.trim() || stdout.trim() || 'Module-load child did not emit a result payload.');
|
|
14
|
+
}
|
|
15
|
+
const payload = stdout.slice(sentinelIndex + RESULT_SENTINEL.length).trim();
|
|
16
|
+
return JSON.parse(payload);
|
|
17
|
+
};
|
|
18
|
+
const runChild = async ({ entrypointUrl, stubModules, }) => new Promise((resolve, reject) => {
|
|
19
|
+
const runtimeBinary = process.env.USHMAN_EQUIV_NODE_BINARY ??
|
|
20
|
+
process.env.NODE_BINARY ??
|
|
21
|
+
(process.versions.bun ? 'node' : process.execPath);
|
|
22
|
+
const child = spawn(runtimeBinary, ['--input-type=module', '--eval', createModuleLoadChildScript(RESULT_SENTINEL)], {
|
|
23
|
+
env: {
|
|
24
|
+
...process.env,
|
|
25
|
+
NODE_NO_WARNINGS: '1',
|
|
26
|
+
USHMAN_EQUIV_MODULE_LOAD_CONFIG: JSON.stringify({
|
|
27
|
+
entrypointUrl,
|
|
28
|
+
stubModules,
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
32
|
+
});
|
|
33
|
+
const readStdout = captureChildText({
|
|
34
|
+
maxBytes: MODULE_LOAD_MAX_LOG_BYTES,
|
|
35
|
+
stream: child.stdout,
|
|
36
|
+
});
|
|
37
|
+
const readStderr = captureChildText({
|
|
38
|
+
maxBytes: MODULE_LOAD_MAX_LOG_BYTES,
|
|
39
|
+
stream: child.stderr,
|
|
40
|
+
});
|
|
41
|
+
const timeoutId = setTimeout(() => {
|
|
42
|
+
child.kill('SIGKILL');
|
|
43
|
+
reject(new Error(`Module-load child timed out after ${MODULE_LOAD_CHILD_TIMEOUT_MS}ms.`));
|
|
44
|
+
}, MODULE_LOAD_CHILD_TIMEOUT_MS);
|
|
45
|
+
child.on('error', (error) => {
|
|
46
|
+
clearTimeout(timeoutId);
|
|
47
|
+
reject(error);
|
|
48
|
+
});
|
|
49
|
+
child.on('close', (code) => {
|
|
50
|
+
clearTimeout(timeoutId);
|
|
51
|
+
const stdout = readStdout();
|
|
52
|
+
const stderr = readStderr();
|
|
53
|
+
if (code !== 0) {
|
|
54
|
+
reject(new Error(stderr || stdout || `Module-load child exited with code ${code}`));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
resolve({
|
|
59
|
+
result: parseChildResult(stdout, stderr),
|
|
60
|
+
stderr,
|
|
61
|
+
stdout,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
reject(error);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
const createBootFailureResult = ({ diagnostics, elapsedMs, mode, }) => ({
|
|
70
|
+
details: [
|
|
71
|
+
{
|
|
72
|
+
evidence: diagnostics,
|
|
73
|
+
message: `Candidate ${mode} boot failed before tier L could import the entrypoint.`,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
elapsedMs,
|
|
77
|
+
severity: 'red',
|
|
78
|
+
summary: `mode=${mode}, booted=false, loaded=false, warnings=0`,
|
|
79
|
+
tier: 'L',
|
|
80
|
+
});
|
|
81
|
+
const buildStubModules = (analysis) => {
|
|
82
|
+
const stubModules = {};
|
|
83
|
+
const warnings = [];
|
|
84
|
+
for (const [specifier, usage] of analysis.bareUsages.entries()) {
|
|
85
|
+
stubModules[specifier] = createStubModuleSource(specifier, [...usage.namedImports]);
|
|
86
|
+
if (importMapMatchesSpecifier(analysis.importMap, specifier) === null) {
|
|
87
|
+
warnings.push({
|
|
88
|
+
message: `Vendor ${specifier} is not present in the importmap; using an empty-shape stub.`,
|
|
89
|
+
symbol: specifier,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
stubModules,
|
|
95
|
+
warnings,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const checkModuleLoadWithContext = async (options, context) => {
|
|
99
|
+
const start = Date.now();
|
|
100
|
+
const mode = options.mode ?? DEFAULT_EQUIV_MODE;
|
|
101
|
+
const bootResult = await context.getCandidateBoot({
|
|
102
|
+
mode,
|
|
103
|
+
workspaceRoot: options.workspaceRoot,
|
|
104
|
+
});
|
|
105
|
+
if (!bootResult.ok) {
|
|
106
|
+
return createBootFailureResult({
|
|
107
|
+
diagnostics: bootResult.diagnostics,
|
|
108
|
+
elapsedMs: Date.now() - start,
|
|
109
|
+
mode,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const analysis = await context.getImportGraph(options);
|
|
113
|
+
const { stubModules, warnings } = buildStubModules(analysis);
|
|
114
|
+
const childResult = await runChild({
|
|
115
|
+
entrypointUrl: toFileImportUrl(analysis.entrypointPath, `${Date.now()}`),
|
|
116
|
+
stubModules,
|
|
117
|
+
});
|
|
118
|
+
const details = [...warnings];
|
|
119
|
+
if (!childResult.result.loaded) {
|
|
120
|
+
details.push({
|
|
121
|
+
evidence: {
|
|
122
|
+
error: childResult.result.error,
|
|
123
|
+
stderr: childResult.stderr || undefined,
|
|
124
|
+
stdout: childResult.stdout || undefined,
|
|
125
|
+
},
|
|
126
|
+
message: childResult.result.error ?? 'Module load failed.',
|
|
127
|
+
path: displayPath(options.workspaceRoot, analysis.entrypointPath),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
details: details.length > 0 ? details : undefined,
|
|
132
|
+
elapsedMs: Date.now() - start,
|
|
133
|
+
severity: childResult.result.loaded ? (warnings.length > 0 ? 'yellow' : 'green') : 'red',
|
|
134
|
+
summary: `mode=${mode}, booted=true, loaded=${childResult.result.loaded}, warnings=${warnings.length}, entrypoint=${displayPath(options.workspaceRoot, analysis.entrypointPath)}`,
|
|
135
|
+
tier: 'L',
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
export const checkModuleLoad = async (options) => checkModuleLoadWithContext(options, createEquivExecutionContext());
|
|
139
|
+
export { checkModuleLoadWithContext };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type StubFactoryNames = {
|
|
2
|
+
readonly callableFactoryName: string;
|
|
3
|
+
readonly objectFactoryName: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const TIER_L_STUB_HELPER_SPECIFIER = "ushman-equiv/tier-l-stub-helper";
|
|
6
|
+
export declare const createStubFactorySource: (names?: Partial<StubFactoryNames>) => string;
|
|
7
|
+
export declare const createBrowserShimSource: (names?: Partial<StubFactoryNames>) => string;
|
|
8
|
+
export declare const createStubHelperModuleSource: () => string;
|
|
9
|
+
export declare const createStubModuleSource: (specifier: string, names: readonly string[], helperSpecifier?: string) => string;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=tier-l-stub-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-l-stub-source.d.ts","sourceRoot":"","sources":["../src/tier-l-stub-source.ts"],"names":[],"mappings":"AAEA,KAAK,gBAAgB,GAAG;IACpB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACtC,CAAC;AAYF,eAAO,MAAM,4BAA4B,oCAAoC,CAAC;AAE9E,eAAO,MAAM,uBAAuB,GAAI,QAAO,OAAO,CAAC,gBAAgB,CAAM,KAAG,MAsF/E,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAO,OAAO,CAAC,gBAAgB,CAAM,KAAG,MAiI/E,CAAC;AAEF,eAAO,MAAM,4BAA4B,QAAO,MAKhC,CAAC;AAEjB,eAAO,MAAM,sBAAsB,GAC/B,WAAW,MAAM,EACjB,OAAO,SAAS,MAAM,EAAE,EACxB,wBAA8C,KAC/C,MAaF,CAAC"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { compareStrings } from "./shared.js";
|
|
2
|
+
const DEFAULT_FACTORY_NAMES = {
|
|
3
|
+
callableFactoryName: 'createCallableStub',
|
|
4
|
+
objectFactoryName: 'createObjectStub',
|
|
5
|
+
};
|
|
6
|
+
const serializeFactoryNames = (names) => ({
|
|
7
|
+
callableFactoryName: names.callableFactoryName ?? DEFAULT_FACTORY_NAMES.callableFactoryName,
|
|
8
|
+
objectFactoryName: names.objectFactoryName ?? DEFAULT_FACTORY_NAMES.objectFactoryName,
|
|
9
|
+
});
|
|
10
|
+
export const TIER_L_STUB_HELPER_SPECIFIER = 'ushman-equiv/tier-l-stub-helper';
|
|
11
|
+
export const createStubFactorySource = (names = {}) => {
|
|
12
|
+
const { callableFactoryName, objectFactoryName } = serializeFactoryNames(names);
|
|
13
|
+
return `
|
|
14
|
+
const ${callableFactoryName} = (label = 'stub') => {
|
|
15
|
+
const target = function () {};
|
|
16
|
+
return new Proxy(target, {
|
|
17
|
+
apply() {
|
|
18
|
+
return ${callableFactoryName}(\`\${label}()\`);
|
|
19
|
+
},
|
|
20
|
+
construct() {
|
|
21
|
+
return ${objectFactoryName}(\`new \${label}\`);
|
|
22
|
+
},
|
|
23
|
+
get(_target, property) {
|
|
24
|
+
if (property === 'then') {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (property === 'prototype') {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
if (property === Symbol.iterator) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
if (property === Symbol.toPrimitive) {
|
|
34
|
+
return () => label;
|
|
35
|
+
}
|
|
36
|
+
return ${callableFactoryName}(\`\${label}.\${String(property)}\`);
|
|
37
|
+
},
|
|
38
|
+
getOwnPropertyDescriptor() {
|
|
39
|
+
return {
|
|
40
|
+
configurable: true,
|
|
41
|
+
enumerable: true,
|
|
42
|
+
value: undefined,
|
|
43
|
+
writable: true,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
has() {
|
|
47
|
+
return true;
|
|
48
|
+
},
|
|
49
|
+
ownKeys() {
|
|
50
|
+
return [];
|
|
51
|
+
},
|
|
52
|
+
set() {
|
|
53
|
+
return true;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ${objectFactoryName} = (label = 'stub', base = {}) =>
|
|
59
|
+
new Proxy(base, {
|
|
60
|
+
get(target, property) {
|
|
61
|
+
if (property === 'then') {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (property === Symbol.iterator) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
if (property === Symbol.toPrimitive) {
|
|
68
|
+
return () => label;
|
|
69
|
+
}
|
|
70
|
+
if (property in target) {
|
|
71
|
+
return Reflect.get(target, property);
|
|
72
|
+
}
|
|
73
|
+
return ${callableFactoryName}(\`\${label}.\${String(property)}\`);
|
|
74
|
+
},
|
|
75
|
+
getOwnPropertyDescriptor(target, property) {
|
|
76
|
+
return (
|
|
77
|
+
Reflect.getOwnPropertyDescriptor(target, property) ?? {
|
|
78
|
+
configurable: true,
|
|
79
|
+
enumerable: true,
|
|
80
|
+
value: undefined,
|
|
81
|
+
writable: true,
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
has() {
|
|
86
|
+
return true;
|
|
87
|
+
},
|
|
88
|
+
ownKeys(target) {
|
|
89
|
+
return Reflect.ownKeys(target);
|
|
90
|
+
},
|
|
91
|
+
set(target, property, value) {
|
|
92
|
+
target[property] = value;
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
`.trim();
|
|
97
|
+
};
|
|
98
|
+
export const createBrowserShimSource = (names = {}) => {
|
|
99
|
+
const { objectFactoryName } = serializeFactoryNames(names);
|
|
100
|
+
return `
|
|
101
|
+
const createStorage = () => {
|
|
102
|
+
const values = new Map();
|
|
103
|
+
return {
|
|
104
|
+
clear() {
|
|
105
|
+
values.clear();
|
|
106
|
+
},
|
|
107
|
+
get length() {
|
|
108
|
+
return values.size;
|
|
109
|
+
},
|
|
110
|
+
getItem(key) {
|
|
111
|
+
return values.has(String(key)) ? values.get(String(key)) : null;
|
|
112
|
+
},
|
|
113
|
+
key(index) {
|
|
114
|
+
return [...values.keys()][index] ?? null;
|
|
115
|
+
},
|
|
116
|
+
removeItem(key) {
|
|
117
|
+
values.delete(String(key));
|
|
118
|
+
},
|
|
119
|
+
setItem(key, value) {
|
|
120
|
+
values.set(String(key), String(value));
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
class HTMLCanvasElement {
|
|
126
|
+
constructor() {
|
|
127
|
+
this.height = 1;
|
|
128
|
+
this.width = 1;
|
|
129
|
+
}
|
|
130
|
+
getContext() {
|
|
131
|
+
return ${objectFactoryName}('canvas-context');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
class OffscreenCanvas {
|
|
136
|
+
constructor(width = 1, height = 1) {
|
|
137
|
+
this.width = width;
|
|
138
|
+
this.height = height;
|
|
139
|
+
}
|
|
140
|
+
getContext() {
|
|
141
|
+
return ${objectFactoryName}('offscreen-canvas-context');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
class HTMLImageElement {}
|
|
146
|
+
class GPUCanvasContext {}
|
|
147
|
+
class IntersectionObserver {
|
|
148
|
+
disconnect() {}
|
|
149
|
+
observe() {}
|
|
150
|
+
takeRecords() {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
unobserve() {}
|
|
154
|
+
}
|
|
155
|
+
class ResizeObserver {
|
|
156
|
+
disconnect() {}
|
|
157
|
+
observe() {}
|
|
158
|
+
unobserve() {}
|
|
159
|
+
}
|
|
160
|
+
class WebGL2RenderingContext {}
|
|
161
|
+
const CSS = { supports: () => false };
|
|
162
|
+
|
|
163
|
+
const document = ${objectFactoryName}('document', {
|
|
164
|
+
addEventListener() {},
|
|
165
|
+
body: ${objectFactoryName}('document.body'),
|
|
166
|
+
createElement(tagName) {
|
|
167
|
+
if (String(tagName).toLowerCase() === 'canvas') {
|
|
168
|
+
return new HTMLCanvasElement();
|
|
169
|
+
}
|
|
170
|
+
return ${objectFactoryName}(\`element:\${String(tagName)}\`, {
|
|
171
|
+
tagName: String(tagName).toUpperCase(),
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
documentElement: ${objectFactoryName}('document.documentElement'),
|
|
175
|
+
getElementById() {
|
|
176
|
+
return null;
|
|
177
|
+
},
|
|
178
|
+
querySelector() {
|
|
179
|
+
return null;
|
|
180
|
+
},
|
|
181
|
+
removeEventListener() {},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const navigator = ${objectFactoryName}('navigator', {
|
|
185
|
+
gpu: ${objectFactoryName}('navigator.gpu'),
|
|
186
|
+
userAgent: 'ushman-equiv',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const requestAnimationFrame = (callback) => setTimeout(() => callback(Date.now()), 16);
|
|
190
|
+
const cancelAnimationFrame = (handle) => clearTimeout(handle);
|
|
191
|
+
|
|
192
|
+
const window = ${objectFactoryName}('window', {
|
|
193
|
+
addEventListener() {},
|
|
194
|
+
cancelAnimationFrame,
|
|
195
|
+
clearTimeout,
|
|
196
|
+
document,
|
|
197
|
+
localStorage: createStorage(),
|
|
198
|
+
navigator,
|
|
199
|
+
removeEventListener() {},
|
|
200
|
+
requestAnimationFrame,
|
|
201
|
+
sessionStorage: createStorage(),
|
|
202
|
+
setTimeout,
|
|
203
|
+
});
|
|
204
|
+
window.self = window;
|
|
205
|
+
window.window = window;
|
|
206
|
+
|
|
207
|
+
Object.defineProperty(globalThis, 'window', { configurable: true, value: window });
|
|
208
|
+
Object.defineProperty(globalThis, 'document', { configurable: true, value: document });
|
|
209
|
+
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: navigator });
|
|
210
|
+
Object.defineProperty(globalThis, 'requestAnimationFrame', { configurable: true, value: requestAnimationFrame });
|
|
211
|
+
Object.defineProperty(globalThis, 'cancelAnimationFrame', { configurable: true, value: cancelAnimationFrame });
|
|
212
|
+
Object.defineProperty(globalThis, 'localStorage', { configurable: true, value: window.localStorage });
|
|
213
|
+
Object.defineProperty(globalThis, 'sessionStorage', { configurable: true, value: window.sessionStorage });
|
|
214
|
+
Object.defineProperty(globalThis, 'HTMLCanvasElement', { configurable: true, value: HTMLCanvasElement });
|
|
215
|
+
Object.defineProperty(globalThis, 'HTMLImageElement', { configurable: true, value: HTMLImageElement });
|
|
216
|
+
Object.defineProperty(globalThis, 'IntersectionObserver', { configurable: true, value: IntersectionObserver });
|
|
217
|
+
Object.defineProperty(globalThis, 'OffscreenCanvas', { configurable: true, value: OffscreenCanvas });
|
|
218
|
+
Object.defineProperty(globalThis, 'GPUCanvasContext', { configurable: true, value: GPUCanvasContext });
|
|
219
|
+
Object.defineProperty(globalThis, 'ResizeObserver', { configurable: true, value: ResizeObserver });
|
|
220
|
+
Object.defineProperty(globalThis, 'WebGL2RenderingContext', { configurable: true, value: WebGL2RenderingContext });
|
|
221
|
+
Object.defineProperty(globalThis, 'CSS', { configurable: true, value: CSS });
|
|
222
|
+
Object.defineProperty(globalThis, 'performance', {
|
|
223
|
+
configurable: true,
|
|
224
|
+
value: globalThis.performance ?? { now: () => Date.now() },
|
|
225
|
+
});
|
|
226
|
+
`.trim();
|
|
227
|
+
};
|
|
228
|
+
export const createStubHelperModuleSource = () => [
|
|
229
|
+
createStubFactorySource(),
|
|
230
|
+
'',
|
|
231
|
+
'export { createCallableStub, createObjectStub };',
|
|
232
|
+
].join('\n');
|
|
233
|
+
export const createStubModuleSource = (specifier, names, helperSpecifier = TIER_L_STUB_HELPER_SPECIFIER) => {
|
|
234
|
+
const exportLines = names
|
|
235
|
+
.filter((name) => name !== 'default')
|
|
236
|
+
.sort(compareStrings)
|
|
237
|
+
.map((name) => `export { __stub as ${name} };`);
|
|
238
|
+
return `
|
|
239
|
+
import { createCallableStub } from ${JSON.stringify(helperSpecifier)};
|
|
240
|
+
|
|
241
|
+
const __stub = createCallableStub(${JSON.stringify(specifier)});
|
|
242
|
+
export default __stub;
|
|
243
|
+
export const __esModule = true;
|
|
244
|
+
${exportLines.join('\n')}
|
|
245
|
+
`.trim();
|
|
246
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type EquivExecutionContext } from './equiv-execution-context.ts';
|
|
2
|
+
import type { EquivCheckResult, ReplayOptions } from './types.ts';
|
|
3
|
+
declare const checkReplayWithContext: (options: ReplayOptions, context: EquivExecutionContext) => Promise<EquivCheckResult>;
|
|
4
|
+
export declare const checkReplay: (options: ReplayOptions) => Promise<EquivCheckResult>;
|
|
5
|
+
export { checkReplayWithContext };
|
|
6
|
+
//# sourceMappingURL=tier-r-replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-r-replay.d.ts","sourceRoot":"","sources":["../src/tier-r-replay.ts"],"names":[],"mappings":"AAIA,OAAO,EAA+B,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAEvG,OAAO,KAAK,EAAE,gBAAgB,EAAkD,aAAa,EAAE,MAAM,YAAY,CAAC;AAqblH,QAAA,MAAM,sBAAsB,GACxB,SAAS,aAAa,EACtB,SAAS,qBAAqB,KAC/B,OAAO,CAAC,gBAAgB,CAwF1B,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,SAAS,aAAa,KAAG,OAAO,CAAC,gBAAgB,CACjB,CAAC;AAEnE,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|