import * as path from 'path' ; import { JsonFile } from './JsonFile' ; import { IPackageJson , INodePackageJson } from './IPackageJson' ; import { FileConstants } from './Constants' ; import { FileSystem } from './FileSystem' ; /**
 * Constructor parameters for  PackageJsonLookup public export interface IPackageJsonLookupParameters { /**
     * Certain package.json fields such as "contributors" can be very large, and may
     * significantly increase the memory footprint for the PackageJsonLookup cache.
     * By default, PackageJsonLookup only loads a subset of standard commonly used
     * fields names.  Set loadExtraFields=true to always return all fields.
     */ loadExtraFields ? : boolean ; } public export class PackageJsonLookup { private static _instance : PackageJsonLookup | undefined ; remarks public static get instance ( ) : PackageJsonLookup { if ( ! PackageJsonLookup . _instance ) { PackageJsonLookup . _instance = new PackageJsonLookup ( { loadExtraFields : true } ) ; } return PackageJsonLookup . _instance ; } private _loadExtraFields : boolean = false ; private _packageFolderCache ! : Map < string , string | undefined > ; private _packageJsonCache ! : Map < string , IPackageJson > ; public constructor ( parameters ? ) { if ( parameters ) { if ( parameters . loadExtraFields ) { this . _loadExtraFields = parameters . loadExtraFields ; } } this . clearCache ( ) ; } remarks example param dirnameOfCaller returns public static loadOwnPackageJson ( dirnameOfCaller ) { const packageJson = PackageJsonLookup . instance . tryLoadPackageJsonFor ( dirnameOfCaller ) ; if ( packageJson === undefined ) { throw new Error ( `PackageJsonLookup.loadOwnPackageJson() failed to find the caller's package.json.` + `  The __dirname was: ${ dirnameOfCaller }` ) ; } if ( packageJson . version !== undefined ) { return packageJson as IPackageJson ; } const errorPath = PackageJsonLookup . instance . tryGetPackageJsonFilePathFor ( dirnameOfCaller ) || 'package.json' ; throw new Error ( `PackageJsonLookup.loadOwnPackageJson() failed because the "version" field is missing in` + ` ${ errorPath }` ) ; } remarks public clearCache ( ) { this . _packageFolderCache = new Map < string , string | undefined > ( ) ; this . _packageJsonCache = new Map < string , IPackageJson > ( ) ; } remarks param fileOrFolderPath returns public tryGetPackageFolderFor ( fileOrFolderPath ) { const resolvedFileOrFolderPath = path . resolve ( fileOrFolderPath ) ; if ( this . _packageFolderCache . has ( resolvedFileOrFolderPath ) ) { return this . _packageFolderCache . get ( resolvedFileOrFolderPath ) ; } return this . _tryGetPackageFolderFor ( resolvedFileOrFolderPath ) ; } remarks The package folder is determined using the same algorithm
     * as  PackageJsonLookup . tryGetPackageFolderFor .
     *
     *  param fileOrFolderPath returns public tryGetPackageJsonFilePathFor ( fileOrFolderPath ) { const packageJsonFolder = this . tryGetPackageFolderFor ( fileOrFolderPath ) ; if ( ! packageJsonFolder ) { return undefined ; } return path . join ( packageJsonFolder , FileConstants . PackageJson ) ; } remarks The package folder is determined using the same algorithm
     * as  PackageJsonLookup . tryGetPackageFolderFor .
     *
     *  param fileOrFolderPath returns public tryLoadPackageJsonFor ( fileOrFolderPath ) { const packageJsonFilePath = this . tryGetPackageJsonFilePathFor ( fileOrFolderPath ) ; if ( ! packageJsonFilePath ) { return undefined ; } return this . loadPackageJson ( packageJsonFilePath ) ; } /**
     * This function is similar to  PackageJsonLookup . tryLoadPackageJsonFor , except that it does not report
     * an error if the `version` field is missing from the package.json file.
      public tryLoadNodePackageJsonFor ( fileOrFolderPath ) { const packageJsonFilePath = this . tryGetPackageJsonFilePathFor ( fileOrFolderPath ) ; if ( ! packageJsonFilePath ) { return undefined ; } return this . loadNodePackageJson ( packageJsonFilePath ) ; } remarks Unless  IPackageJsonLookupParameters . loadExtraFields was specified,
     * the returned IPackageJson object will contain a subset of essential fields.
     * The returned object should be considered to be immutable; the caller must never
     * modify it.
     *
     *  param jsonFilename public loadPackageJson ( jsonFilename ) { const packageJson = this . loadNodePackageJson ( jsonFilename ) ; if ( ! packageJson . version ) { throw new Error ( `Error reading "${ jsonFilename }":\n  The required field "version" was not found` ) ; } return packageJson as IPackageJson ; } /**
     * This function is similar to  PackageJsonLookup . loadPackageJson , except that it does not report an error
     * if the `version` field is missing from the package.json file.
      public loadNodePackageJson ( jsonFilename ) { if ( ! FileSystem . exists ( jsonFilename ) ) { throw new Error ( `Input file not found: ${ jsonFilename }` ) ; } const normalizedFilePath = FileSystem . getRealPath ( jsonFilename ) ; let packageJson = this . _packageJsonCache . get ( normalizedFilePath ) ; if ( ! packageJson ) { const loadedPackageJson = JsonFile . load ( normalizedFilePath ) as IPackageJson ; if ( ! loadedPackageJson . name ) { throw new Error ( `Error reading "${ jsonFilename }":\n  The required field "name" was not found` ) ; } if ( this . _loadExtraFields ) { packageJson = loadedPackageJson ; } else { packageJson = { } as IPackageJson ; packageJson . bin = loadedPackageJson . bin ; packageJson . dependencies = loadedPackageJson . dependencies ; packageJson . description = loadedPackageJson . description ; packageJson . devDependencies = loadedPackageJson . devDependencies ; packageJson . homepage = loadedPackageJson . homepage ; packageJson . license = loadedPackageJson . license ; packageJson . main = loadedPackageJson . main ; packageJson . name = loadedPackageJson . name ; packageJson . optionalDependencies = loadedPackageJson . optionalDependencies ; packageJson . peerDependencies = loadedPackageJson . peerDependencies ; packageJson . private = loadedPackageJson . private ; packageJson . scripts = loadedPackageJson . scripts ; packageJson . typings = loadedPackageJson . typings || loadedPackageJson . types ; packageJson . tsdocMetadata = loadedPackageJson . tsdocMetadata ; packageJson . version = loadedPackageJson . version ; } Object . freeze ( packageJson ) ; this . _packageJsonCache . set ( normalizedFilePath , packageJson ) ; } return packageJson ; } private _tryGetPackageFolderFor ( resolvedFileOrFolderPath ) { if ( this . _packageFolderCache . has ( resolvedFileOrFolderPath ) ) { return this . _packageFolderCache . get ( resolvedFileOrFolderPath ) ; } if ( FileSystem . exists ( path . join ( resolvedFileOrFolderPath , FileConstants . PackageJson ) ) ) { this . _packageFolderCache . set ( resolvedFileOrFolderPath , resolvedFileOrFolderPath ) ; return resolvedFileOrFolderPath ; } const parentFolder = path . dirname ( resolvedFileOrFolderPath ) ; if ( ! parentFolder || parentFolder === resolvedFileOrFolderPath ) { this . _packageFolderCache . set ( resolvedFileOrFolderPath , undefined ) ; return undefined ; } const parentResult = this . _tryGetPackageFolderFor ( parentFolder ) ; this . _packageFolderCache . set ( resolvedFileOrFolderPath , parentResult ) ; return parentResult ; } }