@backstage/cli 0.35.4 → 0.35.5-next.0

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/index.cjs.js +1 -0
  3. package/dist/lib/cache/SuccessCache.cjs.js +2 -2
  4. package/dist/lib/typeDistProject.cjs.js +2 -2
  5. package/dist/lib/version.cjs.js +4 -3
  6. package/dist/lib/yarnPlugin.cjs.js +2 -2
  7. package/dist/modules/build/commands/package/build/command.cjs.js +7 -7
  8. package/dist/modules/build/commands/package/start/command.cjs.js +3 -3
  9. package/dist/modules/build/commands/package/start/startBackend.cjs.js +2 -2
  10. package/dist/modules/build/commands/package/start/startFrontend.cjs.js +3 -4
  11. package/dist/modules/build/commands/repo/build.cjs.js +6 -7
  12. package/dist/modules/build/commands/repo/start.cjs.js +3 -3
  13. package/dist/modules/build/lib/buildBackend.cjs.js +0 -2
  14. package/dist/modules/build/lib/buildFrontend.cjs.js +1 -4
  15. package/dist/modules/build/lib/builder/config.cjs.js +5 -5
  16. package/dist/modules/build/lib/builder/packager.cjs.js +7 -8
  17. package/dist/modules/build/lib/bundler/config.cjs.js +1 -2
  18. package/dist/modules/build/lib/bundler/hasReactDomClient.cjs.js +2 -2
  19. package/dist/modules/build/lib/bundler/linkWorkspaces.cjs.js +2 -2
  20. package/dist/modules/build/lib/bundler/moduleFederation.cjs.js +2 -2
  21. package/dist/modules/build/lib/bundler/packageDetection.cjs.js +2 -2
  22. package/dist/modules/build/lib/bundler/paths.cjs.js +8 -6
  23. package/dist/modules/build/lib/bundler/server.cjs.js +10 -10
  24. package/dist/modules/build/lib/packager/createDistWorkspace.cjs.js +9 -9
  25. package/dist/modules/build/lib/packager/productionPack.cjs.js +1 -1
  26. package/dist/{lib → modules/build/lib}/role.cjs.js +2 -2
  27. package/dist/modules/build/lib/runner/runBackend.cjs.js +2 -2
  28. package/dist/modules/config/lib/config.cjs.js +4 -4
  29. package/dist/modules/create-github-app/commands/create-github-app/index.cjs.js +2 -2
  30. package/dist/modules/info/commands/info.cjs.js +4 -5
  31. package/dist/modules/lint/commands/package/lint.cjs.js +4 -4
  32. package/dist/modules/lint/commands/repo/lint.cjs.js +8 -9
  33. package/dist/modules/maintenance/commands/package/clean.cjs.js +4 -4
  34. package/dist/modules/maintenance/commands/package/pack.cjs.js +5 -5
  35. package/dist/modules/maintenance/commands/repo/clean.cjs.js +3 -4
  36. package/dist/modules/maintenance/commands/repo/fix.cjs.js +7 -7
  37. package/dist/modules/maintenance/commands/repo/list-deprecations.cjs.js +4 -4
  38. package/dist/modules/migrate/commands/packageRole.cjs.js +2 -2
  39. package/dist/modules/migrate/commands/versions/bump.cjs.js +8 -9
  40. package/dist/modules/new/lib/codeowners/codeowners.cjs.js +2 -2
  41. package/dist/modules/new/lib/execution/PortableTemplater.cjs.js +2 -3
  42. package/dist/modules/new/lib/execution/installNewPackage.cjs.js +4 -4
  43. package/dist/modules/new/lib/execution/writeTemplateContents.cjs.js +1 -2
  44. package/dist/modules/new/lib/preparation/collectPortableTemplateInput.cjs.js +2 -2
  45. package/dist/modules/new/lib/preparation/loadPortableTemplate.cjs.js +2 -2
  46. package/dist/modules/new/lib/preparation/loadPortableTemplateConfig.cjs.js +2 -2
  47. package/dist/modules/test/commands/package/test.cjs.js +1 -2
  48. package/dist/modules/test/commands/repo/test.cjs.js +3 -4
  49. package/dist/modules/test/index.cjs.js +3 -1
  50. package/dist/modules/translations/commands/export.cjs.js +104 -0
  51. package/dist/modules/translations/commands/import.cjs.js +141 -0
  52. package/dist/modules/translations/index.cjs.js +59 -0
  53. package/dist/modules/translations/lib/discoverPackages.cjs.js +121 -0
  54. package/dist/modules/translations/lib/extractTranslations.cjs.js +71 -0
  55. package/dist/modules/translations/lib/messageFilePath.cjs.js +43 -0
  56. package/dist/packages/backend-defaults/package.json.cjs.js +1 -1
  57. package/dist/packages/backend-plugin-api/package.json.cjs.js +1 -1
  58. package/dist/packages/backend-test-utils/package.json.cjs.js +1 -1
  59. package/dist/packages/catalog-client/package.json.cjs.js +1 -1
  60. package/dist/packages/cli/package.json.cjs.js +5 -5
  61. package/dist/packages/core-app-api/package.json.cjs.js +1 -1
  62. package/dist/packages/core-components/package.json.cjs.js +1 -1
  63. package/dist/packages/core-plugin-api/package.json.cjs.js +1 -1
  64. package/dist/packages/dev-utils/package.json.cjs.js +1 -1
  65. package/dist/packages/frontend-defaults/package.json.cjs.js +1 -1
  66. package/dist/packages/frontend-plugin-api/package.json.cjs.js +1 -1
  67. package/dist/packages/frontend-test-utils/package.json.cjs.js +1 -1
  68. package/dist/packages/test-utils/package.json.cjs.js +1 -1
  69. package/dist/plugins/auth-backend/package.json.cjs.js +1 -1
  70. package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +1 -1
  71. package/dist/plugins/catalog-node/package.json.cjs.js +1 -1
  72. package/dist/plugins/scaffolder-node/package.json.cjs.js +1 -1
  73. package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js +1 -1
  74. package/package.json +33 -33
  75. package/dist/lib/parallel.cjs.js +0 -141
  76. package/dist/lib/paths.cjs.js +0 -8
  77. /package/dist/{lib → modules/build/lib}/entryPoints.cjs.js +0 -0
