529 lines
23 KiB
JavaScript
529 lines
23 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import fs from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
import { parse } from '@babel/parser'
|
|
import traverseModule from '@babel/traverse'
|
|
import generatorModule from '@babel/generator'
|
|
|
|
const EVIDENCE_PATH = '.tmp/rea-runtime-scripts.json'
|
|
const OUTPUT_DIRECTORY = path.resolve('src/renderer/src/workbuddy/conversation/recovered-virtualizer')
|
|
const EXPECTED_EVIDENCE_ID = 'ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb'
|
|
const EXPECTED_EXPORT_SHA256 = '747e41d215375e1214c366213aea7e077d85421923029c61cbb6e9562be58de0'
|
|
const EXPECTED_MAIN_SHA256 = '6c6ce63c93854783270e855572797d75e536e3b8d4548410e31fe9d147e1feb4'
|
|
const EXPECTED_EXPORT_PATH = './src-DPDj7_qD.js'
|
|
const EXPECTED_ROOT_SHA256 = '035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918'
|
|
const IMPORT_ADAPTERS = new Map([
|
|
['./rolldown-runtime-BJCASTsb.js', new Map([
|
|
['n', '__esmMin'],
|
|
['o', '__toESM'],
|
|
])],
|
|
['./react-z__Ncn__.js', new Map([['t', 'React namespace']])],
|
|
['./react-dom-mnR6psRT.js', new Map([['t', 'ReactDOM namespace']])],
|
|
])
|
|
const traverse = traverseModule.default
|
|
const generate = generatorModule.default ?? generatorModule
|
|
const sha256 = value => createHash('sha256').update(value).digest('hex')
|
|
const fail = message => { throw new Error(message) }
|
|
|
|
function collectPatternNames(node, names = []) {
|
|
if (!node) return names
|
|
if (node.type === 'Identifier') names.push(node.name)
|
|
else if (node.type === 'RestElement') collectPatternNames(node.argument, names)
|
|
else if (node.type === 'AssignmentPattern') collectPatternNames(node.left, names)
|
|
else if (node.type === 'ArrayPattern') node.elements.forEach(entry => collectPatternNames(entry, names))
|
|
else if (node.type === 'ObjectPattern') {
|
|
for (const property of node.properties) {
|
|
if (property.type === 'RestElement') collectPatternNames(property.argument, names)
|
|
else collectPatternNames(property.value, names)
|
|
}
|
|
}
|
|
return names
|
|
}
|
|
|
|
function closeBindings(source, rootNames, { includeImports = false } = {}) {
|
|
const ast = parse(source, { sourceType: 'module' })
|
|
let programPath
|
|
traverse(ast, {
|
|
Program(pathRef) {
|
|
programPath = pathRef
|
|
pathRef.scope.crawl()
|
|
pathRef.stop()
|
|
},
|
|
})
|
|
|
|
const included = new Map()
|
|
const queue = []
|
|
const imported = new Map()
|
|
const enqueue = binding => {
|
|
if (!binding || binding.scope !== programPath.scope || included.has(binding.identifier.name)) return
|
|
included.set(binding.identifier.name, binding)
|
|
queue.push(binding)
|
|
}
|
|
const visitReferences = pathRef => pathRef.traverse({
|
|
Identifier(reference) {
|
|
if (!reference.isReferencedIdentifier() && !reference.isBindingIdentifier()) return
|
|
enqueue(reference.scope.getBinding(reference.node.name))
|
|
},
|
|
})
|
|
|
|
for (const rootName of rootNames) {
|
|
const root = programPath.scope.getBinding(rootName)
|
|
if (!root || root.kind === 'module') fail(`Missing program binding: ${rootName}`)
|
|
enqueue(root)
|
|
}
|
|
while (queue.length > 0) {
|
|
const binding = queue.shift()
|
|
if (binding.kind === 'module') {
|
|
const declaration = binding.path.findParent(candidate => candidate.isImportDeclaration())
|
|
if (!declaration) fail(`Cannot locate import for ${binding.identifier.name}`)
|
|
const names = imported.get(declaration.node.source.value) ?? new Set()
|
|
names.add(binding.identifier.name)
|
|
imported.set(declaration.node.source.value, names)
|
|
continue
|
|
}
|
|
|
|
if (binding.path.isFunctionDeclaration() || binding.path.isClassDeclaration()) {
|
|
visitReferences(binding.path)
|
|
continue
|
|
}
|
|
if (!binding.path.isVariableDeclarator()) continue
|
|
|
|
if (binding.path.node.init) visitReferences(binding.path.get('init'))
|
|
else {
|
|
for (const violation of binding.constantViolations) {
|
|
visitReferences(violation)
|
|
const owner = violation.findParent(candidate => candidate.isVariableDeclarator())
|
|
if (owner && owner !== binding.path && owner.node.id.type === 'Identifier') {
|
|
enqueue(programPath.scope.getBinding(owner.node.id.name))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const importRecords = []
|
|
const declarationChunks = []
|
|
const isRolldownModuleInitializer = binding => {
|
|
if (!binding || !binding.path.isVariableDeclarator()) return false
|
|
const initializer = binding.path.node.init
|
|
if (initializer?.type !== 'CallExpression' || initializer.callee.type !== 'Identifier') return false
|
|
const helperBinding = programPath.scope.getBinding(initializer.callee.name)
|
|
if (helperBinding?.kind !== 'module') return false
|
|
const helperDeclaration = helperBinding.path.findParent(candidate => candidate.isImportDeclaration())
|
|
if (!helperDeclaration || helperDeclaration.node.source.value !== './rolldown-runtime-BJCASTsb.js') return false
|
|
return helperBinding.path.node.imported?.name === 'n'
|
|
}
|
|
const initializerBindings = [...included.entries()]
|
|
.filter(([, binding]) => isRolldownModuleInitializer(binding))
|
|
const nestedInitializers = new Set()
|
|
for (const [, binding] of initializerBindings) {
|
|
const initializer = binding.path.get('init').get('arguments.0')
|
|
if (!initializer?.node || (!initializer.isArrowFunctionExpression() && !initializer.isFunctionExpression())) continue
|
|
initializer.traverse({
|
|
Function(pathRef) { pathRef.skip() },
|
|
CallExpression(pathRef) {
|
|
const callee = pathRef.node.callee
|
|
if (callee.type === 'Identifier' && initializerBindings.some(([name]) => name === callee.name)) {
|
|
nestedInitializers.add(callee.name)
|
|
}
|
|
},
|
|
})
|
|
}
|
|
const initializationCalls = initializerBindings
|
|
.map(([name]) => name)
|
|
.filter(name => !nestedInitializers.has(name))
|
|
.sort()
|
|
|
|
for (const statement of ast.program.body) {
|
|
if (statement.type === 'ImportDeclaration') {
|
|
const names = imported.get(statement.source.value)
|
|
if (!names || names.size === 0) continue
|
|
const specifiers = statement.specifiers.filter(specifier => names.has(specifier.local.name))
|
|
for (const specifier of specifiers) {
|
|
importRecords.push({
|
|
source: statement.source.value,
|
|
local: specifier.local.name,
|
|
imported: specifier.type === 'ImportSpecifier'
|
|
? specifier.imported.name ?? specifier.imported.value
|
|
: 'default',
|
|
})
|
|
}
|
|
if (!includeImports) continue
|
|
const parts = []
|
|
const defaultImport = specifiers.find(specifier => specifier.type === 'ImportDefaultSpecifier')
|
|
const namespaceImport = specifiers.find(specifier => specifier.type === 'ImportNamespaceSpecifier')
|
|
const namedImports = specifiers.filter(specifier => specifier.type === 'ImportSpecifier')
|
|
if (defaultImport) parts.push(defaultImport.local.name)
|
|
if (namespaceImport) parts.push(`* as ${namespaceImport.local.name}`)
|
|
if (namedImports.length > 0) {
|
|
parts.push(`{ ${namedImports.map(specifier => {
|
|
const importedName = specifier.imported.name ?? specifier.imported.value
|
|
return importedName === specifier.local.name ? importedName : `${importedName} as ${specifier.local.name}`
|
|
}).join(', ')} }`)
|
|
}
|
|
declarationChunks.push(`import ${parts.join(', ')} from ${JSON.stringify(statement.source.value)};`)
|
|
continue
|
|
}
|
|
|
|
if (statement.type === 'VariableDeclaration') {
|
|
for (const declaration of statement.declarations) {
|
|
const names = collectPatternNames(declaration.id)
|
|
if (names.some(name => included.has(name))) {
|
|
declarationChunks.push(`${statement.kind} ${source.slice(declaration.start, declaration.end)};`)
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ((statement.type === 'FunctionDeclaration' || statement.type === 'ClassDeclaration') &&
|
|
included.has(statement.id?.name)) {
|
|
declarationChunks.push(source.slice(statement.start, statement.end))
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
declarationChunks.push(...initializationCalls.map(name => `${name}();`))
|
|
|
|
return {
|
|
code: declarationChunks.join('\n'),
|
|
bindingNames: [...included.keys()].sort(),
|
|
imports: importRecords.sort((left, right) => left.source.localeCompare(right.source) || left.local.localeCompare(right.local)),
|
|
initializationCalls,
|
|
}
|
|
}
|
|
|
|
function renameProgramBindings(source, prefix) {
|
|
const ast = parse(source, { sourceType: 'module' })
|
|
let programPath
|
|
traverse(ast, {
|
|
Program(pathRef) {
|
|
programPath = pathRef
|
|
pathRef.scope.crawl()
|
|
pathRef.stop()
|
|
},
|
|
})
|
|
|
|
const renamed = new Map()
|
|
let index = 0
|
|
for (const name of Object.keys(programPath.scope.bindings)) {
|
|
const binding = programPath.scope.getBinding(name)
|
|
if (!binding || binding.kind === 'module') continue
|
|
const newName = `${prefix}${name.replace(/[^A-Za-z0-9_$]/gu, '_')}_${index++}`
|
|
programPath.scope.rename(name, newName)
|
|
renamed.set(name, newName)
|
|
}
|
|
|
|
return { source: generate(ast, { comments: false, compact: true }).code, renamed }
|
|
}
|
|
|
|
function getProperty(objectNode, key) {
|
|
return objectNode?.type === 'ObjectExpression'
|
|
? objectNode.properties.find(property => property.type === 'ObjectProperty' &&
|
|
(property.key.name ?? property.key.value) === key)?.value
|
|
: undefined
|
|
}
|
|
|
|
function readNumber(node, programScope) {
|
|
if (node?.type === 'NumericLiteral') return node.value
|
|
if (node?.type === 'Identifier') {
|
|
const binding = programScope.getBinding(node.name)
|
|
const init = binding?.path.isVariableDeclarator() ? binding.path.node.init : undefined
|
|
if (init?.type === 'NumericLiteral') return init.value
|
|
const assignment = binding?.constantViolations.find(violation =>
|
|
violation.isAssignmentExpression() && violation.node.left.type === 'Identifier' &&
|
|
violation.node.left.name === node.name)
|
|
if (assignment?.node.right.type === 'NumericLiteral') return assignment.node.right.value
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
function verifySourceAnchor(mainSource) {
|
|
const ast = parse(mainSource, { sourceType: 'module' })
|
|
let programPath
|
|
traverse(ast, {
|
|
Program(pathRef) {
|
|
programPath = pathRef
|
|
pathRef.scope.crawl()
|
|
pathRef.stop()
|
|
},
|
|
})
|
|
const alias = programPath.scope.getBinding('Ae')
|
|
const importDeclaration = alias?.path.findParent(candidate => candidate.isImportDeclaration())
|
|
if (!importDeclaration || importDeclaration.node.source.value !== EXPECTED_EXPORT_PATH ||
|
|
alias.path.node.imported?.name !== 'tt') {
|
|
fail('Main REA source no longer maps Ae to the selected useVirtualizer export')
|
|
}
|
|
const component = programPath.scope.getBinding('aE')
|
|
if (!component) fail('Could not find the original aE SourceToolDiff component binding')
|
|
const componentAssignments = component.constantViolations.filter(violation =>
|
|
violation.isAssignmentExpression() && violation.node.left.type === 'Identifier' && violation.node.left.name === 'aE')
|
|
if (componentAssignments.length !== 1) fail(`Expected one aE component assignment, found ${componentAssignments.length}`)
|
|
const calls = alias.referencePaths.filter(reference => {
|
|
const call = reference.parentPath
|
|
return call.isCallExpression() && call.node.callee === reference.node &&
|
|
call.node.start >= componentAssignments[0].node.start && call.node.end <= componentAssignments[0].node.end
|
|
})
|
|
if (calls.length !== 1) fail(`Expected one aE useVirtualizer call, found ${calls.length}`)
|
|
|
|
const options = calls[0].parentPath.node.arguments[0]
|
|
const initialRect = getProperty(options, 'initialRect')
|
|
const width = readNumber(getProperty(initialRect, 'width'), programPath.scope)
|
|
const height = readNumber(getProperty(initialRect, 'height'), programPath.scope)
|
|
const estimateSize = getProperty(options, 'estimateSize')
|
|
const estimate = estimateSize?.type === 'ArrowFunctionExpression'
|
|
? readNumber(estimateSize.body, programPath.scope)
|
|
: undefined
|
|
const overscan = readNumber(getProperty(options, 'overscan'), programPath.scope)
|
|
if (width !== 0 || height !== 260 || estimate !== 20 || overscan !== 12) {
|
|
fail(`Original virtualizer options differ from the requested contract: ${JSON.stringify({ width, height, estimate, overscan })}`)
|
|
}
|
|
return {
|
|
component: 'aE',
|
|
importedLocal: 'Ae',
|
|
exportedName: 'tt',
|
|
exportChunk: EXPECTED_EXPORT_PATH,
|
|
componentAssignmentOffsetUtf16: componentAssignments[0].node.start,
|
|
callOffsetUtf16: calls[0].node.start,
|
|
options: { initialRect: { width, height }, estimateSize: estimate, overscan },
|
|
}
|
|
}
|
|
|
|
function selectEvidenceArtifact(data, expected) {
|
|
const matches = data.items.filter(item => item.source?.artifact?.sha256 === expected.sha256)
|
|
if (matches.length !== 1) fail(`Expected one REA export for ${expected.fileName}, found ${matches.length}`)
|
|
const item = matches[0]
|
|
const text = item.source.artifact.text
|
|
const actualSha256 = sha256(text)
|
|
const bytes = Buffer.byteLength(text, 'utf8')
|
|
if (actualSha256 !== expected.sha256 || bytes !== expected.bytes || item.length !== expected.bytes) {
|
|
fail(`REA artifact identity mismatch for ${expected.fileName}`)
|
|
}
|
|
if (path.posix.basename(item.file_path.replace(/\\/gu, '/')) !== expected.fileName) {
|
|
fail(`REA Evidence path does not match expected ${expected.fileName}: ${item.file_path}`)
|
|
}
|
|
return {
|
|
text,
|
|
record: { path: item.file_path, fileName: expected.fileName, bytes, sha256: actualSha256 },
|
|
}
|
|
}
|
|
|
|
function resolveImportedAdapters(imports) {
|
|
const result = []
|
|
const seenSources = new Set()
|
|
for (const entry of imports) {
|
|
const adapters = IMPORT_ADAPTERS.get(entry.source)
|
|
if (!adapters) fail(`Recovered closure has an unapproved import: ${entry.source}`)
|
|
const adapter = adapters.get(entry.imported)
|
|
if (!adapter) fail(`No adapter for ${entry.source} export ${entry.imported}`)
|
|
if (entry.source.startsWith('./rolldown-runtime-')) {
|
|
result.push({ ...entry, adapter })
|
|
} else if (entry.source === './react-z__Ncn__.js' && entry.local === 'u' && entry.imported === 't') {
|
|
result.push({ ...entry, adapter: 'React namespace factory' })
|
|
} else if (entry.source === './react-dom-mnR6psRT.js' && entry.local === 'p' && entry.imported === 't') {
|
|
result.push({ ...entry, adapter: 'ReactDOM namespace factory' })
|
|
} else {
|
|
fail(`Unexpected adapter binding for ${entry.source}: ${entry.local} as ${entry.imported}`)
|
|
}
|
|
seenSources.add(entry.source)
|
|
}
|
|
for (const source of IMPORT_ADAPTERS.keys()) {
|
|
if (!seenSources.has(source)) fail(`Expected closure dependency was not found: ${source}`)
|
|
}
|
|
return result
|
|
}
|
|
|
|
async function writeGenerated(filePath, content, expectedKind) {
|
|
try {
|
|
const current = await fs.readFile(filePath, 'utf8')
|
|
if (current === content) return
|
|
const isGenerated = expectedKind === 'manifest'
|
|
? JSON.parse(current).kind === 'rea-recovered-tool-virtualizer'
|
|
: current.startsWith('// Generated by scripts/rea/recover-tool-virtualizer.mjs')
|
|
if (!isGenerated) fail(`Refusing to overwrite a non-generated artifact: ${filePath}`)
|
|
} catch (error) {
|
|
if (error.code !== 'ENOENT' && !(error instanceof SyntaxError)) throw error
|
|
if (error instanceof SyntaxError) fail(`Refusing to overwrite an invalid generated manifest: ${filePath}`)
|
|
}
|
|
await fs.writeFile(filePath, content, 'utf8')
|
|
}
|
|
|
|
const evidenceBytes = await fs.readFile(EVIDENCE_PATH)
|
|
const evidence = JSON.parse(evidenceBytes.toString('utf8'))
|
|
if (evidence.evidence_id !== EXPECTED_EVIDENCE_ID) fail(`Unexpected REA Evidence ID: ${evidence.evidence_id}`)
|
|
|
|
const [mainArtifact, virtualizerArtifact, runtimeArtifact, reactArtifact, reactDomArtifact] = [
|
|
selectEvidenceArtifact(evidence, {
|
|
fileName: 'src-DbE1_mgM.js',
|
|
sha256: EXPECTED_MAIN_SHA256,
|
|
bytes: 1968427,
|
|
}),
|
|
selectEvidenceArtifact(evidence, {
|
|
fileName: 'src-DPDj7_qD.js',
|
|
sha256: EXPECTED_EXPORT_SHA256,
|
|
bytes: 1062959,
|
|
}),
|
|
selectEvidenceArtifact(evidence, {
|
|
fileName: 'rolldown-runtime-BJCASTsb.js',
|
|
sha256: '318f798e3ab3fd684d64dce773065dd76581974fcf633e5d4a3f1d31cf9a7ef7',
|
|
bytes: 1413,
|
|
}),
|
|
selectEvidenceArtifact(evidence, {
|
|
fileName: 'react-z__Ncn__.js',
|
|
sha256: '43f15c3eca4613e6a3ff249303f3807e326f02d3f0f3cec5e1ce77caa4c21509',
|
|
bytes: 6517,
|
|
}),
|
|
selectEvidenceArtifact(evidence, {
|
|
fileName: 'react-dom-mnR6psRT.js',
|
|
sha256: '68481241365522811081eecba169d0000151c884621657df3a6080a5213f17ce',
|
|
bytes: 133010,
|
|
}),
|
|
]
|
|
const exportAst = parse(virtualizerArtifact.text, { sourceType: 'module' })
|
|
let exportedUseVirtualizer = false
|
|
traverse(exportAst, {
|
|
Program(pathRef) {
|
|
for (const statement of pathRef.node.body) {
|
|
if (statement.type !== 'ExportNamedDeclaration') continue
|
|
for (const specifier of statement.specifiers) {
|
|
if (specifier.local.name === 'useVirtualizer' && specifier.exported.name === 'tt') {
|
|
exportedUseVirtualizer = true
|
|
}
|
|
}
|
|
}
|
|
pathRef.stop()
|
|
},
|
|
})
|
|
if (!exportedUseVirtualizer) fail('The selected REA module does not export useVirtualizer as tt')
|
|
|
|
const anchor = verifySourceAnchor(mainArtifact.text)
|
|
const closure = closeBindings(virtualizerArtifact.text, ['useVirtualizer'])
|
|
if (closure.bindingNames.length !== 35 || !closure.bindingNames.includes('Virtualizer') ||
|
|
!closure.bindingNames.includes('calculateRangeImpl')) {
|
|
fail(`Unexpected virtualizer closure: ${closure.bindingNames.length} bindings`)
|
|
}
|
|
if (closure.initializationCalls.length === 0) fail('Virtualizer closure is missing its Rolldown module initialization call')
|
|
const importedAdapters = resolveImportedAdapters(closure.imports)
|
|
const rolldownClosure = closeBindings(runtimeArtifact.text, ['__esmMin', '__toESM'])
|
|
if (rolldownClosure.imports.length !== 0) fail('Rolldown helper closure unexpectedly imports another module')
|
|
const renamedRuntime = renameProgramBindings(rolldownClosure.code, '__ycodeRecoveredRolldown_')
|
|
const esmHelper = renamedRuntime.renamed.get('__esmMin')
|
|
const toEsmHelper = renamedRuntime.renamed.get('__toESM')
|
|
if (!esmHelper || !toEsmHelper) fail('Could not bind required Rolldown helpers')
|
|
|
|
const header = [
|
|
`// Generated by scripts/rea/recover-tool-virtualizer.mjs from REA Evidence ${EXPECTED_EVIDENCE_ID}.`,
|
|
`// Source: renderer/assets/src-DPDj7_qD.js; sha256: ${EXPECTED_EXPORT_SHA256}.`,
|
|
`import * as __ycodeReact from 'react';`,
|
|
`import * as __ycodeReactDOM from 'react-dom';`,
|
|
]
|
|
const adapters = [
|
|
`const r = ${esmHelper};`,
|
|
`const s = ${toEsmHelper};`,
|
|
`const u = () => __ycodeReact;`,
|
|
`const p = () => __ycodeReactDOM;`,
|
|
]
|
|
const exports = `export { useVirtualizer as useRecoveredToolVirtualizer, Virtualizer as RecoveredVirtualizer };`
|
|
const engine = `${header.join('\n')}\n${renamedRuntime.source}\n${adapters.join('\n')}\n${closure.code}\n${exports}\n`
|
|
const engineAst = parse(engine, { sourceType: 'module' })
|
|
const outputImports = engineAst.program.body
|
|
.filter(statement => statement.type === 'ImportDeclaration')
|
|
.map(statement => statement.source.value)
|
|
.sort()
|
|
if (JSON.stringify(outputImports) !== JSON.stringify(['react', 'react-dom'])) {
|
|
fail(`Recovered engine has unexpected imports: ${JSON.stringify(outputImports)}`)
|
|
}
|
|
|
|
const declarations = `// Generated by scripts/rea/recover-tool-virtualizer.mjs; source is locked to REA Evidence ${EXPECTED_EVIDENCE_ID}.\n` +
|
|
`import type { RefCallback } from 'react'\n` +
|
|
`export interface RecoveredVirtualItem { index: number; key: string | number; start: number; size: number; end: number; lane: number }\n` +
|
|
`export interface RecoveredVirtualizerOptions { count: number; getScrollElement: () => Element | Window | null; estimateSize: (index: number) => number; overscan?: number; initialRect?: { width: number; height: number }; initialOffset?: number; [key: string]: unknown }\n` +
|
|
`export interface RecoveredVirtualizerInstance { getVirtualItems(): RecoveredVirtualItem[]; getTotalSize(): number; measureElement: RefCallback<HTMLDivElement> }\n` +
|
|
`export declare function useRecoveredToolVirtualizer(options: RecoveredVirtualizerOptions): RecoveredVirtualizerInstance\n` +
|
|
`export declare class RecoveredVirtualizer { constructor(options: RecoveredVirtualizerOptions); scrollOffset: number | null; getVirtualItems(): RecoveredVirtualItem[]; getTotalSize(): number; setOptions(options: RecoveredVirtualizerOptions): void }\n`
|
|
|
|
await fs.mkdir(OUTPUT_DIRECTORY, { recursive: true })
|
|
const outputPaths = {
|
|
engine: path.join(OUTPUT_DIRECTORY, 'index.mjs'),
|
|
declarations: path.join(OUTPUT_DIRECTORY, 'index.d.mts'),
|
|
manifest: path.join(OUTPUT_DIRECTORY, 'manifest.json'),
|
|
}
|
|
await writeGenerated(outputPaths.engine, engine, 'source')
|
|
await writeGenerated(outputPaths.declarations, declarations, 'source')
|
|
|
|
const outputArtifacts = []
|
|
for (const [kind, filePath] of Object.entries(outputPaths).filter(([kind]) => kind !== 'manifest')) {
|
|
const bytes = await fs.readFile(filePath)
|
|
outputArtifacts.push({ path: path.basename(filePath), kind, bytes: bytes.length, sha256: sha256(bytes) })
|
|
}
|
|
const manifest = {
|
|
kind: 'rea-recovered-tool-virtualizer',
|
|
target: {
|
|
name: 'WorkBuddy',
|
|
version: '5.8.2',
|
|
asar_sha256: EXPECTED_ROOT_SHA256,
|
|
},
|
|
evidence: {
|
|
evidence_id: evidence.evidence_id,
|
|
export_path: EVIDENCE_PATH,
|
|
export_bytes: evidenceBytes.length,
|
|
export_sha256: sha256(evidenceBytes),
|
|
selected_artifacts: [
|
|
mainArtifact.record,
|
|
virtualizerArtifact.record,
|
|
runtimeArtifact.record,
|
|
reactArtifact.record,
|
|
reactDomArtifact.record,
|
|
],
|
|
},
|
|
source_anchor: anchor,
|
|
recovered_export: {
|
|
local_binding: 'useVirtualizer',
|
|
exported_name: 'tt',
|
|
closure_binding_count: closure.bindingNames.length,
|
|
closure_bindings: closure.bindingNames,
|
|
rolldown_initialization_calls: closure.initializationCalls,
|
|
},
|
|
rolldown_runtime_closure: {
|
|
source_file: runtimeArtifact.record.fileName,
|
|
source_sha256: runtimeArtifact.record.sha256,
|
|
source_bindings: rolldownClosure.bindingNames,
|
|
renamed_bindings: Object.fromEntries(renamedRuntime.renamed),
|
|
restored_helpers: [
|
|
{ local: 'r', export: '__esmMin', binding: esmHelper },
|
|
{ local: 's', export: '__toESM', binding: toEsmHelper },
|
|
],
|
|
external_imports: [],
|
|
},
|
|
imports: {
|
|
original: importedAdapters,
|
|
output: outputImports,
|
|
unresolved: [],
|
|
},
|
|
transformations: [
|
|
'Babel Program scope closure started at the source binding useVirtualizer.',
|
|
'Included only declarations reachable from useVirtualizer and required Rolldown lazy-module initialization calls.',
|
|
'Recovered Rolldown __esmMin and __toESM helper closures and renamed their Program bindings to avoid collisions.',
|
|
'Rebound WorkBuddy React and ReactDOM module factories to the YCode react and react-dom package namespaces.',
|
|
'Excluded the WorkBuddy application entrypoint, UI components, and unrelated module initializers.',
|
|
'Exported the recovered useVirtualizer hook and its Virtualizer core class for the YCode view and focused regression.',
|
|
],
|
|
outputs: outputArtifacts,
|
|
limitations: [
|
|
'The source is locked to the selected WorkBuddy 5.8.2 runtime bundle; the original TanStack package version is not inferred or installed.',
|
|
'React and ReactDOM resolve to YCode package versions; exact React package version parity with WorkBuddy was not established by this hook recovery.',
|
|
'The focused regression verifies SSR initial ranges and core scroll ranges; full application interaction and pixel parity remain separate acceptance work.',
|
|
],
|
|
}
|
|
await writeGenerated(outputPaths.manifest, `${JSON.stringify(manifest, null, 2)}\n`, 'manifest')
|
|
|
|
console.log(JSON.stringify({
|
|
outputDirectory: OUTPUT_DIRECTORY,
|
|
evidenceId: evidence.evidence_id,
|
|
closureBindings: closure.bindingNames.length,
|
|
importedAdapters,
|
|
initializationCalls: closure.initializationCalls,
|
|
outputImports,
|
|
outputs: outputArtifacts,
|
|
manifest: outputPaths.manifest,
|
|
}, null, 2))
|