1
0
mirror of https://github.com/angular/angular-cli.git synced 2025-05-22 15:02:11 +08:00

refactor(@angular-devkit/core): remove resolve methods and options

BREAKING CHANGE: deprecated API's `ModuleNotFoundException`, `ResolveOptions`, `resolve` have been removed. Use `MODULE_NOT_FOUND` and `require.resolve` instead.

**Note**: this change only effect users using `@angular-devkit/core` public API and not application developers.
This commit is contained in:
Alan Agius 2020-09-02 15:48:33 +02:00 committed by Minko Gechev
parent 5d73e9d04e
commit 208336dee0
6 changed files with 0 additions and 388 deletions
etc/api/angular_devkit/core/node
lib
packages/angular_devkit/core/node

@ -4,13 +4,6 @@ export declare function isDirectory(filePath: string): boolean;
export declare function isFile(filePath: string): boolean;
export declare class ModuleNotFoundException extends BaseException {
readonly basePath: string;
readonly code: string;
readonly moduleName: string;
constructor(moduleName: string, basePath: string);
}
export declare class NodeJsAsyncHost implements virtualFs.Host<fs.Stats> {
get capabilities(): virtualFs.HostCapabilities;
delete(path: Path): Observable<void>;
@ -47,15 +40,3 @@ export declare class NodeModuleJobRegistry<MinimumArgumentValueT extends JsonVal
export interface ProcessOutput {
write(buffer: string | Buffer): boolean;
}
export declare function resolve(packageName: string, options: ResolveOptions): string;
export interface ResolveOptions {
basedir: string;
checkGlobal?: boolean;
checkLocal?: boolean;
extensions?: string[];
paths?: string[];
preserveSymlinks?: boolean;
resolvePackageJson?: boolean;
}

@ -190,29 +190,3 @@ if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) {
}
};
}
// Set the resolve hook to allow resolution of packages from a local dev environment.
require('@angular-devkit/core/node/resolve').setResolveHook(function(request, options) {
try {
if (request in packages) {
if (options.resolvePackageJson) {
return path.join(packages[request].root, 'package.json');
} else {
return packages[request].main;
}
} else {
const match = Object.keys(packages).find(function(pkgName) {
return request.startsWith(pkgName + '/');
});
if (match) {
return path.join(packages[match].root, request.substr(match[0].length));
} else {
return null;
}
}
} catch (_) {
return null;
}
});

@ -15,4 +15,3 @@ export * from './experimental/jobs/job-registry';
export * from './fs';
export * from './cli-logger';
export * from './host';
export { ModuleNotFoundException, ResolveOptions, resolve } from './resolve';