@@ -13,8 +13,7 @@ var Lockfile = require('../../../../lib/versioning/Lockfile.cjs.js');
13
13
  require('minimatch');
14
14
  require('@manypkg/get-packages');
15
15
  require('@backstage/errors');
16
- require('@backstage/cli-common');
17
- var paths = require('../../../../lib/paths.cjs.js');
16
+ var cliCommon = require('@backstage/cli-common');
18
17
  var version = require('../../../../lib/version.cjs.js');
19
18
  var yarnPlugin = require('../../../../lib/yarnPlugin.cjs.js');
20
19
 
@@ -44,7 +43,7 @@ class PortableTemplater {
44
43
  static async create(options = {}) {
45
44
  let lockfile;
46
45
  try {
47
- lockfile = await Lockfile.Lockfile.load(paths.paths.resolveTargetRoot("yarn.lock"));
46
+ lockfile = await Lockfile.Lockfile.load(cliCommon.targetPaths.resolveRoot("yarn.lock"));
48
47
  } catch {
49
48
  }
50
49
  const hasYarnPlugin = await yarnPlugin.getHasYarnPlugin();
@@ -3,7 +3,7 @@
3
3
  var fs = require('fs-extra');
4
4
  var upperFirst = require('lodash/upperFirst');
5
5
  var camelCase = require('lodash/camelCase');
6
- var paths = require('../../../../lib/paths.cjs.js');
6
+ var cliCommon = require('@backstage/cli-common');
7
7
  var tasks = require('../tasks.cjs.js');
8
8
 
9
9
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -44,7 +44,7 @@ async function installNewPackage(input) {
44
44
  }
45
45
  }
46
46
  async function addDependency(input, path) {
47
- const pkgJsonPath = paths.paths.resolveTargetRoot(path);
47
+ const pkgJsonPath = cliCommon.targetPaths.resolveRoot(path);
48
48
  const pkgJson = await fs__default.default.readJson(pkgJsonPath).catch((error) => {
49
49
  if (error.code === "ENOENT") {
50
50
  return void 0;
@@ -71,7 +71,7 @@ async function tryAddFrontendLegacy(input) {
71
71
  "add-frontend-legacy can only be used for frontend plugins"
72
72
  );
73
73
  }
74
- const appDefinitionPath = paths.paths.resolveTargetRoot("packages/app/src/App.tsx");
74
+ const appDefinitionPath = cliCommon.targetPaths.resolveRoot("packages/app/src/App.tsx");
75
75
  if (!await fs__default.default.pathExists(appDefinitionPath)) {
76
76
  return;
77
77
  }
@@ -101,7 +101,7 @@ async function tryAddFrontendLegacy(input) {
101
101
  });
102
102
  }
103
103
  async function tryAddBackend(input) {
104
- const backendIndexPath = paths.paths.resolveTargetRoot(
104
+ const backendIndexPath = cliCommon.targetPaths.resolveRoot(
105
105
  "packages/backend/src/index.ts"
106
106
  );
107
107
  if (!await fs__default.default.pathExists(backendIndexPath)) {
@@ -2,7 +2,6 @@
2
2
 
3
3
  var fs = require('fs-extra');
4
4
  var path = require('node:path');
5
- var paths = require('../../../../lib/paths.cjs.js');
6
5
  var errors = require('@backstage/errors');
7
6
  var cliNode = require('@backstage/cli-node');
8
7
  var PortableTemplater = require('./PortableTemplater.cjs.js');
@@ -13,7 +12,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
13
12
  var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
14
13
 
15
14
  async function writeTemplateContents(template, input) {
16
- const targetDir = paths.paths.resolveTargetRoot(input.packagePath);
15
+ const targetDir = cliCommon.targetPaths.resolveRoot(input.packagePath);
17
16
  if (await fs__default.default.pathExists(targetDir)) {
18
17
  throw new errors.InputError(`Package '${input.packagePath}' already exists`);
19
18
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  var inquirer = require('inquirer');
4
4
  var codeowners = require('../codeowners/codeowners.cjs.js');
5
- var paths = require('../../../../lib/paths.cjs.js');
5
+ var cliCommon = require('@backstage/cli-common');
6
6
  var resolvePackageParams = require('./resolvePackageParams.cjs.js');
7
7
 
8
8
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -11,7 +11,7 @@ var inquirer__default = /*#__PURE__*/_interopDefaultCompat(inquirer);
11
11
 
12
12
  async function collectPortableTemplateInput(options) {
13
13
  const { config, template, prefilledParams } = options;
14
- const codeOwnersFilePath = await codeowners.getCodeownersFilePath(paths.paths.targetRoot);
14
+ const codeOwnersFilePath = await codeowners.getCodeownersFilePath(cliCommon.targetPaths.rootDir);
15
15
  const prompts = getPromptsForRole(template.role);
16
16
  if (codeOwnersFilePath) {
17
17
  prompts.push(ownerPrompt());
@@ -5,7 +5,7 @@ var fs = require('fs-extra');
5
5
  var recursiveReaddir = require('recursive-readdir');
6
6
  var path = require('node:path');
7
7
  var yaml = require('yaml');
8
- var paths = require('../../../../lib/paths.cjs.js');
8
+ var cliCommon = require('@backstage/cli-common');
9
9
  var types = require('../types.cjs.js');
10
10
  var errors = require('@backstage/errors');
11
11
  var v3 = require('zod-validation-error/v3');
@@ -25,7 +25,7 @@ async function loadPortableTemplate(pointer) {
25
25
  if (pointer.target.match(/https?:\/\//)) {
26
26
  throw new Error("Remote templates are not supported yet");
27
27
  }
28
- const templateContent = await fs__default.default.readFile(paths.paths.resolveTargetRoot(pointer.target), "utf-8").catch((error) => {
28
+ const templateContent = await fs__default.default.readFile(cliCommon.targetPaths.resolveRoot(pointer.target), "utf-8").catch((error) => {
29
29
  throw new errors.ForwardedError(
30
30
  `Failed to load template definition from '${pointer.target}'`,
31
31
  error
@@ -2,7 +2,7 @@
2
2
 
3
3
  var fs = require('fs-extra');
4
4
  var path = require('node:path');
5
- var paths = require('../../../../lib/paths.cjs.js');
5
+ var cliCommon = require('@backstage/cli-common');
6
6
  var defaultTemplates = require('../defaultTemplates.cjs.js');
7
7
  var types = require('../types.cjs.js');
8
8
  var yaml = require('yaml');
@@ -48,7 +48,7 @@ function computePackageNamePluginInfix(packageNamePrefix, namePluginInfix) {
48
48
  }
49
49
  async function loadPortableTemplateConfig(options = {}) {
50
50
  const { overrides = {} } = options;
51
- const pkgPath = options.packagePath ?? paths.paths.resolveTargetRoot("package.json");
51
+ const pkgPath = options.packagePath ?? cliCommon.targetPaths.resolveRoot("package.json");
52
52
  const pkgJson = await fs__default.default.readJson(pkgPath);
53
53
  const parsed = pkgJsonWithNewConfigSchema.safeParse(pkgJson);
54
54
  if (!parsed.success) {
@@ -2,7 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var paths = require('../../../../lib/paths.cjs.js');
6
5
  var cliCommon = require('@backstage/cli-common');
7
6
 
8
7
  function includesAnyOf(hayStack, ...needles) {
@@ -21,7 +20,7 @@ var test = async (_opts, cmd) => {
21
20
  const allArgs = parent.args;
22
21
  const args = allArgs.slice(allArgs.indexOf("test") + 1);
23
22
  if (!includesAnyOf(args, "-c", "--config")) {
24
- args.push("--config", paths.paths.resolveOwn("config/jest.js"));
23
+ args.push("--config", cliCommon.findOwnPaths(__dirname).resolve("config/jest.js"));
25
24
  }
26
25
  if (!includesAnyOf(args, "--no-passWithNoTests", "--passWithNoTests=false")) {
27
26
  args.push("--passWithNoTests");
@@ -6,7 +6,6 @@ var yargs = require('yargs');
6
6
  var jestCli = require('jest-cli');
7
7
  var path = require('node:path');
8
8
  var cliNode = require('@backstage/cli-node');
9
- var paths = require('../../../../lib/paths.cjs.js');
10
9
  var cliCommon = require('@backstage/cli-common');
11
10
  var SuccessCache = require('../../../../lib/cache/SuccessCache.cjs.js');
12
11
 
@@ -19,7 +18,7 @@ var yargs__default = /*#__PURE__*/_interopDefaultCompat(yargs);
19
18
  async function readPackageTreeHashes(graph) {
20
19
  const pkgs = Array.from(graph.values()).map((pkg) => ({
21
20
  ...pkg,
22
- path: path.relative(paths.paths.targetRoot, pkg.dir)
21
+ path: path.relative(cliCommon.targetPaths.rootDir, pkg.dir)
23
22
  }));
24
23
  const output = await cliCommon.runOutput([
25
24
  "git",
@@ -100,7 +99,7 @@ async function command(opts, cmd) {
100
99
  const hasFlags = createFlagFinder(args);
101
100
  const { _: parsedArgs } = await yargs__default.default(args).options(jestCli.yargsOptions).argv;
102
101
  if (!hasFlags("-c", "--config")) {
103
- args.push("--config", paths.paths.resolveOwn("config/jest.js"));
102
+ args.push("--config", cliCommon.findOwnPaths(__dirname).resolve("config/jest.js"));
104
103
  }
105
104
  if (!hasFlags("--passWithNoTests")) {
106
105
  args.push("--passWithNoTests");
@@ -211,7 +210,7 @@ async function command(opts, cmd) {
211
210
  async filterConfigs(projectConfigs, globalRootConfig) {
212
211
  const cacheEntries = await cache.read();
213
212
  const lockfile = await cliNode.Lockfile.load(
214
- paths.paths.resolveTargetRoot("yarn.lock")
213
+ cliCommon.targetPaths.resolveRoot("yarn.lock")
215
214
  );
216
215
  const getPackageTreeHash = await readPackageTreeHashes(graph);
217
216
  const baseHash = crypto__default.default.createHash("sha1");
@@ -15,6 +15,7 @@ var index = factory.createCliPlugin({
15
15
  execute: async ({ args }) => {
16
16
  const command = new commander.Command();
17
17
  command.allowUnknownOption(true);
18
+ command.allowExcessArguments(true);
18
19
  command.option(
19
20
  "--since <ref>",
20
21
  "Only test packages that changed since the specified ref"
@@ -38,7 +39,8 @@ var index = factory.createCliPlugin({
38
39
  execute: async ({ args }) => {
39
40
  const command = new commander.Command();
40
41
  command.allowUnknownOption(true);
41
- command.helpOption(", --backstage-cli-help");
42
+ command.allowExcessArguments(true);
43
+ command.helpOption("--backstage-cli-help");
42
44
  command.action(
43
45
  lazy.lazy(() => import('./commands/package/test.cjs.js'), "default")
44
46
  );
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var cliCommon = require('@backstage/cli-common');
6
+ var fs = require('fs-extra');
7
+ var path = require('node:path');
8
+ var discoverPackages = require('../lib/discoverPackages.cjs.js');
9
+ var extractTranslations = require('../lib/extractTranslations.cjs.js');
10
+ var messageFilePath = require('../lib/messageFilePath.cjs.js');
11
+
12
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
13
+
14
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
15
+
16
+ var _export = async (options) => {
17
+ messageFilePath.validatePattern(options.pattern);
18
+ const targetPackageJson = await discoverPackages.readTargetPackage(
19
+ cliCommon.targetPaths.dir,
20
+ cliCommon.targetPaths.rootDir
21
+ );
22
+ const outputDir = path.resolve(cliCommon.targetPaths.dir, options.output);
23
+ const manifestPath = path.resolve(outputDir, "manifest.json");
24
+ const tsconfigPath = cliCommon.targetPaths.resolveRoot("tsconfig.json");
25
+ if (!await fs__default.default.pathExists(tsconfigPath)) {
26
+ throw new Error(
27
+ `No tsconfig.json found at ${tsconfigPath}. The translations export command requires a tsconfig.json in the repo root.`
28
+ );
29
+ }
30
+ console.log(
31
+ `Discovering frontend dependencies of ${targetPackageJson.name}...`
32
+ );
33
+ const packages = await discoverPackages.discoverFrontendPackages(
34
+ targetPackageJson,
35
+ cliCommon.targetPaths.dir
36
+ );
37
+ console.log(`Found ${packages.length} frontend packages to scan`);
38
+ console.log("Creating TypeScript project...");
39
+ const project = extractTranslations.createTranslationProject(tsconfigPath);
40
+ const allRefs = [];
41
+ for (const pkg of packages) {
42
+ for (const [exportPath, filePath] of pkg.entryPoints) {
43
+ try {
44
+ const sourceFile = project.addSourceFileAtPath(filePath);
45
+ const refs = extractTranslations.extractTranslationRefsFromSourceFile(
46
+ sourceFile,
47
+ pkg.name,
48
+ exportPath
49
+ );
50
+ allRefs.push(...refs);
51
+ } catch (error) {
52
+ console.warn(
53
+ ` Warning: failed to process ${pkg.name} (${exportPath}): ${error}`
54
+ );
55
+ }
56
+ }
57
+ }
58
+ if (allRefs.length === 0) {
59
+ console.log("No translation refs found.");
60
+ return;
61
+ }
62
+ console.log(`Found ${allRefs.length} translation ref(s):`);
63
+ for (const ref of allRefs) {
64
+ const messageCount = Object.keys(ref.messages).length;
65
+ console.log(` ${ref.id} (${ref.packageName}, ${messageCount} messages)`);
66
+ }
67
+ for (const ref of allRefs) {
68
+ const relPath = messageFilePath.formatMessagePath(
69
+ options.pattern,
70
+ ref.id,
71
+ messageFilePath.DEFAULT_LANGUAGE
72
+ );
73
+ const filePath = path.resolve(outputDir, relPath);
74
+ await fs__default.default.ensureDir(path.dirname(filePath));
75
+ await fs__default.default.writeJson(filePath, ref.messages, { spaces: 2 });
76
+ }
77
+ const manifest = {};
78
+ for (const ref of allRefs) {
79
+ manifest[ref.id] = {
80
+ package: ref.packageName,
81
+ exportPath: ref.exportPath,
82
+ exportName: ref.exportName
83
+ };
84
+ }
85
+ await fs__default.default.writeJson(
86
+ manifestPath,
87
+ { pattern: options.pattern, refs: manifest },
88
+ { spaces: 2 }
89
+ );
90
+ const examplePath = messageFilePath.formatMessagePath(
91
+ options.pattern,
92
+ "<ref-id>",
93
+ messageFilePath.DEFAULT_LANGUAGE
94
+ );
95
+ console.log(
96
+ `
97
+ Exported ${allRefs.length} translation ref(s) to ${options.output}/`
98
+ );
99
+ console.log(` Messages: ${options.output}/${examplePath}`);
100
+ console.log(` Manifest: ${options.output}/manifest.json`);
101
+ };
102
+
103
+ exports.default = _export;
104
+ //# sourceMappingURL=export.cjs.js.map
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var cliCommon = require('@backstage/cli-common');
6
+ var fs = require('fs-extra');
7
+ var path = require('node:path');
8
+ var discoverPackages = require('../lib/discoverPackages.cjs.js');
9
+ var messageFilePath = require('../lib/messageFilePath.cjs.js');
10
+
11
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
+
13
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
14
+
15
+ var _import = async (options) => {
16
+ await discoverPackages.readTargetPackage(cliCommon.targetPaths.dir, cliCommon.targetPaths.rootDir);
17
+ const inputDir = path.resolve(cliCommon.targetPaths.dir, options.input);
18
+ const manifestPath = path.resolve(inputDir, "manifest.json");
19
+ const outputPath = path.resolve(cliCommon.targetPaths.dir, options.output);
20
+ if (!await fs__default.default.pathExists(manifestPath)) {
21
+ throw new Error(
22
+ `No manifest.json found at ${manifestPath}. Run "backstage-cli translations export" first.`
23
+ );
24
+ }
25
+ const manifest = await fs__default.default.readJson(manifestPath);
26
+ if (!manifest.pattern) {
27
+ throw new Error(
28
+ 'No pattern found in manifest.json. Re-run "backstage-cli translations export" to regenerate it.'
29
+ );
30
+ }
31
+ const pattern = manifest.pattern;
32
+ const parsePath = messageFilePath.createMessagePathParser(pattern);
33
+ const allFiles = (await collectJsonFiles(inputDir)).filter(
34
+ (f) => f !== "manifest.json"
35
+ );
36
+ const translationsByRef = /* @__PURE__ */ new Map();
37
+ let skipped = 0;
38
+ for (const relPath of allFiles) {
39
+ const parsed = parsePath(relPath);
40
+ if (!parsed) {
41
+ skipped++;
42
+ continue;
43
+ }
44
+ if (parsed.lang === messageFilePath.DEFAULT_LANGUAGE) {
45
+ continue;
46
+ }
47
+ if (!manifest.refs[parsed.id]) {
48
+ console.warn(
49
+ ` Warning: skipping ${relPath} - ref '${parsed.id}' not found in manifest`
50
+ );
51
+ continue;
52
+ }
53
+ const existing = translationsByRef.get(parsed.id) ?? [];
54
+ existing.push({ lang: parsed.lang, relPath });
55
+ translationsByRef.set(parsed.id, existing);
56
+ }
57
+ if (skipped > 0) {
58
+ console.warn(
59
+ ` Warning: ${skipped} file(s) did not match the pattern '${pattern}'`
60
+ );
61
+ }
62
+ if (translationsByRef.size === 0) {
63
+ console.log("No translated message files found.");
64
+ const example = messageFilePath.formatMessagePath(pattern, "<ref-id>", "sv");
65
+ console.log(
66
+ `Add translated files as ${example} in the translations directory.`
67
+ );
68
+ return;
69
+ }
70
+ const importLines = [];
71
+ const resourceLines = [];
72
+ importLines.push(
73
+ "import { createTranslationResource } from '@backstage/frontend-plugin-api';"
74
+ );
75
+ for (const [refId, entries] of [...translationsByRef.entries()].sort(
76
+ ([a], [b]) => a.localeCompare(b)
77
+ )) {
78
+ const refEntry = manifest.refs[refId];
79
+ const importPath = refEntry.exportPath === "." ? refEntry.package : `${refEntry.package}/${refEntry.exportPath.replace(/^\.\//, "")}`;
80
+ importLines.push(`import { ${refEntry.exportName} } from '${importPath}';`);
81
+ const translationEntries = entries.sort((a, b) => a.lang.localeCompare(b.lang)).map(({ lang, relPath }) => {
82
+ const jsonRelPath = path.relative(
83
+ path.resolve(outputPath, ".."),
84
+ path.resolve(inputDir, relPath)
85
+ ).split(path.sep).join("/");
86
+ return ` ${JSON.stringify(lang)}: () => import('./${jsonRelPath}'),`;
87
+ }).join("\n");
88
+ resourceLines.push(
89
+ [
90
+ ` createTranslationResource({`,
91
+ ` ref: ${refEntry.exportName},`,
92
+ ` translations: {`,
93
+ translationEntries,
94
+ ` },`,
95
+ ` }),`
96
+ ].join("\n")
97
+ );
98
+ }
99
+ const fileContent = [
100
+ "// This file is auto-generated by backstage-cli translations import",
101
+ "// Do not edit manually.",
102
+ "",
103
+ ...importLines,
104
+ "",
105
+ "export default [",
106
+ ...resourceLines,
107
+ "];",
108
+ ""
109
+ ].join("\n");
110
+ await fs__default.default.ensureDir(path.resolve(outputPath, ".."));
111
+ await fs__default.default.writeFile(outputPath, fileContent, "utf8");
112
+ const totalFiles = [...translationsByRef.values()].reduce(
113
+ (sum, e) => sum + e.length,
114
+ 0
115
+ );
116
+ console.log(`Generated translation resources at ${options.output}`);
117
+ console.log(
118
+ ` ${translationsByRef.size} ref(s), ${totalFiles} translation file(s)`
119
+ );
120
+ console.log(
121
+ "\nImport this file in your app and pass the resources to your translation API setup."
122
+ );
123
+ };
124
+ async function collectJsonFiles(dir, prefix = "") {
125
+ const entries = await fs__default.default.readdir(dir, { withFileTypes: true });
126
+ const results = [];
127
+ for (const entry of entries) {
128
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
129
+ if (entry.isDirectory()) {
130
+ results.push(
131
+ ...await collectJsonFiles(path.resolve(dir, entry.name), relPath)
132
+ );
133
+ } else if (entry.isFile() && entry.name.endsWith(".json")) {
134
+ results.push(relPath);
135
+ }
136
+ }
137
+ return results;
138
+ }
139
+
140
+ exports.default = _import;
141
+ //# sourceMappingURL=import.cjs.js.map
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var yargs = require('yargs');
6
+ var factory = require('../../wiring/factory.cjs.js');
7
+ var lazy = require('../../lib/lazy.cjs.js');
8
+ var messageFilePath = require('./lib/messageFilePath.cjs.js');
9
+
10
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
+
12
+ var yargs__default = /*#__PURE__*/_interopDefaultCompat(yargs);
13
+
14
+ var index = factory.createCliPlugin({
15
+ pluginId: "translations",
16
+ init: async (reg) => {
17
+ reg.addCommand({
18
+ path: ["translations", "export"],
19
+ description: "Export translation messages from an app and all of its frontend plugins to JSON files",
20
+ execute: async ({ args }) => {
21
+ const argv = await yargs__default.default().options({
22
+ output: {
23
+ type: "string",
24
+ default: "translations",
25
+ description: "Output directory for exported messages and manifest"
26
+ },
27
+ pattern: {
28
+ type: "string",
29
+ default: messageFilePath.DEFAULT_MESSAGE_PATTERN,
30
+ description: "File path pattern for message files, with {id} and {lang} placeholders"
31
+ }
32
+ }).help().parse(args);
33
+ await lazy.lazy(() => import('./commands/export.cjs.js'), "default")(argv);
34
+ }
35
+ });
36
+ reg.addCommand({
37
+ path: ["translations", "import"],
38
+ description: "Generate translation resource wiring from translated JSON files",
39
+ execute: async ({ args }) => {
40
+ const argv = await yargs__default.default().options({
41
+ input: {
42
+ type: "string",
43
+ default: "translations",
44
+ description: "Input directory containing the manifest and translated message files"
45
+ },
46
+ output: {
47
+ type: "string",
48
+ default: "src/translations/resources.ts",
49
+ description: "Output path for the generated wiring module"
50
+ }
51
+ }).help().parse(args);
52
+ await lazy.lazy(() => import('./commands/import.cjs.js'), "default")(argv);
53
+ }
54
+ });
55
+ }
56
+ });
57
+
58
+ exports.default = index;
59
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ var cliNode = require('@backstage/cli-node');
4
+ var path = require('node:path');
5
+ var fs = require('fs-extra');
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
+ async function readTargetPackage(packageDir, repoRoot) {
12
+ const packageJsonPath = path.resolve(packageDir, "package.json");
13
+ if (!await fs__default.default.pathExists(packageJsonPath)) {
14
+ throw new Error(
15
+ "No package.json found in the current directory. The translations commands must be run from within a package directory."
16
+ );
17
+ }
18
+ if (path.resolve(packageDir) === path.resolve(repoRoot)) {
19
+ throw new Error(
20
+ "The translations commands must be run from within a package directory, not from the repository root. For example: cd packages/app && backstage-cli translations export"
21
+ );
22
+ }
23
+ return fs__default.default.readJson(packageJsonPath);
24
+ }
25
+ async function discoverFrontendPackages(targetPackageJson, targetDir) {
26
+ let workspaceByName;
27
+ try {
28
+ const workspacePackages = await cliNode.PackageGraph.listTargetPackages();
29
+ workspaceByName = new Map(
30
+ workspacePackages.map((p) => [p.packageJson.name, p])
31
+ );
32
+ } catch {
33
+ workspaceByName = /* @__PURE__ */ new Map();
34
+ }
35
+ const visited = /* @__PURE__ */ new Set();
36
+ const result = [];
37
+ async function visit(packageJson, pkgDir, includeDevDeps) {
38
+ const deps = {
39
+ ...packageJson.dependencies,
40
+ ...includeDevDeps ? packageJson.devDependencies ?? {} : {}
41
+ };
42
+ for (const depName of Object.keys(deps)) {
43
+ if (visited.has(depName)) {
44
+ continue;
45
+ }
46
+ visited.add(depName);
47
+ let depPkgJson;
48
+ let depDir;
49
+ let isWorkspace;
50
+ const workspacePkg = workspaceByName.get(depName);
51
+ if (workspacePkg) {
52
+ depPkgJson = workspacePkg.packageJson;
53
+ depDir = workspacePkg.dir;
54
+ isWorkspace = true;
55
+ } else {
56
+ try {
57
+ const pkgJsonPath = require.resolve(`${depName}/package.json`, {
58
+ paths: [pkgDir]
59
+ });
60
+ depPkgJson = await fs__default.default.readJson(pkgJsonPath);
61
+ depDir = path.dirname(pkgJsonPath);
62
+ isWorkspace = false;
63
+ } catch {
64
+ continue;
65
+ }
66
+ }
67
+ if (!depPkgJson.backstage) {
68
+ continue;
69
+ }
70
+ const role = depPkgJson.backstage?.role;
71
+ if (role && isFrontendRole(role)) {
72
+ const entryPoints = resolveEntryPoints(depPkgJson, depDir, isWorkspace);
73
+ if (entryPoints.size > 0) {
74
+ result.push({ name: depName, dir: depDir, entryPoints });
75
+ }
76
+ }
77
+ await visit(depPkgJson, depDir, false);
78
+ }
79
+ }
80
+ await visit(targetPackageJson, targetDir, true);
81
+ return result;
82
+ }
83
+ function resolveEntryPoints(packageJson, packageDir, isWorkspace) {
84
+ const entryPoints = /* @__PURE__ */ new Map();
85
+ const exports$1 = packageJson.exports;
86
+ if (exports$1) {
87
+ for (const [subpath, target] of Object.entries(exports$1)) {
88
+ if (subpath === "./package.json") {
89
+ continue;
90
+ }
91
+ let filePath;
92
+ if (typeof target === "string") {
93
+ filePath = target;
94
+ } else if (isWorkspace) {
95
+ filePath = target?.import ?? target?.types ?? target?.default;
96
+ } else {
97
+ filePath = target?.types ?? target?.import ?? target?.default;
98
+ }
99
+ if (typeof filePath === "string") {
100
+ entryPoints.set(subpath, path.resolve(packageDir, filePath));
101
+ }
102
+ }
103
+ } else {
104
+ const main = isWorkspace ? packageJson.main ?? packageJson.types : packageJson.types ?? packageJson.main;
105
+ if (main) {
106
+ entryPoints.set(".", path.resolve(packageDir, main));
107
+ }
108
+ }
109
+ return entryPoints;
110
+ }
111
+ function isFrontendRole(role) {
112
+ try {
113
+ return cliNode.PackageRoles.getRoleInfo(role).platform === "web";
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ exports.discoverFrontendPackages = discoverFrontendPackages;
120
+ exports.readTargetPackage = readTargetPackage;
121
+ //# sourceMappingURL=discoverPackages.cjs.js.map