Follow-up to the review of pnpm/pnpm#14900. - The v11 worker parsed the store's package.json with a bare JSON.parse, so a manifest starting with a byte-order mark failed to parse and kept the stale `requiresBuild: true`. It now uses `parseJsonBufferSync`, which strips the mark, as store ingestion does. - Both stacks answer from the manifest's install scripts before scanning the file index, and the TypeScript check no longer copies the index. - The predicate is renamed to `stored_requires_build_needs_manifest_check` / `storedRequiresBuildNeedsManifestCheck`, and its docs state the current contract. - `checkBindingGyp`'s JSDoc states that its caller decides whether the synthesized script applies. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.8 KiB
TypeScript
41 lines
1.8 KiB
TypeScript
import fs from 'node:fs'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
|
|
import { afterAll, expect, test } from '@jest/globals'
|
|
import type { PackageFilesIndex } from '@pnpm/store.cafs'
|
|
import { StoreIndex } from '@pnpm/store.index'
|
|
|
|
import { addFilesFromDir, finishWorkers, readPkgFromCafs } from '../lib/index.js'
|
|
|
|
afterAll(() => finishWorkers())
|
|
|
|
test('a stored requiresBuild that predates gypfile is rechecked against the package.json in the store', async () => {
|
|
expect(await readLegacyRowRequiresBuild({ name: 'opted-out', version: '1.0.0', gypfile: false })).toBe(false)
|
|
expect(await readLegacyRowRequiresBuild({ name: 'not-opted-out', version: '1.0.0' })).toBe(true)
|
|
})
|
|
|
|
test('a package.json with a byte-order mark is rechecked like any other', async () => {
|
|
expect(await readLegacyRowRequiresBuild({ name: 'bom', version: '1.0.0', gypfile: false }, '\uFEFF')).toBe(false)
|
|
})
|
|
|
|
async function readLegacyRowRequiresBuild (manifest: Record<string, unknown>, prefix = ''): Promise<boolean> {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'pnpm-stored-requires-build-'))
|
|
const dir = path.join(tmp, 'pkg')
|
|
fs.mkdirSync(dir)
|
|
fs.writeFileSync(path.join(dir, 'package.json'), prefix + JSON.stringify(manifest))
|
|
fs.writeFileSync(path.join(dir, 'binding.gyp'), '{}')
|
|
const storeDir = path.join(tmp, 'store')
|
|
const storeIndex = new StoreIndex(storeDir)
|
|
const filesIndexFile = path.join(storeDir, 'pkg.json')
|
|
await addFilesFromDir({ storeDir, dir, filesIndexFile, storeIndex })
|
|
|
|
const row = storeIndex.get(filesIndexFile) as PackageFilesIndex
|
|
delete row.manifest?.gypfile
|
|
storeIndex.set(filesIndexFile, { ...row, requiresBuild: true })
|
|
|
|
const result = await readPkgFromCafs({ storeDir, verifyStoreIntegrity: false }, filesIndexFile)
|
|
storeIndex.close()
|
|
return result.files.requiresBuild
|
|
}
|