97 lines
4.3 KiB
JavaScript
97 lines
4.3 KiB
JavaScript
// Recover only the loading component rules used by StreamingFooter from REA-exported CSS.
|
|
// This reads the saved REA export, never the WorkBuddy installation or runtime directly.
|
|
import assert from 'node:assert/strict'
|
|
import { createHash } from 'node:crypto'
|
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
import postcss from 'postcss'
|
|
|
|
const sourceDirectory = path.resolve('.tmp/rea-css-recovered')
|
|
const destination = path.resolve('src/renderer/src/workbuddy/conversation/streaming-footer-source.css')
|
|
const evidenceId = 'ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94'
|
|
const manifest = JSON.parse(await readFile(path.join(sourceDirectory, 'manifest.json'), 'utf8'))
|
|
assert.equal(manifest.sourceEvidenceId, evidenceId)
|
|
|
|
const sourceFiles = [
|
|
{ file: 'src-CBaV_A3S.css', sha256: '2090ed21045c8f8b0fc388d76424c8751bf18fcd065cbbd5d0ef485163a2e36c' },
|
|
{ file: 'contexts-BkjwYSZT.css', sha256: '50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380' }
|
|
]
|
|
const classNames = [
|
|
'assistant-message',
|
|
'_loadingMessage_13r4w_60',
|
|
'_loadingContent_13r4w_69',
|
|
'_loadingText_13r4w_81',
|
|
'_mainText_13r4w_94',
|
|
'_tipPhrase_13r4w_108',
|
|
'_tipDivider_13r4w_121',
|
|
'_tipText_13r4w_126',
|
|
'_tipDismissButton_13r4w_140',
|
|
'_trailingTipPhrase_13r4w_179',
|
|
'_loadingWithCredit_ttf8p_463',
|
|
'cb-loading-tip--trailing'
|
|
]
|
|
|
|
const output = postcss.root()
|
|
const usedAnimations = new Set()
|
|
const sourceIdentities = []
|
|
|
|
function referencesClass(selector) {
|
|
return classNames.some(name => new RegExp(`\\.${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![\\w-])`).test(selector))
|
|
}
|
|
|
|
function copyRelevantNodes(nodes) {
|
|
const copied = []
|
|
for (const node of nodes) {
|
|
if (node.type === 'rule') {
|
|
const selectors = (node.selectors ?? []).filter(referencesClass)
|
|
if (!selectors.length) continue
|
|
const clone = node.clone({ selector: selectors.join(',') })
|
|
clone.walkDecls(/^animation(?:-name)?$/, declaration => {
|
|
for (const token of declaration.value.split(/[\s,]+/)) usedAnimations.add(token)
|
|
})
|
|
copied.push(clone)
|
|
continue
|
|
}
|
|
if (node.type === 'atrule' && /keyframes$/.test(node.name)) continue
|
|
if (node.type === 'atrule' && node.nodes) {
|
|
const children = copyRelevantNodes(node.nodes)
|
|
if (children.length) copied.push(node.clone({ nodes: children }))
|
|
}
|
|
}
|
|
return copied
|
|
}
|
|
|
|
for (const expected of sourceFiles) {
|
|
const metadata = manifest.files.find(file => file.file === expected.file)
|
|
assert.ok(metadata, `REA CSS export must contain ${expected.file}`)
|
|
assert.equal(metadata.sha256, expected.sha256, `REA CSS manifest digest changed for ${expected.file}`)
|
|
const bytes = await readFile(path.join(sourceDirectory, expected.file))
|
|
assert.equal(createHash('sha256').update(bytes).digest('hex'), expected.sha256, `REA CSS bytes changed for ${expected.file}`)
|
|
const source = postcss.parse(bytes, { from: expected.file })
|
|
for (const node of copyRelevantNodes(source.nodes)) output.append(node)
|
|
source.walkAtRules(/^keyframes$/, node => {
|
|
if (usedAnimations.has(node.params)) output.append(node.clone())
|
|
})
|
|
sourceIdentities.push({ file: expected.file, sha256: expected.sha256, asarComparison: metadata.asarComparison?.status ?? 'not-compared' })
|
|
}
|
|
|
|
for (const name of classNames) {
|
|
assert.ok(output.toString().includes(`.${name}`), `REA CSS export is missing the ${name} rule`)
|
|
}
|
|
assert.ok(output.toString().includes('@keyframes _cb-shining-text-sweep_13r4w_1'))
|
|
assert.ok(output.toString().includes('@keyframes _cb-tip-fade-in_13r4w_1'))
|
|
|
|
const header = `/* Generated from REA ${evidenceId} by recover-streaming-footer-styles.mjs.
|
|
* Selected WorkBuddy 5.8.2 loading component rules are preserved verbatim.
|
|
* Runtime CSS identities: ${sourceIdentities.map(item => `${item.file}=${item.sha256} (${item.asarComparison})`).join('; ')}
|
|
*/\n`
|
|
const result = header + output.toString() + '\n'
|
|
|
|
if (process.argv.includes('--check')) {
|
|
assert.equal(await readFile(destination, 'utf8'), result, 'Recovered streaming footer styles are stale')
|
|
console.log(`streaming footer styles check passed (${classNames.length} class families; ${sourceIdentities.length} REA CSS assets)`)
|
|
} else {
|
|
await writeFile(destination, result, 'utf8')
|
|
console.log(`recovered streaming footer styles to ${destination}`)
|
|
}
|