@vltpkg/cli-sdk 1.2.0 → 1.3.1

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.
@@ -4,7 +4,7 @@ import { minimatch } from 'minimatch';
4
4
  import { init } from '@vltpkg/init';
5
5
  import { install } from '@vltpkg/graph';
6
6
  import { load, save } from '@vltpkg/vlt-json';
7
- import { assertWSConfig, asWSConfig } from '@vltpkg/workspaces';
7
+ import { assertWSConfig, resolveWSConfig, splitNegatedPatterns, } from '@vltpkg/workspaces';
8
8
  import { commandUsage } from "../config/usage.js";
9
9
  export const usage = () => commandUsage({
10
10
  command: 'init',
@@ -55,8 +55,18 @@ export const command = async (conf) => {
55
55
  : ':not(*)';
56
56
  /* c8 ignore stop */
57
57
  if (conf.values.workspace?.length) {
58
- const workspacesConfig = load('workspaces', assertWSConfig);
59
- const parsedWSConfig = asWSConfig(workspacesConfig ?? {});
58
+ // the *effective* config, which may come from the root package.json
59
+ // rather than vlt.json
60
+ const { config: parsedWSConfig, source } = resolveWSConfig(conf.options.projectRoot, conf.options.packageJson);
61
+ // what gets written back to vlt.json. The raw vlt.json value is
62
+ // reused as-is so its existing shape is preserved. When the
63
+ // definitions live in package.json instead, seed vlt.json with them
64
+ // first -- otherwise adding a `workspaces` field here would shadow
65
+ // every workspace package.json already declares.
66
+ const workspacesConfig = load('workspaces', assertWSConfig) ??
67
+ (source === 'package.json' ?
68
+ Object.values(parsedWSConfig).flat()
69
+ : undefined);
60
70
  const results = [];
61
71
  const addToConfig = [];
62
72
  // create a new package.json file for every workspace
@@ -69,8 +79,10 @@ export const command = async (conf) => {
69
79
  // run the initialization script and collect results
70
80
  results.push(await init({ cwd }));
71
81
  // Check if this workspace path is covered by existing workspace patterns
72
- const isMatched = Object.values(parsedWSConfig).some((patterns) => {
73
- return patterns.some(pattern => minimatch(workspace, pattern));
82
+ const isMatched = Object.values(parsedWSConfig).some((group) => {
83
+ const { patterns, ignore } = splitNegatedPatterns(group);
84
+ return (patterns.some(pattern => minimatch(workspace, pattern)) &&
85
+ !ignore.some(pattern => minimatch(workspace, pattern)));
74
86
  });
75
87
  // When a workspace is not matched we track it for insertion later
76
88
  if (!isMatched) {
@@ -4,7 +4,8 @@ import { run } from '@vltpkg/run';
4
4
  import { commandUsage } from "../config/usage.js";
5
5
  import { packTarball } from "../pack-tarball.js";
6
6
  import assert from 'node:assert';
7
- import { dirname, resolve } from 'node:path';
7
+ import { readFileSync } from 'node:fs';
8
+ import { dirname, join, resolve } from 'node:path';
8
9
  import prettyBytes from 'pretty-bytes';
9
10
  import { actual } from '@vltpkg/graph';
10
11
  import { Query } from '@vltpkg/query';
@@ -156,6 +157,28 @@ const getPublishConfig = (manifest) => {
156
157
  }
157
158
  return undefined;
158
159
  };
160
+ /** Of several readmes at the package root, npm prefers the markdown one. */
161
+ const README_MARKDOWN_EXTENSION = /\.(?:md|markdown|mdown|mdwn|mkd|mkdn)$/i;
162
+ /**
163
+ * The readme fields npm's CLI puts in a publish payload, read out of the
164
+ * files that were just packed. Registries serve this as the package's front
165
+ * page, so a payload without it leaves the page blank even though the readme
166
+ * is sitting inside the tarball.
167
+ *
168
+ * npm takes the readme at the package root and prefers the markdown one; a
169
+ * package without a readme gets no fields at all.
170
+ */
171
+ const readPublishReadme = (packDir, files) => {
172
+ const readmes = files.filter(file => /^readme(\.[^.]*)?$/i.test(file));
173
+ const readmeFilename = readmes.find(file => README_MARKDOWN_EXTENSION.test(file)) ??
174
+ readmes[0];
175
+ if (!readmeFilename)
176
+ return undefined;
177
+ return {
178
+ readme: readFileSync(join(packDir, readmeFilename), 'utf8'),
179
+ readmeFilename,
180
+ };
181
+ };
159
182
  const commandSingle = async (location, conf) => {
160
183
  const manifestPath = conf.options.packageJson.find(location);
161
184
  assert(manifestPath, 'No package.json found');
@@ -196,7 +219,7 @@ const commandSingle = async (location, conf) => {
196
219
  const updatedManifest = conf.options.packageJson.read(manifestDir, {
197
220
  reload: true,
198
221
  });
199
- const { name, version, tarballName, tarballData, unpackedSize, files, integrity, shasum, resolvedManifest, } = await packTarball(updatedManifest, manifestDir, conf);
222
+ const { name, version, tarballName, tarballData, unpackedSize, files, integrity, shasum, resolvedManifest, packDir, } = await packTarball(updatedManifest, manifestDir, conf);
200
223
  await run({
201
224
  ...runOptions,
202
225
  arg0: 'postpack',
@@ -215,6 +238,7 @@ const commandSingle = async (location, conf) => {
215
238
  versions: {
216
239
  [version]: {
217
240
  ...resolvedManifest,
241
+ ...readPublishReadme(packDir, files),
218
242
  _id: `${name}@${version}`,
219
243
  _nodeVersion: process.versions.node,
220
244
  dist: {
@@ -406,12 +406,17 @@ export declare const definition: import("jackspeak").Jack<{
406
406
  'lockfile-only': {
407
407
  description: string;
408
408
  };
409
+ 'brotli-tarballs': {
410
+ description: string;
411
+ default: true;
412
+ };
409
413
  } & {
410
414
  'dry-run': import("jackspeak").ConfigOption<"boolean", false, undefined>;
411
415
  force: import("jackspeak").ConfigOption<"boolean", false, undefined>;
412
416
  'expect-lockfile': import("jackspeak").ConfigOption<"boolean", false, undefined>;
413
417
  'frozen-lockfile': import("jackspeak").ConfigOption<"boolean", false, undefined>;
414
418
  'lockfile-only': import("jackspeak").ConfigOption<"boolean", false, undefined>;
419
+ 'brotli-tarballs': import("jackspeak").ConfigOption<"boolean", false, undefined>;
415
420
  } & {
416
421
  'allow-scripts': {
417
422
  hint: string;
@@ -751,6 +751,19 @@ export const definition = j
751
751
  'lockfile-only': {
752
752
  description: 'Only update the lockfile (vlt-lock.json) and package.json files, skip all node_modules operations including package extraction and filesystem changes.',
753
753
  },
754
+ 'brotli-tarballs': {
755
+ description: `Resolve to the Brotli (\`.tar.br\`) tarball when the
756
+ registry advertises one for a version, transferring far
757
+ less than the gzip \`.tgz\`.
758
+
759
+ The \`.tar.br\` is its own artifact and hashes
760
+ differently, so a version installed this way records that
761
+ hash in \`vlt-lock.json\`. An existing lockfile keeps
762
+ whichever artifact it already pinned; set
763
+ \`--no-brotli-tarballs\` before resolving to pin the
764
+ \`.tgz\` instead.`,
765
+ default: true,
766
+ },
754
767
  })
755
768
  .opt({
756
769
  'allow-scripts': {
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ const run = async () => {
57
57
  if (vlt.command !== 'init' &&
58
58
  (vlt.get('workspace') || vlt.get('workspace-group')) &&
59
59
  ![...(monorepo?.values() ?? [])].length) {
60
- stderr(`Error: No matching workspaces found. Make sure the vlt.json config contains the correct workspaces.`);
60
+ stderr(`Error: No matching workspaces found. Make sure the vlt.json config, or the "workspaces" field of the root package.json, contains the correct workspaces.`);
61
61
  if (vlt.get('workspace')) {
62
62
  stderr(indent(`Workspace: ${format(vlt.get('workspace'))}`));
63
63
  }
@@ -12,6 +12,8 @@ export type PackTarballResult = {
12
12
  shasum?: string;
13
13
  /** The manifest used for packing (may differ from input when publishConfig.directory is set). */
14
14
  resolvedManifest: NormalizedManifest;
15
+ /** The directory that was packed (differs from input when publishConfig.directory is set). */
16
+ packDir: string;
15
17
  };
16
18
  /**
17
19
  * Build the tar filter function for packing.
@@ -282,6 +282,7 @@ export const packTarball = async (manifest, dir, config) => {
282
282
  integrity,
283
283
  shasum,
284
284
  resolvedManifest: processedManifest,
285
+ packDir,
285
286
  };
286
287
  }
287
288
  finally {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/cli-sdk",
3
3
  "description": "The source for the vlt CLI",
4
- "version": "1.2.0",
4
+ "version": "1.3.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -14,31 +14,31 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@resvg/resvg-wasm": "^2.6.2",
17
- "@vltpkg/config": "1.2.0",
18
- "@vltpkg/dep-id": "1.2.0",
19
- "@vltpkg/dot-prop": "1.2.0",
20
- "@vltpkg/error-cause": "1.2.0",
21
- "@vltpkg/git": "1.2.0",
22
- "@vltpkg/graph": "1.2.0",
23
- "@vltpkg/graph-run": "1.2.0",
24
- "@vltpkg/init": "1.2.0",
25
- "@vltpkg/output": "1.2.0",
26
- "@vltpkg/package-info": "1.2.0",
27
- "@vltpkg/package-json": "1.2.0",
28
- "@vltpkg/promise-spawn": "1.2.0",
29
- "@vltpkg/query": "1.2.0",
30
- "@vltpkg/registry-client": "1.2.0",
31
- "@vltpkg/rollback-remove": "1.2.0",
32
- "@vltpkg/run": "1.2.0",
33
- "@vltpkg/security-archive": "1.2.0",
34
- "@vltpkg/spec": "1.2.0",
35
- "@vltpkg/tar": "1.2.0",
36
- "@vltpkg/types": "1.2.0",
37
- "@vltpkg/url-open": "1.2.0",
38
- "@vltpkg/vlt-json": "1.2.0",
39
- "@vltpkg/vlx": "1.2.0",
40
- "@vltpkg/workspaces": "1.2.0",
41
- "@vltpkg/xdg": "1.2.0",
17
+ "@vltpkg/config": "1.3.1",
18
+ "@vltpkg/dep-id": "1.3.1",
19
+ "@vltpkg/dot-prop": "1.3.1",
20
+ "@vltpkg/error-cause": "1.3.1",
21
+ "@vltpkg/git": "1.3.1",
22
+ "@vltpkg/graph": "1.3.1",
23
+ "@vltpkg/graph-run": "1.3.1",
24
+ "@vltpkg/init": "1.3.1",
25
+ "@vltpkg/output": "1.3.1",
26
+ "@vltpkg/package-info": "1.3.1",
27
+ "@vltpkg/package-json": "1.3.1",
28
+ "@vltpkg/promise-spawn": "1.3.1",
29
+ "@vltpkg/query": "1.3.1",
30
+ "@vltpkg/registry-client": "1.3.1",
31
+ "@vltpkg/rollback-remove": "1.3.1",
32
+ "@vltpkg/run": "1.3.1",
33
+ "@vltpkg/security-archive": "1.3.1",
34
+ "@vltpkg/spec": "1.3.1",
35
+ "@vltpkg/tar": "1.3.1",
36
+ "@vltpkg/types": "1.3.1",
37
+ "@vltpkg/url-open": "1.3.1",
38
+ "@vltpkg/vlt-json": "1.3.1",
39
+ "@vltpkg/vlx": "1.3.1",
40
+ "@vltpkg/workspaces": "1.3.1",
41
+ "@vltpkg/xdg": "1.3.1",
42
42
  "ansi-to-pre": "^1.0.6",
43
43
  "beautiful-mermaid": "^1.1.3",
44
44
  "chalk": "^5.6.2",
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@eslint/js": "^9.39.1",
65
65
  "@types/node": "^22.19.2",
66
- "@types/react": "^18.3.27",
66
+ "@types/react": "^19",
67
67
  "@types/ssri": "^7.1.5",
68
68
  "eslint": "^9.39.1",
69
69
  "prettier": "^3.7.4",