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

feat(core): rename lock file pruning function to createLockFile #13770

Merged
merged 1 commit into from Dec 12, 2022
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
67 changes: 46 additions & 21 deletions docs/generated/devkit/index.md
Expand Up @@ -143,6 +143,8 @@ It only uses language primitives and immutable objects
- [applySharedFunction](../../devkit/index#applysharedfunction)
- [convertNxExecutor](../../devkit/index#convertnxexecutor)
- [convertNxGenerator](../../devkit/index#convertnxgenerator)
- [createLockFile](../../devkit/index#createlockfile)
- [createPackageJson](../../devkit/index#createpackagejson)
- [createProjectGraphAsync](../../devkit/index#createprojectgraphasync)
- [defaultTasksRunner](../../devkit/index#defaulttasksrunner)
- [detectPackageManager](../../devkit/index#detectpackagemanager)
Expand Down Expand Up @@ -171,7 +173,6 @@ It only uses language primitives and immutable objects
- [offsetFromRoot](../../devkit/index#offsetfromroot)
- [parseJson](../../devkit/index#parsejson)
- [parseTargetString](../../devkit/index#parsetargetstring)
- [pruneLockFile](../../devkit/index#prunelockfile)
- [readAllWorkspaceConfiguration](../../devkit/index#readallworkspaceconfiguration)
- [readCachedProjectGraph](../../devkit/index#readcachedprojectgraph)
- [readJson](../../devkit/index#readjson)
Expand Down Expand Up @@ -1064,6 +1065,50 @@ Convert an Nx Generator into an Angular Devkit Schematic.

---

### createLockFile

▸ **createLockFile**(`packageJson`, `packageManager?`): `string`

Create lock file based on the root level lock file and (pruned) package.json

#### Parameters

| Name | Type |
| :--------------- | :---------------------------------------------------- |
| `packageJson` | `PackageJson` |
| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) |

#### Returns

`string`

---

### createPackageJson

▸ **createPackageJson**(`projectName`, `graph`, `options?`): `PackageJson`

Creates a package.json in the output directory for support to install dependencies within containers.

If a package.json exists in the project, it will reuse that.
If isProduction flag is set, it wil remove devDependencies and optional peerDependencies

#### Parameters

| Name | Type |
| :---------------------- | :-------------------------------------------------------- |
| `projectName` | `string` |
| `graph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\> |
| `options` | `Object` |
| `options.isProduction?` | `boolean` |
| `options.root?` | `string` |

#### Returns

`PackageJson`

---

### createProjectGraphAsync

▸ **createProjectGraphAsync**(`opts?`): `Promise`<[`ProjectGraph`](../../devkit/index#projectgraph)\>
Expand Down Expand Up @@ -1725,26 +1770,6 @@ parseTargetString('proj:test:production'); // returns { project: "proj", target:

---

### pruneLockFile

▸ **pruneLockFile**(`projectName`, `isProduction?`, `packageManager?`): `Promise`<`string`\>

Prune lock file based on the given project's dependencies and overrides in local package.json

#### Parameters

| Name | Type | Default value | Description |
| :--------------- | :---------------------------------------------------- | :------------ | :----------------------------------------------------------------- |
| `projectName` | `string` | `undefined` | Project to prune against |
| `isProduction` | `boolean` | `true` | Whether to include optional and dev dependencies |
| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) | `undefined` | Package manager to use (automatically detected based on lock file) |

#### Returns

`Promise`<`string`\>

---

### readAllWorkspaceConfiguration

▸ **readAllWorkspaceConfiguration**(): [`ProjectsConfigurations`](../../devkit/index#projectsconfigurations) & [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/packages/devkit.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/devkit/index.ts
Expand Up @@ -366,4 +366,5 @@ export { cacheDir } from 'nx/src/utils/cache-directory';
/**
* @category Package Manager
*/
export { pruneLockFile } from 'nx/src/lock-file/lock-file';
export { createLockFile } from 'nx/src/lock-file/lock-file';
export { createPackageJson } from 'nx/src/utils/create-package-json';
24 changes: 9 additions & 15 deletions packages/next/src/executors/build/lib/create-package-json.ts
@@ -1,11 +1,11 @@
import type { ExecutorContext } from '@nrwl/devkit';
import { writeJsonFile } from '@nrwl/devkit';
import { writeFileSync } from 'fs';
import {
getLockFileName,
pruneLockFileFromPackageJson,
} from 'nx/src/lock-file/lock-file';
import { createPackageJson as generatePackageJson } from 'nx/src/utils/create-package-json';
writeJsonFile,
createPackageJson as generatePackageJson,
createLockFile,
} from '@nrwl/devkit';
import { writeFileSync } from 'fs';
import { getLockFileName } from 'nx/src/lock-file/lock-file';
import type { NextBuildBuilderOptions } from '../../../utils/types';

export async function createPackageJson(
Expand All @@ -17,14 +17,11 @@ export async function createPackageJson(
context.projectGraph,
{
root: context.root,
// By default we remove devDependencies since this is a production build.
isProduction: options.includeDevDependenciesInPackageJson,
}
);

// By default we remove devDependencies since this is a production build.
if (!options.includeDevDependenciesInPackageJson) {
delete packageJson.devDependencies;
}

if (!packageJson.scripts) {
packageJson.scripts = {};
}
Expand All @@ -39,10 +36,7 @@ export async function createPackageJson(
writeJsonFile(`${options.outputPath}/package.json`, packageJson);

// generate lock file
const prunedLockFile = pruneLockFileFromPackageJson(
packageJson,
!options.includeDevDependenciesInPackageJson
);
const prunedLockFile = createLockFile(packageJson);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't need the option here anymore because it is just based off the package.json that's sent in right?

const lockFileName = getLockFileName();
writeFileSync(`${options.outputPath}/${lockFileName}`, prunedLockFile, {
encoding: 'utf-8',
Expand Down
36 changes: 3 additions & 33 deletions packages/nx/src/lock-file/lock-file.ts
Expand Up @@ -28,8 +28,6 @@ import {
ProjectGraphExternalNode,
} from '../config/project-graph';
import { existsSync } from 'fs';
import { createProjectGraphAsync } from '../project-graph/project-graph';
import { createPackageJson } from '../utils/create-package-json';
import { normalizePackageJson } from './utils/pruning';
import { PackageJson } from '../utils/package-json';

Expand Down Expand Up @@ -182,47 +180,19 @@ export function getLockFileName(
}

/**
* Prune lock file based on the given project's dependencies and overrides in local package.json
*
* @param projectName Project to prune against
* @param isProduction Whether to include optional and dev dependencies
* @param packageManager Package manager to use (automatically detected based on lock file)
* @returns
*/
export async function pruneLockFile(
projectName: string,
isProduction = true,
packageManager: PackageManager = detectPackageManager(workspaceRoot)
): Promise<string> {
const projectGraph = await createProjectGraphAsync();

if (!projectGraph.nodes[projectName]) {
throw Error(`Project "${projectName}" was not found.`);
}

const packageJson = createPackageJson(projectName, projectGraph, {});
return pruneLockFileFromPackageJson(
packageJson,
isProduction,
packageManager
);
}

/**
* Prune lock file based on the package.json
* Create lock file based on the root level lock file and (pruned) package.json
*
* @param packageJson
* @param isProduction
* @param packageManager
* @returns
*/
export function pruneLockFileFromPackageJson(
export function createLockFile(
packageJson: PackageJson,
isProduction = true,
packageManager: PackageManager = detectPackageManager(workspaceRoot)
): string {
const lockFileData = parseLockFile(packageManager);
const normalizedPackageJson = normalizePackageJson(packageJson, isProduction);
const normalizedPackageJson = normalizePackageJson(packageJson);

if (packageManager === 'yarn') {
const prunedData = pruneYarnLockFile(lockFileData, normalizedPackageJson);
Expand Down
61 changes: 19 additions & 42 deletions packages/nx/src/lock-file/utils/pruning.ts
Expand Up @@ -13,55 +13,32 @@ export type PackageJsonDeps = Pick<

/**
* Strip off non-pruning related fields from package.json
* Remove devDependencies if production target
* Remove optional peerDependencies if production target
*
* @param packageJson
* @param isProduction
* @param projectName
* @returns
*/
export function normalizePackageJson(
packageJson: PackageJson,
isProduction: boolean
packageJson: PackageJson
): PackageJsonDeps {
const normalized: PackageJsonDeps = {
name: packageJson.name,
version: packageJson.version || '0.0.0',
...(packageJson.license && { license: packageJson.license }),
};
if (packageJson.dependencies) {
normalized.dependencies = packageJson.dependencies;
}
if (packageJson.devDependencies && !isProduction) {
normalized.devDependencies = packageJson.devDependencies;
}
if (packageJson.peerDependencies) {
if (isProduction) {
const normalizedPeedDeps = filterOptionalPeerDependencies(packageJson);
if (normalizedPeedDeps) {
normalized.peerDependencies = normalizedPeedDeps;
}
} else {
normalized.peerDependencies = packageJson.peerDependencies;
if (packageJson.peerDependenciesMeta) {
normalized.peerDependenciesMeta = packageJson.peerDependenciesMeta;
}
}
}

return normalized;
}
const {
name,
version,
license,
dependencies,
devDependencies,
peerDependencies,
peerDependenciesMeta,
} = packageJson;

function filterOptionalPeerDependencies(
packageJson: PackageJson
): Record<string, string> {
let peerDependencies;
Object.keys(packageJson.peerDependencies).forEach((key) => {
if (!packageJson.peerDependenciesMeta?.[key]?.optional) {
peerDependencies = peerDependencies || {};
peerDependencies[key] = packageJson.peerDependencies[key];
}
});
return peerDependencies;
return {
name,
version,
license,
dependencies,
devDependencies,
peerDependencies,
peerDependenciesMeta,
};
}
35 changes: 32 additions & 3 deletions packages/nx/src/utils/create-package-json.ts
Expand Up @@ -9,13 +9,15 @@ import { workspaceRoot } from './workspace-root';
* Creates a package.json in the output directory for support to install dependencies within containers.
*
* If a package.json exists in the project, it will reuse that.
* If isProduction flag is set, it wil remove devDependencies and optional peerDependencies
*/
export function createPackageJson(
projectName: string,
graph: ProjectGraph,
options: {
root?: string;
}
isProduction?: boolean;
} = {}
): PackageJson {
const npmDeps = findAllNpmDeps(projectName, graph);
// default package.json if one does not exist
Expand All @@ -40,8 +42,11 @@ export function createPackageJson(
!packageJson.dependencies?.[packageName] &&
!packageJson.peerDependencies?.[packageName]
) {
packageJson.devDependencies = packageJson.devDependencies || {};
packageJson.devDependencies[packageName] = version;
// don't store dev dependencies for production
if (!options.isProduction) {
packageJson.devDependencies = packageJson.devDependencies || {};
packageJson.devDependencies[packageName] = version;
}
} else {
if (!packageJson.peerDependencies?.[packageName]) {
packageJson.dependencies = packageJson.dependencies || {};
Expand All @@ -54,12 +59,23 @@ export function createPackageJson(
packageJson.dependencies[packageName] = version;
}
});
if (options.isProduction && packageJson.peerDependencies) {
const mandatoryPeedDeps = filterOptionalPeerDependencies(packageJson);
if (mandatoryPeedDeps) {
packageJson.peerDependencies = mandatoryPeedDeps;
} else {
delete packageJson.peerDependencies;
}
}

packageJson.devDependencies &&= sortObjectByKeys(packageJson.devDependencies);
packageJson.dependencies &&= sortObjectByKeys(packageJson.dependencies);
packageJson.peerDependencies &&= sortObjectByKeys(
packageJson.peerDependencies
);
packageJson.peerDependenciesMeta &&= sortObjectByKeys(
packageJson.peerDependenciesMeta
);

return packageJson;
}
Expand Down Expand Up @@ -143,3 +159,16 @@ function recursivelyCollectPeerDependencies(
return list;
}
}

function filterOptionalPeerDependencies(
packageJson: PackageJson
): Record<string, string> {
let peerDependencies;
Object.keys(packageJson.peerDependencies).forEach((key) => {
if (!packageJson.peerDependenciesMeta?.[key]?.optional) {
peerDependencies = peerDependencies || {};
peerDependencies[key] = packageJson.peerDependencies[key];
}
});
return peerDependencies;
}