@ -9,7 +9,6 @@ import * as experimental from './experimental/jobs/job-registry';
import * as fs from './fs';
export * from './cli-logger';
export * from './host';
export { ModuleNotFoundException, ResolveOptions, resolve } from './resolve';
export {
experimental,

@ -1,316 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as fs from 'fs';
import * as path from 'path';
import { BaseException } from '../src';
import { isFile } from './fs';
/**
* Exception thrown when a module could not be resolved.
* @deprecated since version 8. Use `MODULE_NOT_FOUND` Node error code instead.
*/
export class ModuleNotFoundException extends BaseException {
public readonly code: string;
constructor(public readonly moduleName: string, public readonly basePath: string) {
super(`Could not find module ${JSON.stringify(moduleName)} from ${JSON.stringify(basePath)}.`);
this.code = 'MODULE_NOT_FOUND';
}
}
/**
* Returns a list of all the callers from the resolve() call.
* @returns {string[]}
* @private
*/
function _caller(): string[] {
// see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
const error = Error as {} as { prepareStackTrace: (x: {}, stack: {}) => {} };
const origPrepareStackTrace = error.prepareStackTrace;
error.prepareStackTrace = (_, stack) => stack;
const stack = (new Error()).stack as {} | undefined as { getFileName(): string }[] | undefined;
error.prepareStackTrace = origPrepareStackTrace;
return stack ? stack.map(x => x.getFileName()).filter(x => !!x) : [];
}
/**
* Get the global directory for node_modules. This is based on NPM code itself, and may be subject
* to change, but is relatively stable.
* @returns {string} The path to node_modules itself.
* @private
*/
function _getGlobalNodeModules() {
let globalPrefix;
if (process.env.PREFIX) {
globalPrefix = process.env.PREFIX;
} else if (process.platform === 'win32') {
// c:\node\node.exe --> prefix=c:\node\
globalPrefix = path.dirname(process.execPath);
} else {
// /usr/local/bin/node --> prefix=/usr/local
globalPrefix = path.dirname(path.dirname(process.execPath));
// destdir only is respected on Unix
const destdir = process.env.DESTDIR;
if (destdir) {
globalPrefix = path.join(destdir, globalPrefix);
}
}
return (process.platform !== 'win32')
? path.resolve(globalPrefix || '', 'lib', 'node_modules')
: path.resolve(globalPrefix || '', 'node_modules');
}
/** @deprecated since version 8. Use `require.resolve` instead. */
export interface ResolveOptions {
/**
* The basedir to use from which to resolve.
*/
basedir: string;
/**
* The list of extensions to resolve. By default uses Object.keys(require.extensions).
*/
extensions?: string[];
/**
* An additional list of paths to look into.
*/
paths?: string[];
/**
* Whether or not to preserve symbolic links. If false, the actual paths pointed by
* the symbolic links will be used. This defaults to true.
*/
preserveSymlinks?: boolean;
/**
* Whether to fallback to a global lookup if the basedir one failed.
*/
checkGlobal?: boolean;
/**
* Whether to fallback to using the local caller's directory if the basedir failed.
*/
checkLocal?: boolean;
/**
* Whether to only resolve and return the first package.json file found. By default,
* resolves the main field or the index of the package.
*/
resolvePackageJson?: boolean;
}
let _resolveHook: ((x: string, options: ResolveOptions) => string | null) | null = null;
/** @deprecated since version 8. Use `require.resolve` instead. */
export function setResolveHook(
hook: ((x: string, options: ResolveOptions) => string | null) | null,
) {
_resolveHook = hook;
}
/**
* Resolve a package using a logic similar to npm require.resolve, but with more options.
* @param packageName The package name to resolve.
* @param options A list of options. See documentation of those options.
* @returns {string} Path to the index to include, or if `resolvePackageJson` option was
* passed, a path to that file.
* @throws {ModuleNotFoundException} If no module with that name was found anywhere.
* @deprecated since version 8. Use `require.resolve` instead.
*/
export function resolve(packageName: string, options: ResolveOptions): string {
if (_resolveHook) {
const maybe = _resolveHook(packageName, options);
if (maybe) {
return maybe;
}
}
const readFileSync = fs.readFileSync;
const extensions: string[] = options.extensions || Object.keys(require.extensions);
const basePath = options.basedir;
options.paths = options.paths || [];
if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\/\\])/.test(packageName)) {
let res = path.resolve(basePath, packageName);
if (packageName === '..' || packageName.slice(-1) === '/') {
res += '/';
}
const m = loadAsFileSync(res) || loadAsDirectorySync(res);
if (m) {
return m;
}
} else {
const n = loadNodeModulesSync(packageName, basePath);
if (n) {
return n;
}
}
// Fallback to checking the local (callee) node modules.
if (options.checkLocal) {
const callers = _caller();
for (const caller of callers) {
const localDir = path.dirname(caller);
if (localDir !== options.basedir) {
try {
return resolve(packageName, {
...options,
checkLocal: false,
checkGlobal: false,
basedir: localDir,
});
} catch (e) {
// Just swap the basePath with the original call one.
if (!(e instanceof ModuleNotFoundException)) {
throw e;
}
}
}
}
}
// Fallback to checking the global node modules.
if (options.checkGlobal) {
const globalDir = path.dirname(_getGlobalNodeModules());
if (globalDir !== options.basedir) {
try {
return resolve(packageName, {
...options,
checkLocal: false,
checkGlobal: false,
basedir: globalDir,
});
} catch (e) {
// Just swap the basePath with the original call one.
if (!(e instanceof ModuleNotFoundException)) {
throw e;
}
}
}
}
throw new ModuleNotFoundException(packageName, basePath);
function loadAsFileSync(x: string): string | null {
if (isFile(x)) {
return x;
}
return extensions.map(ex => x + ex).find(f => isFile(f)) || null;
}
function loadAsDirectorySync(x: string): string | null {
const pkgfile = path.join(x, 'package.json');
if (isFile(pkgfile)) {
if (options.resolvePackageJson) {
return pkgfile;
}
try {
const body = readFileSync(pkgfile, 'UTF8');
const pkg = JSON.parse(body);
if (pkg['main']) {
if (pkg['main'] === '.' || pkg['main'] === './') {
pkg['main'] = 'index';
}
const m = loadAsFileSync(path.resolve(x, pkg['main']));
if (m) {
return m;
}
const n = loadAsDirectorySync(path.resolve(x, pkg['main']));
if (n) {
return n;
}
}
} catch {}
}
return loadAsFileSync(path.join(x, '/index'));
}
function loadNodeModulesSync(x: string, start: string): string | null {
const dirs = nodeModulesPaths(start, options);
for (const dir of dirs) {
const m = loadAsFileSync(path.join(dir, x));
if (m) {
return m;
}
const n = loadAsDirectorySync(path.join(dir, x));
if (n) {
return n;
}
}
return null;
}
function nodeModulesPaths(start: string, opts: ResolveOptions) {
const modules = ['node_modules'];
if (process.env.BAZEL_TARGET) {
// When running test under Bazel, node_modules have to be resolved
// differently. node_modules are installed in the `npm` workspace.
// For more info, see `yarn_install` rule in WORKSPACE file.
modules.push(path.join('npm', 'node_modules'));
}
// ensure that `start` is an absolute path at this point,
// resolving against the process' current working directory
let absoluteStart = path.resolve(start);
if (opts && opts.preserveSymlinks === false) {
try {
absoluteStart = fs.realpathSync(absoluteStart);
} catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
}
let prefix = '/';
if (/^([A-Za-z]:)/.test(absoluteStart)) {
prefix = '';
} else if (/^\\\\/.test(absoluteStart)) {
prefix = '\\\\';
}
const paths = [absoluteStart];
let parsed = path.parse(absoluteStart);
while (parsed.dir !== paths[paths.length - 1]) {
paths.push(parsed.dir);
parsed = path.parse(parsed.dir);
}
const dirs = paths.reduce((dirs: string[], aPath: string) => {
return dirs.concat(modules.map(function (moduleDir) {
return path.join(prefix, aPath, moduleDir);
}));
}, []);
if (process.env.NG_TEMP_MODULES_DIR) {
// When running from a temporary installations, node_modules have to be resolved
// differently and they should be prefered over others.
dirs.unshift(process.env.NG_TEMP_MODULES_DIR);
}
return opts && opts.paths ? dirs.concat(opts.paths) : dirs;
}
}

@ -1,25 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// tslint:disable:no-any
// tslint:disable-next-line:no-implicit-dependencies
import { resolve } from '@angular-devkit/core/node';
describe('resolve', () => {
it('works', () => {
const tslintRe = /[\\/]node_modules[\\/]tslint[\\/]lib[\\/]index.js$/;
expect(resolve('tslint', { basedir: __dirname })).toMatch(tslintRe);
expect(() => resolve('npm', { basedir: '/' })).toThrow();
if (!process.env['BAZEL_TARGET']) {
expect(() => resolve('npm', { basedir: '/', checkGlobal: true })).not.toThrow();
}
});
});