@smoothbricks/cli 0.3.2 → 0.3.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../../src/monorepo/lockfile.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,8BAA8B;IAC7C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAWD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,8BAAmC,GAAG,MAAM,CA0C1G;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BhE"}
1
+ {"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../../src/monorepo/lockfile.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,8BAA8B;IAC7C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAWD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,8BAAmC,GAAG,MAAM,CAkD1G;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiChE"}
@@ -1,3 +1,4 @@
1
+ import { execSync } from 'node:child_process';
1
2
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
3
  import { join } from 'node:path';
3
4
  import { escapeRegex, getWorkspacePackages } from '../lib/workspace.js';
@@ -20,6 +21,12 @@ export function syncBunLockfileVersions(root, options = {}) {
20
21
  let lockfile = readFileSync(lockfilePath, 'utf8');
21
22
  let updated = 0;
22
23
  for (const pkg of packages) {
24
+ // If the package.json version is a prerelease (e.g. 0.2.2-next.0) it may
25
+ // never have been published. Use the latest stable git tag version so
26
+ // that `bun pm pack` writes an installable dependency range for consumers.
27
+ const targetVersion = pkg.version.includes('-')
28
+ ? (latestStableTagVersion(root, pkg.projectName) ?? pkg.version)
29
+ : pkg.version;
23
30
  const relativePath = pkg.path.replaceAll('\\', '/');
24
31
  const escaped = escapeRegex(relativePath);
25
32
  const pattern = new RegExp(`("${escaped}":\\s*\\{[^}]*"version":\\s*")([^"]+)(")`);
@@ -31,15 +38,16 @@ export function syncBunLockfileVersions(root, options = {}) {
31
38
  continue;
32
39
  }
33
40
  const lockVersion = match[2];
34
- if (lockVersion === pkg.version) {
41
+ if (lockVersion === targetVersion) {
35
42
  if (log) {
36
- console.log(`ok: ${relativePath} = ${pkg.version}`);
43
+ console.log(`ok: ${relativePath} = ${targetVersion}`);
37
44
  }
38
45
  continue;
39
46
  }
40
- lockfile = lockfile.replace(pattern, `$1${pkg.version}$3`);
47
+ lockfile = lockfile.replace(pattern, `$1${targetVersion}$3`);
41
48
  if (log) {
42
- console.log(`fix: ${relativePath}: ${lockVersion} -> ${pkg.version}`);
49
+ const suffix = targetVersion !== pkg.version ? ` (latest stable tag; package.json has ${pkg.version})` : '';
50
+ console.log(`fix: ${relativePath}: ${lockVersion} -> ${targetVersion}${suffix}`);
43
51
  }
44
52
  updated++;
45
53
  }
@@ -61,6 +69,9 @@ export function validateBunLockfileVersions(root) {
61
69
  const lockfile = readFileSync(lockfilePath, 'utf8');
62
70
  let failures = 0;
63
71
  for (const pkg of packages) {
72
+ const targetVersion = pkg.version.includes('-')
73
+ ? (latestStableTagVersion(root, pkg.projectName) ?? pkg.version)
74
+ : pkg.version;
64
75
  const relativePath = pkg.path.replaceAll('\\', '/');
65
76
  const escaped = escapeRegex(relativePath);
66
77
  const pattern = new RegExp(`("${escaped}":\\s*\\{[^}]*"version":\\s*")([^"]+)(")`);
@@ -71,8 +82,8 @@ export function validateBunLockfileVersions(root) {
71
82
  continue;
72
83
  }
73
84
  const lockVersion = match[2];
74
- if (lockVersion !== pkg.version) {
75
- console.error(`${relativePath}: bun.lock workspace version must be ${pkg.version}, got ${lockVersion}`);
85
+ if (lockVersion !== targetVersion) {
86
+ console.error(`${relativePath}: bun.lock workspace version must be ${targetVersion}, got ${lockVersion}`);
76
87
  failures++;
77
88
  }
78
89
  }
@@ -81,3 +92,26 @@ export function validateBunLockfileVersions(root) {
81
92
  }
82
93
  return failures;
83
94
  }
95
+ function latestStableTagVersion(root, projectName) {
96
+ try {
97
+ const output = execSync(`git tag --list '${projectName}@*' --sort=-v:refname`, {
98
+ cwd: root,
99
+ encoding: 'utf8',
100
+ stdio: ['pipe', 'pipe', 'pipe'],
101
+ });
102
+ const prefix = `${projectName}@`;
103
+ for (const line of output.split('\n')) {
104
+ const tag = line.trim();
105
+ if (!tag.startsWith(prefix))
106
+ continue;
107
+ const version = tag.slice(prefix.length);
108
+ if (version && !version.includes('-')) {
109
+ return version;
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"packed-manifest.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,WAAW,EAC1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,EAAE,CAoCV"}
1
+ {"version":3,"file":"packed-manifest.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,WAAW,EAC1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,EAAE,CA8CV"}
@@ -1,3 +1,4 @@
1
+ import { execSync } from 'node:child_process';
1
2
  import { $ } from 'bun';
2
3
  import { isRecord, recordProperty } from '../lib/json.js';
3
4
  import { decode } from '../lib/run.js';
@@ -14,7 +15,9 @@ export async function readPackedPackageJson(root, tarball, packageName) {
14
15
  return parsed;
15
16
  }
16
17
  export function validatePackedWorkspaceDependencies(root, sourcePackage, packedPackage) {
17
- const workspaceVersions = new Map(getWorkspacePackages(root).map((pkg) => [pkg.name, pkg.version]));
18
+ const workspacePackages = getWorkspacePackages(root);
19
+ const workspaceVersions = new Map(workspacePackages.map((pkg) => [pkg.name, pkg.version]));
20
+ const projectNameByPackage = new Map(workspacePackages.map((pkg) => [pkg.name, pkg.projectName]));
18
21
  const failures = [];
19
22
  for (const field of workspaceDependencyFields) {
20
23
  const sourceDependencies = recordProperty(sourcePackage.json, field);
@@ -39,8 +42,15 @@ export function validatePackedWorkspaceDependencies(root, sourcePackage, packedP
39
42
  if (sourceRange !== 'workspace:*') {
40
43
  failures.push(`${sourcePackage.path}: source ${field}.${name} must use workspace:*`);
41
44
  }
42
- if (packedRange !== workspaceVersion) {
43
- failures.push(`${sourcePackage.path}: packed ${field}.${name} must be ${workspaceVersion}, got ${formatRange(packedRange)}`);
45
+ // When the workspace dep is at a prerelease version that was never
46
+ // published, the lockfile sync rewrites it to the latest stable tag
47
+ // version. Accept that version as valid.
48
+ const projectName = projectNameByPackage.get(name);
49
+ const expectedVersion = workspaceVersion.includes('-') && projectName
50
+ ? (latestStableTagVersion(root, projectName) ?? workspaceVersion)
51
+ : workspaceVersion;
52
+ if (packedRange !== expectedVersion) {
53
+ failures.push(`${sourcePackage.path}: packed ${field}.${name} must be ${expectedVersion}, got ${formatRange(packedRange)}`);
44
54
  }
45
55
  }
46
56
  }
@@ -49,3 +59,26 @@ export function validatePackedWorkspaceDependencies(root, sourcePackage, packedP
49
59
  function formatRange(value) {
50
60
  return typeof value === 'string' ? value : '<missing>';
51
61
  }
62
+ function latestStableTagVersion(root, projectName) {
63
+ try {
64
+ const output = execSync(`git tag --list '${projectName}@*' --sort=-v:refname`, {
65
+ cwd: root,
66
+ encoding: 'utf8',
67
+ stdio: ['pipe', 'pipe', 'pipe'],
68
+ });
69
+ const prefix = `${projectName}@`;
70
+ for (const line of output.split('\n')) {
71
+ const tag = line.trim();
72
+ if (!tag.startsWith(prefix))
73
+ continue;
74
+ const version = tag.slice(prefix.length);
75
+ if (version && !version.includes('-')) {
76
+ return version;
77
+ }
78
+ }
79
+ return null;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smoothbricks/cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "type": "module",
5
5
  "description": "SmoothBricks monorepo automation CLI",
6
6
  "bin": {
@@ -45,7 +45,7 @@
45
45
  ],
46
46
  "dependencies": {
47
47
  "@arethetypeswrong/cli": "^0.18.2",
48
- "@smoothbricks/nx-plugin": "0.2.2-next.0",
48
+ "@smoothbricks/nx-plugin": "0.2.2",
49
49
  "@smoothbricks/validation": "0.1.1",
50
50
  "commander": "^14.0.3",
51
51
  "publint": "^0.3.18",
@@ -1,3 +1,4 @@
1
+ import { execSync } from 'node:child_process';
1
2
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
3
  import { join } from 'node:path';
3
4
  import { escapeRegex, getWorkspacePackages } from '../lib/workspace.js';
@@ -25,6 +26,13 @@ export function syncBunLockfileVersions(root: string, options: SyncBunLockfileVe
25
26
  let lockfile = readFileSync(lockfilePath, 'utf8');
26
27
  let updated = 0;
27
28
  for (const pkg of packages) {
29
+ // If the package.json version is a prerelease (e.g. 0.2.2-next.0) it may
30
+ // never have been published. Use the latest stable git tag version so
31
+ // that `bun pm pack` writes an installable dependency range for consumers.
32
+ const targetVersion = pkg.version.includes('-')
33
+ ? (latestStableTagVersion(root, pkg.projectName) ?? pkg.version)
34
+ : pkg.version;
35
+
28
36
  const relativePath = pkg.path.replaceAll('\\', '/');
29
37
  const escaped = escapeRegex(relativePath);
30
38
  const pattern = new RegExp(`("${escaped}":\\s*\\{[^}]*"version":\\s*")([^"]+)(")`);
@@ -36,15 +44,16 @@ export function syncBunLockfileVersions(root: string, options: SyncBunLockfileVe
36
44
  continue;
37
45
  }
38
46
  const lockVersion = match[2];
39
- if (lockVersion === pkg.version) {
47
+ if (lockVersion === targetVersion) {
40
48
  if (log) {
41
- console.log(`ok: ${relativePath} = ${pkg.version}`);
49
+ console.log(`ok: ${relativePath} = ${targetVersion}`);
42
50
  }
43
51
  continue;
44
52
  }
45
- lockfile = lockfile.replace(pattern, `$1${pkg.version}$3`);
53
+ lockfile = lockfile.replace(pattern, `$1${targetVersion}$3`);
46
54
  if (log) {
47
- console.log(`fix: ${relativePath}: ${lockVersion} -> ${pkg.version}`);
55
+ const suffix = targetVersion !== pkg.version ? ` (latest stable tag; package.json has ${pkg.version})` : '';
56
+ console.log(`fix: ${relativePath}: ${lockVersion} -> ${targetVersion}${suffix}`);
48
57
  }
49
58
  updated++;
50
59
  }
@@ -69,6 +78,10 @@ export function validateBunLockfileVersions(root: string): number {
69
78
  const lockfile = readFileSync(lockfilePath, 'utf8');
70
79
  let failures = 0;
71
80
  for (const pkg of packages) {
81
+ const targetVersion = pkg.version.includes('-')
82
+ ? (latestStableTagVersion(root, pkg.projectName) ?? pkg.version)
83
+ : pkg.version;
84
+
72
85
  const relativePath = pkg.path.replaceAll('\\', '/');
73
86
  const escaped = escapeRegex(relativePath);
74
87
  const pattern = new RegExp(`("${escaped}":\\s*\\{[^}]*"version":\\s*")([^"]+)(")`);
@@ -79,8 +92,8 @@ export function validateBunLockfileVersions(root: string): number {
79
92
  continue;
80
93
  }
81
94
  const lockVersion = match[2];
82
- if (lockVersion !== pkg.version) {
83
- console.error(`${relativePath}: bun.lock workspace version must be ${pkg.version}, got ${lockVersion}`);
95
+ if (lockVersion !== targetVersion) {
96
+ console.error(`${relativePath}: bun.lock workspace version must be ${targetVersion}, got ${lockVersion}`);
84
97
  failures++;
85
98
  }
86
99
  }
@@ -89,3 +102,25 @@ export function validateBunLockfileVersions(root: string): number {
89
102
  }
90
103
  return failures;
91
104
  }
105
+
106
+ function latestStableTagVersion(root: string, projectName: string): string | null {
107
+ try {
108
+ const output = execSync(`git tag --list '${projectName}@*' --sort=-v:refname`, {
109
+ cwd: root,
110
+ encoding: 'utf8',
111
+ stdio: ['pipe', 'pipe', 'pipe'],
112
+ });
113
+ const prefix = `${projectName}@`;
114
+ for (const line of output.split('\n')) {
115
+ const tag = line.trim();
116
+ if (!tag.startsWith(prefix)) continue;
117
+ const version = tag.slice(prefix.length);
118
+ if (version && !version.includes('-')) {
119
+ return version;
120
+ }
121
+ }
122
+ return null;
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
@@ -1,3 +1,4 @@
1
+ import { execSync } from 'node:child_process';
1
2
  import { $ } from 'bun';
2
3
  import { isRecord, recordProperty } from '../lib/json.js';
3
4
  import { decode } from '../lib/run.js';
@@ -25,7 +26,9 @@ export function validatePackedWorkspaceDependencies(
25
26
  sourcePackage: PackageInfo,
26
27
  packedPackage: Record<string, unknown>,
27
28
  ): string[] {
28
- const workspaceVersions = new Map(getWorkspacePackages(root).map((pkg) => [pkg.name, pkg.version]));
29
+ const workspacePackages = getWorkspacePackages(root);
30
+ const workspaceVersions = new Map(workspacePackages.map((pkg) => [pkg.name, pkg.version]));
31
+ const projectNameByPackage = new Map(workspacePackages.map((pkg) => [pkg.name, pkg.projectName]));
29
32
  const failures: string[] = [];
30
33
  for (const field of workspaceDependencyFields) {
31
34
  const sourceDependencies = recordProperty(sourcePackage.json, field);
@@ -52,9 +55,17 @@ export function validatePackedWorkspaceDependencies(
52
55
  if (sourceRange !== 'workspace:*') {
53
56
  failures.push(`${sourcePackage.path}: source ${field}.${name} must use workspace:*`);
54
57
  }
55
- if (packedRange !== workspaceVersion) {
58
+ // When the workspace dep is at a prerelease version that was never
59
+ // published, the lockfile sync rewrites it to the latest stable tag
60
+ // version. Accept that version as valid.
61
+ const projectName = projectNameByPackage.get(name);
62
+ const expectedVersion =
63
+ workspaceVersion.includes('-') && projectName
64
+ ? (latestStableTagVersion(root, projectName) ?? workspaceVersion)
65
+ : workspaceVersion;
66
+ if (packedRange !== expectedVersion) {
56
67
  failures.push(
57
- `${sourcePackage.path}: packed ${field}.${name} must be ${workspaceVersion}, got ${formatRange(packedRange)}`,
68
+ `${sourcePackage.path}: packed ${field}.${name} must be ${expectedVersion}, got ${formatRange(packedRange)}`,
58
69
  );
59
70
  }
60
71
  }
@@ -65,3 +76,25 @@ export function validatePackedWorkspaceDependencies(
65
76
  function formatRange(value: unknown): string {
66
77
  return typeof value === 'string' ? value : '<missing>';
67
78
  }
79
+
80
+ function latestStableTagVersion(root: string, projectName: string): string | null {
81
+ try {
82
+ const output = execSync(`git tag --list '${projectName}@*' --sort=-v:refname`, {
83
+ cwd: root,
84
+ encoding: 'utf8',
85
+ stdio: ['pipe', 'pipe', 'pipe'],
86
+ });
87
+ const prefix = `${projectName}@`;
88
+ for (const line of output.split('\n')) {
89
+ const tag = line.trim();
90
+ if (!tag.startsWith(prefix)) continue;
91
+ const version = tag.slice(prefix.length);
92
+ if (version && !version.includes('-')) {
93
+ return version;
94
+ }
95
+ }
96
+ return null;
97
+ } catch {
98
+ return null;
99
+ }
100
+ }