@backstage/cli-module-new 0.0.0-nightly-20260317031259

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 (87) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +14 -0
  3. package/bin/backstage-cli-module-new +32 -0
  4. package/dist/commands/new.cjs.js +115 -0
  5. package/dist/commands/new.cjs.js.map +1 -0
  6. package/dist/index.cjs.js +41 -0
  7. package/dist/index.cjs.js.map +1 -0
  8. package/dist/index.d.ts +5 -0
  9. package/dist/lib/codeowners/codeowners.cjs.js +92 -0
  10. package/dist/lib/codeowners/codeowners.cjs.js.map +1 -0
  11. package/dist/lib/createNewPackage.cjs.js +32 -0
  12. package/dist/lib/createNewPackage.cjs.js.map +1 -0
  13. package/dist/lib/defaultTemplates.cjs.js +17 -0
  14. package/dist/lib/defaultTemplates.cjs.js.map +1 -0
  15. package/dist/lib/execution/PortableTemplater.cjs.js +89 -0
  16. package/dist/lib/execution/PortableTemplater.cjs.js.map +1 -0
  17. package/dist/lib/execution/executePortableTemplate.cjs.js +66 -0
  18. package/dist/lib/execution/executePortableTemplate.cjs.js.map +1 -0
  19. package/dist/lib/execution/installNewPackage.cjs.js +127 -0
  20. package/dist/lib/execution/installNewPackage.cjs.js.map +1 -0
  21. package/dist/lib/execution/writeTemplateContents.cjs.js +116 -0
  22. package/dist/lib/execution/writeTemplateContents.cjs.js.map +1 -0
  23. package/dist/lib/preparation/collectPortableTemplateInput.cjs.js +157 -0
  24. package/dist/lib/preparation/collectPortableTemplateInput.cjs.js.map +1 -0
  25. package/dist/lib/preparation/loadPortableTemplate.cjs.js +81 -0
  26. package/dist/lib/preparation/loadPortableTemplate.cjs.js.map +1 -0
  27. package/dist/lib/preparation/loadPortableTemplateConfig.cjs.js +132 -0
  28. package/dist/lib/preparation/loadPortableTemplateConfig.cjs.js.map +1 -0
  29. package/dist/lib/preparation/resolvePackageParams.cjs.js +40 -0
  30. package/dist/lib/preparation/resolvePackageParams.cjs.js.map +1 -0
  31. package/dist/lib/preparation/selectTemplateInteractively.cjs.js +38 -0
  32. package/dist/lib/preparation/selectTemplateInteractively.cjs.js.map +1 -0
  33. package/dist/lib/tasks.cjs.js +51 -0
  34. package/dist/lib/tasks.cjs.js.map +1 -0
  35. package/dist/lib/types.cjs.js +19 -0
  36. package/dist/lib/types.cjs.js.map +1 -0
  37. package/dist/lib/version.cjs.js +93 -0
  38. package/dist/lib/version.cjs.js.map +1 -0
  39. package/dist/packages/backend-defaults/package.json.cjs.js +6 -0
  40. package/dist/packages/backend-defaults/package.json.cjs.js.map +1 -0
  41. package/dist/packages/backend-plugin-api/package.json.cjs.js +6 -0
  42. package/dist/packages/backend-plugin-api/package.json.cjs.js.map +1 -0
  43. package/dist/packages/backend-test-utils/package.json.cjs.js +6 -0
  44. package/dist/packages/backend-test-utils/package.json.cjs.js.map +1 -0
  45. package/dist/packages/catalog-client/package.json.cjs.js +6 -0
  46. package/dist/packages/catalog-client/package.json.cjs.js.map +1 -0
  47. package/dist/packages/cli/package.json.cjs.js +6 -0
  48. package/dist/packages/cli/package.json.cjs.js.map +1 -0
  49. package/dist/packages/cli-module-new/package.json.cjs.js +99 -0
  50. package/dist/packages/cli-module-new/package.json.cjs.js.map +1 -0
  51. package/dist/packages/config/package.json.cjs.js +6 -0
  52. package/dist/packages/config/package.json.cjs.js.map +1 -0
  53. package/dist/packages/core-app-api/package.json.cjs.js +6 -0
  54. package/dist/packages/core-app-api/package.json.cjs.js.map +1 -0
  55. package/dist/packages/core-components/package.json.cjs.js +6 -0
  56. package/dist/packages/core-components/package.json.cjs.js.map +1 -0
  57. package/dist/packages/core-plugin-api/package.json.cjs.js +6 -0
  58. package/dist/packages/core-plugin-api/package.json.cjs.js.map +1 -0
  59. package/dist/packages/dev-utils/package.json.cjs.js +6 -0
  60. package/dist/packages/dev-utils/package.json.cjs.js.map +1 -0
  61. package/dist/packages/errors/package.json.cjs.js +6 -0
  62. package/dist/packages/errors/package.json.cjs.js.map +1 -0
  63. package/dist/packages/frontend-defaults/package.json.cjs.js +6 -0
  64. package/dist/packages/frontend-defaults/package.json.cjs.js.map +1 -0
  65. package/dist/packages/frontend-dev-utils/package.json.cjs.js +6 -0
  66. package/dist/packages/frontend-dev-utils/package.json.cjs.js.map +1 -0
  67. package/dist/packages/frontend-plugin-api/package.json.cjs.js +6 -0
  68. package/dist/packages/frontend-plugin-api/package.json.cjs.js.map +1 -0
  69. package/dist/packages/frontend-test-utils/package.json.cjs.js +6 -0
  70. package/dist/packages/frontend-test-utils/package.json.cjs.js.map +1 -0
  71. package/dist/packages/test-utils/package.json.cjs.js +6 -0
  72. package/dist/packages/test-utils/package.json.cjs.js.map +1 -0
  73. package/dist/packages/theme/package.json.cjs.js +6 -0
  74. package/dist/packages/theme/package.json.cjs.js.map +1 -0
  75. package/dist/packages/types/package.json.cjs.js +6 -0
  76. package/dist/packages/types/package.json.cjs.js.map +1 -0
  77. package/dist/plugins/auth-backend/package.json.cjs.js +6 -0
  78. package/dist/plugins/auth-backend/package.json.cjs.js.map +1 -0
  79. package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +6 -0
  80. package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js.map +1 -0
  81. package/dist/plugins/catalog-node/package.json.cjs.js +6 -0
  82. package/dist/plugins/catalog-node/package.json.cjs.js.map +1 -0
  83. package/dist/plugins/scaffolder-node/package.json.cjs.js +6 -0
  84. package/dist/plugins/scaffolder-node/package.json.cjs.js.map +1 -0
  85. package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js +6 -0
  86. package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js.map +1 -0
  87. package/package.json +69 -0
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs-extra');
4
+ var upperFirst = require('lodash/upperFirst');
5
+ var camelCase = require('lodash/camelCase');
6
+ var cliCommon = require('@backstage/cli-common');
7
+ var tasks = require('../tasks.cjs.js');
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 upperFirst__default = /*#__PURE__*/_interopDefaultCompat(upperFirst);
13
+ var camelCase__default = /*#__PURE__*/_interopDefaultCompat(camelCase);
14
+
15
+ async function installNewPackage(input) {
16
+ switch (input.roleParams.role) {
17
+ case "web-library":
18
+ case "node-library":
19
+ case "common-library":
20
+ case "plugin-web-library":
21
+ case "plugin-node-library":
22
+ case "plugin-common-library":
23
+ return;
24
+ // No installation action needed for library packages
25
+ case "frontend-plugin":
26
+ await addDependency(input, "packages/app/package.json");
27
+ await tryAddFrontendLegacy(input);
28
+ return;
29
+ case "frontend-plugin-module":
30
+ await addDependency(input, "packages/app/package.json");
31
+ return;
32
+ case "backend-plugin":
33
+ await addDependency(input, "packages/backend/package.json");
34
+ await tryAddBackend(input);
35
+ return;
36
+ case "backend-plugin-module":
37
+ await addDependency(input, "packages/backend/package.json");
38
+ await tryAddBackend(input);
39
+ return;
40
+ default:
41
+ throw new Error(
42
+ `Unsupported role ${input.roleParams.role}`
43
+ );
44
+ }
45
+ }
46
+ async function addDependency(input, path) {
47
+ const pkgJsonPath = cliCommon.targetPaths.resolveRoot(path);
48
+ const pkgJson = await fs__default.default.readJson(pkgJsonPath).catch((error) => {
49
+ if (error.code === "ENOENT") {
50
+ return void 0;
51
+ }
52
+ throw error;
53
+ });
54
+ if (!pkgJson) {
55
+ return;
56
+ }
57
+ try {
58
+ pkgJson.dependencies = {
59
+ ...pkgJson.dependencies,
60
+ [input.packageName]: `workspace:^`
61
+ };
62
+ await fs__default.default.writeJson(path, pkgJson, { spaces: 2 });
63
+ } catch (error) {
64
+ throw new Error(`Failed to add package dependencies, ${error}`);
65
+ }
66
+ }
67
+ async function tryAddFrontendLegacy(input) {
68
+ const { roleParams } = input;
69
+ if (roleParams.role !== "frontend-plugin") {
70
+ throw new Error(
71
+ "add-frontend-legacy can only be used for frontend plugins"
72
+ );
73
+ }
74
+ const appDefinitionPath = cliCommon.targetPaths.resolveRoot("packages/app/src/App.tsx");
75
+ if (!await fs__default.default.pathExists(appDefinitionPath)) {
76
+ return;
77
+ }
78
+ await tasks.Task.forItem("app", "adding import", async () => {
79
+ const content = await fs__default.default.readFile(appDefinitionPath, "utf8");
80
+ const revLines = content.split("\n").reverse();
81
+ const lastImportIndex = revLines.findIndex(
82
+ (line) => line.match(/ from ("|').*("|')/)
83
+ );
84
+ const lastRouteIndex = revLines.findIndex(
85
+ (line) => line.match(/<\/FlatRoutes/)
86
+ );
87
+ if (lastImportIndex !== -1 && lastRouteIndex !== -1) {
88
+ const extensionName = upperFirst__default.default(`${camelCase__default.default(roleParams.pluginId)}Page`);
89
+ const importLine = `import { ${extensionName} } from '${input.packageName}';`;
90
+ if (!content.includes(importLine)) {
91
+ revLines.splice(lastImportIndex, 0, importLine);
92
+ }
93
+ const componentLine = `<Route path="/${roleParams.pluginId}" element={<${extensionName} />} />`;
94
+ if (!content.includes(componentLine)) {
95
+ const [indentation] = revLines[lastRouteIndex + 1].match(/^\s*/) ?? [];
96
+ revLines.splice(lastRouteIndex + 1, 0, indentation + componentLine);
97
+ }
98
+ const newContent = revLines.reverse().join("\n");
99
+ await fs__default.default.writeFile(appDefinitionPath, newContent, "utf8");
100
+ }
101
+ });
102
+ }
103
+ async function tryAddBackend(input) {
104
+ const backendIndexPath = cliCommon.targetPaths.resolveRoot(
105
+ "packages/backend/src/index.ts"
106
+ );
107
+ if (!await fs__default.default.pathExists(backendIndexPath)) {
108
+ return;
109
+ }
110
+ await tasks.Task.forItem("backend", `adding ${input.packageName}`, async () => {
111
+ const content = await fs__default.default.readFile(backendIndexPath, "utf8");
112
+ const lines = content.split("\n");
113
+ const backendAddLine = `backend.add(import('${input.packageName}'));`;
114
+ const backendStartIndex = lines.findIndex(
115
+ (line) => line.match(/backend.start/)
116
+ );
117
+ if (backendStartIndex !== -1) {
118
+ const [indentation] = lines[backendStartIndex].match(/^\s*/);
119
+ lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`);
120
+ const newContent = lines.join("\n");
121
+ await fs__default.default.writeFile(backendIndexPath, newContent, "utf8");
122
+ }
123
+ });
124
+ }
125
+
126
+ exports.installNewPackage = installNewPackage;
127
+ //# sourceMappingURL=installNewPackage.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installNewPackage.cjs.js","sources":["../../../src/lib/execution/installNewPackage.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 */\nimport fs from 'fs-extra';\nimport upperFirst from 'lodash/upperFirst';\nimport camelCase from 'lodash/camelCase';\nimport { targetPaths } from '@backstage/cli-common';\n\nimport { Task } from '../tasks';\nimport { PortableTemplateInput } from '../types';\n\nexport async function installNewPackage(input: PortableTemplateInput) {\n switch (input.roleParams.role) {\n case 'web-library':\n case 'node-library':\n case 'common-library':\n case 'plugin-web-library':\n case 'plugin-node-library':\n case 'plugin-common-library':\n return; // No installation action needed for library packages\n case 'frontend-plugin':\n await addDependency(input, 'packages/app/package.json');\n await tryAddFrontendLegacy(input);\n return;\n case 'frontend-plugin-module':\n await addDependency(input, 'packages/app/package.json');\n return;\n case 'backend-plugin':\n await addDependency(input, 'packages/backend/package.json');\n await tryAddBackend(input);\n return;\n case 'backend-plugin-module':\n await addDependency(input, 'packages/backend/package.json');\n await tryAddBackend(input);\n return;\n default:\n throw new Error(\n `Unsupported role ${(input.roleParams as { role: string }).role}`,\n );\n }\n}\n\nasync function addDependency(input: PortableTemplateInput, path: string) {\n const pkgJsonPath = targetPaths.resolveRoot(path);\n\n const pkgJson = await fs.readJson(pkgJsonPath).catch(error => {\n if (error.code === 'ENOENT') {\n return undefined;\n }\n throw error;\n });\n if (!pkgJson) {\n return;\n }\n\n try {\n pkgJson.dependencies = {\n ...pkgJson.dependencies,\n [input.packageName]: `workspace:^`,\n };\n\n await fs.writeJson(path, pkgJson, { spaces: 2 });\n } catch (error) {\n throw new Error(`Failed to add package dependencies, ${error}`);\n }\n}\n\nasync function tryAddFrontendLegacy(input: PortableTemplateInput) {\n const { roleParams } = input;\n if (roleParams.role !== 'frontend-plugin') {\n throw new Error(\n 'add-frontend-legacy can only be used for frontend plugins',\n );\n }\n\n const appDefinitionPath = targetPaths.resolveRoot('packages/app/src/App.tsx');\n if (!(await fs.pathExists(appDefinitionPath))) {\n return;\n }\n\n await Task.forItem('app', 'adding import', async () => {\n const content = await fs.readFile(appDefinitionPath, 'utf8');\n const revLines = content.split('\\n').reverse();\n\n const lastImportIndex = revLines.findIndex(line =>\n line.match(/ from (\"|').*(\"|')/),\n );\n const lastRouteIndex = revLines.findIndex(line =>\n line.match(/<\\/FlatRoutes/),\n );\n\n if (lastImportIndex !== -1 && lastRouteIndex !== -1) {\n const extensionName = upperFirst(`${camelCase(roleParams.pluginId)}Page`);\n const importLine = `import { ${extensionName} } from '${input.packageName}';`;\n if (!content.includes(importLine)) {\n revLines.splice(lastImportIndex, 0, importLine);\n }\n\n const componentLine = `<Route path=\"/${roleParams.pluginId}\" element={<${extensionName} />} />`;\n if (!content.includes(componentLine)) {\n const [indentation] = revLines[lastRouteIndex + 1].match(/^\\s*/) ?? [];\n revLines.splice(lastRouteIndex + 1, 0, indentation + componentLine);\n }\n\n const newContent = revLines.reverse().join('\\n');\n await fs.writeFile(appDefinitionPath, newContent, 'utf8');\n }\n });\n}\n\nasync function tryAddBackend(input: PortableTemplateInput) {\n const backendIndexPath = targetPaths.resolveRoot(\n 'packages/backend/src/index.ts',\n );\n if (!(await fs.pathExists(backendIndexPath))) {\n return;\n }\n\n await Task.forItem('backend', `adding ${input.packageName}`, async () => {\n const content = await fs.readFile(backendIndexPath, 'utf8');\n const lines = content.split('\\n');\n const backendAddLine = `backend.add(import('${input.packageName}'));`;\n\n const backendStartIndex = lines.findIndex(line =>\n line.match(/backend.start/),\n );\n\n if (backendStartIndex !== -1) {\n const [indentation] = lines[backendStartIndex].match(/^\\s*/)!;\n lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`);\n\n const newContent = lines.join('\\n');\n await fs.writeFile(backendIndexPath, newContent, 'utf8');\n }\n });\n}\n"],"names":["targetPaths","fs","Task","upperFirst","camelCase"],"mappings":";;;;;;;;;;;;;;AAuBA,eAAsB,kBAAkB,KAAA,EAA8B;AACpE,EAAA,QAAQ,KAAA,CAAM,WAAW,IAAA;AAAM,IAC7B,KAAK,aAAA;AAAA,IACL,KAAK,cAAA;AAAA,IACL,KAAK,gBAAA;AAAA,IACL,KAAK,oBAAA;AAAA,IACL,KAAK,qBAAA;AAAA,IACL,KAAK,uBAAA;AACH,MAAA;AAAA;AAAA,IACF,KAAK,iBAAA;AACH,MAAA,MAAM,aAAA,CAAc,OAAO,2BAA2B,CAAA;AACtD,MAAA,MAAM,qBAAqB,KAAK,CAAA;AAChC,MAAA;AAAA,IACF,KAAK,wBAAA;AACH,MAAA,MAAM,aAAA,CAAc,OAAO,2BAA2B,CAAA;AACtD,MAAA;AAAA,IACF,KAAK,gBAAA;AACH,MAAA,MAAM,aAAA,CAAc,OAAO,+BAA+B,CAAA;AAC1D,MAAA,MAAM,cAAc,KAAK,CAAA;AACzB,MAAA;AAAA,IACF,KAAK,uBAAA;AACH,MAAA,MAAM,aAAA,CAAc,OAAO,+BAA+B,CAAA;AAC1D,MAAA,MAAM,cAAc,KAAK,CAAA;AACzB,MAAA;AAAA,IACF;AACE,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,iBAAA,EAAqB,KAAA,CAAM,UAAA,CAAgC,IAAI,CAAA;AAAA,OACjE;AAAA;AAEN;AAEA,eAAe,aAAA,CAAc,OAA8B,IAAA,EAAc;AACvE,EAAA,MAAM,WAAA,GAAcA,qBAAA,CAAY,WAAA,CAAY,IAAI,CAAA;AAEhD,EAAA,MAAM,UAAU,MAAMC,mBAAA,CAAG,SAAS,WAAW,CAAA,CAAE,MAAM,CAAA,KAAA,KAAS;AAC5D,IAAA,IAAI,KAAA,CAAM,SAAS,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,MAAM,KAAA;AAAA,EACR,CAAC,CAAA;AACD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,YAAA,GAAe;AAAA,MACrB,GAAG,OAAA,CAAQ,YAAA;AAAA,MACX,CAAC,KAAA,CAAM,WAAW,GAAG,CAAA,WAAA;AAAA,KACvB;AAEA,IAAA,MAAMA,oBAAG,SAAA,CAAU,IAAA,EAAM,SAAS,EAAE,MAAA,EAAQ,GAAG,CAAA;AAAA,EACjD,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oCAAA,EAAuC,KAAK,CAAA,CAAE,CAAA;AAAA,EAChE;AACF;AAEA,eAAe,qBAAqB,KAAA,EAA8B;AAChE,EAAA,MAAM,EAAE,YAAW,GAAI,KAAA;AACvB,EAAA,IAAI,UAAA,CAAW,SAAS,iBAAA,EAAmB;AACzC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,iBAAA,GAAoBD,qBAAA,CAAY,WAAA,CAAY,0BAA0B,CAAA;AAC5E,EAAA,IAAI,CAAE,MAAMC,mBAAA,CAAG,UAAA,CAAW,iBAAiB,CAAA,EAAI;AAC7C,IAAA;AAAA,EACF;AAEA,EAAA,MAAMC,UAAA,CAAK,OAAA,CAAQ,KAAA,EAAO,eAAA,EAAiB,YAAY;AACrD,IAAA,MAAM,OAAA,GAAU,MAAMD,mBAAA,CAAG,QAAA,CAAS,mBAAmB,MAAM,CAAA;AAC3D,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,CAAM,IAAI,EAAE,OAAA,EAAQ;AAE7C,IAAA,MAAM,kBAAkB,QAAA,CAAS,SAAA;AAAA,MAAU,CAAA,IAAA,KACzC,IAAA,CAAK,KAAA,CAAM,oBAAoB;AAAA,KACjC;AACA,IAAA,MAAM,iBAAiB,QAAA,CAAS,SAAA;AAAA,MAAU,CAAA,IAAA,KACxC,IAAA,CAAK,KAAA,CAAM,eAAe;AAAA,KAC5B;AAEA,IAAA,IAAI,eAAA,KAAoB,EAAA,IAAM,cAAA,KAAmB,EAAA,EAAI;AACnD,MAAA,MAAM,gBAAgBE,2BAAA,CAAW,CAAA,EAAGC,2BAAU,UAAA,CAAW,QAAQ,CAAC,CAAA,IAAA,CAAM,CAAA;AACxE,MAAA,MAAM,UAAA,GAAa,CAAA,SAAA,EAAY,aAAa,CAAA,SAAA,EAAY,MAAM,WAAW,CAAA,EAAA,CAAA;AACzE,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,UAAU,CAAA,EAAG;AACjC,QAAA,QAAA,CAAS,MAAA,CAAO,eAAA,EAAiB,CAAA,EAAG,UAAU,CAAA;AAAA,MAChD;AAEA,MAAA,MAAM,aAAA,GAAgB,CAAA,cAAA,EAAiB,UAAA,CAAW,QAAQ,eAAe,aAAa,CAAA,OAAA,CAAA;AACtF,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,aAAa,CAAA,EAAG;AACpC,QAAA,MAAM,CAAC,WAAW,CAAA,GAAI,QAAA,CAAS,cAAA,GAAiB,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA,IAAK,EAAC;AACrE,QAAA,QAAA,CAAS,MAAA,CAAO,cAAA,GAAiB,CAAA,EAAG,CAAA,EAAG,cAAc,aAAa,CAAA;AAAA,MACpE;AAEA,MAAA,MAAM,UAAA,GAAa,QAAA,CAAS,OAAA,EAAQ,CAAE,KAAK,IAAI,CAAA;AAC/C,MAAA,MAAMH,mBAAA,CAAG,SAAA,CAAU,iBAAA,EAAmB,UAAA,EAAY,MAAM,CAAA;AAAA,IAC1D;AAAA,EACF,CAAC,CAAA;AACH;AAEA,eAAe,cAAc,KAAA,EAA8B;AACzD,EAAA,MAAM,mBAAmBD,qBAAA,CAAY,WAAA;AAAA,IACnC;AAAA,GACF;AACA,EAAA,IAAI,CAAE,MAAMC,mBAAA,CAAG,UAAA,CAAW,gBAAgB,CAAA,EAAI;AAC5C,IAAA;AAAA,EACF;AAEA,EAAA,MAAMC,WAAK,OAAA,CAAQ,SAAA,EAAW,UAAU,KAAA,CAAM,WAAW,IAAI,YAAY;AACvE,IAAA,MAAM,OAAA,GAAU,MAAMD,mBAAA,CAAG,QAAA,CAAS,kBAAkB,MAAM,CAAA;AAC1D,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AAChC,IAAA,MAAM,cAAA,GAAiB,CAAA,oBAAA,EAAuB,KAAA,CAAM,WAAW,CAAA,IAAA,CAAA;AAE/D,IAAA,MAAM,oBAAoB,KAAA,CAAM,SAAA;AAAA,MAAU,CAAA,IAAA,KACxC,IAAA,CAAK,KAAA,CAAM,eAAe;AAAA,KAC5B;AAEA,IAAA,IAAI,sBAAsB,EAAA,EAAI;AAC5B,MAAA,MAAM,CAAC,WAAW,CAAA,GAAI,MAAM,iBAAiB,CAAA,CAAE,MAAM,MAAM,CAAA;AAC3D,MAAA,KAAA,CAAM,OAAO,iBAAA,EAAmB,CAAA,EAAG,GAAG,WAAW,CAAA,EAAG,cAAc,CAAA,CAAE,CAAA;AAEpE,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAClC,MAAA,MAAMA,mBAAA,CAAG,SAAA,CAAU,gBAAA,EAAkB,UAAA,EAAY,MAAM,CAAA;AAAA,IACzD;AAAA,EACF,CAAC,CAAA;AACH;;;;"}
@@ -0,0 +1,116 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs-extra');
4
+ var path = require('node:path');
5
+ var errors = require('@backstage/errors');
6
+ var cliNode = require('@backstage/cli-node');
7
+ var PortableTemplater = require('./PortableTemplater.cjs.js');
8
+ var cliCommon = require('@backstage/cli-common');
9
+
10
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
+
12
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
13
+
14
+ async function writeTemplateContents(template, input) {
15
+ const targetDir = cliCommon.targetPaths.resolveRoot(input.packagePath);
16
+ if (await fs__default.default.pathExists(targetDir)) {
17
+ throw new errors.InputError(`Package '${input.packagePath}' already exists`);
18
+ }
19
+ try {
20
+ const isMonoRepo = await cliNode.isMonoRepo();
21
+ const { role, ...roleValues } = input.roleParams;
22
+ const templater = await PortableTemplater.PortableTemplater.create({
23
+ values: {
24
+ ...roleValues,
25
+ packageName: input.packageName
26
+ },
27
+ templatedValues: template.values
28
+ });
29
+ if (!isMonoRepo) {
30
+ await fs__default.default.writeJson(
31
+ path.resolve(targetDir, "tsconfig.json"),
32
+ {
33
+ extends: "@backstage/cli/config/tsconfig.json",
34
+ include: ["src", "dev", "migrations"],
35
+ exclude: ["node_modules"],
36
+ compilerOptions: {
37
+ outDir: "dist-types",
38
+ rootDir: "."
39
+ }
40
+ },
41
+ { spaces: 2 }
42
+ );
43
+ }
44
+ for (const file of template.files) {
45
+ const destPath = path.resolve(targetDir, templater.template(file.path));
46
+ if (!cliCommon.isChildPath(targetDir, destPath)) {
47
+ throw new Error(
48
+ `Path ${destPath} is outside of target directory ${targetDir}`
49
+ );
50
+ }
51
+ await fs__default.default.ensureDir(path.dirname(destPath));
52
+ let content = file.syntax === "handlebars" ? templater.template(file.content) : file.content;
53
+ if (file.path === "package.json") {
54
+ try {
55
+ content = injectPackageJsonInput(input, content);
56
+ } catch (error) {
57
+ throw new errors.ForwardedError(
58
+ "Failed to transform templated package.json",
59
+ error
60
+ );
61
+ }
62
+ }
63
+ await fs__default.default.writeFile(destPath, content).catch((error) => {
64
+ throw new errors.ForwardedError(`Failed to copy file to ${destPath}`, error);
65
+ });
66
+ }
67
+ return { targetDir };
68
+ } catch (error) {
69
+ await fs__default.default.rm(targetDir, { recursive: true, force: true, maxRetries: 10 });
70
+ throw error;
71
+ }
72
+ }
73
+ function injectPackageJsonInput(input, content) {
74
+ const pkgJson = JSON.parse(content);
75
+ const toAdd = new Array();
76
+ if (pkgJson.version) {
77
+ pkgJson.version = input.version;
78
+ } else {
79
+ toAdd.push(["version", input.version]);
80
+ }
81
+ if (pkgJson.license) {
82
+ pkgJson.license = input.license;
83
+ } else {
84
+ toAdd.push(["license", input.license]);
85
+ }
86
+ if (input.private) {
87
+ if (pkgJson.private === false) {
88
+ pkgJson.private = true;
89
+ } else if (!pkgJson.private) {
90
+ toAdd.push(["private", true]);
91
+ }
92
+ } else {
93
+ delete pkgJson.private;
94
+ }
95
+ if (input.publishRegistry) {
96
+ if (pkgJson.publishConfig) {
97
+ pkgJson.publishConfig = {
98
+ ...pkgJson.publishConfig,
99
+ registry: input.publishRegistry
100
+ };
101
+ } else {
102
+ toAdd.push(["publishConfig", { registry: input.publishRegistry }]);
103
+ }
104
+ }
105
+ const entries = Object.entries(pkgJson);
106
+ const nameIndex = entries.findIndex(([name]) => name === "name");
107
+ if (nameIndex === -1) {
108
+ throw new Error("templated package.json does not contain a name field");
109
+ }
110
+ entries.splice(nameIndex + 1, 0, ...toAdd);
111
+ return JSON.stringify(Object.fromEntries(entries), null, 2);
112
+ }
113
+
114
+ exports.injectPackageJsonInput = injectPackageJsonInput;
115
+ exports.writeTemplateContents = writeTemplateContents;
116
+ //# sourceMappingURL=writeTemplateContents.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeTemplateContents.cjs.js","sources":["../../../src/lib/execution/writeTemplateContents.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { dirname, resolve as resolvePath } from 'node:path';\n\nimport { PortableTemplate, PortableTemplateInput } from '../types';\nimport { ForwardedError, InputError } from '@backstage/errors';\nimport { isMonoRepo as getIsMonoRepo } from '@backstage/cli-node';\nimport { PortableTemplater } from './PortableTemplater';\nimport { isChildPath, targetPaths } from '@backstage/cli-common';\n\nexport async function writeTemplateContents(\n template: PortableTemplate,\n input: PortableTemplateInput,\n): Promise<{ targetDir: string }> {\n const targetDir = targetPaths.resolveRoot(input.packagePath);\n\n if (await fs.pathExists(targetDir)) {\n throw new InputError(`Package '${input.packagePath}' already exists`);\n }\n\n try {\n const isMonoRepo = await getIsMonoRepo();\n\n const { role, ...roleValues } = input.roleParams;\n\n const templater = await PortableTemplater.create({\n values: {\n ...roleValues,\n packageName: input.packageName,\n },\n templatedValues: template.values,\n });\n\n if (!isMonoRepo) {\n await fs.writeJson(\n resolvePath(targetDir, 'tsconfig.json'),\n {\n extends: '@backstage/cli/config/tsconfig.json',\n include: ['src', 'dev', 'migrations'],\n exclude: ['node_modules'],\n compilerOptions: {\n outDir: 'dist-types',\n rootDir: '.',\n },\n },\n { spaces: 2 },\n );\n }\n\n for (const file of template.files) {\n const destPath = resolvePath(targetDir, templater.template(file.path));\n if (!isChildPath(targetDir, destPath)) {\n throw new Error(\n `Path ${destPath} is outside of target directory ${targetDir}`,\n );\n }\n await fs.ensureDir(dirname(destPath));\n\n let content =\n file.syntax === 'handlebars'\n ? templater.template(file.content)\n : file.content;\n\n // Automatically inject input values into package.json\n if (file.path === 'package.json') {\n try {\n content = injectPackageJsonInput(input, content);\n } catch (error) {\n throw new ForwardedError(\n 'Failed to transform templated package.json',\n error,\n );\n }\n }\n\n await fs.writeFile(destPath, content).catch(error => {\n throw new ForwardedError(`Failed to copy file to ${destPath}`, error);\n });\n }\n\n return { targetDir };\n } catch (error) {\n await fs.rm(targetDir, { recursive: true, force: true, maxRetries: 10 });\n throw error;\n }\n}\n\nexport function injectPackageJsonInput(\n input: PortableTemplateInput,\n content: string,\n) {\n const pkgJson = JSON.parse(content);\n\n const toAdd = new Array<[name: string, value: unknown]>();\n\n if (pkgJson.version) {\n pkgJson.version = input.version;\n } else {\n toAdd.push(['version', input.version]);\n }\n if (pkgJson.license) {\n pkgJson.license = input.license;\n } else {\n toAdd.push(['license', input.license]);\n }\n if (input.private) {\n if (pkgJson.private === false) {\n pkgJson.private = true;\n } else if (!pkgJson.private) {\n toAdd.push(['private', true]);\n }\n } else {\n delete pkgJson.private;\n }\n\n if (input.publishRegistry) {\n if (pkgJson.publishConfig) {\n pkgJson.publishConfig = {\n ...pkgJson.publishConfig,\n registry: input.publishRegistry,\n };\n } else {\n toAdd.push(['publishConfig', { registry: input.publishRegistry }]);\n }\n }\n\n const entries = Object.entries(pkgJson);\n\n const nameIndex = entries.findIndex(([name]) => name === 'name');\n if (nameIndex === -1) {\n throw new Error('templated package.json does not contain a name field');\n }\n\n entries.splice(nameIndex + 1, 0, ...toAdd);\n\n return JSON.stringify(Object.fromEntries(entries), null, 2);\n}\n"],"names":["targetPaths","fs","InputError","getIsMonoRepo","PortableTemplater","resolvePath","isChildPath","dirname","ForwardedError"],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ var inquirer = require('inquirer');
4
+ var codeowners = require('../codeowners/codeowners.cjs.js');
5
+ var cliCommon = require('@backstage/cli-common');
6
+ var resolvePackageParams = require('./resolvePackageParams.cjs.js');
7
+
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
9
+
10
+ var inquirer__default = /*#__PURE__*/_interopDefaultCompat(inquirer);
11
+
12
+ async function collectPortableTemplateInput(options) {
13
+ const { config, template, prefilledParams } = options;
14
+ const codeOwnersFilePath = await codeowners.getCodeownersFilePath(cliCommon.targetPaths.rootDir);
15
+ const prompts = getPromptsForRole(template.role);
16
+ if (codeOwnersFilePath) {
17
+ prompts.push(ownerPrompt());
18
+ }
19
+ const deprecatedParams = {};
20
+ if (config.isUsingDefaultTemplates && prefilledParams.id) {
21
+ console.warn(
22
+ `DEPRECATION WARNING: The 'id' parameter is deprecated, use 'pluginId' instead`
23
+ );
24
+ deprecatedParams.pluginId = prefilledParams.id;
25
+ }
26
+ const parameters = {
27
+ ...template.values,
28
+ ...prefilledParams,
29
+ ...deprecatedParams
30
+ };
31
+ const needsAnswer = [];
32
+ const prefilledAnswers = {};
33
+ for (const prompt of prompts) {
34
+ if (prompt.name && parameters[prompt.name] !== void 0) {
35
+ prefilledAnswers[prompt.name] = parameters[prompt.name];
36
+ } else {
37
+ needsAnswer.push(prompt);
38
+ }
39
+ }
40
+ const promptAnswers = await inquirer__default.default.prompt(
41
+ needsAnswer
42
+ );
43
+ const answers = {
44
+ ...prefilledAnswers,
45
+ ...promptAnswers
46
+ };
47
+ const roleParams = {
48
+ role: template.role,
49
+ name: answers.name,
50
+ pluginId: answers.pluginId,
51
+ moduleId: answers.moduleId
52
+ };
53
+ const packageParams = resolvePackageParams.resolvePackageParams({
54
+ roleParams,
55
+ packagePrefix: config.packageNamePrefix,
56
+ pluginInfix: config.packageNamePluginInfix
57
+ });
58
+ return {
59
+ roleParams,
60
+ owner: answers.owner,
61
+ license: config.license,
62
+ version: config.version,
63
+ private: config.private,
64
+ publishRegistry: config.publishRegistry,
65
+ packageName: packageParams.packageName,
66
+ packagePath: packageParams.packagePath
67
+ };
68
+ }
69
+ function namePrompt() {
70
+ return {
71
+ type: "input",
72
+ name: "name",
73
+ message: "Enter the name of the package, without scope [required]",
74
+ validate: (value) => {
75
+ if (!value) {
76
+ return "Please enter the name of the package";
77
+ } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
78
+ return "Package names must be lowercase and contain only letters, digits, and dashes.";
79
+ }
80
+ return true;
81
+ }
82
+ };
83
+ }
84
+ function pluginIdPrompt() {
85
+ return {
86
+ type: "input",
87
+ name: "pluginId",
88
+ message: "Enter the ID of the plugin [required]",
89
+ validate: (value) => {
90
+ if (!value) {
91
+ return "Please enter the ID of the plugin";
92
+ } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
93
+ return "Plugin IDs must be lowercase and contain only letters, digits, and dashes.";
94
+ }
95
+ return true;
96
+ }
97
+ };
98
+ }
99
+ function moduleIdIdPrompt() {
100
+ return {
101
+ type: "input",
102
+ name: "moduleId",
103
+ message: "Enter the ID of the module [required]",
104
+ validate: (value) => {
105
+ if (!value) {
106
+ return "Please enter the ID of the module";
107
+ } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
108
+ return "Module IDs must be lowercase and contain only letters, digits, and dashes.";
109
+ }
110
+ return true;
111
+ }
112
+ };
113
+ }
114
+ function getPromptsForRole(role) {
115
+ switch (role) {
116
+ case "web-library":
117
+ case "node-library":
118
+ case "common-library":
119
+ return [namePrompt()];
120
+ case "plugin-web-library":
121
+ case "plugin-node-library":
122
+ case "plugin-common-library":
123
+ case "frontend-plugin":
124
+ case "backend-plugin":
125
+ return [pluginIdPrompt()];
126
+ case "frontend-plugin-module":
127
+ case "backend-plugin-module":
128
+ return [pluginIdPrompt(), moduleIdIdPrompt()];
129
+ default:
130
+ return [];
131
+ }
132
+ }
133
+ function ownerPrompt() {
134
+ return {
135
+ type: "input",
136
+ name: "owner",
137
+ message: "Enter an owner to add to CODEOWNERS [optional]",
138
+ validate: (value) => {
139
+ if (!value) {
140
+ return true;
141
+ }
142
+ const ownerIds = codeowners.parseOwnerIds(value);
143
+ if (!ownerIds) {
144
+ return "The owner must be a space separated list of team names (e.g. @org/team-name), usernames (e.g. @username), or the email addresses (e.g. user@example.com).";
145
+ }
146
+ return true;
147
+ }
148
+ };
149
+ }
150
+
151
+ exports.collectPortableTemplateInput = collectPortableTemplateInput;
152
+ exports.getPromptsForRole = getPromptsForRole;
153
+ exports.moduleIdIdPrompt = moduleIdIdPrompt;
154
+ exports.namePrompt = namePrompt;
155
+ exports.ownerPrompt = ownerPrompt;
156
+ exports.pluginIdPrompt = pluginIdPrompt;
157
+ //# sourceMappingURL=collectPortableTemplateInput.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectPortableTemplateInput.cjs.js","sources":["../../../src/lib/preparation/collectPortableTemplateInput.ts"],"sourcesContent":["/*\n * Copyright 2025 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 inquirer, { DistinctQuestion } from 'inquirer';\nimport { getCodeownersFilePath, parseOwnerIds } from '../codeowners';\nimport { targetPaths } from '@backstage/cli-common';\n\nimport {\n PortableTemplateConfig,\n PortableTemplateInput,\n PortableTemplateInputRoleParams,\n PortableTemplateParams,\n PortableTemplateRole,\n} from '../types';\nimport { PortableTemplate } from '../types';\nimport { resolvePackageParams } from './resolvePackageParams';\n\ntype CollectTemplateParamsOptions = {\n config: PortableTemplateConfig;\n template: PortableTemplate;\n prefilledParams: PortableTemplateParams;\n};\n\nexport async function collectPortableTemplateInput(\n options: CollectTemplateParamsOptions,\n): Promise<PortableTemplateInput> {\n const { config, template, prefilledParams } = options;\n\n const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.rootDir);\n\n const prompts = getPromptsForRole(template.role);\n\n if (codeOwnersFilePath) {\n prompts.push(ownerPrompt());\n }\n\n const deprecatedParams: PortableTemplateParams = {};\n if (config.isUsingDefaultTemplates && prefilledParams.id) {\n console.warn(\n `DEPRECATION WARNING: The 'id' parameter is deprecated, use 'pluginId' instead`,\n );\n deprecatedParams.pluginId = prefilledParams.id;\n }\n\n const parameters = {\n ...template.values,\n ...prefilledParams,\n ...deprecatedParams,\n };\n\n const needsAnswer = [];\n const prefilledAnswers = {} as PortableTemplateParams;\n for (const prompt of prompts) {\n if (prompt.name && parameters[prompt.name] !== undefined) {\n prefilledAnswers[prompt.name] = parameters[prompt.name];\n } else {\n needsAnswer.push(prompt);\n }\n }\n\n const promptAnswers = await inquirer.prompt<PortableTemplateParams>(\n needsAnswer,\n );\n\n const answers = {\n ...prefilledAnswers,\n ...promptAnswers,\n };\n\n const roleParams = {\n role: template.role,\n name: answers.name,\n pluginId: answers.pluginId,\n moduleId: answers.moduleId,\n } as PortableTemplateInputRoleParams;\n\n const packageParams = resolvePackageParams({\n roleParams,\n packagePrefix: config.packageNamePrefix,\n pluginInfix: config.packageNamePluginInfix,\n });\n\n return {\n roleParams,\n owner: answers.owner as string | undefined,\n license: config.license,\n version: config.version,\n private: config.private,\n publishRegistry: config.publishRegistry,\n packageName: packageParams.packageName,\n packagePath: packageParams.packagePath,\n };\n}\n\nexport function namePrompt(): DistinctQuestion {\n return {\n type: 'input',\n name: 'name',\n message: 'Enter the name of the package, without scope [required]',\n validate: (value: string) => {\n if (!value) {\n return 'Please enter the name of the package';\n } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return 'Package names must be lowercase and contain only letters, digits, and dashes.';\n }\n return true;\n },\n };\n}\n\nexport function pluginIdPrompt(): DistinctQuestion {\n return {\n type: 'input',\n name: 'pluginId',\n message: 'Enter the ID of the plugin [required]',\n validate: (value: string) => {\n if (!value) {\n return 'Please enter the ID of the plugin';\n } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return 'Plugin IDs must be lowercase and contain only letters, digits, and dashes.';\n }\n return true;\n },\n };\n}\n\nexport function moduleIdIdPrompt(): DistinctQuestion {\n return {\n type: 'input',\n name: 'moduleId',\n message: 'Enter the ID of the module [required]',\n validate: (value: string) => {\n if (!value) {\n return 'Please enter the ID of the module';\n } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return 'Module IDs must be lowercase and contain only letters, digits, and dashes.';\n }\n return true;\n },\n };\n}\n\nexport function getPromptsForRole(\n role: PortableTemplateRole,\n): Array<DistinctQuestion> {\n switch (role) {\n case 'web-library':\n case 'node-library':\n case 'common-library':\n return [namePrompt()];\n case 'plugin-web-library':\n case 'plugin-node-library':\n case 'plugin-common-library':\n case 'frontend-plugin':\n case 'backend-plugin':\n return [pluginIdPrompt()];\n case 'frontend-plugin-module':\n case 'backend-plugin-module':\n return [pluginIdPrompt(), moduleIdIdPrompt()];\n default:\n return [];\n }\n}\n\nexport function ownerPrompt(): DistinctQuestion {\n return {\n type: 'input',\n name: 'owner',\n message: 'Enter an owner to add to CODEOWNERS [optional]',\n validate: (value: string) => {\n if (!value) {\n return true;\n }\n\n const ownerIds = parseOwnerIds(value);\n if (!ownerIds) {\n return 'The owner must be a space separated list of team names (e.g. @org/team-name), usernames (e.g. @username), or the email addresses (e.g. user@example.com).';\n }\n\n return true;\n },\n };\n}\n"],"names":["getCodeownersFilePath","targetPaths","inquirer","resolvePackageParams","parseOwnerIds"],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ var fs = require('fs-extra');
5
+ var recursiveReaddir = require('recursive-readdir');
6
+ var path = require('node:path');
7
+ var yaml = require('yaml');
8
+ var cliCommon = require('@backstage/cli-common');
9
+ var types = require('../types.cjs.js');
10
+ var errors = require('@backstage/errors');
11
+ var v3 = require('zod-validation-error/v3');
12
+
13
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
14
+
15
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
16
+ var recursiveReaddir__default = /*#__PURE__*/_interopDefaultCompat(recursiveReaddir);
17
+
18
+ const templateDefinitionSchema = zod.z.object({
19
+ name: zod.z.string(),
20
+ role: zod.z.enum(types.TEMPLATE_ROLES),
21
+ description: zod.z.string().optional(),
22
+ values: zod.z.record(zod.z.string()).optional()
23
+ }).strict();
24
+ async function loadPortableTemplate(pointer) {
25
+ if (pointer.target.match(/https?:\/\//)) {
26
+ throw new Error("Remote templates are not supported yet");
27
+ }
28
+ const templateContent = await fs__default.default.readFile(cliCommon.targetPaths.resolveRoot(pointer.target), "utf-8").catch((error) => {
29
+ throw new errors.ForwardedError(
30
+ `Failed to load template definition from '${pointer.target}'`,
31
+ error
32
+ );
33
+ });
34
+ const rawTemplate = yaml.parse(templateContent);
35
+ const parsed = templateDefinitionSchema.safeParse(rawTemplate);
36
+ if (!parsed.success) {
37
+ throw new errors.ForwardedError(
38
+ `Invalid template definition at '${pointer.target}'`,
39
+ v3.fromZodError(parsed.error)
40
+ );
41
+ }
42
+ const { role, values = {} } = parsed.data;
43
+ const templatePath = path.resolve(path.dirname(pointer.target));
44
+ const filePaths = await recursiveReaddir__default.default(templatePath).catch((error) => {
45
+ throw new errors.ForwardedError(
46
+ `Failed to load template contents from '${templatePath}'`,
47
+ error
48
+ );
49
+ });
50
+ const loadedFiles = new Array();
51
+ for (const filePath of filePaths) {
52
+ const path$1 = path.relative(templatePath, filePath);
53
+ if (filePath === pointer.target) {
54
+ continue;
55
+ }
56
+ const content = await fs__default.default.readFile(filePath, "utf-8").catch((error) => {
57
+ throw new errors.ForwardedError(
58
+ `Failed to load file contents from '${path$1}'`,
59
+ error
60
+ );
61
+ });
62
+ if (path$1.endsWith(".hbs")) {
63
+ loadedFiles.push({
64
+ path: path$1.slice(0, -4),
65
+ content,
66
+ syntax: "handlebars"
67
+ });
68
+ } else {
69
+ loadedFiles.push({ path: path$1, content });
70
+ }
71
+ }
72
+ return {
73
+ name: pointer.name,
74
+ role,
75
+ files: loadedFiles,
76
+ values
77
+ };
78
+ }
79
+
80
+ exports.loadPortableTemplate = loadPortableTemplate;
81
+ //# sourceMappingURL=loadPortableTemplate.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadPortableTemplate.cjs.js","sources":["../../../src/lib/preparation/loadPortableTemplate.ts"],"sourcesContent":["/*\n * Copyright 2025 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 fs from 'fs-extra';\nimport recursiveReaddir from 'recursive-readdir';\nimport { resolve as resolvePath, relative as relativePath } from 'node:path';\nimport { dirname } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { targetPaths } from '@backstage/cli-common';\n\nimport {\n PortableTemplateFile,\n PortableTemplatePointer,\n TEMPLATE_ROLES,\n} from '../types';\nimport { PortableTemplate } from '../types';\nimport { ForwardedError } from '@backstage/errors';\nimport { fromZodError } from 'zod-validation-error/v3';\n\nconst templateDefinitionSchema = z\n .object({\n name: z.string(),\n role: z.enum(TEMPLATE_ROLES),\n description: z.string().optional(),\n values: z.record(z.string()).optional(),\n })\n .strict();\n\nexport async function loadPortableTemplate(\n pointer: PortableTemplatePointer,\n): Promise<PortableTemplate> {\n if (pointer.target.match(/https?:\\/\\//)) {\n throw new Error('Remote templates are not supported yet');\n }\n const templateContent = await fs\n .readFile(targetPaths.resolveRoot(pointer.target), 'utf-8')\n .catch(error => {\n throw new ForwardedError(\n `Failed to load template definition from '${pointer.target}'`,\n error,\n );\n });\n const rawTemplate = parseYaml(templateContent);\n\n const parsed = templateDefinitionSchema.safeParse(rawTemplate);\n if (!parsed.success) {\n throw new ForwardedError(\n `Invalid template definition at '${pointer.target}'`,\n fromZodError(parsed.error),\n );\n }\n\n const { role, values = {} } = parsed.data;\n\n const templatePath = resolvePath(dirname(pointer.target));\n const filePaths = await recursiveReaddir(templatePath).catch(error => {\n throw new ForwardedError(\n `Failed to load template contents from '${templatePath}'`,\n error,\n );\n });\n\n const loadedFiles = new Array<PortableTemplateFile>();\n\n for (const filePath of filePaths) {\n const path = relativePath(templatePath, filePath);\n if (filePath === pointer.target) {\n continue;\n }\n\n const content = await fs.readFile(filePath, 'utf-8').catch(error => {\n throw new ForwardedError(\n `Failed to load file contents from '${path}'`,\n error,\n );\n });\n\n if (path.endsWith('.hbs')) {\n loadedFiles.push({\n path: path.slice(0, -4),\n content,\n syntax: 'handlebars',\n });\n } else {\n loadedFiles.push({ path, content });\n }\n }\n\n return {\n name: pointer.name,\n role,\n files: loadedFiles,\n values,\n };\n}\n"],"names":["z","TEMPLATE_ROLES","fs","targetPaths","ForwardedError","parseYaml","fromZodError","resolvePath","dirname","recursiveReaddir","path","relativePath"],"mappings":"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"}