mb-run 0.0.1-dev-20260504-b6b8a3a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.js ADDED
@@ -0,0 +1,233 @@
1
+ import path from 'node:path';
2
+ import process from 'node:process';
3
+ import { clearEnd, getElapsed, green, log, moveUp, savePos, shouldUseAnsi } from './ansi.js';
4
+ import { runBin, runWorkspaceBuild } from './build.js';
5
+ import { cleanOnly, fileExists, resetClean } from './clean.js';
6
+ import { runEsbuild } from './esbuild.js';
7
+ import { printUsage, printVersionUsage } from './help.js';
8
+ import { isPlugin } from './helpers.js';
9
+ import { systemInfo } from './info.js';
10
+ import { initLogger } from './logger.js';
11
+ import { runPack } from './pack.js';
12
+ import { runPublish } from './publish.js';
13
+ import { sortAll } from './sort.js';
14
+ import { ExitError, runCommand } from './spawn.js';
15
+ import { runUpdate } from './update.js';
16
+ import { parseVersionTag, updateRootVersion, updateWorkspaceDependencyVersions } from './version.js';
17
+ const isWindows = process.platform === 'win32';
18
+ export async function main() {
19
+ const repoRoot = process.cwd();
20
+ const rawArgs = process.argv.slice(2);
21
+ if (!(await fileExists(path.join(repoRoot, 'package.json')))) {
22
+ printUsage();
23
+ throw new ExitError(1, `No package.json found in current working directory: ${repoRoot}`);
24
+ }
25
+ if (rawArgs.length === 0) {
26
+ printUsage();
27
+ throw new ExitError(1, 'No arguments provided');
28
+ }
29
+ if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
30
+ printUsage();
31
+ return;
32
+ }
33
+ const known = new Set([
34
+ '--build',
35
+ '--production',
36
+ '--install',
37
+ '--clean',
38
+ '--watch',
39
+ '--test',
40
+ '--lint',
41
+ '--lint-fix',
42
+ '--format',
43
+ '--format-check',
44
+ '--dry-run',
45
+ '--sort',
46
+ '--update',
47
+ '--reset',
48
+ '--deep-clean',
49
+ '--version',
50
+ '--pack',
51
+ '--publish',
52
+ '--esbuild',
53
+ '--verbose',
54
+ '--info',
55
+ '--help',
56
+ '-h',
57
+ ]);
58
+ const dryRunMode = rawArgs.includes('--dry-run');
59
+ const verboseCommands = rawArgs.includes('--verbose');
60
+ initLogger({ dryRun: dryRunMode, verbose: verboseCommands, rootDir: repoRoot });
61
+ const restorePos = (rows = 1) => (rows > 0 && shouldUseAnsi() && !dryRunMode && !verboseCommands ? moveUp(rows) : '');
62
+ const buildOpts = { rootDir: repoRoot, isWindows, dryRun: dryRunMode };
63
+ const versionIndex = rawArgs.indexOf('--version');
64
+ const candidateVersionArg = versionIndex >= 0 ? rawArgs[versionIndex + 1] : undefined;
65
+ const rawVersionTag = typeof candidateVersionArg === 'string' && !candidateVersionArg.startsWith('-') ? candidateVersionArg : undefined;
66
+ const unknownFlags = rawArgs.filter((a) => a.startsWith('-') && !known.has(a));
67
+ if (unknownFlags.length > 0) {
68
+ printUsage();
69
+ throw new ExitError(1, `Unknown argument(s): ${unknownFlags.join(' ')}`);
70
+ }
71
+ const unknownPositionals = rawArgs.filter((a, i) => !a.startsWith('-') && !(versionIndex >= 0 && rawVersionTag !== undefined && i === versionIndex + 1));
72
+ if (unknownPositionals.length > 0) {
73
+ printUsage();
74
+ throw new ExitError(1, `Unknown argument(s): ${unknownPositionals.join(' ')}`);
75
+ }
76
+ let versionTag = null;
77
+ if (versionIndex >= 0 && rawVersionTag !== undefined) {
78
+ try {
79
+ versionTag = parseVersionTag(rawVersionTag);
80
+ }
81
+ catch {
82
+ printVersionUsage();
83
+ throw new ExitError(1, 'Invalid --version usage');
84
+ }
85
+ }
86
+ const want = {
87
+ install: rawArgs.includes('--install'),
88
+ clean: rawArgs.includes('--clean'),
89
+ build: rawArgs.includes('--build'),
90
+ production: rawArgs.includes('--production'),
91
+ version: rawArgs.includes('--version'),
92
+ watch: rawArgs.includes('--watch'),
93
+ test: rawArgs.includes('--test'),
94
+ lint: rawArgs.includes('--lint'),
95
+ lintFix: rawArgs.includes('--lint-fix'),
96
+ format: rawArgs.includes('--format'),
97
+ formatCheck: rawArgs.includes('--format-check'),
98
+ sort: rawArgs.includes('--sort'),
99
+ update: rawArgs.includes('--update'),
100
+ reset: rawArgs.includes('--reset'),
101
+ deepClean: rawArgs.includes('--deep-clean'),
102
+ pack: rawArgs.includes('--pack'),
103
+ publish: rawArgs.includes('--publish'),
104
+ esbuild: rawArgs.includes('--esbuild'),
105
+ info: rawArgs.includes('--info'),
106
+ };
107
+ if (want.info) {
108
+ systemInfo();
109
+ }
110
+ if (want.update) {
111
+ want.install = false;
112
+ }
113
+ if (want.reset) {
114
+ want.install = false;
115
+ want.deepClean = false;
116
+ want.clean = false;
117
+ want.build = false;
118
+ }
119
+ if (want.install) {
120
+ log(`${savePos()}⏳ Installing...`);
121
+ await runCommand('npm', ['install', '--no-fund', '--no-audit', '--silent'], { dryRun: dryRunMode });
122
+ if (await isPlugin(repoRoot))
123
+ await runCommand('npm', ['link', 'matterbridge', '--no-fund', '--no-audit', '--silent'], { cwd: repoRoot, dryRun: dryRunMode });
124
+ log(`${restorePos()}${green('✅')} Install complete in ${getElapsed()}.${clearEnd()}`);
125
+ }
126
+ if (want.update) {
127
+ log(`${savePos()}⏳ Updating dependencies...`);
128
+ await runUpdate(buildOpts);
129
+ await runCommand('npm', ['install', '--no-fund', '--no-audit', '--silent'], { dryRun: dryRunMode });
130
+ if (await isPlugin(repoRoot))
131
+ await runCommand('npm', ['link', 'matterbridge', '--no-fund', '--no-audit', '--silent'], { cwd: repoRoot, dryRun: dryRunMode });
132
+ log(`${restorePos()}${green('✅')} Update complete in ${getElapsed()}.${clearEnd()}`);
133
+ }
134
+ if (want.deepClean) {
135
+ log(`${savePos()}⏳ Deep cleaning...`);
136
+ await resetClean({ rootDir: repoRoot, dryRun: dryRunMode });
137
+ log(`${restorePos()}${green('✅')} Deep clean complete in ${getElapsed()}.${clearEnd()}`);
138
+ }
139
+ if (want.reset) {
140
+ log(`${savePos()}⏳ Cleaning...`);
141
+ await resetClean({ rootDir: repoRoot, dryRun: dryRunMode });
142
+ log(`${restorePos()}⏳ Installing...`);
143
+ await runCommand('npm', ['install', '--no-fund', '--no-audit', '--silent'], { dryRun: dryRunMode });
144
+ if (await isPlugin(repoRoot)) {
145
+ log(`${restorePos()}⏳ Linking...`);
146
+ await runCommand('npm', ['link', 'matterbridge', '--no-fund', '--no-audit', '--silent'], { cwd: repoRoot, dryRun: dryRunMode });
147
+ }
148
+ log(`${restorePos()}⏳ Building...`);
149
+ await runWorkspaceBuild({ ...buildOpts, mode: want.production ? 'production' : 'build', watch: false });
150
+ log(`${restorePos()}${green('✅')} Reset complete in ${getElapsed()}.${clearEnd()}`);
151
+ }
152
+ if (want.version) {
153
+ log(`${savePos()}⏳ Versioning...`);
154
+ const versionOpts = { rootDir: repoRoot, dryRun: dryRunMode };
155
+ const nextVersion = await updateRootVersion(versionTag, versionOpts);
156
+ await updateWorkspaceDependencyVersions(nextVersion, versionOpts);
157
+ await runCommand('npm', ['install', '--package-lock-only', '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-offline', '--silent'], {
158
+ cwd: repoRoot,
159
+ dryRun: dryRunMode,
160
+ });
161
+ log(`${restorePos()}${green('✅')} Versioning to ${nextVersion} complete in ${getElapsed()}.${clearEnd()}`);
162
+ }
163
+ if (want.clean) {
164
+ log(`${savePos()}⏳ Cleaning...`);
165
+ await cleanOnly({ rootDir: repoRoot, dryRun: dryRunMode });
166
+ log(`${restorePos()}${green('✅')} Clean complete in ${getElapsed()}.${clearEnd()}`);
167
+ }
168
+ if (want.build && want.production) {
169
+ log(`${savePos()}⏳ Building for production...`);
170
+ await runWorkspaceBuild({ ...buildOpts, mode: 'production', watch: false });
171
+ log(`${restorePos()}${green('✅')} Build for production complete in ${getElapsed()}.${clearEnd()}`);
172
+ }
173
+ else if (want.build) {
174
+ log(`${savePos()}⏳ Building...`);
175
+ await runWorkspaceBuild({ ...buildOpts, mode: 'build', watch: false });
176
+ log(`${restorePos()}${green('✅')} Build complete in ${getElapsed()}.${clearEnd()}`);
177
+ }
178
+ if (want.test) {
179
+ log(`${savePos()}⏳ Testing...`);
180
+ await runBin('jest', ['--maxWorkers=100%'], { ...buildOpts, mode: 'build', watch: false }, {
181
+ env: {
182
+ NODE_OPTIONS: '--experimental-vm-modules --no-warnings',
183
+ },
184
+ });
185
+ log(`${restorePos()}${green('✅')} Tests complete in ${getElapsed()}.${clearEnd()}`);
186
+ }
187
+ if (want.format) {
188
+ log(`${savePos()}⏳ Formatting...`);
189
+ await runBin('prettier', ['--log-level=silent', '--cache', '--cache-location', '.cache/.prettiercache', '--write', '.'], { ...buildOpts, mode: 'build', watch: false });
190
+ log(`${restorePos()}${green('✅')} Format complete in ${getElapsed()}.${clearEnd()}`);
191
+ }
192
+ else if (want.formatCheck) {
193
+ log(`${savePos()}⏳ Checking format...`);
194
+ await runBin('prettier', ['--log-level=silent', '--cache', '--cache-location', '.cache/.prettiercache', '--check', '.'], { ...buildOpts, mode: 'build', watch: false });
195
+ log(`${restorePos()}${green('✅')} Format check complete in ${getElapsed()}.${clearEnd()}`);
196
+ }
197
+ if (want.lintFix) {
198
+ log(`${savePos()}⏳ Linting with fix...`);
199
+ await runBin('eslint', ['--cache', '--cache-location', '.cache/.eslintcache', '--fix', '--max-warnings=0', '.'], { ...buildOpts, mode: 'build', watch: false });
200
+ log(`${restorePos()}${green('✅')} Lint fix complete in ${getElapsed()}.${clearEnd()}`);
201
+ }
202
+ else if (want.lint) {
203
+ log(`${savePos()}⏳ Linting...`);
204
+ await runBin('eslint', ['--cache', '--cache-location', '.cache/.eslintcache', '--max-warnings=0', '.'], { ...buildOpts, mode: 'build', watch: false });
205
+ log(`${restorePos()}${green('✅')} Lint complete in ${getElapsed()}.${clearEnd()}`);
206
+ }
207
+ if (want.sort) {
208
+ log(`${savePos()}⏳ Sorting package.json files...`);
209
+ if (!dryRunMode) {
210
+ await sortAll(repoRoot);
211
+ }
212
+ await runBin('prettier', ['--log-level=silent', '--cache', '--cache-location', '.cache/.prettiercache', '--write', '.'], { ...buildOpts, mode: 'build', watch: false });
213
+ log(`${restorePos()}${green('✅')} Sort complete in ${getElapsed()}.${clearEnd()}`);
214
+ }
215
+ if (want.pack) {
216
+ log(`${savePos()}⏳ Packing...`);
217
+ await runPack(buildOpts);
218
+ log(`${restorePos(0)}${green('✅')} Pack complete in ${getElapsed()}.${clearEnd()}`);
219
+ }
220
+ if (want.publish) {
221
+ log(`${savePos()}⏳ Publishing...`);
222
+ await runPublish({ rootDir: repoRoot, isWindows, dryRun: dryRunMode });
223
+ log(`${restorePos(0)}${green('✅')} Publish complete in ${getElapsed()}.${clearEnd()}`);
224
+ }
225
+ if (want.esbuild) {
226
+ log(`${savePos()}⏳ Bundling with esbuild...`);
227
+ await runEsbuild(buildOpts);
228
+ log(`${restorePos()}${green('✅')} Esbuild complete in ${getElapsed()}.${clearEnd()}`);
229
+ }
230
+ if (want.watch) {
231
+ await runWorkspaceBuild({ ...buildOpts, mode: 'build', watch: true });
232
+ }
233
+ }
package/dist/pack.js ADDED
@@ -0,0 +1,84 @@
1
+ import { readFile, rm, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { runBin, runWorkspaceBuild } from './build.js';
4
+ import { backup, resolveWorkspacePackageJsonPaths, restore } from './cache.js';
5
+ import { cleanOnly, emptyDir } from './clean.js';
6
+ import { runEsbuild } from './esbuild.js';
7
+ import { isPlugin } from './helpers.js';
8
+ import { logDelete, logWriteFile } from './logger.js';
9
+ import { runCommand } from './spawn.js';
10
+ async function removeFile(filePath, opts) {
11
+ logDelete(filePath);
12
+ if (opts.dryRun)
13
+ return;
14
+ await rm(filePath, { force: true });
15
+ }
16
+ export async function runPack(opts) {
17
+ const packageJsonPath = path.join(opts.rootDir, 'package.json');
18
+ if (!opts.dryRun) {
19
+ await backup(opts.rootDir);
20
+ }
21
+ try {
22
+ await cleanOnly({ rootDir: opts.rootDir, dryRun: opts.dryRun });
23
+ await runWorkspaceBuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun, mode: 'production', watch: false });
24
+ await runEsbuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun });
25
+ logWriteFile(packageJsonPath);
26
+ if (!opts.dryRun) {
27
+ const raw = await readFile(packageJsonPath, 'utf8');
28
+ const pkg = JSON.parse(raw);
29
+ delete pkg['devDependencies'];
30
+ delete pkg['scripts'];
31
+ await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
32
+ }
33
+ const workspacePkgPaths = await resolveWorkspacePackageJsonPaths(opts.rootDir);
34
+ if (!opts.dryRun && workspacePkgPaths.length > 0) {
35
+ const raw = await readFile(packageJsonPath, 'utf8');
36
+ const pkg = JSON.parse(raw);
37
+ const rootDeps = (pkg['dependencies'] ?? {});
38
+ for (const wPkgPath of workspacePkgPaths) {
39
+ const wRaw = await readFile(wPkgPath, 'utf8');
40
+ const wPkg = JSON.parse(wRaw);
41
+ for (const [dep, ver] of Object.entries(wPkg.dependencies ?? {})) {
42
+ if (!(dep in rootDeps))
43
+ rootDeps[dep] = ver;
44
+ }
45
+ }
46
+ for (const wPkgPath of workspacePkgPaths) {
47
+ const wNameRaw = await readFile(wPkgPath, 'utf8');
48
+ const wNamePkg = JSON.parse(wNameRaw);
49
+ if (wNamePkg.name) {
50
+ delete rootDeps[wNamePkg.name];
51
+ }
52
+ }
53
+ pkg['dependencies'] = rootDeps;
54
+ delete pkg['workspaces'];
55
+ logWriteFile(packageJsonPath);
56
+ await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
57
+ }
58
+ await emptyDir(path.join(opts.rootDir, 'node_modules'), opts);
59
+ await removeFile(path.join(opts.rootDir, 'package-lock.json'), opts);
60
+ await removeFile(path.join(opts.rootDir, 'npm-shrinkwrap.json'), opts);
61
+ await runCommand('npm', ['install', '--omit=dev', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
62
+ await runCommand('npm', ['shrinkwrap', '--omit=dev', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
63
+ await runCommand('npm', ['pack'], { cwd: opts.rootDir, dryRun: opts.dryRun });
64
+ }
65
+ finally {
66
+ logWriteFile(packageJsonPath);
67
+ if (!opts.dryRun) {
68
+ await restore(opts.rootDir);
69
+ }
70
+ }
71
+ await removeFile(path.join(opts.rootDir, 'package-lock.json'), opts);
72
+ await removeFile(path.join(opts.rootDir, 'npm-shrinkwrap.json'), opts);
73
+ await runCommand('npm', ['install', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
74
+ if (await isPlugin(opts.rootDir))
75
+ await runCommand('npm', ['link', 'matterbridge', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
76
+ await runBin('prettier', ['--log-level=silent', '--cache', '--cache-location', '.cache/.prettiercache', '--write', '.'], {
77
+ rootDir: opts.rootDir,
78
+ isWindows: opts.isWindows,
79
+ dryRun: opts.dryRun,
80
+ mode: 'build',
81
+ watch: false,
82
+ });
83
+ await runWorkspaceBuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun, mode: 'build', watch: false });
84
+ }
@@ -0,0 +1,78 @@
1
+ import { readFile, rm, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { runBin, runWorkspaceBuild } from './build.js';
4
+ import { backup, resolveWorkspacePackageJsonPaths, restore } from './cache.js';
5
+ import { cleanOnly, emptyDir } from './clean.js';
6
+ import { isPlugin } from './helpers.js';
7
+ import { logDelete, logWriteFile } from './logger.js';
8
+ import { runCommand } from './spawn.js';
9
+ async function removeFile(filePath, opts) {
10
+ logDelete(filePath);
11
+ if (opts.dryRun)
12
+ return;
13
+ await rm(filePath, { force: true });
14
+ }
15
+ async function stripPackageJson(pkgPath, opts) {
16
+ logWriteFile(pkgPath);
17
+ if (opts.dryRun)
18
+ return;
19
+ const raw = await readFile(pkgPath, 'utf8');
20
+ const pkg = JSON.parse(raw);
21
+ delete pkg['devDependencies'];
22
+ delete pkg['scripts'];
23
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
24
+ }
25
+ export async function runPublish(opts) {
26
+ const rootPkgPath = path.join(opts.rootDir, 'package.json');
27
+ const workspacePkgPaths = await resolveWorkspacePackageJsonPaths(opts.rootDir);
28
+ if (!opts.dryRun) {
29
+ await backup(opts.rootDir);
30
+ }
31
+ try {
32
+ await stripPackageJson(rootPkgPath, opts);
33
+ for (const wPkgPath of workspacePkgPaths) {
34
+ await stripPackageJson(wPkgPath, opts);
35
+ }
36
+ await cleanOnly({ rootDir: opts.rootDir, dryRun: opts.dryRun });
37
+ await runWorkspaceBuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun, mode: 'production', watch: false });
38
+ await emptyDir(path.join(opts.rootDir, 'node_modules'), opts);
39
+ await removeFile(path.join(opts.rootDir, 'package-lock.json'), opts);
40
+ await removeFile(path.join(opts.rootDir, 'npm-shrinkwrap.json'), opts);
41
+ for (const wPkgPath of workspacePkgPaths) {
42
+ const wDir = path.dirname(wPkgPath);
43
+ await emptyDir(path.join(wDir, 'node_modules'), opts);
44
+ await removeFile(path.join(wDir, 'package-lock.json'), opts);
45
+ await removeFile(path.join(wDir, 'npm-shrinkwrap.json'), opts);
46
+ }
47
+ await runCommand('npm', ['install', '--omit=dev', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
48
+ await runCommand('npm', ['shrinkwrap', '--omit=dev', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
49
+ for (const wPkgPath of workspacePkgPaths) {
50
+ const wDir = path.dirname(wPkgPath);
51
+ await runCommand('npm', ['publish', '--dry-run'], { cwd: wDir, dryRun: opts.dryRun });
52
+ }
53
+ await runCommand('npm', ['publish', '--dry-run'], { cwd: opts.rootDir, dryRun: opts.dryRun });
54
+ }
55
+ finally {
56
+ if (!opts.dryRun) {
57
+ await restore(opts.rootDir);
58
+ }
59
+ await removeFile(path.join(opts.rootDir, 'package-lock.json'), opts);
60
+ await removeFile(path.join(opts.rootDir, 'npm-shrinkwrap.json'), opts);
61
+ for (const wPkgPath of workspacePkgPaths) {
62
+ const wDir = path.dirname(wPkgPath);
63
+ await removeFile(path.join(wDir, 'package-lock.json'), opts);
64
+ await removeFile(path.join(wDir, 'npm-shrinkwrap.json'), opts);
65
+ }
66
+ await runCommand('npm', ['install', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
67
+ if (await isPlugin(opts.rootDir))
68
+ await runCommand('npm', ['link', 'matterbridge', '--no-fund', '--no-audit', '--silent'], { cwd: opts.rootDir, dryRun: opts.dryRun });
69
+ await runWorkspaceBuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun, mode: 'build', watch: false });
70
+ await runBin('prettier', ['--log-level=silent', '--cache', '--cache-location', '.cache/.prettiercache', '--write', '.'], {
71
+ rootDir: opts.rootDir,
72
+ isWindows: opts.isWindows,
73
+ dryRun: opts.dryRun,
74
+ mode: 'build',
75
+ watch: false,
76
+ });
77
+ }
78
+ }
package/dist/sort.js ADDED
@@ -0,0 +1,49 @@
1
+ import { backup, packageJsonMap, restore } from './cache.js';
2
+ export const PACKAGE_JSON_KEY_ORDER = [
3
+ 'name',
4
+ 'version',
5
+ 'description',
6
+ 'author',
7
+ 'license',
8
+ 'homepage',
9
+ 'repository',
10
+ 'bugs',
11
+ 'funding',
12
+ 'keywords',
13
+ 'type',
14
+ 'main',
15
+ 'types',
16
+ 'exports',
17
+ 'workspaces',
18
+ 'engines',
19
+ 'bin',
20
+ 'files',
21
+ 'scripts',
22
+ 'dependencies',
23
+ 'devDependencies',
24
+ 'peerDependencies',
25
+ 'peerDependenciesMeta',
26
+ 'optionalDependencies',
27
+ 'bundleDependencies',
28
+ ];
29
+ export function sortPackageJson(pkg) {
30
+ const sorted = {};
31
+ for (const key of PACKAGE_JSON_KEY_ORDER) {
32
+ if (Object.prototype.hasOwnProperty.call(pkg, key)) {
33
+ sorted[key] = pkg[key];
34
+ }
35
+ }
36
+ for (const key of Object.keys(pkg)) {
37
+ if (!Object.prototype.hasOwnProperty.call(sorted, key)) {
38
+ sorted[key] = pkg[key];
39
+ }
40
+ }
41
+ return sorted;
42
+ }
43
+ export async function sortAll(rootDir) {
44
+ await backup(rootDir);
45
+ for (const [name, pkg] of packageJsonMap) {
46
+ packageJsonMap.set(name, sortPackageJson(pkg));
47
+ }
48
+ await restore(rootDir);
49
+ }
package/dist/spawn.js ADDED
@@ -0,0 +1,27 @@
1
+ import process from 'node:process';
2
+ import spawn from 'cross-spawn';
3
+ import { logCommand } from './logger.js';
4
+ export class ExitError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.code = code;
9
+ }
10
+ }
11
+ export async function runCommand(command, args, options = {}) {
12
+ logCommand(options.label ?? command, options.displayArgs ?? args, options.cwd);
13
+ if (options.dryRun)
14
+ return;
15
+ const child = spawn(command, args, {
16
+ stdio: options.silent ? ['inherit', 'ignore', 'ignore'] : 'inherit',
17
+ env: { ...process.env, ...options.env },
18
+ cwd: options.cwd,
19
+ });
20
+ const exitCode = await new Promise((resolve, reject) => {
21
+ child.on('error', reject);
22
+ child.on('exit', (code) => resolve(code ?? 1));
23
+ });
24
+ if (exitCode !== 0) {
25
+ throw new ExitError(exitCode, `${options.label ?? command} failed with exit code ${exitCode}`);
26
+ }
27
+ }
package/dist/update.js ADDED
@@ -0,0 +1,14 @@
1
+ import { run as ncuRun } from 'npm-check-updates';
2
+ import { parsePackageJson } from './helpers.js';
3
+ export async function runUpdate(opts) {
4
+ if (opts.dryRun)
5
+ return;
6
+ const rootPkg = (await parsePackageJson(opts.rootDir));
7
+ const isWorkspace = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces.length > 0 : false;
8
+ if (isWorkspace) {
9
+ await ncuRun({ upgrade: true, workspaces: true, root: true, silent: true, cwd: opts.rootDir });
10
+ }
11
+ else {
12
+ await ncuRun({ upgrade: true, silent: true, cwd: opts.rootDir });
13
+ }
14
+ }
@@ -0,0 +1,159 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { readdir, readFile, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { fileExists } from './clean.js';
5
+ import { parsePackageJson } from './helpers.js';
6
+ import { logCommand, logWriteFile } from './logger.js';
7
+ import { ExitError, runCommand } from './spawn.js';
8
+ export function parseVersionTag(tag) {
9
+ const normalized = String(tag ?? '')
10
+ .trim()
11
+ .toLowerCase();
12
+ if (normalized === 'dev' || normalized === 'edge' || normalized === 'git' || normalized === 'local' || normalized === 'next' || normalized === 'alpha' || normalized === 'beta') {
13
+ return normalized;
14
+ }
15
+ throw new ExitError(1, 'Missing or invalid --version tag (expected dev, edge, git, local, next, alpha, or beta).');
16
+ }
17
+ function formatYyyymmdd(date) {
18
+ const year = String(date.getFullYear());
19
+ const month = String(date.getMonth() + 1).padStart(2, '0');
20
+ const day = String(date.getDate()).padStart(2, '0');
21
+ return `${year}${month}${day}`;
22
+ }
23
+ function shortSha7FromGit(cwd) {
24
+ logCommand('git', ['rev-parse', '--short=7', 'HEAD'], cwd);
25
+ const out = execFileSync('git', ['rev-parse', '--short=7', 'HEAD'], {
26
+ cwd,
27
+ encoding: 'utf8',
28
+ stdio: ['ignore', 'pipe', 'ignore'],
29
+ });
30
+ const sha = String(out).trim();
31
+ if (!/^[0-9a-f]{7}$/i.test(sha)) {
32
+ throw new Error(`Unexpected git short SHA output: ${JSON.stringify(sha)}`);
33
+ }
34
+ return sha.toLowerCase();
35
+ }
36
+ function getShortSha7(cwd) {
37
+ try {
38
+ return shortSha7FromGit(cwd);
39
+ }
40
+ catch (err) {
41
+ throw new ExitError(1, `Unable to determine git short SHA. (${err instanceof Error ? err.message : String(err)})`);
42
+ }
43
+ }
44
+ function extractBaseSemver(version) {
45
+ const trimmed = String(version ?? '').trim();
46
+ const match = /^([0-9]+\.[0-9]+\.[0-9]+)(?:-.+)?$/.exec(trimmed);
47
+ if (!match) {
48
+ throw new ExitError(1, `package.json version must start with plain x.y.z (got: ${JSON.stringify(trimmed)})`);
49
+ }
50
+ return match[1];
51
+ }
52
+ async function getWorkspacePackageJsonPaths(opts) {
53
+ const rootPkg = await parsePackageJson(opts.rootDir);
54
+ const workspacesConfig = rootPkg?.workspaces;
55
+ let patterns = [];
56
+ if (Array.isArray(workspacesConfig)) {
57
+ patterns = workspacesConfig.filter((p) => typeof p === 'string');
58
+ }
59
+ else if (workspacesConfig && typeof workspacesConfig === 'object' && Array.isArray(workspacesConfig.packages)) {
60
+ patterns = workspacesConfig.packages.filter((p) => typeof p === 'string');
61
+ }
62
+ if (patterns.length === 0) {
63
+ return [];
64
+ }
65
+ const hasGlobChars = (s) => /[*?\[]/.test(s);
66
+ const packageJsonPaths = [];
67
+ for (const pattern of patterns) {
68
+ const trimmed = pattern.trim();
69
+ if (!trimmed)
70
+ continue;
71
+ if (!hasGlobChars(trimmed)) {
72
+ const candidate = path.join(opts.rootDir, trimmed, 'package.json');
73
+ if (await fileExists(candidate))
74
+ packageJsonPaths.push(candidate);
75
+ continue;
76
+ }
77
+ if (trimmed.endsWith('/*') && trimmed.indexOf('*') === trimmed.length - 1 && !/[?\[]/.test(trimmed)) {
78
+ const baseRel = trimmed.slice(0, -2);
79
+ const baseAbs = path.join(opts.rootDir, baseRel);
80
+ let entries;
81
+ try {
82
+ entries = await readdir(baseAbs, { withFileTypes: true });
83
+ }
84
+ catch {
85
+ continue;
86
+ }
87
+ for (const entry of entries) {
88
+ if (!entry.isDirectory())
89
+ continue;
90
+ const candidate = path.join(baseAbs, entry.name, 'package.json');
91
+ if (await fileExists(candidate))
92
+ packageJsonPaths.push(candidate);
93
+ }
94
+ continue;
95
+ }
96
+ throw new ExitError(1, `Unsupported workspaces pattern in root package.json: ${JSON.stringify(trimmed)} (use explicit paths or a simple 'dir/*' glob)`);
97
+ }
98
+ return Array.from(new Set(packageJsonPaths));
99
+ }
100
+ export async function updateRootVersion(tag, opts) {
101
+ const pkg = await parsePackageJson(opts.rootDir);
102
+ const currentVersion = pkg.version;
103
+ const baseVersion = extractBaseSemver(currentVersion);
104
+ const nextVersion = tag ? `${baseVersion}-${tag}-${formatYyyymmdd(new Date())}-${getShortSha7(opts.rootDir)}` : baseVersion;
105
+ const workspacesConfig = pkg?.workspaces;
106
+ const hasWorkspaces = Array.isArray(workspacesConfig) || (workspacesConfig && typeof workspacesConfig === 'object' && Array.isArray(workspacesConfig.packages));
107
+ const args = hasWorkspaces
108
+ ? ['version', nextVersion, '--workspaces', '--include-workspace-root', '--no-workspaces-update', '--no-git-tag-version', '--ignore-scripts', '--allow-same-version']
109
+ : ['version', nextVersion, '--no-git-tag-version', '--ignore-scripts', '--allow-same-version'];
110
+ await runCommand('npm', args, { cwd: opts.rootDir, dryRun: opts.dryRun, silent: true });
111
+ return nextVersion;
112
+ }
113
+ export async function updateWorkspaceDependencyVersions(targetVersion, opts) {
114
+ const packageJsonPaths = await getWorkspacePackageJsonPaths(opts);
115
+ if (packageJsonPaths.length === 0)
116
+ return;
117
+ const workspacePkgs = await Promise.all(packageJsonPaths.map(async (p) => {
118
+ const raw = await readFile(p, 'utf8');
119
+ const pkg = JSON.parse(raw);
120
+ const name = typeof pkg?.name === 'string' ? pkg.name : null;
121
+ if (!name) {
122
+ throw new ExitError(1, `Workspace package.json missing name: ${p}`);
123
+ }
124
+ return { path: p, name };
125
+ }));
126
+ const workspaceNames = new Set(workspacePkgs.map((p) => p.name));
127
+ const sections = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
128
+ const rootPackageJsonPath = path.join(opts.rootDir, 'package.json');
129
+ const rootParsed = (await parsePackageJson(opts.rootDir));
130
+ const rootName = typeof rootParsed.name === 'string' ? rootParsed.name : '';
131
+ const pkgsToUpdate = [...workspacePkgs, { path: rootPackageJsonPath, name: rootName }];
132
+ await Promise.all(pkgsToUpdate.map(async ({ path: packageJsonPath, name: selfName }) => {
133
+ const raw = await readFile(packageJsonPath, 'utf8');
134
+ const pkg = JSON.parse(raw);
135
+ let changed = false;
136
+ for (const section of sections) {
137
+ const deps = pkg?.[section];
138
+ if (!deps || typeof deps !== 'object')
139
+ continue;
140
+ for (const depName of Object.keys(deps)) {
141
+ if (!workspaceNames.has(depName))
142
+ continue;
143
+ if (depName === selfName)
144
+ continue;
145
+ const nextRange = targetVersion;
146
+ if (deps[depName] !== nextRange) {
147
+ deps[depName] = nextRange;
148
+ changed = true;
149
+ }
150
+ }
151
+ }
152
+ if (changed) {
153
+ logWriteFile(packageJsonPath);
154
+ if (opts.dryRun)
155
+ return;
156
+ await writeFile(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
157
+ }
158
+ }));
159
+ }