import fs from 'node:fs'; import path from 'node:path'; import zlib from 'node:zlib'; const root = process.cwd(); const expected = process.env.EXPECTED_UNI_COMPILER || ''; function readJson(file) { return JSON.parse(fs.readFileSync(file, 'utf8')); } function compilerOf(manifest) { return manifest?.plus?.['uni-app']?.compilerVersion || manifest?.['uni-app']?.compilerVersion || ''; } function versionOf(manifest) { const version = manifest?.version || {}; return [version.name, version.code].filter(Boolean).join(' / '); } function walk(dir, accept, out = []) { if (!fs.existsSync(dir)) return out; for (const item of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, item.name); if (item.isDirectory()) { walk(full, accept, out); } else if (accept(full)) { out.push(full); } } return out; } function extractZipEntries(file, matcher) { const buf = fs.readFileSync(file); const eocdSig = 0x06054b50; let eocd = -1; for (let i = buf.length - 22; i >= Math.max(0, buf.length - 0x10000); i -= 1) { if (buf.readUInt32LE(i) === eocdSig) { eocd = i; break; } } if (eocd < 0) return []; const total = buf.readUInt16LE(eocd + 10); const cdOffset = buf.readUInt32LE(eocd + 16); const entries = []; let offset = cdOffset; for (let i = 0; i < total && offset < buf.length; i += 1) { if (buf.readUInt32LE(offset) !== 0x02014b50) break; const method = buf.readUInt16LE(offset + 10); const compressedSize = buf.readUInt32LE(offset + 20); const nameLen = buf.readUInt16LE(offset + 28); const extraLen = buf.readUInt16LE(offset + 30); const commentLen = buf.readUInt16LE(offset + 32); const localOffset = buf.readUInt32LE(offset + 42); const name = buf.toString('utf8', offset + 46, offset + 46 + nameLen); if (matcher(name)) { const localNameLen = buf.readUInt16LE(localOffset + 26); const localExtraLen = buf.readUInt16LE(localOffset + 28); const dataStart = localOffset + 30 + localNameLen + localExtraLen; const compressed = buf.subarray(dataStart, dataStart + compressedSize); let data; if (method === 0) { data = compressed; } else if (method === 8) { data = zlib.inflateRawSync(compressed); } else { throw new Error(`Unsupported zip compression method ${method} in ${file}:${name}`); } entries.push({ name, text: data.toString('utf8') }); } offset += 46 + nameLen + extraLen + commentLen; } return entries; } const reports = []; const manifestFiles = [ path.join(root, 'unpackage/dist/build/app-plus/manifest.json'), path.join(root, 'unpackage/dist/dev/app-plus/manifest.json'), ...walk(path.join(root, 'unpackage/cache/wgt'), file => path.basename(file) === 'manifest.json'), ].filter(file => fs.existsSync(file)); for (const file of manifestFiles) { const manifest = readJson(file); reports.push({ source: path.relative(root, file), version: versionOf(manifest), compiler: compilerOf(manifest), }); } for (const apk of walk(path.join(root, 'unpackage/cache/apk'), file => file.endsWith('.apk'))) { for (const entry of extractZipEntries(apk, name => /assets\/apps\/.+\/www\/manifest\.json$/.test(name))) { const manifest = JSON.parse(entry.text); reports.push({ source: `${path.relative(root, apk)}:${entry.name}`, version: versionOf(manifest), compiler: compilerOf(manifest), }); } } if (!reports.length) { console.log('No App-Plus build manifests found.'); process.exit(0); } const width = Math.max(...reports.map(item => item.source.length), 'source'.length); console.log(`${'source'.padEnd(width)} app version compiler`); console.log(`${'-'.repeat(width)} ----------- --------`); for (const item of reports) { console.log(`${item.source.padEnd(width)} ${(item.version || '-').padEnd(11)} ${item.compiler || '-'}`); } const compilers = [...new Set(reports.map(item => item.compiler).filter(Boolean))]; const badExpected = expected && compilers.some(item => item !== expected); if (compilers.length > 1 || badExpected) { if (expected) { console.error(`Runtime compiler version mismatch. Expected ${expected}.`); } else { console.error(`Runtime compiler version mismatch: ${compilers.join(', ')}.`); } process.exit(1); } console.log(`Runtime compiler version OK: ${compilers[0] || 'unknown'}.`);