@rushstack/node-core-library
Advanced tools
Comparing version 3.29.1 to 3.30.0
@@ -5,2 +5,19 @@ { | ||
{ | ||
"version": "3.30.0", | ||
"tag": "@rushstack/node-core-library_v3.30.0", | ||
"date": "Thu, 27 Aug 2020 11:27:06 GMT", | ||
"comments": { | ||
"minor": [ | ||
{ | ||
"comment": "Include an API for resolving packages and modules." | ||
} | ||
], | ||
"dependency": [ | ||
{ | ||
"comment": "Updating dependency \"@rushstack/eslint-config\" to `1.3.0`" | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"version": "3.29.1", | ||
@@ -7,0 +24,0 @@ "tag": "@rushstack/node-core-library_v3.29.1", |
# Change Log - @rushstack/node-core-library | ||
This log was last generated on Mon, 24 Aug 2020 07:35:20 GMT and should not be manually modified. | ||
This log was last generated on Thu, 27 Aug 2020 11:27:06 GMT and should not be manually modified. | ||
## 3.30.0 | ||
Thu, 27 Aug 2020 11:27:06 GMT | ||
### Minor changes | ||
- Include an API for resolving packages and modules. | ||
## 3.29.1 | ||
@@ -6,0 +13,0 @@ Mon, 24 Aug 2020 07:35:20 GMT |
/** | ||
* Common options shared by {@link IImportResolveModuleOptions} and {@link IImportResolvePackageOptions} | ||
* @public | ||
*/ | ||
export interface IImportResolveOptions { | ||
/** | ||
* The path from which {@link IImportResolveModuleOptions.modulePath} or | ||
* {@link IImportResolvePackageOptions.packageName} should be resolved. | ||
*/ | ||
baseFolderPath: string; | ||
/** | ||
* If true, if the package name matches a Node.js system module, then the return | ||
* value will be the package name without any path. | ||
* | ||
* @remarks | ||
* This will take precedence over an installed NPM package of the same name. | ||
* | ||
* Example: | ||
* ```ts | ||
* // Returns the string "fs" indicating the Node.js system module | ||
* Import.resolveModulePath({ | ||
* resolvePath: "fs", | ||
* basePath: process.cwd() | ||
* }) | ||
* ``` | ||
*/ | ||
includeSystemModules?: boolean; | ||
/** | ||
* If true, then resolvePath is allowed to refer to the package.json of the active project. | ||
* | ||
* @remarks | ||
* This will take precedence over any installed dependency with the same name. | ||
* Note that this requires an additional PackageJsonLookup calculation. | ||
* | ||
* Example: | ||
* ```ts | ||
* // Returns an absolute path to the current package | ||
* Import.resolveModulePath({ | ||
* resolvePath: "current-project", | ||
* basePath: process.cwd(), | ||
* allowSelfReference: true | ||
* }) | ||
* ``` | ||
*/ | ||
allowSelfReference?: boolean; | ||
} | ||
/** | ||
* Options for {@link Import.resolveModule} | ||
* @public | ||
*/ | ||
export interface IImportResolveModuleOptions extends IImportResolveOptions { | ||
/** | ||
* The module identifier to resolve. For example "\@rushstack/node-core-library" or | ||
* "\@rushstack/node-core-library/lib/index.js" | ||
*/ | ||
modulePath: string; | ||
} | ||
/** | ||
* Options for {@link Import.resolvePackage} | ||
* @public | ||
*/ | ||
export interface IImportResolvePackageOptions extends IImportResolveOptions { | ||
/** | ||
* The package name to resolve. For example "\@rushstack/node-core-library" | ||
*/ | ||
packageName: string; | ||
} | ||
/** | ||
* Helpers for resolving and importing Node.js modules. | ||
@@ -6,2 +73,4 @@ * @public | ||
export declare class Import { | ||
private static __builtInModules; | ||
private static readonly _builtInModules; | ||
/** | ||
@@ -78,3 +147,50 @@ * Provides a way to improve process startup times by lazy-loading imported modules. | ||
static lazy(moduleName: string, require: (id: string) => unknown): any; | ||
/** | ||
* This resolves a module path using similar logic as the Node.js `require.resolve()` API, | ||
* but supporting extra features such as specifying the base folder. | ||
* | ||
* @remarks | ||
* A module path is a text string that might appear in a statement such as | ||
* `import { X } from "____";` or `const x = require("___");`. The implementation is based | ||
* on the popular `resolve` NPM package. | ||
* | ||
* Suppose `example` is an NPM package whose entry point is `lib/index.js`: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example/lib/index.js" | ||
* Import.resolveModule({ modulePath: 'example' }); | ||
* | ||
* // Returns "/path/to/project/node_modules/example/lib/other.js" | ||
* Import.resolveModule({ modulePath: 'example/lib/other' }); | ||
* ``` | ||
* If you need to determine the containing package folder | ||
* (`/path/to/project/node_modules/example`), use {@link Import.resolvePackage} instead. | ||
* | ||
* @returns the absolute path of the resolved module. | ||
* If {@link IImportResolveOptions.includeSystemModules} is specified | ||
* and a system module is found, then its name is returned without any file path. | ||
*/ | ||
static resolveModule(options: IImportResolveModuleOptions): string; | ||
/** | ||
* Performs module resolution to determine the folder where a package is installed. | ||
* | ||
* @remarks | ||
* Suppose `example` is an NPM package whose entry point is `lib/index.js`: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example" | ||
* Import.resolvePackage({ packageName: 'example' }); | ||
* ``` | ||
* | ||
* If you need to resolve a module path, use {@link Import.resolveModule} instead: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example/lib/index.js" | ||
* Import.resolveModule({ modulePath: 'example' }); | ||
* ``` | ||
* | ||
* @returns the absolute path of the package folder. | ||
* If {@link IImportResolveOptions.includeSystemModules} is specified | ||
* and a system module is found, then its name is returned without any file path. | ||
*/ | ||
static resolvePackage(options: IImportResolvePackageOptions): string; | ||
private static _getPackageName; | ||
} | ||
//# sourceMappingURL=Import.d.ts.map |
@@ -5,3 +5,8 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const path = require("path"); | ||
const importLazy = require("import-lazy"); | ||
const Resolve = require("resolve"); | ||
const nodeModule = require("module"); | ||
const PackageJsonLookup_1 = require("./PackageJsonLookup"); | ||
const FileSystem_1 = require("./FileSystem"); | ||
/** | ||
@@ -12,2 +17,8 @@ * Helpers for resolving and importing Node.js modules. | ||
class Import { | ||
static get _builtInModules() { | ||
if (!Import.__builtInModules) { | ||
Import.__builtInModules = new Set(nodeModule.builtinModules); | ||
} | ||
return Import.__builtInModules; | ||
} | ||
/** | ||
@@ -88,4 +99,133 @@ * Provides a way to improve process startup times by lazy-loading imported modules. | ||
} | ||
/** | ||
* This resolves a module path using similar logic as the Node.js `require.resolve()` API, | ||
* but supporting extra features such as specifying the base folder. | ||
* | ||
* @remarks | ||
* A module path is a text string that might appear in a statement such as | ||
* `import { X } from "____";` or `const x = require("___");`. The implementation is based | ||
* on the popular `resolve` NPM package. | ||
* | ||
* Suppose `example` is an NPM package whose entry point is `lib/index.js`: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example/lib/index.js" | ||
* Import.resolveModule({ modulePath: 'example' }); | ||
* | ||
* // Returns "/path/to/project/node_modules/example/lib/other.js" | ||
* Import.resolveModule({ modulePath: 'example/lib/other' }); | ||
* ``` | ||
* If you need to determine the containing package folder | ||
* (`/path/to/project/node_modules/example`), use {@link Import.resolvePackage} instead. | ||
* | ||
* @returns the absolute path of the resolved module. | ||
* If {@link IImportResolveOptions.includeSystemModules} is specified | ||
* and a system module is found, then its name is returned without any file path. | ||
*/ | ||
static resolveModule(options) { | ||
const { modulePath } = options; | ||
if (path.isAbsolute(modulePath)) { | ||
return modulePath; | ||
} | ||
const normalizedRootPath = FileSystem_1.FileSystem.getRealPath(options.baseFolderPath); | ||
if (modulePath.startsWith('.')) { | ||
// This looks like a conventional relative path | ||
return path.resolve(normalizedRootPath, modulePath); | ||
} | ||
if (options.includeSystemModules === true && Import._builtInModules.has(modulePath)) { | ||
return modulePath; | ||
} | ||
if (options.allowSelfReference === true) { | ||
const ownPackage = Import._getPackageName(options.baseFolderPath); | ||
if (ownPackage && modulePath.startsWith(ownPackage.packageName)) { | ||
const packagePath = modulePath.substr(ownPackage.packageName.length + 1); | ||
return path.resolve(ownPackage.packageRootPath, packagePath); | ||
} | ||
} | ||
try { | ||
return Resolve.sync( | ||
// Append a slash to the package name to ensure `resolve.sync` doesn't attempt to return a system package | ||
options.includeSystemModules !== true && modulePath.indexOf('/') === -1 | ||
? `${modulePath}/` | ||
: modulePath, { | ||
basedir: normalizedRootPath, | ||
preserveSymlinks: false | ||
}); | ||
} | ||
catch (e) { | ||
throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}".`); | ||
} | ||
} | ||
/** | ||
* Performs module resolution to determine the folder where a package is installed. | ||
* | ||
* @remarks | ||
* Suppose `example` is an NPM package whose entry point is `lib/index.js`: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example" | ||
* Import.resolvePackage({ packageName: 'example' }); | ||
* ``` | ||
* | ||
* If you need to resolve a module path, use {@link Import.resolveModule} instead: | ||
* ```ts | ||
* // Returns "/path/to/project/node_modules/example/lib/index.js" | ||
* Import.resolveModule({ modulePath: 'example' }); | ||
* ``` | ||
* | ||
* @returns the absolute path of the package folder. | ||
* If {@link IImportResolveOptions.includeSystemModules} is specified | ||
* and a system module is found, then its name is returned without any file path. | ||
*/ | ||
static resolvePackage(options) { | ||
const { packageName } = options; | ||
if (options.includeSystemModules && Import._builtInModules.has(packageName)) { | ||
return packageName; | ||
} | ||
const normalizedRootPath = FileSystem_1.FileSystem.getRealPath(options.baseFolderPath); | ||
if (options.allowSelfReference) { | ||
const ownPackage = Import._getPackageName(options.baseFolderPath); | ||
if (ownPackage && ownPackage.packageName === packageName) { | ||
return ownPackage.packageRootPath; | ||
} | ||
} | ||
try { | ||
const resolvedPath = Resolve.sync(packageName, { | ||
basedir: normalizedRootPath, | ||
preserveSymlinks: false, | ||
packageFilter: (pkg) => { | ||
// Hardwire "main" to point to a file that is guaranteed to exist. | ||
// This helps resolve packages such as @types/node that have no entry point. | ||
// And then we can use path.dirname() below to locate the package folder, | ||
// even if the real entry point was in an subfolder with arbitrary nesting. | ||
pkg.main = 'package.json'; | ||
return pkg; | ||
} | ||
}); | ||
const packagePath = path.dirname(resolvedPath); | ||
const packageJson = PackageJsonLookup_1.PackageJsonLookup.instance.loadPackageJson(path.join(packagePath, 'package.json')); | ||
if (packageJson.name === packageName) { | ||
return packagePath; | ||
} | ||
else { | ||
throw new Error(); | ||
} | ||
} | ||
catch (e) { | ||
throw new Error(`Cannot find package "${packageName}" from "${options.baseFolderPath}".`); | ||
} | ||
} | ||
static _getPackageName(rootPath) { | ||
const packageJsonPath = PackageJsonLookup_1.PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(rootPath); | ||
if (packageJsonPath) { | ||
const packageJson = PackageJsonLookup_1.PackageJsonLookup.instance.loadPackageJson(packageJsonPath); | ||
return { | ||
packageRootPath: path.dirname(packageJsonPath), | ||
packageName: packageJson.name | ||
}; | ||
} | ||
else { | ||
return undefined; | ||
} | ||
} | ||
} | ||
exports.Import = Import; | ||
//# sourceMappingURL=Import.js.map |
@@ -10,3 +10,3 @@ /** | ||
export { INodePackageJson, IPackageJson, IPackageJsonDependencyTable, IPackageJsonScriptTable } from './IPackageJson'; | ||
export { Import } from './Import'; | ||
export { Import, IImportResolveOptions, IImportResolveModuleOptions, IImportResolvePackageOptions } from './Import'; | ||
export { InternalError } from './InternalError'; | ||
@@ -13,0 +13,0 @@ export { JsonObject, JsonFile, JsonNull, IJsonFileSaveOptions, IJsonFileStringifyOptions } from './JsonFile'; |
@@ -83,2 +83,6 @@ import { JsonSchema, IJsonSchemaErrorInfo, IJsonSchemaValidateOptions } from './JsonSchema'; | ||
/** | ||
* @internal | ||
*/ | ||
static _formatPathForError: (path: string) => string; | ||
/** | ||
* Loads a JSON file. | ||
@@ -85,0 +89,0 @@ */ |
@@ -28,3 +28,3 @@ "use strict"; | ||
else { | ||
throw new Error(`Error reading "${jsonFilename}":` + os.EOL + ` ${error.message}`); | ||
throw new Error(`Error reading "${JsonFile._formatPathForError(jsonFilename)}":` + os.EOL + ` ${error.message}`); | ||
} | ||
@@ -46,3 +46,3 @@ } | ||
else { | ||
throw new Error(`Error reading "${jsonFilename}":` + os.EOL + ` ${error.message}`); | ||
throw new Error(`Error reading "${JsonFile._formatPathForError(jsonFilename)}":` + os.EOL + ` ${error.message}`); | ||
} | ||
@@ -310,3 +310,7 @@ } | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
JsonFile._formatPathForError = (path) => path; | ||
exports.JsonFile = JsonFile; | ||
//# sourceMappingURL=JsonFile.js.map |
@@ -23,3 +23,14 @@ import { IPackageJson, INodePackageJson } from './IPackageJson'; | ||
export declare class PackageJsonLookup { | ||
private static _loadOwnPackageJsonLookup; | ||
private static _instance; | ||
/** | ||
* A singleton instance of `PackageJsonLookup`, which is useful for short-lived processes | ||
* that can reasonably assume that the file system will not be modified after the cache | ||
* is populated. | ||
* | ||
* @remarks | ||
* For long-running processes that need to clear the cache at appropriate times, | ||
* it is recommended to create your own instance of `PackageJsonLookup` instead | ||
* of relying on this instance. | ||
*/ | ||
static readonly instance: PackageJsonLookup; | ||
private _loadExtraFields; | ||
@@ -26,0 +37,0 @@ private _packageFolderCache; |
@@ -25,2 +25,18 @@ "use strict"; | ||
/** | ||
* A singleton instance of `PackageJsonLookup`, which is useful for short-lived processes | ||
* that can reasonably assume that the file system will not be modified after the cache | ||
* is populated. | ||
* | ||
* @remarks | ||
* For long-running processes that need to clear the cache at appropriate times, | ||
* it is recommended to create your own instance of `PackageJsonLookup` instead | ||
* of relying on this instance. | ||
*/ | ||
static get instance() { | ||
if (!PackageJsonLookup._instance) { | ||
PackageJsonLookup._instance = new PackageJsonLookup({ loadExtraFields: true }); | ||
} | ||
return PackageJsonLookup._instance; | ||
} | ||
/** | ||
* A helper for loading the caller's own package.json file. | ||
@@ -49,3 +65,3 @@ * | ||
static loadOwnPackageJson(dirnameOfCaller) { | ||
const packageJson = PackageJsonLookup._loadOwnPackageJsonLookup.tryLoadPackageJsonFor(dirnameOfCaller); | ||
const packageJson = PackageJsonLookup.instance.tryLoadPackageJsonFor(dirnameOfCaller); | ||
if (packageJson === undefined) { | ||
@@ -58,4 +74,3 @@ throw new Error(`PackageJsonLookup.loadOwnPackageJson() failed to find the caller's package.json.` + | ||
} | ||
const errorPath = PackageJsonLookup._loadOwnPackageJsonLookup.tryGetPackageJsonFilePathFor(dirnameOfCaller) || | ||
'package.json'; | ||
const errorPath = PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(dirnameOfCaller) || 'package.json'; | ||
throw new Error(`PackageJsonLookup.loadOwnPackageJson() failed because the "version" field is missing in` + | ||
@@ -243,6 +258,3 @@ ` ${errorPath}`); | ||
} | ||
PackageJsonLookup._loadOwnPackageJsonLookup = new PackageJsonLookup({ | ||
loadExtraFields: true | ||
}); | ||
exports.PackageJsonLookup = PackageJsonLookup; | ||
//# sourceMappingURL=PackageJsonLookup.js.map |
{ | ||
"name": "@rushstack/node-core-library", | ||
"version": "3.29.1", | ||
"version": "3.30.0", | ||
"description": "Core libraries that every NodeJS toolchain project should use", | ||
@@ -18,4 +18,5 @@ "main": "lib/index.js", | ||
"fs-extra": "~7.0.1", | ||
"import-lazy": "~4.0.0", | ||
"jju": "~1.4.0", | ||
"import-lazy": "~4.0.0", | ||
"resolve": "~1.17.0", | ||
"semver": "~7.3.0", | ||
@@ -27,3 +28,3 @@ "timsort": "~0.3.0", | ||
"@microsoft/rush-stack-compiler-3.5": "0.8.8", | ||
"@rushstack/eslint-config": "1.2.1", | ||
"@rushstack/eslint-config": "1.3.0", | ||
"@rushstack/heft": "0.6.5", | ||
@@ -33,2 +34,3 @@ "@types/fs-extra": "7.0.0", | ||
"@types/jju": "1.4.1", | ||
"@types/resolve": "1.17.1", | ||
"@types/semver": "~7.3.1", | ||
@@ -35,0 +37,0 @@ "@types/timsort": "0.3.0", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
820131
11211
9
10
6
+ Addedresolve@~1.17.0
+ Addedpath-parse@1.0.7(transitive)
+ Addedresolve@1.17.0(transitive)