-
Notifications
You must be signed in to change notification settings - Fork 683
Expand file tree
/
Copy pathPnpmWorkspaceFile.ts
More file actions
121 lines (101 loc) · 3.93 KB
/
PnpmWorkspaceFile.ts
File metadata and controls
121 lines (101 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as path from 'node:path';
import { FileSystem, Sort, Import, Path } from '@rushstack/node-core-library';
import { BaseWorkspaceFile } from '../base/BaseWorkspaceFile';
import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon';
const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require);
const globEscape: (unescaped: string) => string = require('glob-escape'); // No @types/glob-escape package exists
/**
* This interface represents the raw pnpm-workspace.YAML file
* Example:
* {
* "packages": [
* "../../apps/project1"
* ],
* "catalogs": {
* "default": {
* "react": "^18.0.0"
* }
* }
* }
*/
interface IPnpmWorkspaceYaml {
/** The list of local package directories */
packages: string[];
/** Named catalog definitions for centralized version management */
catalogs?: Record<string, Record<string, string>>;
}
export class PnpmWorkspaceFile extends BaseWorkspaceFile {
/**
* The filename of the workspace file.
*/
public readonly workspaceFilename: string;
private _workspacePackages: Set<string>;
private _catalogs: Record<string, Record<string, string>> | undefined;
/**
* The PNPM workspace file is used to specify the location of workspaces relative to the root
* of your PNPM install.
*/
public constructor(workspaceYamlFilename: string) {
super();
this.workspaceFilename = workspaceYamlFilename;
// Ignore any existing file since this file is generated and we need to handle deleting packages
// If we need to support manual customization, that should be an additional parameter for "base file"
this._workspacePackages = new Set<string>();
this._catalogs = undefined;
}
/**
* Loads and returns the catalogs section from an existing pnpm-workspace.yaml file.
* This method handles both the singular 'catalog' field (for the default catalog) and
* the plural 'catalogs' field (for named catalogs), merging them into a single object.
*
* @param workspaceYamlFilename - The path to the pnpm-workspace.yaml file
* @returns The catalogs object, or undefined if the file doesn't exist or has no catalogs
*/
public static async loadCatalogsFromFileAsync(
workspaceYamlFilename: string
): Promise<Record<string, Record<string, string>> | undefined> {
let content: string;
try {
content = await FileSystem.readFileAsync(workspaceYamlFilename);
} catch (error) {
if (FileSystem.isNotExistError(error)) {
return undefined;
} else {
throw error;
}
}
const parsed: IPnpmWorkspaceYaml | undefined = yamlModule.load(content) as IPnpmWorkspaceYaml | undefined;
return parsed?.catalogs;
}
/**
* Sets the catalog definitions for the workspace.
* @param catalogs - A map of catalog name to package versions
*/
public setCatalogs(catalogs: Record<string, Record<string, string>> | undefined): void {
this._catalogs = catalogs;
}
/** @override */
public addPackage(packagePath: string): void {
// Ensure the path is relative to the pnpm-workspace.yaml file
if (path.isAbsolute(packagePath)) {
packagePath = path.relative(path.dirname(this.workspaceFilename), packagePath);
}
// Glob can't handle Windows paths
const globPath: string = Path.convertToSlashes(packagePath);
this._workspacePackages.add(globEscape(globPath));
}
/** @override */
protected serialize(): string {
// Ensure stable sort order when serializing
Sort.sortSet(this._workspacePackages);
const workspaceYaml: IPnpmWorkspaceYaml = {
packages: Array.from(this._workspacePackages)
};
if (this._catalogs && Object.keys(this._catalogs).length > 0) {
workspaceYaml.catalogs = this._catalogs;
}
return yamlModule.dump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT);
}
}