Skip to content

Commit

Permalink
fix(core): require.resolve(m/package.json) is not guarunteed to work …
Browse files Browse the repository at this point in the history
…for modern module format
  • Loading branch information
AgentEnder committed May 27, 2022
1 parent fea7e39 commit 4bcfeac
Show file tree
Hide file tree
Showing 18 changed files with 112 additions and 51 deletions.
2 changes: 2 additions & 0 deletions e2e/cli/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ describe('migrate', () => {
`./node_modules/migrate-parent-package/package.json`,
JSON.stringify({
version: '1.0.0',
name: 'migrate-parent-package',
'nx-migrations': './migrations.json',
})
);
Expand Down Expand Up @@ -212,6 +213,7 @@ describe('migrate', () => {
`./node_modules/migrate-child-package/package.json`,
JSON.stringify({
version: '1.0.0',
name: 'migrate-child-package',
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Schema } from './schema';
import { watch } from 'chokidar';
import { platform } from 'os';
import { resolve } from 'path';
import { readModulePackageJson } from 'nx/src/utils/package-json';

// platform specific command name
const pmCmd = platform() === 'win32' ? `npx.cmd` : 'npx';
Expand Down Expand Up @@ -153,7 +154,7 @@ export default async function* fileServerExecutor(
const outputPath = getBuildTargetOutputPath(options, context);
const args = getHttpServerArgs(options);

const pathToHttpServerPkgJson = require.resolve('http-server/package.json');
const pathToHttpServerPkgJson = readModulePackageJson('http-server').path;
const pathToHttpServerBin = readJsonFile(pathToHttpServerPkgJson).bin[
'http-server'
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { resolveUserExistingPrettierConfig } from '@nrwl/workspace/src/utilities
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
import { prettierVersion } from '@nrwl/workspace/src/utils/versions';
import { readFileSync } from 'fs';
import { readModulePackageJson } from 'nx/src/utils/package-json';
import { dirname, join } from 'path';
import { angularDevkitVersion, nxVersion } from '../../../utils/versions';
import { GeneratorOptions } from '../schema';
Expand Down Expand Up @@ -82,7 +83,7 @@ export function createNxJson(
}

export function decorateAngularCli(tree: Tree): void {
const nrwlWorkspacePath = require.resolve('@nrwl/workspace/package.json');
const nrwlWorkspacePath = readModulePackageJson('@nrwl/workspace').path;
const decorateCli = readFileSync(
join(
dirname(nrwlWorkspacePath),
Expand Down
5 changes: 2 additions & 3 deletions packages/angular/src/utils/mfe/mfe-webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
readTsConfig,
} from '@nrwl/workspace/src/utilities/typescript';
import { existsSync, lstatSync, readdirSync } from 'fs';
import { readModulePackageJson } from 'nx/src/utils/package-json';
import { dirname, join, normalize, relative } from 'path';
import { ParsedCommandLine } from 'typescript';
import { NormalModuleReplacementPlugin } from 'webpack';
Expand Down Expand Up @@ -143,9 +144,7 @@ function collectPackageSecondaryEntryPoints(
): void {
let pathToPackage: string;
try {
const packageJsonPath = require.resolve(`${pkgName}/package.json`, {
paths: [workspaceRoot],
});
const packageJsonPath = readModulePackageJson(pkgName).path;
pathToPackage = dirname(packageJsonPath);
} catch {
// the package.json might not resolve if the package has the "exports"
Expand Down
6 changes: 2 additions & 4 deletions packages/make-angular-cli-faster/src/utilities/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '@nrwl/devkit';
import { execSync } from 'child_process';
import { prompt } from 'enquirer';
import { readModulePackageJson } from 'nx/src/utils/package-json';
import { lt, lte, major, satisfies } from 'semver';
import { resolvePackageVersion } from './package-manager';
import { MigrationDefinition } from './types';
Expand Down Expand Up @@ -173,10 +174,7 @@ async function promptForVersion(version: string): Promise<boolean> {
}

function getInstalledAngularVersion(): string {
const packageJsonPath = require.resolve('@angular/core/package.json', {
paths: [workspaceRoot],
});
return readJsonFile(packageJsonPath).version;
return readModulePackageJson('@angular/core').packageJson.version;
}

async function normalizeVersion(version: string): Promise<string> {
Expand Down
5 changes: 2 additions & 3 deletions packages/nx/src/adapter/ngcli-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
WorkspaceJsonConfiguration,
} from '../config/workspace-json-project-json';
import { readNxJson } from '../generators/utils/project-configuration';
import { readModulePackageJson } from '../utils/package-json';

export async function scheduleTarget(
root: string,
Expand Down Expand Up @@ -891,9 +892,7 @@ function resolveMigrationsCollection(name: string): string {
} else {
let packageJsonPath;
try {
packageJsonPath = require.resolve(join(name, 'package.json'), {
paths: [process.cwd()],
});
packageJsonPath = readModulePackageJson(name, [process.cwd()]).path;
} catch (e) {
// workaround for a bug in node 12
packageJsonPath = require.resolve(
Expand Down
15 changes: 7 additions & 8 deletions packages/nx/src/command-line/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
NxMigrationsConfiguration,
PackageGroup,
PackageJson,
readModulePackageJson,
} from '../utils/package-json';
import {
createTempNpmDirectory,
Expand Down Expand Up @@ -466,10 +467,8 @@ function versions(root: string, from: Record<string, string>) {
}

if (!cache[packageName]) {
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
paths: [root],
});
cache[packageName] = readJsonFile(packageJsonPath).version;
const { packageJson } = readModulePackageJson(packageName, [root]);
cache[packageName] = packageJson.version;
}

return cache[packageName];
Expand Down Expand Up @@ -713,11 +712,11 @@ function readPackageMigrationConfig(
packageName: string,
dir: string
): PackageMigrationConfig {
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
paths: [dir],
});
const { path: packageJsonPath, packageJson: json } = readModulePackageJson(
packageName,
[dir]
);

const json = readJsonFile<PackageJson>(packageJsonPath);
const migrationConfigOrFile = json['nx-migrations'] || json['ng-update'];

if (!migrationConfigOrFile) {
Expand Down
15 changes: 7 additions & 8 deletions packages/nx/src/command-line/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getPackageManagerVersion,
} from '../utils/package-manager';
import { readJsonFile } from '../utils/fileutils';
import { PackageJson, readModulePackageJson } from '../utils/package-json';

export const packagesWeCareAbout = [
'nx',
Expand Down Expand Up @@ -77,19 +78,16 @@ export function reportHandler() {
});
}

export function readPackageJson(p: string) {
export function readPackageJson(p: string): PackageJson | null {
try {
const packageJsonPath = require.resolve(`${p}/package.json`, {
paths: [workspaceRoot],
});
return readJsonFile(packageJsonPath);
return readModulePackageJson(p).packageJson;
} catch {
return {};
return null;
}
}

export function readPackageVersion(p: string): string {
return readPackageJson(p).version || 'Not Found';
return readPackageJson(p)?.version || 'Not Found';
}

export function findInstalledCommunityPlugins(): {
Expand All @@ -116,7 +114,8 @@ export function findInstalledCommunityPlugins(): {
return arr;
}
try {
const depPackageJson = readPackageJson(nextDep);
const depPackageJson: Partial<PackageJson> =
readPackageJson(nextDep) || {};
if (
[
'ng-update',
Expand Down
12 changes: 6 additions & 6 deletions packages/nx/src/utils/nx-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Workspaces } from '../config/workspaces';

import { workspaceRoot } from '../utils/app-root';
import { readJsonFile } from '../utils/fileutils';
import { PackageJson } from './package-json';
import { PackageJson, readModulePackageJson } from './package-json';
import { registerTsProject } from './register';
import {
ProjectConfiguration,
Expand Down Expand Up @@ -117,11 +117,12 @@ export function readPluginPackageJson(
path: string;
json: PackageJson;
} {
let packageJsonPath: string;
try {
packageJsonPath = require.resolve(`${pluginName}/package.json`, {
paths,
});
const result = readModulePackageJson(pluginName, paths);
return {
json: result.packageJson,
path: result.path,
};
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
const localPluginPath = resolveLocalNxPlugin(pluginName);
Expand All @@ -138,7 +139,6 @@ export function readPluginPackageJson(
}
throw e;
}
return { json: readJsonFile(packageJsonPath), path: packageJsonPath };
}

/**
Expand Down
20 changes: 20 additions & 0 deletions packages/nx/src/utils/package-json.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { join } from 'path';
import { workspaceRoot } from './app-root';
import { readJsonFile } from './fileutils';
import {
buildTargetFromScript,
PackageJson,
PackageJsonTargetConfiguration,
readModulePackageJson,
} from './package-json';

describe('buildTargetFromScript', () => {
Expand Down Expand Up @@ -38,3 +43,18 @@ describe('buildTargetFromScript', () => {
expect(target.executor).toEqual('nx:run-script');
});
});

const rootPackageJson: PackageJson = readJsonFile(
join(workspaceRoot, 'package.json')
);

const dependencies = [
...Object.keys(rootPackageJson.dependencies),
...Object.keys(rootPackageJson.devDependencies),
];

describe('readModulePackageJson', () => {
it.each(dependencies)(`should be able to find %s`, (s) => {
expect(() => readModulePackageJson(s)).not.toThrow();
});
});
43 changes: 43 additions & 0 deletions packages/nx/src/utils/package-json.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { existsSync } from 'fs';
import { dirname, join } from 'path';
import { TargetConfiguration } from '../config/workspace-json-project-json';
import { workspaceRoot } from './app-root';
import { readJsonFile } from './fileutils';

export type PackageJsonTargetConfiguration = Omit<
TargetConfiguration,
Expand Down Expand Up @@ -69,3 +73,42 @@ export function buildTargetFromScript(
},
};
}

export function readModulePackageJson(
moduleSpecifier: string,
requirePaths = [workspaceRoot]
): {
packageJson: PackageJson;
path: string;
} {
let packageJsonPath: string;
try {
packageJsonPath = require.resolve(`${moduleSpecifier}/package.json`, {
paths: requirePaths,
});
} catch (e) {
const entryPoint = require.resolve(moduleSpecifier, {
paths: requirePaths,
});
let moduleRootPath = dirname(entryPoint);
packageJsonPath = join(moduleRootPath, 'package.json');

while (!existsSync(packageJsonPath)) {
moduleRootPath = dirname(moduleRootPath);
packageJsonPath = join(moduleRootPath, 'package.json');
}
}

const packageJson = readJsonFile(packageJsonPath);

if (packageJson.name !== moduleSpecifier) {
throw new Error(
`Found module ${packageJson.name} while trying to locate ${moduleSpecifier}/package.json`
);
}

return {
packageJson,
path: packageJsonPath,
};
}
8 changes: 3 additions & 5 deletions packages/nx/src/utils/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { dirname, join } from 'path';
import { dirSync } from 'tmp';
import { promisify } from 'util';
import { readJsonFile, writeJsonFile } from './fileutils';
import { PackageJson } from './package-json';
import { PackageJson, readModulePackageJson } from './package-json';
import { gte, lt } from 'semver';

const execAsync = promisify(exec);
Expand Down Expand Up @@ -198,11 +198,9 @@ export async function resolvePackageVersionUsingInstallation(
const pmc = getPackageManagerCommand();
await execAsync(`${pmc.add} ${packageName}@${version}`, { cwd: dir });

const packageJsonPath = require.resolve(`${packageName}/package.json`, {
paths: [dir],
});
const { packageJson } = readModulePackageJson(packageName, [dir]);

return readJsonFile<PackageJson>(packageJsonPath).version;
return packageJson.version;
} finally {
await cleanup();
}
Expand Down
3 changes: 2 additions & 1 deletion packages/nx/src/utils/plugins/installed-plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { CommunityPlugin, CorePlugin, PluginCapabilities } from './models';
import { getPluginCapabilities } from './plugin-capabilities';
import { hasElements } from './shared';
import { readJsonFile } from '../fileutils';
import { readModulePackageJson } from '../package-json';

export function getInstalledPluginsFromPackageJson(
workspaceRoot: string,
Expand All @@ -25,7 +26,7 @@ export function getInstalledPluginsFromPackageJson(
try {
// Check for `package.json` existence instead of requiring the module itself
// because malformed entries like `main`, may throw false exceptions.
require.resolve(`${name}/package.json`, { paths: [workspaceRoot] });
readModulePackageJson(name, [workspaceRoot]);
return true;
} catch {
return false;
Expand Down
7 changes: 3 additions & 4 deletions packages/nx/src/utils/plugins/plugin-capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { PluginCapabilities } from './models';
import { hasElements } from './shared';
import { readJsonFile } from '../fileutils';
import { getPackageManagerCommand } from '../package-manager';
import { readModulePackageJson } from '../package-json';

function tryGetCollection<T extends object>(
packageJsonPath: string,
Expand All @@ -29,10 +30,8 @@ export function getPluginCapabilities(
pluginName: string
): PluginCapabilities | null {
try {
const packageJsonPath = require.resolve(`${pluginName}/package.json`, {
paths: [workspaceRoot],
});
const packageJson = readJsonFile(packageJsonPath);
const { packageJson, path: packageJsonPath } =
readModulePackageJson(pluginName);
return {
name: pluginName,
generators:
Expand Down
3 changes: 2 additions & 1 deletion packages/web/src/executors/file-server/file-server.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Schema } from './schema';
import { watch } from 'chokidar';
import { platform } from 'os';
import { resolve } from 'path';
import { readModulePackageJson } from 'nx/src/utils/package-json';

// platform specific command name
const pmCmd = platform() === 'win32' ? `npx.cmd` : 'npx';
Expand Down Expand Up @@ -153,7 +154,7 @@ export default async function* fileServerExecutor(
const outputPath = getBuildTargetOutputPath(options, context);
const args = getHttpServerArgs(options);

const pathToHttpServerPkgJson = require.resolve('http-server/package.json');
const pathToHttpServerPkgJson = readModulePackageJson('http-server').path;
const pathToHttpServerBin = readJsonFile(pathToHttpServerPkgJson).bin[
'http-server'
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { output } from '../output';
import type { CommunityPlugin, CorePlugin, PluginCapabilities } from './models';
import { getPluginCapabilities } from './plugin-capabilities';
import { hasElements } from './shared';
import { readModulePackageJson } from 'nx/src/utils/package-json';

export function getInstalledPluginsFromPackageJson(
workspaceRoot: string,
Expand All @@ -25,7 +26,7 @@ export function getInstalledPluginsFromPackageJson(
try {
// Check for `package.json` existence instead of requiring the module itself
// because malformed entries like `main`, may throw false exceptions.
require.resolve(`${name}/package.json`, { paths: [workspaceRoot] });
readModulePackageJson(name);
return true;
} catch {
return false;
Expand Down

0 comments on commit 4bcfeac

Please sign in to comment.