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 (#10497)

* fix(core): require.resolve(m/package.json) is not guarunteed to work for modern module format

* chore(repo): update usage of new readModulePackageJson function
  • Loading branch information
AgentEnder committed Jun 3, 2022
1 parent 66f2e77 commit 7f7bc1a
Show file tree
Hide file tree
Showing 18 changed files with 122 additions and 68 deletions.
2 changes: 2 additions & 0 deletions e2e/cli/src/cli.test.ts
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 @@ -211,6 +212,7 @@ describe('migrate', () => {
updateFile(
`./node_modules/migrate-child-package/package.json`,
JSON.stringify({
name: 'migrate-child-package',
version: '1.0.0',
})
);
Expand Down
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,10 +154,9 @@ export default async function* fileServerExecutor(
const outputPath = getBuildTargetOutputPath(options, context);
const args = getHttpServerArgs(options);

const pathToHttpServerPkgJson = require.resolve('http-server/package.json');
const pathToHttpServerBin = readJsonFile(pathToHttpServerPkgJson).bin[
'http-server'
];
const { path: pathToHttpServerPkgJson, packageJson } =
readModulePackageJson('http-server');
const pathToHttpServerBin = packageJson.bin['http-server'];
const pathToHttpServer = resolve(
pathToHttpServerPkgJson.replace('package.json', ''),
pathToHttpServerBin
Expand Down
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
9 changes: 5 additions & 4 deletions packages/angular/src/utils/mfe/mfe-webpack.ts
Expand Up @@ -9,6 +9,7 @@ import {
readTsConfig,
} from '@nrwl/workspace/src/utilities/typescript';
import { existsSync, lstatSync, readdirSync } from 'fs';
import { PackageJson, 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 @@ -153,10 +154,9 @@ function collectPackageSecondaryEntryPoints(
): void {
let pathToPackage: string;
let packageJsonPath: string;
let packageJson: PackageJson;
try {
packageJsonPath = require.resolve(`${pkgName}/package.json`, {
paths: [workspaceRoot],
});
({ path: packageJsonPath, packageJson } = readModulePackageJson(pkgName));
pathToPackage = dirname(packageJsonPath);
} catch {
// the package.json might not resolve if the package has the "exports"
Expand All @@ -168,9 +168,10 @@ function collectPackageSecondaryEntryPoints(
// might not exist if it's nested in another package, just return here
return;
}
packageJson = readJsonFile(packageJsonPath);
}

const { exports } = readJsonFile(packageJsonPath);
const { exports } = packageJson;
const subDirs = getNonNodeModulesSubDirs(pathToPackage);
recursivelyCollectSecondaryEntryPointsFromDirectory(
pkgName,
Expand Down
6 changes: 2 additions & 4 deletions packages/make-angular-cli-faster/src/utilities/migration.ts
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 @@ -177,10 +178,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
17 changes: 4 additions & 13 deletions packages/nx/src/adapter/ngcli-adapter.ts
Expand Up @@ -39,6 +39,7 @@ import {
ProjectsConfigurations,
} from '../config/workspace-json-project-json';
import { readNxJson } from '../generators/utils/project-configuration';
import { PackageJson, readModulePackageJson } from '../utils/package-json';

export async function scheduleTarget(
root: string,
Expand Down Expand Up @@ -896,20 +897,10 @@ function resolveMigrationsCollection(name: string): string {
if (extname(name)) {
collectionPath = require.resolve(name);
} else {
let packageJsonPath;
try {
packageJsonPath = require.resolve(join(name, 'package.json'), {
paths: [process.cwd()],
});
} catch (e) {
// workaround for a bug in node 12
packageJsonPath = require.resolve(
join(process.cwd(), name, 'package.json')
);
}
const { path: packageJsonPath, packageJson } = readModulePackageJson(name, [
process.cwd(),
]);

// eslint-disable-next-line @typescript-eslint/no-var-requires
const packageJson = require(packageJsonPath);
let pkgJsonSchematics =
packageJson['nx-migrations'] ?? packageJson['ng-update'];
if (!pkgJsonSchematics) {
Expand Down
15 changes: 7 additions & 8 deletions packages/nx/src/command-line/migrate.ts
Expand Up @@ -21,6 +21,7 @@ import {
PackageGroup,
PackageJson,
readNxMigrateConfig,
readModulePackageJson,
} from '../utils/package-json';
import {
createTempNpmDirectory,
Expand Down Expand Up @@ -467,10 +468,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 @@ -687,11 +686,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
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
Expand Up @@ -6,7 +6,7 @@ import { Workspaces } from '../config/workspaces';

import { workspaceRoot } from './workspace-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
@@ -1,6 +1,11 @@
import { join } from 'path';
import { workspaceRoot } from './workspace-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();
});
});
44 changes: 44 additions & 0 deletions packages/nx/src/utils/package-json.ts
@@ -1,4 +1,8 @@
import { existsSync } from 'fs';
import { dirname, join } from 'path';
import { TargetConfiguration } from '../config/workspace-json-project-json';
import { readJsonFile } from './fileutils';
import { workspaceRoot } from './workspace-root';

export type PackageJsonTargetConfiguration = Omit<
TargetConfiguration,
Expand Down Expand Up @@ -36,6 +40,7 @@ export interface PackageJson {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
bin?: Record<string, string>;
workspaces?:
| string[]
| {
Expand Down Expand Up @@ -96,3 +101,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 {
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
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
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

1 comment on commit 7f7bc1a

@vercel
Copy link

@vercel vercel bot commented on 7f7bc1a Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev
nx-dev-nrwl.vercel.app

Please sign in to comment.