1import * as _ from 'lodash-es' 15export const jsShebangA = ['#!/usr/bin/env ptnode', '#!/usr/bin/env node'] 16export const pathBinDirname = 'path_bin' 18export const isPathBinJsScript = (filePath: string) => { 19 if (!filePath.includes(`/${pathBinDirname}/`) && !filePath.startsWith(`${pathBinDirname}/`)) return false 20 const absPath = filePath.startsWith('/') ? filePath : ptDir + '/' + filePath 22 const firstLine = fs.readFileSync(absPath, 'utf8').split('\n')[0] 23 return jsShebangA.includes(firstLine) 32const acornH = async (pathsA: string[]) => { 33 const store = madgeDepFilterCtx.getStore() as {dependencyFilter?: (p: string) => boolean} | undefined 34 let dependencyFilter = store?.dependencyFilter ?? defaultDepFilter 35 dependencyFilter ||= () => true 37 const seedPathSet = new Set(pathsA) 38 const remainPathsA = _.clone(_.castArray(pathsA)) 40 const transformFn = contentTransformCtx.getStore() as ((s: string) => string) | undefined 41 const retH: Record<string, string[]> = {} 44 const filePath = remainPathsA.shift() 46 if (retH[filePath]) continue 47 // ptMadge is the sanctioned bulk-walk tool (the acorn budget breaker's message directs callers here). 48 // Reset periodically so legitimately large closures (pages/ reachability ~1900 files) don't trip the 49 // OOM breaker, while raw acornSingleFile loops (the actual bug class) still do. 51 if (!seedPathSet.has(filePath) && !dependencyFilter(filePath)) continue 53 let acornOpts: {contents: string} | undefined 56 acornOpts = {contents: transformFn(fs.readFileSync(ptDir + '/' + filePath, 'utf8'))} 58 console.warn(`ptMadge: skipping unreadable stale-path ${filePath}: ${err.message}`) 63 if (importsA.length == 0) continue 64 retH[filePath] = importsA 65 importsA.forEach((ptPath) => remainPathsA.push(ptPath)) 70export const ptMadge = async (paths: string[]) => { 72 if (paths.length == 0) return {} 73 const origPaths = paths 78 throwIf(() => paths.length == 0, {paths, origPaths}) 80 return await betDurMs(`ptMadge:${paths.length}seeds`, () => acornH(paths))