1 line
21 KiB
Plaintext
1 line
21 KiB
Plaintext
{"version":3,"file":"PackageJsonLookup.js","sourceRoot":"","sources":["../src/PackageJsonLookup.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'path';\nimport { JsonFile } from './JsonFile';\nimport type { IPackageJson, INodePackageJson } from './IPackageJson';\nimport { FileConstants } from './Constants';\nimport { FileSystem } from './FileSystem';\n\n/**\n * Constructor parameters for {@link PackageJsonLookup}\n *\n * @public\n */\nexport interface IPackageJsonLookupParameters {\n /**\n * Certain package.json fields such as \"contributors\" can be very large, and may\n * significantly increase the memory footprint for the PackageJsonLookup cache.\n * By default, PackageJsonLookup only loads a subset of standard commonly used\n * fields names. Set loadExtraFields=true to always return all fields.\n */\n loadExtraFields?: boolean;\n}\n\ntype TryLoadPackageJsonInternalErrorCode =\n | 'MISSING_NAME_FIELD'\n | 'FILE_NOT_FOUND'\n | 'MISSING_VERSION_FIELD'\n | 'OTHER_ERROR';\n\ninterface ITryLoadPackageJsonInternalSuccessResult {\n packageJson: IPackageJson;\n error?: never;\n}\n\ninterface ITryLoadPackageJsonInternalFailureResult {\n error: TryLoadPackageJsonInternalErrorCode;\n}\ninterface ITryLoadPackageJsonInternalKnownFailureResult extends ITryLoadPackageJsonInternalFailureResult {\n error: 'MISSING_NAME_FIELD' | 'FILE_NOT_FOUND';\n}\n\ninterface ITryLoadPackageJsonInternalUnknownFailureResult extends ITryLoadPackageJsonInternalFailureResult {\n error: 'OTHER_ERROR';\n errorObject: Error;\n}\n\ntype ITryLoadPackageJsonInternalResult =\n | ITryLoadPackageJsonInternalSuccessResult\n | ITryLoadPackageJsonInternalKnownFailureResult\n | ITryLoadPackageJsonInternalUnknownFailureResult;\n\n/**\n * This class provides methods for finding the nearest \"package.json\" for a folder\n * and retrieving the name of the package. The results are cached.\n *\n * @public\n */\nexport class PackageJsonLookup {\n private static _instance: PackageJsonLookup | undefined;\n\n /**\n * A singleton instance of `PackageJsonLookup`, which is useful for short-lived processes\n * that can reasonably assume that the file system will not be modified after the cache\n * is populated.\n *\n * @remarks\n * For long-running processes that need to clear the cache at appropriate times,\n * it is recommended to create your own instance of `PackageJsonLookup` instead\n * of relying on this instance.\n */\n public static get instance(): PackageJsonLookup {\n if (!PackageJsonLookup._instance) {\n PackageJsonLookup._instance = new PackageJsonLookup({ loadExtraFields: true });\n }\n\n return PackageJsonLookup._instance;\n }\n\n private _loadExtraFields: boolean = false;\n\n // Cached the return values for tryGetPackageFolder():\n // sourceFilePath --> packageJsonFolder\n private _packageFolderCache!: Map<string, string | undefined>;\n\n // Cached the return values for getPackageName():\n // packageJsonPath --> packageName\n private _packageJsonCache!: Map<string, IPackageJson>;\n\n public constructor(parameters?: IPackageJsonLookupParameters) {\n if (parameters) {\n if (parameters.loadExtraFields) {\n this._loadExtraFields = parameters.loadExtraFields;\n }\n }\n this.clearCache();\n }\n\n /**\n * A helper for loading the caller's own package.json file.\n *\n * @remarks\n *\n * This function provides a concise and efficient way for an NPM package to report metadata about itself.\n * For example, a tool might want to report its version.\n *\n * The `loadOwnPackageJson()` probes upwards from the caller's folder, expecting to find a package.json file,\n * which is assumed to be the caller's package. The result is cached, under the assumption that a tool's\n * own package.json (and intermediary folders) will never change during the lifetime of the process.\n *\n * @example\n * ```ts\n * // Report the version of our NPM package\n * const myPackageVersion: string = PackageJsonLookup.loadOwnPackageJson(__dirname).version;\n * console.log(`Cool Tool - Version ${myPackageVersion}`);\n * ```\n *\n * @param dirnameOfCaller - The NodeJS `__dirname` macro for the caller.\n * @returns This function always returns a valid `IPackageJson` object. If any problems are encountered during\n * loading, an exception will be thrown instead.\n */\n public static loadOwnPackageJson(dirnameOfCaller: string): IPackageJson {\n const packageJson: IPackageJson | undefined =\n PackageJsonLookup.instance.tryLoadPackageJsonFor(dirnameOfCaller);\n\n if (packageJson === undefined) {\n throw new Error(\n `PackageJsonLookup.loadOwnPackageJson() failed to find the caller's package.json.` +\n ` The __dirname was: ${dirnameOfCaller}`\n );\n }\n\n if (packageJson.version !== undefined) {\n return packageJson as IPackageJson;\n }\n\n const errorPath: string =\n PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(dirnameOfCaller) || 'package.json';\n throw new Error(\n `PackageJsonLookup.loadOwnPackageJson() failed because the \"version\" field is missing in` +\n ` ${errorPath}`\n );\n }\n\n /**\n * Clears the internal file cache.\n * @remarks\n * Call this method if changes have been made to the package.json files on disk.\n */\n public clearCache(): void {\n this._packageFolderCache = new Map<string, string | undefined>();\n this._packageJsonCache = new Map<string, IPackageJson>();\n }\n\n /**\n * Returns the absolute path of a folder containing a package.json file, by looking\n * upwards from the specified fileOrFolderPath. If no package.json can be found,\n * undefined is returned.\n *\n * @remarks\n * The fileOrFolderPath is not required to actually exist on disk.\n * The fileOrFolderPath itself can be the return value, if it is a folder containing\n * a package.json file.\n * Both positive and negative lookup results are cached.\n *\n * @param fileOrFolderPath - a relative or absolute path to a source file or folder\n * that may be part of a package\n * @returns an absolute path to a folder containing a package.json file\n */\n public tryGetPackageFolderFor(fileOrFolderPath: string): string | undefined {\n // Convert it to an absolute path\n const resolvedFileOrFolderPath: string = path.resolve(fileOrFolderPath);\n\n // Optimistically hope that the starting string is already in the cache,\n // in which case we can avoid disk access entirely.\n //\n // (Two lookups are required, because get() cannot distinguish the undefined value\n // versus a missing key.)\n if (this._packageFolderCache.has(resolvedFileOrFolderPath)) {\n return this._packageFolderCache.get(resolvedFileOrFolderPath);\n }\n\n // Now call the recursive part of the algorithm\n return this._tryGetPackageFolderFor(resolvedFileOrFolderPath);\n }\n\n /**\n * If the specified file or folder is part of a package, this returns the absolute path\n * to the associated package.json file.\n *\n * @remarks\n * The package folder is determined using the same algorithm\n * as {@link PackageJsonLookup.tryGetPackageFolderFor}.\n *\n * @param fileOrFolderPath - a relative or absolute path to a source file or folder\n * that may be part of a package\n * @returns an absolute path to * package.json file\n */\n public tryGetPackageJsonFilePathFor(fileOrFolderPath: string): string | undefined {\n const packageJsonFolder: string | undefined = this.tryGetPackageFolderFor(fileOrFolderPath);\n if (!packageJsonFolder) {\n return undefined;\n }\n return path.join(packageJsonFolder, FileConstants.PackageJson);\n }\n\n /**\n * If the specified file or folder is part of a package, this loads and returns the\n * associated package.json file.\n *\n * @remarks\n * The package folder is determined using the same algorithm\n * as {@link PackageJsonLookup.tryGetPackageFolderFor}.\n *\n * @param fileOrFolderPath - a relative or absolute path to a source file or folder\n * that may be part of a package\n * @returns an IPackageJson object, or undefined if the fileOrFolderPath does not\n * belong to a package\n */\n public tryLoadPackageJsonFor(fileOrFolderPath: string): IPackageJson | undefined {\n const packageJsonFilePath: string | undefined = this.tryGetPackageJsonFilePathFor(fileOrFolderPath);\n if (!packageJsonFilePath) {\n return undefined;\n }\n return this.loadPackageJson(packageJsonFilePath);\n }\n\n /**\n * This function is similar to {@link PackageJsonLookup.tryLoadPackageJsonFor}, except that it does not report\n * an error if the `version` field is missing from the package.json file.\n */\n public tryLoadNodePackageJsonFor(fileOrFolderPath: string): INodePackageJson | undefined {\n const packageJsonFilePath: string | undefined = this.tryGetPackageJsonFilePathFor(fileOrFolderPath);\n if (!packageJsonFilePath) {\n return undefined;\n }\n return this.loadNodePackageJson(packageJsonFilePath);\n }\n\n /**\n * Loads the specified package.json file, if it is not already present in the cache.\n *\n * @remarks\n * Unless {@link IPackageJsonLookupParameters.loadExtraFields} was specified,\n * the returned IPackageJson object will contain a subset of essential fields.\n * The returned object should be considered to be immutable; the caller must never\n * modify it.\n *\n * @param jsonFilename - a relative or absolute path to a package.json file\n */\n public loadPackageJson(jsonFilename: string): IPackageJson {\n const packageJson: INodePackageJson = this.loadNodePackageJson(jsonFilename);\n\n if (!packageJson.version) {\n throw new Error(`Error reading \"${jsonFilename}\":\\n The required field \"version\" was not found`);\n }\n\n return packageJson as IPackageJson;\n }\n\n /**\n * This function is similar to {@link PackageJsonLookup.loadPackageJson}, except that it does not report an error\n * if the `version` field is missing from the package.json file.\n */\n public loadNodePackageJson(jsonFilename: string): INodePackageJson {\n return this._loadPackageJsonInner(jsonFilename);\n }\n\n private _loadPackageJsonInner(jsonFilename: string): IPackageJson;\n private _loadPackageJsonInner(\n jsonFilename: string,\n errorsToIgnore: Set<TryLoadPackageJsonInternalErrorCode>\n ): IPackageJson | undefined;\n private _loadPackageJsonInner(\n jsonFilename: string,\n errorsToIgnore?: Set<TryLoadPackageJsonInternalErrorCode>\n ): IPackageJson | undefined {\n const loadResult: ITryLoadPackageJsonInternalResult = this._tryLoadNodePackageJsonInner(jsonFilename);\n\n if (loadResult.error && errorsToIgnore?.has(loadResult.error)) {\n return undefined;\n }\n\n switch (loadResult.error) {\n case 'FILE_NOT_FOUND': {\n throw new Error(`Input file not found: ${jsonFilename}`);\n }\n\n case 'MISSING_NAME_FIELD': {\n throw new Error(`Error reading \"${jsonFilename}\":\\n The required field \"name\" was not found`);\n }\n\n case 'OTHER_ERROR': {\n throw loadResult.errorObject;\n }\n\n default: {\n return loadResult.packageJson;\n }\n }\n }\n\n /**\n * Try to load a package.json file as an INodePackageJson,\n * returning undefined if the found file does not contain a `name` field.\n */\n private _tryLoadNodePackageJsonInner(jsonFilename: string): ITryLoadPackageJsonInternalResult {\n // Since this will be a cache key, follow any symlinks and get an absolute path\n // to minimize duplication. (Note that duplication can still occur due to e.g. character case.)\n let normalizedFilePath: string;\n try {\n normalizedFilePath = FileSystem.getRealPath(jsonFilename);\n } catch (e) {\n if (FileSystem.isNotExistError(e)) {\n return {\n error: 'FILE_NOT_FOUND'\n };\n } else {\n return {\n error: 'OTHER_ERROR',\n errorObject: e\n };\n }\n }\n\n let packageJson: IPackageJson | undefined = this._packageJsonCache.get(normalizedFilePath);\n\n if (!packageJson) {\n const loadedPackageJson: IPackageJson = JsonFile.load(normalizedFilePath);\n\n // Make sure this is really a package.json file. CommonJS has fairly strict requirements,\n // but NPM only requires \"name\" and \"version\"\n if (!loadedPackageJson.name) {\n return {\n error: 'MISSING_NAME_FIELD'\n };\n }\n\n if (this._loadExtraFields) {\n packageJson = loadedPackageJson;\n } else {\n packageJson = {} as IPackageJson;\n\n // Unless \"loadExtraFields\" was requested, copy over the essential fields only\n packageJson.bin = loadedPackageJson.bin;\n packageJson.dependencies = loadedPackageJson.dependencies;\n packageJson.description = loadedPackageJson.description;\n packageJson.devDependencies = loadedPackageJson.devDependencies;\n packageJson.homepage = loadedPackageJson.homepage;\n packageJson.license = loadedPackageJson.license;\n packageJson.main = loadedPackageJson.main;\n packageJson.name = loadedPackageJson.name;\n packageJson.optionalDependencies = loadedPackageJson.optionalDependencies;\n packageJson.peerDependencies = loadedPackageJson.peerDependencies;\n packageJson.private = loadedPackageJson.private;\n packageJson.scripts = loadedPackageJson.scripts;\n packageJson.typings = loadedPackageJson.typings || loadedPackageJson.types;\n packageJson.tsdocMetadata = loadedPackageJson.tsdocMetadata;\n packageJson.version = loadedPackageJson.version;\n }\n\n Object.freeze(packageJson);\n this._packageJsonCache.set(normalizedFilePath, packageJson);\n }\n\n return {\n packageJson\n };\n }\n\n // Recursive part of the algorithm from tryGetPackageFolderFor()\n private _tryGetPackageFolderFor(resolvedFileOrFolderPath: string): string | undefined {\n // Two lookups are required, because get() cannot distinguish the undefined value\n // versus a missing key.\n if (this._packageFolderCache.has(resolvedFileOrFolderPath)) {\n return this._packageFolderCache.get(resolvedFileOrFolderPath);\n }\n\n // Is resolvedFileOrFolderPath itself a folder with a valid package.json file? If so, return it.\n const packageJsonFilePath: string = `${resolvedFileOrFolderPath}/${FileConstants.PackageJson}`;\n const packageJson: IPackageJson | undefined = this._loadPackageJsonInner(\n packageJsonFilePath,\n new Set(['FILE_NOT_FOUND', 'MISSING_NAME_FIELD'])\n );\n if (packageJson) {\n this._packageFolderCache.set(resolvedFileOrFolderPath, resolvedFileOrFolderPath);\n return resolvedFileOrFolderPath;\n }\n\n // Otherwise go up one level\n const parentFolder: string | undefined = path.dirname(resolvedFileOrFolderPath);\n if (!parentFolder || parentFolder === resolvedFileOrFolderPath) {\n // We reached the root directory without finding a package.json file,\n // so cache the negative result\n this._packageFolderCache.set(resolvedFileOrFolderPath, undefined);\n return undefined; // no match\n }\n\n // Recurse upwards, caching every step along the way\n const parentResult: string | undefined = this._tryGetPackageFolderFor(parentFolder);\n // Cache the parent's answer as well\n this._packageFolderCache.set(resolvedFileOrFolderPath, parentResult);\n\n return parentResult;\n }\n}\n"]} |