Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -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
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,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
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
9 changes: 5 additions & 4 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 { 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
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 @@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
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 './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
Original file line number Diff line number Diff line change
@@ -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
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 { 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(
Copy link
Collaborator

Choose a reason for hiding this comment

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

This happens?

Copy link
Member Author

Choose a reason for hiding this comment

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

This shouldn't happen. This would occur if for some reason require.resolve(packageName) pointed to a folder that didn't have a moduleName. Its a safety guard, but thats it.

`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