@backstage/cli-node 0.2.19-next.0 → 0.2.19-next.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @backstage/cli-node
2
2
 
3
+ ## 0.2.19-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 61cb976: Added `toString()` method to `Lockfile` for serializing lockfiles back to string format.
8
+ - 3c811bf: Added `hasBackstageYarnPlugin` and `SuccessCache` exports, moved from `@backstage/cli`.
9
+ - a9d23c4: Properly support `package.json` `workspaces` field
10
+ - Updated dependencies
11
+ - @backstage/cli-common@0.2.0-next.1
12
+ - @backstage/errors@1.2.7
13
+ - @backstage/types@1.2.2
14
+
3
15
  ## 0.2.19-next.0
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs-extra');
4
+ var path = require('node:path');
5
+ var cliCommon = require('@backstage/cli-common');
6
+
7
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
+
9
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
10
+
11
+ const DEFAULT_CACHE_BASE_PATH = "node_modules/.cache/backstage-cli";
12
+ const CACHE_MAX_AGE_MS = 7 * 24 * 36e5;
13
+ class SuccessCache {
14
+ #path;
15
+ /**
16
+ * Trim any occurrences of the workspace root path from the input string. This
17
+ * is useful to ensure stable hashes that don't vary based on the workspace
18
+ * location.
19
+ */
20
+ static trimPaths(input) {
21
+ return input.replaceAll(cliCommon.targetPaths.rootDir, "");
22
+ }
23
+ static create(options) {
24
+ return new SuccessCache(options);
25
+ }
26
+ constructor(options) {
27
+ this.#path = path.resolve(
28
+ options.basePath ?? DEFAULT_CACHE_BASE_PATH,
29
+ options.name
30
+ );
31
+ }
32
+ async read() {
33
+ try {
34
+ const stat = await fs__default.default.stat(this.#path);
35
+ if (!stat.isDirectory()) {
36
+ await fs__default.default.rm(this.#path);
37
+ return /* @__PURE__ */ new Set();
38
+ }
39
+ } catch (error) {
40
+ if (error.code === "ENOENT") {
41
+ return /* @__PURE__ */ new Set();
42
+ }
43
+ throw error;
44
+ }
45
+ const items = await fs__default.default.readdir(this.#path);
46
+ const returned = /* @__PURE__ */ new Set();
47
+ const removed = /* @__PURE__ */ new Set();
48
+ const now = Date.now();
49
+ for (const item of items) {
50
+ const split = item.split("_");
51
+ if (split.length !== 2) {
52
+ removed.add(item);
53
+ continue;
54
+ }
55
+ const createdAt = parseInt(split[0], 10);
56
+ if (Number.isNaN(createdAt) || now - createdAt > CACHE_MAX_AGE_MS) {
57
+ removed.add(item);
58
+ } else {
59
+ returned.add(split[1]);
60
+ }
61
+ }
62
+ for (const item of removed) {
63
+ await fs__default.default.unlink(path.resolve(this.#path, item));
64
+ }
65
+ return returned;
66
+ }
67
+ async write(newEntries) {
68
+ const now = Date.now();
69
+ await fs__default.default.ensureDir(this.#path);
70
+ const existingItems = await fs__default.default.readdir(this.#path);
71
+ const empty = Buffer.alloc(0);
72
+ for (const key of newEntries) {
73
+ const trimmedItems = existingItems.filter(
74
+ (item) => item.endsWith(`_${key}`)
75
+ );
76
+ for (const trimmedItem of trimmedItems) {
77
+ await fs__default.default.unlink(path.resolve(this.#path, trimmedItem));
78
+ }
79
+ await fs__default.default.writeFile(path.resolve(this.#path, `${now}_${key}`), empty);
80
+ }
81
+ }
82
+ }
83
+
84
+ exports.SuccessCache = SuccessCache;
85
+ //# sourceMappingURL=SuccessCache.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuccessCache.cjs.js","sources":["../../src/cache/SuccessCache.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath } from 'node:path';\nimport { targetPaths } from '@backstage/cli-common';\n\nconst DEFAULT_CACHE_BASE_PATH = 'node_modules/.cache/backstage-cli';\n\nconst CACHE_MAX_AGE_MS = 7 * 24 * 3600_000;\n\n/**\n * A file-system-based cache that tracks successful operations by storing\n * timestamped marker files.\n *\n * @public\n */\nexport class SuccessCache {\n readonly #path: string;\n\n /**\n * Trim any occurrences of the workspace root path from the input string. This\n * is useful to ensure stable hashes that don't vary based on the workspace\n * location.\n */\n static trimPaths(input: string) {\n return input.replaceAll(targetPaths.rootDir, '');\n }\n\n static create(options: { name: string; basePath?: string }): SuccessCache {\n return new SuccessCache(options);\n }\n\n private constructor(options: { name: string; basePath?: string }) {\n this.#path = resolvePath(\n options.basePath ?? DEFAULT_CACHE_BASE_PATH,\n options.name,\n );\n }\n\n async read(): Promise<Set<string>> {\n try {\n const stat = await fs.stat(this.#path);\n if (!stat.isDirectory()) {\n await fs.rm(this.#path);\n return new Set();\n }\n } catch (error) {\n if (error.code === 'ENOENT') {\n return new Set();\n }\n throw error;\n }\n\n const items = await fs.readdir(this.#path);\n\n const returned = new Set<string>();\n const removed = new Set<string>();\n\n const now = Date.now();\n\n for (const item of items) {\n const split = item.split('_');\n if (split.length !== 2) {\n removed.add(item);\n continue;\n }\n const createdAt = parseInt(split[0], 10);\n if (Number.isNaN(createdAt) || now - createdAt > CACHE_MAX_AGE_MS) {\n removed.add(item);\n } else {\n returned.add(split[1]);\n }\n }\n\n for (const item of removed) {\n await fs.unlink(resolvePath(this.#path, item));\n }\n\n return returned;\n }\n\n async write(newEntries: Iterable<string>): Promise<void> {\n const now = Date.now();\n\n await fs.ensureDir(this.#path);\n\n const existingItems = await fs.readdir(this.#path);\n\n const empty = Buffer.alloc(0);\n for (const key of newEntries) {\n const trimmedItems = existingItems.filter(item =>\n item.endsWith(`_${key}`),\n );\n for (const trimmedItem of trimmedItems) {\n await fs.unlink(resolvePath(this.#path, trimmedItem));\n }\n\n await fs.writeFile(resolvePath(this.#path, `${now}_${key}`), empty);\n }\n }\n}\n"],"names":["targetPaths","resolvePath","fs"],"mappings":"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"}
package/dist/index.cjs.js CHANGED
@@ -1,21 +1,25 @@
1
1
  'use strict';
2
2
 
3
+ var SuccessCache = require('./cache/SuccessCache.cjs.js');
4
+ var runConcurrentTasks = require('./concurrency/runConcurrentTasks.cjs.js');
5
+ var runWorkerQueueThreads = require('./concurrency/runWorkerQueueThreads.cjs.js');
3
6
  var GitUtils = require('./git/GitUtils.cjs.js');
4
7
  var isMonoRepo = require('./monorepo/isMonoRepo.cjs.js');
5
8
  var PackageGraph = require('./monorepo/PackageGraph.cjs.js');
6
9
  var Lockfile = require('./monorepo/Lockfile.cjs.js');
7
- var runConcurrentTasks = require('./concurrency/runConcurrentTasks.cjs.js');
8
- var runWorkerQueueThreads = require('./concurrency/runWorkerQueueThreads.cjs.js');
9
10
  var PackageRoles = require('./roles/PackageRoles.cjs.js');
11
+ var yarnPlugin = require('./yarn/yarnPlugin.cjs.js');
10
12
 
11
13
 
12
14
 
15
+ exports.SuccessCache = SuccessCache.SuccessCache;
16
+ exports.runConcurrentTasks = runConcurrentTasks.runConcurrentTasks;
17
+ exports.runWorkerQueueThreads = runWorkerQueueThreads.runWorkerQueueThreads;
13
18
  exports.GitUtils = GitUtils.GitUtils;
14
19
  exports.isMonoRepo = isMonoRepo.isMonoRepo;
15
20
  exports.PackageGraph = PackageGraph.PackageGraph;
16
21
  exports.packageFeatureType = PackageGraph.packageFeatureType;
17
22
  exports.Lockfile = Lockfile.Lockfile;
18
- exports.runConcurrentTasks = runConcurrentTasks.runConcurrentTasks;
19
- exports.runWorkerQueueThreads = runWorkerQueueThreads.runWorkerQueueThreads;
20
23
  exports.PackageRoles = PackageRoles.PackageRoles;
24
+ exports.hasBackstageYarnPlugin = yarnPlugin.hasBackstageYarnPlugin;
21
25
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,87 @@
1
1
  import { Package } from '@manypkg/get-packages';
2
2
  import { JsonValue } from '@backstage/types';
3
3
 
4
+ /**
5
+ * A file-system-based cache that tracks successful operations by storing
6
+ * timestamped marker files.
7
+ *
8
+ * @public
9
+ */
10
+ declare class SuccessCache {
11
+ #private;
12
+ /**
13
+ * Trim any occurrences of the workspace root path from the input string. This
14
+ * is useful to ensure stable hashes that don't vary based on the workspace
15
+ * location.
16
+ */
17
+ static trimPaths(input: string): string;
18
+ static create(options: {
19
+ name: string;
20
+ basePath?: string;
21
+ }): SuccessCache;
22
+ private constructor();
23
+ read(): Promise<Set<string>>;
24
+ write(newEntries: Iterable<string>): Promise<void>;
25
+ }
26
+
27
+ /**
28
+ * Options for {@link runConcurrentTasks}.
29
+ *
30
+ * @public
31
+ */
32
+ type ConcurrentTasksOptions<TItem> = {
33
+ /**
34
+ * Decides the number of concurrent workers by multiplying
35
+ * this with the configured concurrency.
36
+ *
37
+ * Defaults to 1.
38
+ */
39
+ concurrencyFactor?: number;
40
+ items: Iterable<TItem>;
41
+ worker: (item: TItem) => Promise<void>;
42
+ };
43
+ /**
44
+ * Runs items through a worker function concurrently across multiple async workers.
45
+ *
46
+ * @public
47
+ */
48
+ declare function runConcurrentTasks<TItem>(options: ConcurrentTasksOptions<TItem>): Promise<void>;
49
+
50
+ /**
51
+ * Options for {@link runWorkerQueueThreads}.
52
+ *
53
+ * @public
54
+ */
55
+ type WorkerQueueThreadsOptions<TItem, TResult, TContext> = {
56
+ /** The items to process */
57
+ items: Iterable<TItem>;
58
+ /**
59
+ * A function that will be called within each worker thread at startup,
60
+ * which should return the worker function that will be called for each item.
61
+ *
62
+ * This function must be defined as an arrow function or using the
63
+ * function keyword, and must be entirely self contained, not referencing
64
+ * any variables outside of its scope. This is because the function source
65
+ * is stringified and evaluated in the worker thread.
66
+ *
67
+ * To pass data to the worker, use the `context` option and `items`, but
68
+ * note that they are both copied by value into the worker thread, except for
69
+ * types that are explicitly shareable across threads, such as `SharedArrayBuffer`.
70
+ */
71
+ workerFactory: (context: TContext) => ((item: TItem) => Promise<TResult>) | Promise<(item: TItem) => Promise<TResult>>;
72
+ /** Context data supplied to each worker factory */
73
+ context?: TContext;
74
+ };
75
+ /**
76
+ * Spawns one or more worker threads using the `worker_threads` module.
77
+ * Each thread processes one item at a time from the provided `options.items`.
78
+ *
79
+ * @public
80
+ */
81
+ declare function runWorkerQueueThreads<TItem, TResult, TContext>(options: WorkerQueueThreadsOptions<TItem, TResult, TContext>): Promise<{
82
+ results: TResult[];
83
+ }>;
84
+
4
85
  /**
5
86
  * Utilities for working with git.
6
87
  *
@@ -19,7 +100,10 @@ declare class GitUtils {
19
100
  }
20
101
 
21
102
  /**
22
- * Returns try if the current project is a monorepo.
103
+ * Returns true if the current project is a monorepo.
104
+ *
105
+ * Uses a simple presence check on the `workspaces` field. Empty or invalid
106
+ * workspace config is treated as a monorepo; we do not validate patterns.
23
107
  *
24
108
  * @public
25
109
  */
@@ -286,11 +370,16 @@ declare class Lockfile {
286
370
  static parse(content: string): Lockfile;
287
371
  private readonly packages;
288
372
  private readonly data;
373
+ private readonly legacy;
289
374
  private constructor();
290
375
  /** Returns the name of all packages available in the lockfile */
291
376
  get(name: string): LockfileQueryEntry[] | undefined;
292
377
  /** Get the entries for a single package in the lockfile */
293
378
  keys(): IterableIterator<string>;
379
+ /**
380
+ * Serialize the lockfile back to a string.
381
+ */
382
+ toString(): string;
294
383
  /**
295
384
  * Creates a simplified dependency graph from the lockfile data, where each
296
385
  * key is a package, and the value is a set of all packages that it depends on
@@ -309,62 +398,13 @@ declare class Lockfile {
309
398
  }
310
399
 
311
400
  /**
312
- * Options for {@link runConcurrentTasks}.
401
+ * Detects whether the Backstage Yarn plugin is installed in the given workspace directory.
313
402
  *
403
+ * @param workspaceDir - The workspace root directory to check. Defaults to the target root.
404
+ * @returns Promise resolving to true if the plugin is installed, false otherwise
314
405
  * @public
315
406
  */
316
- type ConcurrentTasksOptions<TItem> = {
317
- /**
318
- * Decides the number of concurrent workers by multiplying
319
- * this with the configured concurrency.
320
- *
321
- * Defaults to 1.
322
- */
323
- concurrencyFactor?: number;
324
- items: Iterable<TItem>;
325
- worker: (item: TItem) => Promise<void>;
326
- };
327
- /**
328
- * Runs items through a worker function concurrently across multiple async workers.
329
- *
330
- * @public
331
- */
332
- declare function runConcurrentTasks<TItem>(options: ConcurrentTasksOptions<TItem>): Promise<void>;
333
-
334
- /**
335
- * Options for {@link runWorkerQueueThreads}.
336
- *
337
- * @public
338
- */
339
- type WorkerQueueThreadsOptions<TItem, TResult, TContext> = {
340
- /** The items to process */
341
- items: Iterable<TItem>;
342
- /**
343
- * A function that will be called within each worker thread at startup,
344
- * which should return the worker function that will be called for each item.
345
- *
346
- * This function must be defined as an arrow function or using the
347
- * function keyword, and must be entirely self contained, not referencing
348
- * any variables outside of its scope. This is because the function source
349
- * is stringified and evaluated in the worker thread.
350
- *
351
- * To pass data to the worker, use the `context` option and `items`, but
352
- * note that they are both copied by value into the worker thread, except for
353
- * types that are explicitly shareable across threads, such as `SharedArrayBuffer`.
354
- */
355
- workerFactory: (context: TContext) => ((item: TItem) => Promise<TResult>) | Promise<(item: TItem) => Promise<TResult>>;
356
- /** Context data supplied to each worker factory */
357
- context?: TContext;
358
- };
359
- /**
360
- * Spawns one or more worker threads using the `worker_threads` module.
361
- * Each thread processes one item at a time from the provided `options.items`.
362
- *
363
- * @public
364
- */
365
- declare function runWorkerQueueThreads<TItem, TResult, TContext>(options: WorkerQueueThreadsOptions<TItem, TResult, TContext>): Promise<{
366
- results: TResult[];
367
- }>;
407
+ declare function hasBackstageYarnPlugin(workspaceDir?: string): Promise<boolean>;
368
408
 
369
- export { GitUtils, Lockfile, PackageGraph, PackageRoles, isMonoRepo, packageFeatureType, runConcurrentTasks, runWorkerQueueThreads };
409
+ export { GitUtils, Lockfile, PackageGraph, PackageRoles, SuccessCache, hasBackstageYarnPlugin, isMonoRepo, packageFeatureType, runConcurrentTasks, runWorkerQueueThreads };
370
410
  export type { BackstagePackage, BackstagePackageFeatureType, BackstagePackageJson, ConcurrentTasksOptions, LockfileDiff, LockfileDiffEntry, LockfileQueryEntry, PackageGraphNode, PackageOutputType, PackagePlatform, PackageRole, PackageRoleInfo, WorkerQueueThreadsOptions };
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var parsers = require('@yarnpkg/parsers');
4
+ var lockfile = require('@yarnpkg/lockfile');
4
5
  var crypto = require('node:crypto');
5
6
  var fs = require('fs-extra');
6
7
 
@@ -10,6 +11,14 @@ var crypto__default = /*#__PURE__*/_interopDefaultCompat(crypto);
10
11
  var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
11
12
 
12
13
  const ENTRY_PATTERN = /^((?:@[^/]+\/)?[^@/]+)@(.+)$/;
14
+ const NEW_HEADER = `${[
15
+ `# This file is generated by running "yarn install" inside your project.
16
+ `,
17
+ `# Manual changes might be lost - proceed with caution!
18
+ `
19
+ ].join(``)}
20
+ `;
21
+ const LEGACY_REGEX = /^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i;
13
22
  const SPECIAL_OBJECT_KEYS = [
14
23
  `__metadata`,
15
24
  `version`,
@@ -34,6 +43,7 @@ class Lockfile {
34
43
  * @public
35
44
  */
36
45
  static parse(content) {
46
+ const legacy = LEGACY_REGEX.test(content);
37
47
  let data;
38
48
  try {
39
49
  data = parsers.parseSyml(content);
@@ -62,13 +72,15 @@ class Lockfile {
62
72
  queries.push({ range, version: value.version, dataKey: key });
63
73
  }
64
74
  }
65
- return new Lockfile(packages, data);
75
+ return new Lockfile(packages, data, legacy);
66
76
  }
67
77
  packages;
68
78
  data;
69
- constructor(packages, data) {
79
+ legacy;
80
+ constructor(packages, data, legacy = false) {
70
81
  this.packages = packages;
71
82
  this.data = data;
83
+ this.legacy = legacy;
72
84
  }
73
85
  /** Returns the name of all packages available in the lockfile */
74
86
  get(name) {
@@ -78,6 +90,12 @@ class Lockfile {
78
90
  keys() {
79
91
  return this.packages.keys();
80
92
  }
93
+ /**
94
+ * Serialize the lockfile back to a string.
95
+ */
96
+ toString() {
97
+ return this.legacy ? lockfile.stringify(this.data) : NEW_HEADER + parsers.stringifySyml(this.data);
98
+ }
81
99
  /**
82
100
  * Creates a simplified dependency graph from the lockfile data, where each
83
101
  * key is a package, and the value is a set of all packages that it depends on
@@ -1 +1 @@
1
- {"version":3,"file":"Lockfile.cjs.js","sources":["../../src/monorepo/Lockfile.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseSyml } from '@yarnpkg/parsers';\nimport crypto from 'node:crypto';\nimport fs from 'fs-extra';\n\nconst ENTRY_PATTERN = /^((?:@[^/]+\\/)?[^@/]+)@(.+)$/;\n\n/** @internal */\ntype LockfileData = {\n [entry: string]: {\n version: string;\n resolved?: string;\n integrity?: string /* old */;\n checksum?: string /* new */;\n dependencies?: { [name: string]: string };\n peerDependencies?: { [name: string]: string };\n };\n};\n\n/**\n * A single entry in a {@link Lockfile}.\n *\n * @public\n */\nexport type LockfileQueryEntry = {\n range: string;\n version: string;\n dataKey: string;\n};\n\n/**\n * An entry for a single difference between two {@link Lockfile}s.\n *\n * @public\n */\nexport type LockfileDiffEntry = {\n name: string;\n range: string;\n};\n\n/**\n * Represents the difference between two {@link Lockfile}s.\n *\n * @public\n */\nexport type LockfileDiff = {\n added: LockfileDiffEntry[];\n changed: LockfileDiffEntry[];\n removed: LockfileDiffEntry[];\n};\n\n// these are special top level yarn keys.\n// https://github.com/yarnpkg/berry/blob/9bd61fbffb83d0b8166a9cc26bec3a58743aa453/packages/yarnpkg-parsers/sources/syml.ts#L9\nconst SPECIAL_OBJECT_KEYS = [\n `__metadata`,\n `version`,\n `resolution`,\n `dependencies`,\n `peerDependencies`,\n `dependenciesMeta`,\n `peerDependenciesMeta`,\n `binaries`,\n];\n\n/**\n * Represents a package manager lockfile.\n *\n * @public\n */\nexport class Lockfile {\n /**\n * Load a {@link Lockfile} from a file path.\n */\n static async load(path: string): Promise<Lockfile> {\n const lockfileContents = await fs.readFile(path, 'utf8');\n return Lockfile.parse(lockfileContents);\n }\n\n /**\n * Parse lockfile contents into a {@link Lockfile}.\n *\n * @public\n */\n static parse(content: string): Lockfile {\n let data: LockfileData;\n try {\n data = parseSyml(content);\n } catch (err) {\n throw new Error(`Failed yarn.lock parse, ${err}`);\n }\n\n const packages = new Map<string, LockfileQueryEntry[]>();\n\n for (const [key, value] of Object.entries(data)) {\n if (SPECIAL_OBJECT_KEYS.includes(key)) continue;\n\n const [, name, ranges] = ENTRY_PATTERN.exec(key) ?? [];\n if (!name) {\n throw new Error(`Failed to parse yarn.lock entry '${key}'`);\n }\n\n let queries = packages.get(name);\n if (!queries) {\n queries = [];\n packages.set(name, queries);\n }\n for (let range of ranges.split(/\\s*,\\s*/)) {\n if (range.startsWith(`${name}@`)) {\n range = range.slice(`${name}@`.length);\n }\n if (range.startsWith('npm:')) {\n range = range.slice('npm:'.length);\n }\n queries.push({ range, version: value.version, dataKey: key });\n }\n }\n\n return new Lockfile(packages, data);\n }\n\n private readonly packages: Map<string, LockfileQueryEntry[]>;\n private readonly data: LockfileData;\n\n private constructor(\n packages: Map<string, LockfileQueryEntry[]>,\n data: LockfileData,\n ) {\n this.packages = packages;\n this.data = data;\n }\n\n /** Returns the name of all packages available in the lockfile */\n get(name: string): LockfileQueryEntry[] | undefined {\n return this.packages.get(name);\n }\n\n /** Get the entries for a single package in the lockfile */\n keys(): IterableIterator<string> {\n return this.packages.keys();\n }\n\n /**\n * Creates a simplified dependency graph from the lockfile data, where each\n * key is a package, and the value is a set of all packages that it depends on\n * across all versions.\n */\n createSimplifiedDependencyGraph(): Map<string, Set<string>> {\n const graph = new Map<string, Set<string>>();\n\n for (const [name, entries] of this.packages) {\n const dependencies = new Set(\n entries.flatMap(e => {\n const data = this.data[e.dataKey];\n return [\n ...Object.keys(data?.dependencies ?? {}),\n ...Object.keys(data?.peerDependencies ?? {}),\n ];\n }),\n );\n graph.set(name, dependencies);\n }\n\n return graph;\n }\n\n /**\n * Diff with another lockfile, returning entries that have been\n * added, changed, and removed compared to the other lockfile.\n */\n diff(otherLockfile: Lockfile): LockfileDiff {\n const diff = {\n added: new Array<{ name: string; range: string }>(),\n changed: new Array<{ name: string; range: string }>(),\n removed: new Array<{ name: string; range: string }>(),\n };\n\n // Keeps track of packages that only exist in this lockfile\n const remainingOldNames = new Set(this.packages.keys());\n\n for (const [name, otherQueries] of otherLockfile.packages) {\n remainingOldNames.delete(name);\n\n const thisQueries = this.packages.get(name);\n // If the packages doesn't exist in this lockfile, add all entries\n if (!thisQueries) {\n diff.removed.push(...otherQueries.map(q => ({ name, range: q.range })));\n continue;\n }\n\n const remainingOldRanges = new Set(thisQueries.map(q => q.range));\n\n for (const otherQuery of otherQueries) {\n remainingOldRanges.delete(otherQuery.range);\n\n const thisQuery = thisQueries.find(q => q.range === otherQuery.range);\n if (!thisQuery) {\n diff.removed.push({ name, range: otherQuery.range });\n continue;\n }\n\n const otherPkg = otherLockfile.data[otherQuery.dataKey];\n const thisPkg = this.data[thisQuery.dataKey];\n if (otherPkg && thisPkg) {\n const thisCheck = thisPkg.integrity || thisPkg.checksum;\n const otherCheck = otherPkg.integrity || otherPkg.checksum;\n if (thisCheck !== otherCheck) {\n diff.changed.push({ name, range: otherQuery.range });\n }\n }\n }\n\n for (const thisRange of remainingOldRanges) {\n diff.added.push({ name, range: thisRange });\n }\n }\n\n for (const name of remainingOldNames) {\n const queries = this.packages.get(name) ?? [];\n diff.added.push(...queries.map(q => ({ name, range: q.range })));\n }\n\n return diff;\n }\n\n /**\n * Generates a sha1 hex hash of the dependency graph for a package.\n */\n getDependencyTreeHash(startName: string): string {\n if (!this.packages.has(startName)) {\n throw new Error(`Package '${startName}' not found in lockfile`);\n }\n\n const hash = crypto.createHash('sha1');\n\n const queue = [startName];\n const seen = new Set<string>();\n\n while (queue.length > 0) {\n const name = queue.pop()!;\n\n if (seen.has(name)) {\n continue;\n }\n seen.add(name);\n\n const entries = this.packages.get(name);\n if (!entries) {\n continue; // In case of missing optional peer dependencies\n }\n\n hash.update(`pkg:${name}`);\n hash.update('\\0');\n\n // TODO(Rugvip): This uses the same simplified lookup as createSimplifiedDependencyGraph()\n // we could match version queries to make the resulting tree a bit smaller.\n const deps = new Array<string>();\n for (const entry of entries) {\n // We're not being particular about stable ordering here. If the lockfile ordering changes, so will likely hash.\n hash.update(entry.version);\n\n const data = this.data[entry.dataKey];\n if (!data) {\n continue;\n }\n\n const checksum = data.checksum || data.integrity;\n if (checksum) {\n hash.update('#');\n hash.update(checksum);\n }\n\n hash.update(' ');\n\n deps.push(...Object.keys(data.dependencies ?? {}));\n deps.push(...Object.keys(data.peerDependencies ?? {}));\n }\n\n queue.push(...new Set(deps));\n }\n\n return hash.digest('hex');\n }\n}\n"],"names":["fs","parseSyml","crypto"],"mappings":"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"}
1
+ {"version":3,"file":"Lockfile.cjs.js","sources":["../../src/monorepo/Lockfile.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { parseSyml, stringifySyml } from '@yarnpkg/parsers';\nimport { stringify as legacyStringifyLockfile } from '@yarnpkg/lockfile';\nimport crypto from 'node:crypto';\nimport fs from 'fs-extra';\n\nconst ENTRY_PATTERN = /^((?:@[^/]+\\/)?[^@/]+)@(.+)$/;\n\n// https://github.com/yarnpkg/berry/blob/0c5974f193a9397630e9aee2b3876cca62611149/packages/yarnpkg-core/sources/Project.ts#L1741-L1746\nconst NEW_HEADER = `${[\n `# This file is generated by running \"yarn install\" inside your project.\\n`,\n `# Manual changes might be lost - proceed with caution!\\n`,\n].join(``)}\\n`;\n\n// https://github.com/yarnpkg/berry/blob/0c5974f193a9397630e9aee2b3876cca62611149/packages/yarnpkg-parsers/sources/syml.ts#L136\nconst LEGACY_REGEX = /^(#.*(\\r?\\n))*?#\\s+yarn\\s+lockfile\\s+v1\\r?\\n/i;\n\n/** @internal */\ntype LockfileData = {\n [entry: string]: {\n version: string;\n resolved?: string;\n integrity?: string /* old */;\n checksum?: string /* new */;\n dependencies?: { [name: string]: string };\n peerDependencies?: { [name: string]: string };\n };\n};\n\n/**\n * A single entry in a {@link Lockfile}.\n *\n * @public\n */\nexport type LockfileQueryEntry = {\n range: string;\n version: string;\n dataKey: string;\n};\n\n/**\n * An entry for a single difference between two {@link Lockfile}s.\n *\n * @public\n */\nexport type LockfileDiffEntry = {\n name: string;\n range: string;\n};\n\n/**\n * Represents the difference between two {@link Lockfile}s.\n *\n * @public\n */\nexport type LockfileDiff = {\n added: LockfileDiffEntry[];\n changed: LockfileDiffEntry[];\n removed: LockfileDiffEntry[];\n};\n\n// these are special top level yarn keys.\n// https://github.com/yarnpkg/berry/blob/9bd61fbffb83d0b8166a9cc26bec3a58743aa453/packages/yarnpkg-parsers/sources/syml.ts#L9\nconst SPECIAL_OBJECT_KEYS = [\n `__metadata`,\n `version`,\n `resolution`,\n `dependencies`,\n `peerDependencies`,\n `dependenciesMeta`,\n `peerDependenciesMeta`,\n `binaries`,\n];\n\n/**\n * Represents a package manager lockfile.\n *\n * @public\n */\nexport class Lockfile {\n /**\n * Load a {@link Lockfile} from a file path.\n */\n static async load(path: string): Promise<Lockfile> {\n const lockfileContents = await fs.readFile(path, 'utf8');\n return Lockfile.parse(lockfileContents);\n }\n\n /**\n * Parse lockfile contents into a {@link Lockfile}.\n *\n * @public\n */\n static parse(content: string): Lockfile {\n const legacy = LEGACY_REGEX.test(content);\n\n let data: LockfileData;\n try {\n data = parseSyml(content);\n } catch (err) {\n throw new Error(`Failed yarn.lock parse, ${err}`);\n }\n\n const packages = new Map<string, LockfileQueryEntry[]>();\n\n for (const [key, value] of Object.entries(data)) {\n if (SPECIAL_OBJECT_KEYS.includes(key)) continue;\n\n const [, name, ranges] = ENTRY_PATTERN.exec(key) ?? [];\n if (!name) {\n throw new Error(`Failed to parse yarn.lock entry '${key}'`);\n }\n\n let queries = packages.get(name);\n if (!queries) {\n queries = [];\n packages.set(name, queries);\n }\n for (let range of ranges.split(/\\s*,\\s*/)) {\n if (range.startsWith(`${name}@`)) {\n range = range.slice(`${name}@`.length);\n }\n if (range.startsWith('npm:')) {\n range = range.slice('npm:'.length);\n }\n queries.push({ range, version: value.version, dataKey: key });\n }\n }\n\n return new Lockfile(packages, data, legacy);\n }\n\n private readonly packages: Map<string, LockfileQueryEntry[]>;\n private readonly data: LockfileData;\n private readonly legacy: boolean;\n\n private constructor(\n packages: Map<string, LockfileQueryEntry[]>,\n data: LockfileData,\n legacy: boolean = false,\n ) {\n this.packages = packages;\n this.data = data;\n this.legacy = legacy;\n }\n\n /** Returns the name of all packages available in the lockfile */\n get(name: string): LockfileQueryEntry[] | undefined {\n return this.packages.get(name);\n }\n\n /** Get the entries for a single package in the lockfile */\n keys(): IterableIterator<string> {\n return this.packages.keys();\n }\n\n /**\n * Serialize the lockfile back to a string.\n */\n toString(): string {\n return this.legacy\n ? legacyStringifyLockfile(this.data)\n : NEW_HEADER + stringifySyml(this.data);\n }\n\n /**\n * Creates a simplified dependency graph from the lockfile data, where each\n * key is a package, and the value is a set of all packages that it depends on\n * across all versions.\n */\n createSimplifiedDependencyGraph(): Map<string, Set<string>> {\n const graph = new Map<string, Set<string>>();\n\n for (const [name, entries] of this.packages) {\n const dependencies = new Set(\n entries.flatMap(e => {\n const data = this.data[e.dataKey];\n return [\n ...Object.keys(data?.dependencies ?? {}),\n ...Object.keys(data?.peerDependencies ?? {}),\n ];\n }),\n );\n graph.set(name, dependencies);\n }\n\n return graph;\n }\n\n /**\n * Diff with another lockfile, returning entries that have been\n * added, changed, and removed compared to the other lockfile.\n */\n diff(otherLockfile: Lockfile): LockfileDiff {\n const diff = {\n added: new Array<{ name: string; range: string }>(),\n changed: new Array<{ name: string; range: string }>(),\n removed: new Array<{ name: string; range: string }>(),\n };\n\n // Keeps track of packages that only exist in this lockfile\n const remainingOldNames = new Set(this.packages.keys());\n\n for (const [name, otherQueries] of otherLockfile.packages) {\n remainingOldNames.delete(name);\n\n const thisQueries = this.packages.get(name);\n // If the packages doesn't exist in this lockfile, add all entries\n if (!thisQueries) {\n diff.removed.push(...otherQueries.map(q => ({ name, range: q.range })));\n continue;\n }\n\n const remainingOldRanges = new Set(thisQueries.map(q => q.range));\n\n for (const otherQuery of otherQueries) {\n remainingOldRanges.delete(otherQuery.range);\n\n const thisQuery = thisQueries.find(q => q.range === otherQuery.range);\n if (!thisQuery) {\n diff.removed.push({ name, range: otherQuery.range });\n continue;\n }\n\n const otherPkg = otherLockfile.data[otherQuery.dataKey];\n const thisPkg = this.data[thisQuery.dataKey];\n if (otherPkg && thisPkg) {\n const thisCheck = thisPkg.integrity || thisPkg.checksum;\n const otherCheck = otherPkg.integrity || otherPkg.checksum;\n if (thisCheck !== otherCheck) {\n diff.changed.push({ name, range: otherQuery.range });\n }\n }\n }\n\n for (const thisRange of remainingOldRanges) {\n diff.added.push({ name, range: thisRange });\n }\n }\n\n for (const name of remainingOldNames) {\n const queries = this.packages.get(name) ?? [];\n diff.added.push(...queries.map(q => ({ name, range: q.range })));\n }\n\n return diff;\n }\n\n /**\n * Generates a sha1 hex hash of the dependency graph for a package.\n */\n getDependencyTreeHash(startName: string): string {\n if (!this.packages.has(startName)) {\n throw new Error(`Package '${startName}' not found in lockfile`);\n }\n\n const hash = crypto.createHash('sha1');\n\n const queue = [startName];\n const seen = new Set<string>();\n\n while (queue.length > 0) {\n const name = queue.pop()!;\n\n if (seen.has(name)) {\n continue;\n }\n seen.add(name);\n\n const entries = this.packages.get(name);\n if (!entries) {\n continue; // In case of missing optional peer dependencies\n }\n\n hash.update(`pkg:${name}`);\n hash.update('\\0');\n\n // TODO(Rugvip): This uses the same simplified lookup as createSimplifiedDependencyGraph()\n // we could match version queries to make the resulting tree a bit smaller.\n const deps = new Array<string>();\n for (const entry of entries) {\n // We're not being particular about stable ordering here. If the lockfile ordering changes, so will likely hash.\n hash.update(entry.version);\n\n const data = this.data[entry.dataKey];\n if (!data) {\n continue;\n }\n\n const checksum = data.checksum || data.integrity;\n if (checksum) {\n hash.update('#');\n hash.update(checksum);\n }\n\n hash.update(' ');\n\n deps.push(...Object.keys(data.dependencies ?? {}));\n deps.push(...Object.keys(data.peerDependencies ?? {}));\n }\n\n queue.push(...new Set(deps));\n }\n\n return hash.digest('hex');\n }\n}\n"],"names":["fs","parseSyml","legacyStringifyLockfile","stringifySyml","crypto"],"mappings":"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"}
@@ -11,7 +11,7 @@ async function isMonoRepo() {
11
11
  const rootPackageJsonPath = cliCommon.targetPaths.resolveRoot("package.json");
12
12
  try {
13
13
  const pkg = await fs__default.default.readJson(rootPackageJsonPath);
14
- return Boolean(pkg?.workspaces?.packages);
14
+ return Boolean(pkg?.workspaces);
15
15
  } catch (error) {
16
16
  return false;
17
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"isMonoRepo.cjs.js","sources":["../../src/monorepo/isMonoRepo.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { targetPaths } from '@backstage/cli-common';\nimport fs from 'fs-extra';\n\n/**\n * Returns try if the current project is a monorepo.\n *\n * @public\n */\nexport async function isMonoRepo(): Promise<boolean> {\n const rootPackageJsonPath = targetPaths.resolveRoot('package.json');\n try {\n const pkg = await fs.readJson(rootPackageJsonPath);\n return Boolean(pkg?.workspaces?.packages);\n } catch (error) {\n return false;\n }\n}\n"],"names":["targetPaths","fs"],"mappings":";;;;;;;;;AAwBA,eAAsB,UAAA,GAA+B;AACnD,EAAA,MAAM,mBAAA,GAAsBA,qBAAA,CAAY,WAAA,CAAY,cAAc,CAAA;AAClE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAMC,mBAAA,CAAG,QAAA,CAAS,mBAAmB,CAAA;AACjD,IAAA,OAAO,OAAA,CAAQ,GAAA,EAAK,UAAA,EAAY,QAAQ,CAAA;AAAA,EAC1C,SAAS,KAAA,EAAO;AACd,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;;"}
1
+ {"version":3,"file":"isMonoRepo.cjs.js","sources":["../../src/monorepo/isMonoRepo.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { targetPaths } from '@backstage/cli-common';\nimport fs from 'fs-extra';\n\n/**\n * Returns true if the current project is a monorepo.\n *\n * Uses a simple presence check on the `workspaces` field. Empty or invalid\n * workspace config is treated as a monorepo; we do not validate patterns.\n *\n * @public\n */\nexport async function isMonoRepo(): Promise<boolean> {\n const rootPackageJsonPath = targetPaths.resolveRoot('package.json');\n try {\n const pkg = await fs.readJson(rootPackageJsonPath);\n return Boolean(pkg?.workspaces);\n } catch (error) {\n return false;\n }\n}\n"],"names":["targetPaths","fs"],"mappings":";;;;;;;;;AA2BA,eAAsB,UAAA,GAA+B;AACnD,EAAA,MAAM,mBAAA,GAAsBA,qBAAA,CAAY,WAAA,CAAY,cAAc,CAAA;AAClE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAMC,mBAAA,CAAG,QAAA,CAAS,mBAAmB,CAAA;AACjD,IAAA,OAAO,OAAA,CAAQ,KAAK,UAAU,CAAA;AAAA,EAChC,SAAS,KAAA,EAAO;AACd,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var zod = require('zod');
3
+ var z = require('zod');
4
4
 
5
5
  const packageRoleInfos = [
6
6
  {
@@ -60,26 +60,26 @@ const packageRoleInfos = [
60
60
  output: ["types", "cjs"]
61
61
  }
62
62
  ];
63
- const readSchema = zod.z.object({
64
- name: zod.z.string().optional(),
65
- backstage: zod.z.object({
66
- role: zod.z.string().optional()
63
+ const readSchema = z.z.object({
64
+ name: z.z.string().optional(),
65
+ backstage: z.z.object({
66
+ role: z.z.string().optional()
67
67
  }).optional()
68
68
  });
69
- const detectionSchema = zod.z.object({
70
- name: zod.z.string().optional(),
71
- scripts: zod.z.object({
72
- start: zod.z.string().optional(),
73
- build: zod.z.string().optional()
69
+ const detectionSchema = z.z.object({
70
+ name: z.z.string().optional(),
71
+ scripts: z.z.object({
72
+ start: z.z.string().optional(),
73
+ build: z.z.string().optional()
74
74
  }).optional(),
75
- publishConfig: zod.z.object({
76
- main: zod.z.string().optional(),
77
- types: zod.z.string().optional(),
78
- module: zod.z.string().optional()
75
+ publishConfig: z.z.object({
76
+ main: z.z.string().optional(),
77
+ types: z.z.string().optional(),
78
+ module: z.z.string().optional()
79
79
  }).optional(),
80
- main: zod.z.string().optional(),
81
- types: zod.z.string().optional(),
82
- module: zod.z.string().optional()
80
+ main: z.z.string().optional(),
81
+ types: z.z.string().optional(),
82
+ module: z.z.string().optional()
83
83
  });
84
84
  class PackageRoles {
85
85
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"PackageRoles.cjs.js","sources":["../../src/roles/PackageRoles.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod';\nimport { PackageRole, PackageRoleInfo } from './types';\n\nconst packageRoleInfos: PackageRoleInfo[] = [\n {\n role: 'frontend',\n platform: 'web',\n output: ['bundle'],\n },\n {\n role: 'backend',\n platform: 'node',\n output: ['bundle'],\n },\n {\n role: 'cli',\n platform: 'node',\n output: ['cjs'],\n },\n {\n role: 'web-library',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'node-library',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n {\n role: 'common-library',\n platform: 'common',\n output: ['types', 'esm', 'cjs'],\n },\n {\n role: 'frontend-plugin',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'frontend-plugin-module',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'frontend-dynamic-container' as PackageRole, // experimental\n platform: 'web',\n output: ['bundle'],\n },\n {\n role: 'backend-plugin',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n {\n role: 'backend-plugin-module',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n];\n\nconst readSchema = z.object({\n name: z.string().optional(),\n backstage: z\n .object({\n role: z.string().optional(),\n })\n .optional(),\n});\n\nconst detectionSchema = z.object({\n name: z.string().optional(),\n scripts: z\n .object({\n start: z.string().optional(),\n build: z.string().optional(),\n })\n .optional(),\n publishConfig: z\n .object({\n main: z.string().optional(),\n types: z.string().optional(),\n module: z.string().optional(),\n })\n .optional(),\n main: z.string().optional(),\n types: z.string().optional(),\n module: z.string().optional(),\n});\n\n/**\n * Utilities for working with Backstage package roles.\n *\n * @public\n */\nexport class PackageRoles {\n /**\n * Get the associated info for a package role.\n */\n static getRoleInfo(role: string): PackageRoleInfo {\n const roleInfo = packageRoleInfos.find(r => r.role === role);\n if (!roleInfo) {\n throw new Error(`Unknown package role '${role}'`);\n }\n return roleInfo;\n }\n\n /**\n * Given package JSON data, get the package role.\n */\n static getRoleFromPackage(pkgJson: unknown): PackageRole | undefined {\n const pkg = readSchema.parse(pkgJson);\n\n if (pkg.backstage) {\n const { role } = pkg.backstage;\n if (!role) {\n throw new Error(\n `Package ${pkg.name} must specify a role in the \"backstage\" field`,\n );\n }\n\n return this.getRoleInfo(role).role;\n }\n\n return undefined;\n }\n\n /**\n * Attempt to detect the role of a package from its package.json.\n */\n static detectRoleFromPackage(pkgJson: unknown): PackageRole | undefined {\n const pkg = detectionSchema.parse(pkgJson);\n\n if (pkg.scripts?.start?.includes('app:serve')) {\n return 'frontend';\n }\n if (pkg.scripts?.build?.includes('backend:bundle')) {\n return 'backend';\n }\n if (\n pkg.name?.includes('plugin-') &&\n pkg.name?.includes('-backend-module-')\n ) {\n return 'backend-plugin-module';\n }\n if (pkg.name?.includes('plugin-') && pkg.name?.includes('-module-')) {\n return 'frontend-plugin-module';\n }\n if (pkg.scripts?.start?.includes('plugin:serve')) {\n return 'frontend-plugin';\n }\n if (pkg.scripts?.start?.includes('backend:dev')) {\n return 'backend-plugin';\n }\n\n const mainEntry = pkg.publishConfig?.main || pkg.main;\n const moduleEntry = pkg.publishConfig?.module || pkg.module;\n const typesEntry = pkg.publishConfig?.types || pkg.types;\n if (typesEntry) {\n if (mainEntry && moduleEntry) {\n return 'common-library';\n }\n if (moduleEntry || mainEntry?.endsWith('.esm.js')) {\n return 'web-library';\n }\n if (mainEntry) {\n return 'node-library';\n }\n } else if (mainEntry) {\n return 'cli';\n }\n\n return undefined;\n }\n}\n"],"names":["z"],"mappings":"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"}
1
+ {"version":3,"file":"PackageRoles.cjs.js","sources":["../../src/roles/PackageRoles.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod';\nimport { PackageRole, PackageRoleInfo } from './types';\n\nconst packageRoleInfos: PackageRoleInfo[] = [\n {\n role: 'frontend',\n platform: 'web',\n output: ['bundle'],\n },\n {\n role: 'backend',\n platform: 'node',\n output: ['bundle'],\n },\n {\n role: 'cli',\n platform: 'node',\n output: ['cjs'],\n },\n {\n role: 'web-library',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'node-library',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n {\n role: 'common-library',\n platform: 'common',\n output: ['types', 'esm', 'cjs'],\n },\n {\n role: 'frontend-plugin',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'frontend-plugin-module',\n platform: 'web',\n output: ['types', 'esm'],\n },\n {\n role: 'frontend-dynamic-container' as PackageRole, // experimental\n platform: 'web',\n output: ['bundle'],\n },\n {\n role: 'backend-plugin',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n {\n role: 'backend-plugin-module',\n platform: 'node',\n output: ['types', 'cjs'],\n },\n];\n\nconst readSchema = z.object({\n name: z.string().optional(),\n backstage: z\n .object({\n role: z.string().optional(),\n })\n .optional(),\n});\n\nconst detectionSchema = z.object({\n name: z.string().optional(),\n scripts: z\n .object({\n start: z.string().optional(),\n build: z.string().optional(),\n })\n .optional(),\n publishConfig: z\n .object({\n main: z.string().optional(),\n types: z.string().optional(),\n module: z.string().optional(),\n })\n .optional(),\n main: z.string().optional(),\n types: z.string().optional(),\n module: z.string().optional(),\n});\n\n/**\n * Utilities for working with Backstage package roles.\n *\n * @public\n */\nexport class PackageRoles {\n /**\n * Get the associated info for a package role.\n */\n static getRoleInfo(role: string): PackageRoleInfo {\n const roleInfo = packageRoleInfos.find(r => r.role === role);\n if (!roleInfo) {\n throw new Error(`Unknown package role '${role}'`);\n }\n return roleInfo;\n }\n\n /**\n * Given package JSON data, get the package role.\n */\n static getRoleFromPackage(pkgJson: unknown): PackageRole | undefined {\n const pkg = readSchema.parse(pkgJson);\n\n if (pkg.backstage) {\n const { role } = pkg.backstage;\n if (!role) {\n throw new Error(\n `Package ${pkg.name} must specify a role in the \"backstage\" field`,\n );\n }\n\n return this.getRoleInfo(role).role;\n }\n\n return undefined;\n }\n\n /**\n * Attempt to detect the role of a package from its package.json.\n */\n static detectRoleFromPackage(pkgJson: unknown): PackageRole | undefined {\n const pkg = detectionSchema.parse(pkgJson);\n\n if (pkg.scripts?.start?.includes('app:serve')) {\n return 'frontend';\n }\n if (pkg.scripts?.build?.includes('backend:bundle')) {\n return 'backend';\n }\n if (\n pkg.name?.includes('plugin-') &&\n pkg.name?.includes('-backend-module-')\n ) {\n return 'backend-plugin-module';\n }\n if (pkg.name?.includes('plugin-') && pkg.name?.includes('-module-')) {\n return 'frontend-plugin-module';\n }\n if (pkg.scripts?.start?.includes('plugin:serve')) {\n return 'frontend-plugin';\n }\n if (pkg.scripts?.start?.includes('backend:dev')) {\n return 'backend-plugin';\n }\n\n const mainEntry = pkg.publishConfig?.main || pkg.main;\n const moduleEntry = pkg.publishConfig?.module || pkg.module;\n const typesEntry = pkg.publishConfig?.types || pkg.types;\n if (typesEntry) {\n if (mainEntry && moduleEntry) {\n return 'common-library';\n }\n if (moduleEntry || mainEntry?.endsWith('.esm.js')) {\n return 'web-library';\n }\n if (mainEntry) {\n return 'node-library';\n }\n } else if (mainEntry) {\n return 'cli';\n }\n\n return undefined;\n }\n}\n"],"names":["z"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs-extra');
4
+ var path = require('node:path');
5
+ var yaml = require('yaml');
6
+ var z = require('zod');
7
+ var cliCommon = require('@backstage/cli-common');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
10
+
11
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
+ var yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
13
+ var z__default = /*#__PURE__*/_interopDefaultCompat(z);
14
+
15
+ const yarnRcSchema = z__default.default.object({
16
+ plugins: z__default.default.array(
17
+ z__default.default.object({
18
+ path: z__default.default.string()
19
+ })
20
+ ).optional()
21
+ });
22
+ async function hasBackstageYarnPlugin(workspaceDir) {
23
+ const yarnRcPath = path.resolve(
24
+ workspaceDir ?? cliCommon.targetPaths.rootDir,
25
+ ".yarnrc.yml"
26
+ );
27
+ const yarnRcContent = await fs__default.default.readFile(yarnRcPath, "utf-8").catch((e) => {
28
+ if (e.code === "ENOENT") {
29
+ return "";
30
+ }
31
+ throw e;
32
+ });
33
+ if (!yarnRcContent) {
34
+ return false;
35
+ }
36
+ const parseResult = yarnRcSchema.safeParse(yaml__default.default.parse(yarnRcContent));
37
+ if (!parseResult.success) {
38
+ throw new Error(
39
+ `Unexpected content in .yarnrc.yml: ${parseResult.error.toString()}`
40
+ );
41
+ }
42
+ const yarnRc = parseResult.data;
43
+ const backstagePlugin = yarnRc.plugins?.some(
44
+ (plugin) => plugin.path === ".yarn/plugins/@yarnpkg/plugin-backstage.cjs"
45
+ );
46
+ return Boolean(backstagePlugin);
47
+ }
48
+
49
+ exports.hasBackstageYarnPlugin = hasBackstageYarnPlugin;
50
+ //# sourceMappingURL=yarnPlugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yarnPlugin.cjs.js","sources":["../../src/yarn/yarnPlugin.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath } from 'node:path';\nimport yaml from 'yaml';\nimport z from 'zod';\nimport { targetPaths } from '@backstage/cli-common';\n\nconst yarnRcSchema = z.object({\n plugins: z\n .array(\n z.object({\n path: z.string(),\n }),\n )\n .optional(),\n});\n\n/**\n * Detects whether the Backstage Yarn plugin is installed in the given workspace directory.\n *\n * @param workspaceDir - The workspace root directory to check. Defaults to the target root.\n * @returns Promise resolving to true if the plugin is installed, false otherwise\n * @public\n */\nexport async function hasBackstageYarnPlugin(\n workspaceDir?: string,\n): Promise<boolean> {\n const yarnRcPath = resolvePath(\n workspaceDir ?? targetPaths.rootDir,\n '.yarnrc.yml',\n );\n const yarnRcContent = await fs.readFile(yarnRcPath, 'utf-8').catch(e => {\n if (e.code === 'ENOENT') {\n return '';\n }\n throw e;\n });\n\n if (!yarnRcContent) {\n return false;\n }\n\n const parseResult = yarnRcSchema.safeParse(yaml.parse(yarnRcContent));\n\n if (!parseResult.success) {\n throw new Error(\n `Unexpected content in .yarnrc.yml: ${parseResult.error.toString()}`,\n );\n }\n\n const yarnRc = parseResult.data;\n\n const backstagePlugin = yarnRc.plugins?.some(\n plugin => plugin.path === '.yarn/plugins/@yarnpkg/plugin-backstage.cjs',\n );\n\n return Boolean(backstagePlugin);\n}\n"],"names":["z","resolvePath","targetPaths","fs","yaml"],"mappings":";;;;;;;;;;;;;;AAsBA,MAAM,YAAA,GAAeA,mBAAE,MAAA,CAAO;AAAA,EAC5B,SAASA,kBAAA,CACN,KAAA;AAAA,IACCA,mBAAE,MAAA,CAAO;AAAA,MACP,IAAA,EAAMA,mBAAE,MAAA;AAAO,KAChB;AAAA,IAEF,QAAA;AACL,CAAC,CAAA;AASD,eAAsB,uBACpB,YAAA,EACkB;AAClB,EAAA,MAAM,UAAA,GAAaC,YAAA;AAAA,IACjB,gBAAgBC,qBAAA,CAAY,OAAA;AAAA,IAC5B;AAAA,GACF;AACA,EAAA,MAAM,aAAA,GAAgB,MAAMC,mBAAA,CAAG,QAAA,CAAS,YAAY,OAAO,CAAA,CAAE,MAAM,CAAA,CAAA,KAAK;AACtE,IAAA,IAAI,CAAA,CAAE,SAAS,QAAA,EAAU;AACvB,MAAA,OAAO,EAAA;AAAA,IACT;AACA,IAAA,MAAM,CAAA;AAAA,EACR,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,YAAA,CAAa,SAAA,CAAUC,qBAAA,CAAK,KAAA,CAAM,aAAa,CAAC,CAAA;AAEpE,EAAA,IAAI,CAAC,YAAY,OAAA,EAAS;AACxB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,mCAAA,EAAsC,WAAA,CAAY,KAAA,CAAM,QAAA,EAAU,CAAA;AAAA,KACpE;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,WAAA,CAAY,IAAA;AAE3B,EAAA,MAAM,eAAA,GAAkB,OAAO,OAAA,EAAS,IAAA;AAAA,IACtC,CAAA,MAAA,KAAU,OAAO,IAAA,KAAS;AAAA,GAC5B;AAEA,EAAA,OAAO,QAAQ,eAAe,CAAA;AAChC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli-node",
3
- "version": "0.2.19-next.0",
3
+ "version": "0.2.19-next.1",
4
4
  "description": "Node.js library for Backstage CLIs",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -31,19 +31,22 @@
31
31
  "test": "backstage-cli package test"
32
32
  },
33
33
  "dependencies": {
34
- "@backstage/cli-common": "0.2.0-next.0",
34
+ "@backstage/cli-common": "0.2.0-next.1",
35
35
  "@backstage/errors": "1.2.7",
36
36
  "@backstage/types": "1.2.2",
37
37
  "@manypkg/get-packages": "^1.1.3",
38
+ "@yarnpkg/lockfile": "^1.1.0",
38
39
  "@yarnpkg/parsers": "^3.0.0",
39
40
  "fs-extra": "^11.2.0",
40
41
  "semver": "^7.5.3",
42
+ "yaml": "^2.0.0",
41
43
  "zod": "^3.25.76"
42
44
  },
43
45
  "devDependencies": {
44
- "@backstage/backend-test-utils": "1.11.1-next.0",
45
- "@backstage/cli": "0.35.5-next.0",
46
- "@backstage/test-utils": "1.7.16-next.0"
46
+ "@backstage/backend-test-utils": "1.11.1-next.1",
47
+ "@backstage/cli": "0.36.0-next.1",
48
+ "@backstage/test-utils": "1.7.16-next.0",
49
+ "@types/yarnpkg__lockfile": "^1.1.4"
47
50
  },
48
51
  "typesVersions": {
49
52
  "*": {