@smoothbricks/cli 0.10.3 → 0.10.4
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/README.md +9 -13
- package/dist/bun/preload.d.ts +13 -0
- package/dist/bun/preload.d.ts.map +1 -0
- package/dist/bun/preload.js +12 -0
- package/dist/cli.js +12 -4
- package/dist/generate/index.d.ts.map +1 -1
- package/dist/generate/index.js +0 -6
- package/dist/github-ci/index.d.ts.map +1 -1
- package/dist/github-ci/index.js +52 -16
- package/dist/github-ci/outputs.d.ts.map +1 -1
- package/dist/github-ci/outputs.js +1 -2
- package/dist/lib/cli-package.js +2 -2
- package/dist/lib/json.d.ts +118 -11
- package/dist/lib/json.d.ts.map +1 -1
- package/dist/lib/json.js +317 -29
- package/dist/lib/workspace.d.ts +7 -14
- package/dist/lib/workspace.d.ts.map +1 -1
- package/dist/lib/workspace.js +76 -82
- package/dist/monorepo/ci-workflow.d.ts +2 -0
- package/dist/monorepo/ci-workflow.d.ts.map +1 -1
- package/dist/monorepo/ci-workflow.js +27 -1
- package/dist/monorepo/git-config.js +2 -2
- package/dist/monorepo/index.d.ts +3 -1
- package/dist/monorepo/index.d.ts.map +1 -1
- package/dist/monorepo/index.js +6 -2
- package/dist/monorepo/lockfile.d.ts +13 -1
- package/dist/monorepo/lockfile.d.ts.map +1 -1
- package/dist/monorepo/lockfile.js +33 -21
- package/dist/monorepo/managed-files.d.ts +11 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +52 -32
- package/dist/monorepo/package-policy.d.ts.map +1 -1
- package/dist/monorepo/package-policy.js +52 -45
- package/dist/monorepo/packed-manifest.d.ts +5 -2
- package/dist/monorepo/packed-manifest.d.ts.map +1 -1
- package/dist/monorepo/packed-manifest.js +16 -47
- package/dist/monorepo/packed-package.d.ts.map +1 -1
- package/dist/monorepo/packed-package.js +28 -16
- package/dist/monorepo/packs/index.d.ts.map +1 -1
- package/dist/monorepo/packs/index.js +13 -4
- package/dist/monorepo/publish-workflow.js +3 -1
- package/dist/monorepo/runtime.d.ts +15 -0
- package/dist/monorepo/runtime.d.ts.map +1 -1
- package/dist/monorepo/runtime.js +66 -12
- package/dist/monorepo/tool-validation.d.ts.map +1 -1
- package/dist/monorepo/tool-validation.js +32 -23
- package/dist/monorepo/wrangler.d.ts.map +1 -1
- package/dist/monorepo/wrangler.js +13 -13
- package/dist/nx/index.d.ts +9 -7
- package/dist/nx/index.d.ts.map +1 -1
- package/dist/nx/index.js +48 -31
- package/dist/pr/index.d.ts.map +1 -1
- package/dist/pr/index.js +28 -32
- package/dist/release/candidates.d.ts +3 -2
- package/dist/release/candidates.d.ts.map +1 -1
- package/dist/release/candidates.js +4 -5
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +82 -59
- package/dist/wrangler/prepare-env.d.ts +0 -1
- package/dist/wrangler/prepare-env.d.ts.map +1 -1
- package/dist/wrangler/prepare-env.js +100 -51
- package/dist/wrangler/scaffold.d.ts.map +1 -1
- package/dist/wrangler/scaffold.js +12 -12
- package/managed/raw/git-format-staged.yml +19 -1
- package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +2 -1
- package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
- package/managed/raw/tooling/direnv/setup-environment.ts +150 -19
- package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
- package/managed/templates/github/actions/cache-node-modules/action.yml +5 -2
- package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
- package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
- package/managed/templates/github/workflows/managed-files.yml +80 -0
- package/package.json +15 -4
- package/src/bun/preload.ts +12 -0
- package/src/cli.ts +19 -7
- package/src/generate/index.ts +0 -6
- package/src/github-ci/index.ts +49 -18
- package/src/github-ci/outputs.ts +1 -2
- package/src/lib/cli-package.ts +2 -2
- package/src/lib/json.ts +291 -32
- package/src/lib/workspace.ts +88 -100
- package/src/monorepo/__tests__/ci-workflow.test.ts +3 -3
- package/src/monorepo/ci-workflow.ts +27 -1
- package/src/monorepo/git-config.ts +2 -2
- package/src/monorepo/index.ts +6 -2
- package/src/monorepo/lockfile.test.ts +35 -36
- package/src/monorepo/lockfile.ts +48 -24
- package/src/monorepo/managed-files.test.ts +1 -0
- package/src/monorepo/managed-files.ts +57 -38
- package/src/monorepo/package-policy.test.ts +20 -50
- package/src/monorepo/package-policy.ts +76 -59
- package/src/monorepo/packed-manifest.ts +18 -52
- package/src/monorepo/packed-package.ts +43 -22
- package/src/monorepo/packs/index.ts +13 -4
- package/src/monorepo/publish-workflow.ts +3 -1
- package/src/monorepo/runtime.test.ts +42 -3
- package/src/monorepo/runtime.ts +90 -12
- package/src/monorepo/tool-validation.ts +35 -25
- package/src/monorepo/wrangler.test.ts +11 -15
- package/src/monorepo/wrangler.ts +15 -15
- package/src/nx/index.test.ts +9 -5
- package/src/nx/index.ts +69 -42
- package/src/pr/index.ts +42 -36
- package/src/release/__tests__/candidates.test.ts +5 -4
- package/src/release/__tests__/trust-publisher.test.ts +7 -0
- package/src/release/candidates.ts +10 -17
- package/src/release/index.ts +104 -73
- package/src/wrangler/prepare-env.ts +75 -54
- package/src/wrangler/scaffold.test.ts +9 -12
- package/src/wrangler/scaffold.ts +13 -13
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { appendFileSync, existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { PLATFORM_TARGET_GLOBS } from '@smoothbricks/nx-plugin/workspace-config-policy';
|
|
6
|
+
import { parseNxProjectJsonText, parseStringArrayText } from '../lib/json.js';
|
|
6
7
|
import { listReleasePackages, readPackageJson } from '../lib/workspace.js';
|
|
7
8
|
import { renderCiWorkflowYaml } from './ci-workflow.js';
|
|
8
9
|
import { renderPublishWorkflowYaml } from './publish-workflow.js';
|
|
@@ -156,6 +157,11 @@ const managedFiles = [
|
|
|
156
157
|
target: '.github/workflows/publish.yml',
|
|
157
158
|
releasePackagesOnly: true,
|
|
158
159
|
},
|
|
160
|
+
{
|
|
161
|
+
kind: 'template',
|
|
162
|
+
source: 'github/workflows/managed-files.yml',
|
|
163
|
+
target: '.github/workflows/managed-files.yml',
|
|
164
|
+
},
|
|
159
165
|
{
|
|
160
166
|
kind: 'template',
|
|
161
167
|
source: 'github/actions/cache-nix-devenv/action.yml',
|
|
@@ -176,6 +182,11 @@ const managedFiles = [
|
|
|
176
182
|
source: 'github/actions/cache-node-modules/action.yml',
|
|
177
183
|
target: '.github/actions/cache-node-modules/action.yml',
|
|
178
184
|
},
|
|
185
|
+
{
|
|
186
|
+
kind: 'template',
|
|
187
|
+
source: 'github/actions/cache-ttsc-plugins/action.yml',
|
|
188
|
+
target: '.github/actions/cache-ttsc-plugins/action.yml',
|
|
189
|
+
},
|
|
179
190
|
{
|
|
180
191
|
kind: 'template',
|
|
181
192
|
source: 'github/actions/cache-nx/action.yml',
|
|
@@ -283,8 +294,8 @@ function readResolvedNxTargetNames(root) {
|
|
|
283
294
|
encoding: 'utf8',
|
|
284
295
|
stdio: ['ignore', 'pipe', 'inherit'],
|
|
285
296
|
});
|
|
286
|
-
const projects =
|
|
287
|
-
if (!
|
|
297
|
+
const projects = parseStringArrayText(output);
|
|
298
|
+
if (!projects) {
|
|
288
299
|
return [];
|
|
289
300
|
}
|
|
290
301
|
const targetNames = new Set();
|
|
@@ -294,8 +305,8 @@ function readResolvedNxTargetNames(root) {
|
|
|
294
305
|
encoding: 'utf8',
|
|
295
306
|
stdio: ['ignore', 'pipe', 'inherit'],
|
|
296
307
|
});
|
|
297
|
-
const projectJson =
|
|
298
|
-
const targets =
|
|
308
|
+
const projectJson = parseNxProjectJsonText(projectOutput);
|
|
309
|
+
const targets = projectJson?.targets;
|
|
299
310
|
if (targets) {
|
|
300
311
|
for (const targetName of Object.keys(targets)) {
|
|
301
312
|
targetNames.add(targetName);
|
|
@@ -316,8 +327,8 @@ function getDeployTargetInfo(root, configuration) {
|
|
|
316
327
|
encoding: 'utf8',
|
|
317
328
|
stdio: ['ignore', 'pipe', 'inherit'],
|
|
318
329
|
});
|
|
319
|
-
const projects =
|
|
320
|
-
if (!
|
|
330
|
+
const projects = parseStringArrayText(output);
|
|
331
|
+
if (!projects) {
|
|
321
332
|
return { exists: false };
|
|
322
333
|
}
|
|
323
334
|
let exists = false;
|
|
@@ -338,41 +349,23 @@ function nxDeployTarget(root, project, configuration) {
|
|
|
338
349
|
encoding: 'utf8',
|
|
339
350
|
stdio: ['ignore', 'pipe', 'inherit'],
|
|
340
351
|
});
|
|
341
|
-
const
|
|
342
|
-
const
|
|
343
|
-
const
|
|
344
|
-
const deploy = recordValue(targets?.deploy);
|
|
345
|
-
const configurations = recordValue(deploy?.configurations);
|
|
346
|
-
const config = recordValue(configurations?.[configuration]);
|
|
352
|
+
const projectJson = parseNxProjectJsonText(output);
|
|
353
|
+
const deploy = projectJson?.targets?.deploy;
|
|
354
|
+
const config = deploy?.configurations?.[configuration];
|
|
347
355
|
if (!config) {
|
|
348
356
|
return { exists: false };
|
|
349
357
|
}
|
|
350
|
-
const
|
|
358
|
+
const commandValue = config.command ?? config.options?.command ?? deploy?.options?.command;
|
|
359
|
+
const command = typeof commandValue === 'string' ? commandValue : '';
|
|
351
360
|
return { exists: true, provider: command.includes('wrangler ') ? 'cloudflare' : undefined };
|
|
352
361
|
}
|
|
353
|
-
function deployCommand(deploy, config) {
|
|
354
|
-
const command = stringValue(config.command) ?? stringValue(recordValue(config.options)?.command);
|
|
355
|
-
return command ?? stringValue(recordValue(deploy?.options)?.command) ?? '';
|
|
356
|
-
}
|
|
357
|
-
function stringValue(value) {
|
|
358
|
-
return typeof value === 'string' ? value : undefined;
|
|
359
|
-
}
|
|
360
362
|
function getCiPushBranches(packageJson) {
|
|
361
363
|
const configured = readCiPushBranches(packageJson);
|
|
362
364
|
return configured.length > 0 ? configured : ['main'];
|
|
363
365
|
}
|
|
364
366
|
function readCiPushBranches(packageJson) {
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
const github = recordValue(smoo?.github);
|
|
368
|
-
const branches = Array.isArray(github?.pushBranches) ? github.pushBranches : [];
|
|
369
|
-
return branches.filter((branch) => typeof branch === 'string' && branch.length > 0);
|
|
370
|
-
}
|
|
371
|
-
function recordValue(value) {
|
|
372
|
-
return isRecord(value) ? value : undefined;
|
|
373
|
-
}
|
|
374
|
-
function isRecord(value) {
|
|
375
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
367
|
+
const branches = packageJson?.smoo?.github?.pushBranches ?? [];
|
|
368
|
+
return branches.filter((branch) => branch.length > 0);
|
|
376
369
|
}
|
|
377
370
|
function renderYamlFlowList(values) {
|
|
378
371
|
return JSON.stringify(values);
|
|
@@ -395,3 +388,30 @@ export function validateManagedFiles(root) {
|
|
|
395
388
|
}
|
|
396
389
|
return failures;
|
|
397
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Non-blocking drift report: prints the per-file table and surfaces drift as
|
|
393
|
+
* GitHub Actions warning annotations (plain stderr elsewhere) without failing
|
|
394
|
+
* the run. Managed-file drift is derived state with its own remediation flow
|
|
395
|
+
* (the persistent managed-files PR); only `monorepo check` without --warn and
|
|
396
|
+
* PR-scoped gates treat it as an error.
|
|
397
|
+
*
|
|
398
|
+
* Under GitHub Actions the drifted-file count is published as the step output
|
|
399
|
+
* `drifted`, so downstream steps gate declaratively instead of parsing logs.
|
|
400
|
+
*/
|
|
401
|
+
export function warnOnManagedFileDrift(root) {
|
|
402
|
+
const results = applyManagedFiles(root, 'check');
|
|
403
|
+
printResults(results);
|
|
404
|
+
const drifted = results.filter((result) => result.action === 'drifted');
|
|
405
|
+
if (process.env.GITHUB_OUTPUT) {
|
|
406
|
+
appendFileSync(process.env.GITHUB_OUTPUT, `drifted=${drifted.length}\n`);
|
|
407
|
+
}
|
|
408
|
+
if (drifted.length === 0) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (process.env.GITHUB_ACTIONS === 'true') {
|
|
412
|
+
for (const result of drifted) {
|
|
413
|
+
console.log(`::warning title=Managed file drift::${result.target} drifted from the @smoothbricks/cli template; run 'smoo monorepo update'`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
console.error(`${drifted.length} managed monorepo file(s) drifted (non-blocking). Run: smoo monorepo update`);
|
|
417
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;AAoCvD,YAAY,EAAE,0BAA0B,IAAI,iCAAiC,EAAE,sBAAsB,EAAE,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,CAAC;AAYhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0C7D;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI,CAwB7G;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoB7D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAczD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsC9D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB3D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgElE;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,MAAM,CAkC5G"}
|
|
@@ -4,7 +4,7 @@ import { applyPackageTargetPolicy, checkPackageTargetPolicy, } from '@smoothbric
|
|
|
4
4
|
import { applyReleaseConfigPolicy, checkReleaseConfigPolicy, SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS, } from '@smoothbricks/nx-plugin/release-config-policy';
|
|
5
5
|
import { applyTypecheckTestPolicy, checkTypecheckTestPolicy } from '@smoothbricks/nx-plugin/typecheck-test-policy';
|
|
6
6
|
import { applyWorkspaceConfigPolicy, checkWorkspaceConfigPolicy, } from '@smoothbricks/nx-plugin/workspace-config-policy';
|
|
7
|
-
import {
|
|
7
|
+
import { ensureNx, ensurePublishConfig, ensureRepositoryObject, ensureScripts, readJsonObject, requiredJsonObject, setMissingPackageStringField, setMissingRepositoryField, setNxName, setPublishAccess, setRepositoryField, setStringProperty, writeJsonObject, } from '../lib/json.js';
|
|
8
8
|
import { getWorkspacePackageManifests, getWorkspacePackages, listPackageJsonRecords, listPublicPackages, packageRepositoryInfo, repositoryInfo, sameRepositoryAfterNormalization, workspaceDependencyFields, } from '../lib/workspace.js';
|
|
9
9
|
export { SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS };
|
|
10
10
|
const extraCommitScopes = ['release'];
|
|
@@ -27,12 +27,12 @@ export function applyRootScriptDefaults(root) {
|
|
|
27
27
|
if (!rootPackage) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
const scripts =
|
|
30
|
+
const scripts = ensureScripts(rootPackage);
|
|
31
31
|
let changed = false;
|
|
32
32
|
for (const [name, command] of Object.entries(rootScriptPolicy)) {
|
|
33
33
|
changed = setStringProperty(scripts, name, command) || changed;
|
|
34
34
|
}
|
|
35
|
-
const nx =
|
|
35
|
+
const nx = ensureNx(rootPackage);
|
|
36
36
|
if (!Array.isArray(nx.includedScripts) || nx.includedScripts.length !== 0) {
|
|
37
37
|
nx.includedScripts = [];
|
|
38
38
|
changed = true;
|
|
@@ -56,7 +56,7 @@ export function applyNxPluginDefaults(root) {
|
|
|
56
56
|
}
|
|
57
57
|
export function applyPublicPackageDefaults(root) {
|
|
58
58
|
const rootPackage = requiredJsonObject(join(root, 'package.json'));
|
|
59
|
-
const rootLicense =
|
|
59
|
+
const rootLicense = rootPackage.license;
|
|
60
60
|
const rootRepository = repositoryInfo(rootPackage);
|
|
61
61
|
for (const pkg of listPublicPackages(root)) {
|
|
62
62
|
let changed = false;
|
|
@@ -66,17 +66,19 @@ export function applyPublicPackageDefaults(root) {
|
|
|
66
66
|
existingRepository.url === rootRepository.url &&
|
|
67
67
|
rootLicense &&
|
|
68
68
|
rootLicense !== 'UNLICENSED') {
|
|
69
|
-
changed =
|
|
69
|
+
changed = setMissingPackageStringField(pkg.json, 'license', rootLicense) || changed;
|
|
70
70
|
}
|
|
71
|
-
const publishConfig =
|
|
72
|
-
changed =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
const publishConfig = ensurePublishConfig(pkg.json);
|
|
72
|
+
changed = setPublishAccess(publishConfig, 'public') || changed;
|
|
73
|
+
if (typeof pkg.json.repository !== 'string') {
|
|
74
|
+
const repository = ensureRepositoryObject(pkg.json);
|
|
75
|
+
changed =
|
|
76
|
+
setRepositoryField(repository, 'type', existingRepository?.type ?? rootRepository?.type ?? 'git') || changed;
|
|
77
|
+
if (existingRepository) {
|
|
78
|
+
changed = setMissingRepositoryField(repository, 'url', existingRepository.url) || changed;
|
|
79
|
+
}
|
|
80
|
+
changed = setRepositoryField(repository, 'directory', pkg.path.replaceAll('\\', '/')) || changed;
|
|
78
81
|
}
|
|
79
|
-
changed = setStringProperty(repository, 'directory', pkg.path.replaceAll('\\', '/')) || changed;
|
|
80
82
|
changed = normalizeExportConditionOrder(pkg.json.exports) || changed;
|
|
81
83
|
if (hasDevelopmentSourceExport(pkg.json.exports)) {
|
|
82
84
|
changed = addFileEntry(pkg.json, 'src') || changed;
|
|
@@ -128,7 +130,7 @@ export function applyNxReleaseDefaults(root) {
|
|
|
128
130
|
}
|
|
129
131
|
export function applyNxProjectNameDefaults(root) {
|
|
130
132
|
const rootPackage = requiredJsonObject(join(root, 'package.json'));
|
|
131
|
-
const rootName =
|
|
133
|
+
const rootName = rootPackage.name;
|
|
132
134
|
if (!rootName) {
|
|
133
135
|
return;
|
|
134
136
|
}
|
|
@@ -137,8 +139,8 @@ export function applyNxProjectNameDefaults(root) {
|
|
|
137
139
|
if (!suggestedName) {
|
|
138
140
|
continue;
|
|
139
141
|
}
|
|
140
|
-
const nx =
|
|
141
|
-
const changed =
|
|
142
|
+
const nx = ensureNx(pkg.json);
|
|
143
|
+
const changed = setNxName(nx, suggestedName);
|
|
142
144
|
if (changed) {
|
|
143
145
|
writeJsonObject(pkg.packageJsonPath, pkg.json);
|
|
144
146
|
console.log(`updated ${pkg.path}/package.json nx.name`);
|
|
@@ -153,11 +155,10 @@ export function listValidCommitScopes(root) {
|
|
|
153
155
|
}
|
|
154
156
|
export function listNxProjectNames(root) {
|
|
155
157
|
const rootPackage = readJsonObject(join(root, 'package.json'));
|
|
156
|
-
const rootName = rootPackage
|
|
158
|
+
const rootName = rootPackage?.name ?? null;
|
|
157
159
|
const names = [];
|
|
158
160
|
for (const pkg of getWorkspacePackageManifests(root)) {
|
|
159
|
-
const
|
|
160
|
-
const configuredName = nx ? stringProperty(nx, 'name') : null;
|
|
161
|
+
const configuredName = pkg.json.nx?.name;
|
|
161
162
|
const suggestedName = rootName ? suggestNxProjectName(rootName, pkg.name) : null;
|
|
162
163
|
if (configuredName) {
|
|
163
164
|
names.push(configuredName);
|
|
@@ -175,11 +176,11 @@ export function validateRootPackagePolicy(root) {
|
|
|
175
176
|
return 1;
|
|
176
177
|
}
|
|
177
178
|
let failures = 0;
|
|
178
|
-
if (!
|
|
179
|
+
if (!rootPackage.name) {
|
|
179
180
|
console.error('package.json must define name');
|
|
180
181
|
failures++;
|
|
181
182
|
}
|
|
182
|
-
if (!
|
|
183
|
+
if (!rootPackage.license) {
|
|
183
184
|
console.error('package.json must define repo-wide license');
|
|
184
185
|
failures++;
|
|
185
186
|
}
|
|
@@ -189,19 +190,19 @@ export function validateRootPackagePolicy(root) {
|
|
|
189
190
|
}
|
|
190
191
|
failures += validateRootScripts(rootPackage);
|
|
191
192
|
failures += validateRootNxScriptInference(rootPackage);
|
|
192
|
-
const packageManager =
|
|
193
|
+
const packageManager = rootPackage.packageManager;
|
|
193
194
|
if (!packageManager?.startsWith('bun@')) {
|
|
194
195
|
console.error('package.json packageManager must use bun@<version>');
|
|
195
196
|
failures++;
|
|
196
197
|
}
|
|
197
198
|
const bunVersion = packageManager?.startsWith('bun@') ? packageManager.slice('bun@'.length) : null;
|
|
198
|
-
const devDependencies =
|
|
199
|
+
const devDependencies = rootPackage.devDependencies;
|
|
199
200
|
if (!bunVersion || !devDependencies || devDependencies['@types/bun'] !== bunVersion) {
|
|
200
201
|
console.error('package.json devDependencies.@types/bun must match packageManager bun version');
|
|
201
202
|
failures++;
|
|
202
203
|
}
|
|
203
|
-
const engines =
|
|
204
|
-
if (!engines
|
|
204
|
+
const engines = rootPackage.engines;
|
|
205
|
+
if (!engines?.node) {
|
|
205
206
|
console.error('package.json engines.node must be defined');
|
|
206
207
|
failures++;
|
|
207
208
|
}
|
|
@@ -221,7 +222,7 @@ export function validateNxReleaseConfig(root) {
|
|
|
221
222
|
}
|
|
222
223
|
export function validateNxProjectNames(root) {
|
|
223
224
|
const rootPackage = readJsonObject(join(root, 'package.json'));
|
|
224
|
-
const rootName = rootPackage
|
|
225
|
+
const rootName = rootPackage?.name ?? null;
|
|
225
226
|
if (!rootName) {
|
|
226
227
|
return 0;
|
|
227
228
|
}
|
|
@@ -231,8 +232,7 @@ export function validateNxProjectNames(root) {
|
|
|
231
232
|
if (!suggestedName) {
|
|
232
233
|
continue;
|
|
233
234
|
}
|
|
234
|
-
const
|
|
235
|
-
const configuredName = nx ? stringProperty(nx, 'name') : null;
|
|
235
|
+
const configuredName = pkg.json.nx?.name ?? null;
|
|
236
236
|
if (configuredName !== suggestedName) {
|
|
237
237
|
console.error(`${pkg.path}: package.json nx.name must be "${suggestedName}" so fix(${suggestedName}): maps to this project`);
|
|
238
238
|
failures++;
|
|
@@ -267,16 +267,18 @@ export function validatePublicPackageMetadata(root) {
|
|
|
267
267
|
console.error(`${pkg.path}: npm:public package must not be private`);
|
|
268
268
|
failures++;
|
|
269
269
|
}
|
|
270
|
-
if (!
|
|
270
|
+
if (!pkg.json.license) {
|
|
271
271
|
console.error(`${pkg.path}: public package must define license`);
|
|
272
272
|
failures++;
|
|
273
273
|
}
|
|
274
|
-
const publishConfig =
|
|
275
|
-
if (
|
|
274
|
+
const publishConfig = pkg.json.publishConfig;
|
|
275
|
+
if (publishConfig?.access !== 'public') {
|
|
276
276
|
console.error(`${pkg.path}: public package must define publishConfig.access = public`);
|
|
277
277
|
failures++;
|
|
278
278
|
}
|
|
279
|
-
const repository =
|
|
279
|
+
const repository = pkg.json.repository !== null && pkg.json.repository !== undefined && typeof pkg.json.repository !== 'string'
|
|
280
|
+
? pkg.json.repository
|
|
281
|
+
: null;
|
|
280
282
|
const packageRepository = packageRepositoryInfo(pkg);
|
|
281
283
|
if (!packageRepository) {
|
|
282
284
|
console.error(`${pkg.path}: public package must define repository.url`);
|
|
@@ -290,11 +292,11 @@ export function validatePublicPackageMetadata(root) {
|
|
|
290
292
|
`Use ${rootRepository.url}`);
|
|
291
293
|
failures++;
|
|
292
294
|
}
|
|
293
|
-
if (!repository
|
|
295
|
+
if (!repository?.type) {
|
|
294
296
|
console.error(`${pkg.path}: public package must define repository.type`);
|
|
295
297
|
failures++;
|
|
296
298
|
}
|
|
297
|
-
if (!repository ||
|
|
299
|
+
if (!repository || repository.directory !== pkg.path.replaceAll('\\', '/')) {
|
|
298
300
|
console.error(`${pkg.path}: public package repository.directory must be ${pkg.path.replaceAll('\\', '/')}`);
|
|
299
301
|
failures++;
|
|
300
302
|
}
|
|
@@ -302,11 +304,13 @@ export function validatePublicPackageMetadata(root) {
|
|
|
302
304
|
console.error(`${pkg.path}: public package must define files`);
|
|
303
305
|
failures++;
|
|
304
306
|
}
|
|
305
|
-
|
|
307
|
+
const hasBin = typeof pkg.json.bin === 'string' ||
|
|
308
|
+
(pkg.json.bin !== null && pkg.json.bin !== undefined && typeof pkg.json.bin === 'object');
|
|
309
|
+
if (!isPackageExportMap(pkg.json.exports) && !hasBin) {
|
|
306
310
|
console.error(`${pkg.path}: public package must define exports or bin`);
|
|
307
311
|
failures++;
|
|
308
312
|
}
|
|
309
|
-
if (
|
|
313
|
+
if (typeof pkg.json.types !== 'string' && !hasBin) {
|
|
310
314
|
console.error(`${pkg.path}: public library package must define types`);
|
|
311
315
|
failures++;
|
|
312
316
|
}
|
|
@@ -319,7 +323,7 @@ export function validateWorkspaceDependencies(root, options = {}) {
|
|
|
319
323
|
const workspaceNames = new Set(getWorkspacePackages(root).map((pkg) => pkg.name));
|
|
320
324
|
for (const pkg of listPackageJsonRecords(root)) {
|
|
321
325
|
for (const field of workspaceDependencyFields) {
|
|
322
|
-
const dependencies =
|
|
326
|
+
const dependencies = pkg.json[field];
|
|
323
327
|
if (!dependencies) {
|
|
324
328
|
continue;
|
|
325
329
|
}
|
|
@@ -379,7 +383,7 @@ function validateCiSkipTags(root, options) {
|
|
|
379
383
|
function fixWorkspaceDependencyRanges(pkg, workspaceNames) {
|
|
380
384
|
let changed = false;
|
|
381
385
|
for (const field of workspaceDependencyFields) {
|
|
382
|
-
const dependencies =
|
|
386
|
+
const dependencies = pkg[field];
|
|
383
387
|
if (!dependencies) {
|
|
384
388
|
continue;
|
|
385
389
|
}
|
|
@@ -393,7 +397,7 @@ function fixWorkspaceDependencyRanges(pkg, workspaceNames) {
|
|
|
393
397
|
return changed;
|
|
394
398
|
}
|
|
395
399
|
function validateRootScripts(rootPackage) {
|
|
396
|
-
const scripts =
|
|
400
|
+
const scripts = rootPackage.scripts;
|
|
397
401
|
let failures = 0;
|
|
398
402
|
for (const [name, command] of Object.entries(rootScriptPolicy)) {
|
|
399
403
|
if (scripts?.[name] !== command) {
|
|
@@ -408,8 +412,8 @@ function validateRootScripts(rootPackage) {
|
|
|
408
412
|
return failures;
|
|
409
413
|
}
|
|
410
414
|
function validateRootNxScriptInference(rootPackage) {
|
|
411
|
-
const
|
|
412
|
-
if (
|
|
415
|
+
const includedScripts = rootPackage.nx?.includedScripts;
|
|
416
|
+
if (Array.isArray(includedScripts) && includedScripts.length === 0) {
|
|
413
417
|
return 0;
|
|
414
418
|
}
|
|
415
419
|
console.error('package.json nx.includedScripts must be [] so root scripts do not become recursive Nx targets.');
|
|
@@ -431,7 +435,7 @@ function unscopedPackageName(packageName) {
|
|
|
431
435
|
}
|
|
432
436
|
function recordKeysAreSorted(record) {
|
|
433
437
|
const keys = Object.keys(record);
|
|
434
|
-
return keys.every((key, index) => index === 0 || keys[index - 1] <= key);
|
|
438
|
+
return keys.every((key, index) => index === 0 || (keys[index - 1] ?? '') <= key);
|
|
435
439
|
}
|
|
436
440
|
function sortRecordInPlace(record) {
|
|
437
441
|
if (recordKeysAreSorted(record)) {
|
|
@@ -446,8 +450,11 @@ function sortRecordInPlace(record) {
|
|
|
446
450
|
}
|
|
447
451
|
return true;
|
|
448
452
|
}
|
|
453
|
+
function isPackageExportMap(value) {
|
|
454
|
+
return value !== null && value !== undefined && typeof value === 'object';
|
|
455
|
+
}
|
|
449
456
|
function normalizeExportConditionOrder(value) {
|
|
450
|
-
if (!
|
|
457
|
+
if (!isPackageExportMap(value)) {
|
|
451
458
|
return false;
|
|
452
459
|
}
|
|
453
460
|
let changed = false;
|
|
@@ -476,7 +483,7 @@ function normalizeExportConditionOrder(value) {
|
|
|
476
483
|
return true;
|
|
477
484
|
}
|
|
478
485
|
function hasDevelopmentSourceExport(value) {
|
|
479
|
-
if (!
|
|
486
|
+
if (!isPackageExportMap(value)) {
|
|
480
487
|
return false;
|
|
481
488
|
}
|
|
482
489
|
for (const [key, child] of Object.entries(value)) {
|
|
@@ -494,7 +501,7 @@ function addFileEntry(pkg, entry) {
|
|
|
494
501
|
if (!Array.isArray(files) || files.includes(entry)) {
|
|
495
502
|
return false;
|
|
496
503
|
}
|
|
497
|
-
const firstNegated = files.findIndex((file) =>
|
|
504
|
+
const firstNegated = files.findIndex((file) => file.startsWith('!'));
|
|
498
505
|
if (firstNegated === -1) {
|
|
499
506
|
files.push(entry);
|
|
500
507
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { type PackageJson } from '../lib/json.js';
|
|
1
2
|
import type { PackageInfo } from '../lib/workspace.js';
|
|
2
|
-
export declare function readPackedPackageJson(root: string, tarball: string, packageName: string): Promise<
|
|
3
|
-
export declare function validatePackedWorkspaceDependencies(root: string, sourcePackage: PackageInfo, packedPackage:
|
|
3
|
+
export declare function readPackedPackageJson(root: string, tarball: string, packageName: string): Promise<PackageJson>;
|
|
4
|
+
export declare function validatePackedWorkspaceDependencies(root: string, sourcePackage: PackageInfo, packedPackage: PackageJson, options?: {
|
|
5
|
+
mode?: 'install' | 'publish';
|
|
6
|
+
}): string[];
|
|
4
7
|
//# sourceMappingURL=packed-manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packed-manifest.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"packed-manifest.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-manifest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,gBAAgB,CAAC;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAUpH;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,WAAW,EAC1B,aAAa,EAAE,WAAW,EAC1B,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAO,GAC7C,MAAM,EAAE,CAyCV"}
|
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
2
1
|
import { $ } from 'bun';
|
|
3
|
-
import {
|
|
2
|
+
import { parsePackageJsonText } from '../lib/json.js';
|
|
4
3
|
import { decode } from '../lib/run.js';
|
|
5
4
|
import { getWorkspacePackages, workspaceDependencyFields } from '../lib/workspace.js';
|
|
5
|
+
import { publishPackDependencyVersion } from './lockfile.js';
|
|
6
6
|
export async function readPackedPackageJson(root, tarball, packageName) {
|
|
7
7
|
const result = await $ `tar -xOf ${tarball} package/package.json`.cwd(root).quiet().nothrow();
|
|
8
8
|
if (result.exitCode !== 0) {
|
|
9
9
|
throw new Error(`${packageName}: unable to inspect packed package.json.`);
|
|
10
10
|
}
|
|
11
|
-
const parsed =
|
|
12
|
-
if (!
|
|
13
|
-
throw new Error(`${packageName}: packed package.json is
|
|
11
|
+
const parsed = parsePackageJsonText(decode(result.stdout));
|
|
12
|
+
if (!parsed) {
|
|
13
|
+
throw new Error(`${packageName}: packed package.json is invalid.`);
|
|
14
14
|
}
|
|
15
15
|
return parsed;
|
|
16
16
|
}
|
|
17
|
-
export function validatePackedWorkspaceDependencies(root, sourcePackage, packedPackage) {
|
|
17
|
+
export function validatePackedWorkspaceDependencies(root, sourcePackage, packedPackage, options = {}) {
|
|
18
|
+
const mode = options.mode ?? 'publish';
|
|
18
19
|
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]));
|
|
21
20
|
const failures = [];
|
|
22
21
|
for (const field of workspaceDependencyFields) {
|
|
23
|
-
const sourceDependencies =
|
|
24
|
-
const packedDependencies =
|
|
22
|
+
const sourceDependencies = sourcePackage.json[field];
|
|
23
|
+
const packedDependencies = packedPackage[field];
|
|
25
24
|
if (!sourceDependencies && !packedDependencies) {
|
|
26
25
|
continue;
|
|
27
26
|
}
|
|
28
27
|
for (const [name, range] of Object.entries(packedDependencies ?? {})) {
|
|
29
|
-
if (
|
|
28
|
+
if (range.startsWith('workspace:')) {
|
|
30
29
|
failures.push(`${sourcePackage.path}: packed ${field}.${name} must not contain ${range}`);
|
|
31
30
|
}
|
|
32
31
|
}
|
|
@@ -34,51 +33,21 @@ export function validatePackedWorkspaceDependencies(root, sourcePackage, packedP
|
|
|
34
33
|
continue;
|
|
35
34
|
}
|
|
36
35
|
for (const [name, sourceRange] of Object.entries(sourceDependencies)) {
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
36
|
+
const dep = workspacePackages.find((pkg) => pkg.name === name);
|
|
37
|
+
if (!dep) {
|
|
39
38
|
continue;
|
|
40
39
|
}
|
|
41
40
|
const packedRange = packedDependencies?.[name];
|
|
42
41
|
if (sourceRange !== 'workspace:*') {
|
|
43
42
|
failures.push(`${sourcePackage.path}: source ${field}.${name} must use workspace:*`);
|
|
44
43
|
}
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
const projectName = projectNameByPackage.get(name);
|
|
49
|
-
const expectedVersion = workspaceVersion.includes('-') && projectName
|
|
50
|
-
? (latestStableTagVersion(root, projectName) ?? workspaceVersion)
|
|
51
|
-
: workspaceVersion;
|
|
44
|
+
// install: what day-to-day pack embeds (package.json / lockfile aligned)
|
|
45
|
+
// publish: what pre-publish sync embeds (unpublished -next → last stable tag)
|
|
46
|
+
const expectedVersion = mode === 'publish' ? publishPackDependencyVersion(root, dep.projectName, dep.version) : dep.version;
|
|
52
47
|
if (packedRange !== expectedVersion) {
|
|
53
|
-
failures.push(`${sourcePackage.path}: packed ${field}.${name} must be ${expectedVersion}, got ${
|
|
48
|
+
failures.push(`${sourcePackage.path}: packed ${field}.${name} must be ${expectedVersion}, got ${packedRange ?? '<missing>'}`);
|
|
54
49
|
}
|
|
55
50
|
}
|
|
56
51
|
}
|
|
57
52
|
return failures;
|
|
58
53
|
}
|
|
59
|
-
function formatRange(value) {
|
|
60
|
-
return typeof value === 'string' ? value : '<missing>';
|
|
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
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"packed-package.d.ts","sourceRoot":"","sources":["../../src/monorepo/packed-package.ts"],"names":[],"mappings":"AAcA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF;AAED,wBAAsB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMvF;AAED,wBAAsB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpF"}
|