npm-ws-tools
Version:
Command line tools for working with npm workspaces. Includes version bumping and dependencies version update
170 lines • 5.11 kB
JavaScript
import fs from 'fs';
import { globSync } from 'glob';
import yaml from "js-yaml";
import path from 'path';
import { Version } from './Version.js';
function resolveWorkspacePaths(paths, baseDir) {
if (!paths) {
throw new Error('Not a root package');
}
if (!Array.isArray(paths)) {
throw new Error('workspaces must be an array');
}
return globSync(paths, { cwd: baseDir, absolute: true, }).filter(p => {
return fs.statSync(p).isDirectory();
});
}
function listPnpmProjects(file) {
try {
const doc = yaml.load(fs.readFileSync(file, 'utf8'));
return (doc.packages || []);
}
catch (e) {
console.log("Failed to load pnpm workspace file", e);
process.exit(1);
}
}
export function findClosestPackage(dir) {
let current = dir;
while (current) {
const file = `${current}/package.json`;
if (file && fs.existsSync(file)) {
return file;
}
else {
const parent = path.dirname(current);
if (parent === current) {
break;
}
current = parent;
}
}
return null;
}
export class Package {
content;
tab;
nlAtEof;
parent;
file;
// whether or not is a workspace root. undefined if not yet known
isRoot;
isPnpmRoot;
// if is workspace root contains the list of projects
projects;
constructor(file, content, tab = 4, nlAtEof = false) {
this.content = content;
this.tab = tab;
this.nlAtEof = nlAtEof;
this.file = path.resolve(file);
// check if there is a pnpm workspace file
const wdir = this.dir;
let _isRoot = false;
let _isPnpmRoot = false;
if (this.content.workspaces && Array.isArray(this.content.workspaces)) {
_isRoot = true;
const projectPaths = resolveWorkspacePaths(this.content.workspaces, wdir);
this.projects = this._resolveWorkspaces(projectPaths);
}
else {
const wsPath = path.join(wdir, "pnpm-workspace.yaml");
if (fs.existsSync(wsPath)) {
_isRoot = true;
_isPnpmRoot = true;
const projectPaths = resolveWorkspacePaths(listPnpmProjects(wsPath), wdir);
this.projects = this._resolveWorkspaces(projectPaths);
}
}
this.isPnpmRoot = _isPnpmRoot;
this.isRoot = _isRoot;
}
get dir() {
return path.dirname(this.file);
}
get name() {
return this.content.name;
}
set name(value) {
this.content.name = value;
}
get version() {
return this.content.version;
}
set version(value) {
if (value === 'major') {
const v = new Version(this.content.version);
v.incrMajor();
this.content.version = v.toString();
}
else if (value === 'minor') {
const v = new Version(this.content.version);
v.incrMinor();
this.content.version = v.toString();
}
else if (value === 'patch') {
const v = new Version(this.content.version);
v.incrPatch();
this.content.version = v.toString();
}
else {
this.content.version = value;
}
}
excludeProjects(prefix) {
if (!prefix)
return this;
prefix = path.resolve(this.dir, prefix);
if (!this.projects)
return this;
this.projects = this.projects.filter(p => !p.file.startsWith(prefix));
return this;
}
_resolveWorkspaces(projectPaths) {
return projectPaths.map((projectPath) => {
const file = path.resolve(projectPath, 'package.json');
const pkg = Package.load(file);
pkg.parent = this;
return pkg;
});
}
loadParent() {
if (!this.parent) {
this.parent = Package.findClosest(path.dirname(this.dir));
}
return this.parent;
}
loadRoot() {
if (this.isRoot) {
return this;
}
const pkg = this.loadParent();
if (!pkg)
throw new Error('No root package.json found');
return pkg.loadRoot();
}
save() {
fs.writeFileSync(this.file, JSON.stringify(this.content, null, this.tab) + (this.nlAtEof ? '\n' : ''));
}
static load(file) {
let tab = 4;
let content = fs.readFileSync(file, 'utf8');
const nlAtEof = /\s*\n\s*$/.test(content);
content = content.trim();
const m = /^(\s+)/m.exec(content);
if (m) {
tab = m[1].length;
}
return new Package(file, JSON.parse(content), tab, nlAtEof);
}
static findClosest(cwd) {
if (!cwd) {
cwd = process.cwd();
}
const file = findClosestPackage(cwd);
if (!file) {
throw new Error('No package.json found');
}
return Package.load(file);
}
}
//# sourceMappingURL=Package.js.map