Files
Ncurator/scripts/build/package/prune-runtime.mjs
T

125 lines
4.3 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
const normalizePath = (value) => String(value).replaceAll('\\', '/')
const collectPackageTracePaths = (runtimeTrace, packageName) => {
const packageSegments = packageName.split('/')
const result = new Set()
for (const rawPath of runtimeTrace.trace?.files || []) {
const segments = normalizePath(rawPath).split('/')
for (let index = 0; index < segments.length; index += 1) {
if (segments[index] !== 'node_modules') continue
const packageStart = index + 1
if (
packageSegments.every(
(segment, segmentIndex) => segments[packageStart + segmentIndex] === segment
)
) {
result.add(segments.slice(packageStart + packageSegments.length).join('/'))
}
}
}
return [...result].sort()
}
const assertTracedPackage = (runtimeTrace, packageName) => {
if (!(runtimeTrace.packages || []).some((item) => item.name === packageName)) {
throw new Error(`runtime pruning requires traced package ${packageName}`)
}
const paths = collectPackageTracePaths(runtimeTrace, packageName)
if (paths.length === 0) {
throw new Error(`runtime pruning has no traced files for ${packageName}`)
}
return paths
}
export const assertRuntimePruningTrace = (runtimeTrace, platform = process.platform) => {
const mathJaxPaths = assertTracedPackage(runtimeTrace, 'mathjax-full')
const unsafeMathJaxPath = mathJaxPaths.find(
(relativePath) => relativePath !== 'package.json' && !relativePath.startsWith('js/')
)
if (unsafeMathJaxPath) {
throw new Error(`mathjax-full trace reaches a removable path: ${unsafeMathJaxPath}`)
}
const pdfParsePaths = assertTracedPackage(runtimeTrace, 'pdf-parse')
const unsafePdfVersion = pdfParsePaths.find((relativePath) => {
const match = relativePath.match(/^lib\/pdf\.js\/(v[^/]+)(?:\/|$)/u)
return match && match[1] !== 'v1.10.100'
})
if (unsafePdfVersion) {
throw new Error(`pdf-parse trace reaches a removable PDF.js version: ${unsafePdfVersion}`)
}
const excelJsPaths = assertTracedPackage(runtimeTrace, 'exceljs')
const unsafeExcelJsPath = excelJsPaths.find(
(relativePath) => relativePath === 'dist' || relativePath.startsWith('dist/')
)
if (unsafeExcelJsPath) {
throw new Error(`exceljs trace reaches removable browser dist: ${unsafeExcelJsPath}`)
}
if (platform !== 'win32') {
const nodePtyPaths = assertTracedPackage(runtimeTrace, 'node-pty')
const unsafeNodePtyPath = nodePtyPaths.find(
(relativePath) => relativePath === 'third_party' || relativePath.startsWith('third_party/')
)
if (unsafeNodePtyPath) {
throw new Error(`node-pty trace reaches removable Windows sources: ${unsafeNodePtyPath}`)
}
}
}
const directorySize = (targetPath) => {
if (!fs.existsSync(targetPath)) return 0
const stat = fs.lstatSync(targetPath)
if (!stat.isDirectory()) return stat.size
return fs
.readdirSync(targetPath)
.reduce((total, name) => total + directorySize(path.join(targetPath, name)), 0)
}
export const pruneRuntimePackages = ({
nodeModulesDirectory,
runtimeTrace,
platform = process.platform
}) => {
assertRuntimePruningTrace(runtimeTrace, platform)
const targets = [
['mathjax-full/es5', path.join(nodeModulesDirectory, 'mathjax-full', 'es5')],
['mathjax-full/components', path.join(nodeModulesDirectory, 'mathjax-full', 'components')],
['mathjax-full/ts', path.join(nodeModulesDirectory, 'mathjax-full', 'ts')],
[
'pdf-parse PDF.js v1.9.426',
path.join(nodeModulesDirectory, 'pdf-parse', 'lib', 'pdf.js', 'v1.9.426')
],
[
'pdf-parse PDF.js v1.10.88',
path.join(nodeModulesDirectory, 'pdf-parse', 'lib', 'pdf.js', 'v1.10.88')
],
[
'pdf-parse PDF.js v2.0.550',
path.join(nodeModulesDirectory, 'pdf-parse', 'lib', 'pdf.js', 'v2.0.550')
],
['exceljs/dist', path.join(nodeModulesDirectory, 'exceljs', 'dist')]
]
if (platform !== 'win32') {
targets.push([
'node-pty Windows ConPTY',
path.join(nodeModulesDirectory, 'node-pty', 'third_party')
])
}
const removed = targets.map(([label, targetPath]) => {
const bytes = directorySize(targetPath)
fs.rmSync(targetPath, { recursive: true, force: true })
return { label, bytes }
})
return {
removed,
totalBytes: removed.reduce((total, item) => total + item.bytes, 0)
}
}