@backstage/repo-tools 0.11.0-next.0 → 0.11.0-next.2

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 (40) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/commands/generate-patch/generate-patch.cjs.js +321 -0
  3. package/dist/commands/index.cjs.js +22 -0
  4. package/dist/commands/package/schema/openapi/generate/client.cjs.js +10 -6
  5. package/dist/commands/package/schema/openapi/generate/server.cjs.js +84 -17
  6. package/dist/commands/repo/schema/openapi/verify.cjs.js +8 -3
  7. package/dist/lib/openapi/constants.cjs.js +5 -2
  8. package/dist/package.json.cjs.js +1 -1
  9. package/package.json +9 -8
  10. package/templates/{typescript-backstage → typescript-backstage-client}/api.mustache +37 -29
  11. package/templates/{typescript-backstage → typescript-backstage-client}/modelAlias.mustache +3 -0
  12. package/templates/{typescript-backstage → typescript-backstage-client}/modelEnum.mustache +9 -0
  13. package/templates/{typescript-backstage → typescript-backstage-client}/modelGeneric.mustache +11 -4
  14. package/templates/{typescript-backstage → typescript-backstage-client}/modelGenericEnums.mustache +13 -0
  15. package/templates/{typescript-backstage → typescript-backstage-client}/modelOneOf.mustache +3 -2
  16. package/templates/typescript-backstage-client.yaml +40 -0
  17. package/templates/typescript-backstage-server/api.mustache +54 -0
  18. package/templates/typescript-backstage-server/apis/index.mustache +3 -0
  19. package/templates/typescript-backstage-server/index.mustache +4 -0
  20. package/templates/typescript-backstage-server/licenseInfo.mustache +5 -0
  21. package/templates/typescript-backstage-server/model.mustache +11 -0
  22. package/templates/typescript-backstage-server/modelAlias.mustache +6 -0
  23. package/templates/typescript-backstage-server/modelEnum.mustache +31 -0
  24. package/templates/typescript-backstage-server/modelGeneric.mustache +45 -0
  25. package/templates/typescript-backstage-server/modelGenericAdditionalProperties.mustache +5 -0
  26. package/templates/typescript-backstage-server/modelGenericEnums.mustache +45 -0
  27. package/templates/typescript-backstage-server/modelOneOf.mustache +17 -0
  28. package/templates/typescript-backstage-server/modelTaggedUnion.mustache +23 -0
  29. package/templates/typescript-backstage-server/models/models_all.mustache +7 -0
  30. package/templates/{typescript-backstage.yaml → typescript-backstage-server.yaml} +9 -11
  31. /package/templates/{typescript-backstage → typescript-backstage-client}/apis/index.mustache +0 -0
  32. /package/templates/{typescript-backstage → typescript-backstage-client}/index.mustache +0 -0
  33. /package/templates/{typescript-backstage → typescript-backstage-client}/licenseInfo.mustache +0 -0
  34. /package/templates/{typescript-backstage → typescript-backstage-client}/model.mustache +0 -0
  35. /package/templates/{typescript-backstage → typescript-backstage-client}/modelGenericAdditionalProperties.mustache +0 -0
  36. /package/templates/{typescript-backstage → typescript-backstage-client}/modelTaggedUnion.mustache +0 -0
  37. /package/templates/{typescript-backstage → typescript-backstage-client}/models/models_all.mustache +0 -0
  38. /package/templates/{typescript-backstage → typescript-backstage-client}/pluginId.mustache +0 -0
  39. /package/templates/{typescript-backstage → typescript-backstage-client}/types/discovery.ts +0 -0
  40. /package/templates/{typescript-backstage → typescript-backstage-client}/types/fetch.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @backstage/repo-tools
2
2
 
3
+ ## 0.11.0-next.2
4
+
5
+ ### Minor Changes
6
+
7
+ - 1440232: `backstage-repo-tools package schema openapi generate --server` now generates complete TS interfaces for all request/response objects in your OpenAPI schema. This fixes an edge case around recursive schemas and standardizes both the generated client and server to have similar generated types.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/backend-plugin-api@1.0.2-next.2
13
+ - @backstage/catalog-model@1.7.0
14
+ - @backstage/cli-common@0.1.15-next.0
15
+ - @backstage/cli-node@0.2.10-next.0
16
+ - @backstage/config-loader@1.9.2-next.0
17
+ - @backstage/errors@1.2.4
18
+
19
+ ## 0.11.0-next.1
20
+
21
+ ### Patch Changes
22
+
23
+ - dde85ee: Added a new `generate-patch` command that can be used to generate patches for current changes in a source workspace to be installed it a target workspace.
24
+ - 702f41d: Bumped dev dependencies `@types/node`
25
+ - Updated dependencies
26
+ - @backstage/cli-common@0.1.15-next.0
27
+ - @backstage/backend-plugin-api@1.0.2-next.1
28
+ - @backstage/catalog-model@1.7.0
29
+ - @backstage/cli-node@0.2.10-next.0
30
+ - @backstage/config-loader@1.9.2-next.0
31
+ - @backstage/errors@1.2.4
32
+
3
33
  ## 0.11.0-next.0
4
34
 
5
35
  ### Minor Changes
@@ -0,0 +1,321 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var getPackages = require('@manypkg/get-packages');
6
+ var os = require('os');
7
+ var fs = require('fs-extra');
8
+ var path = require('path');
9
+ var exec = require('../../lib/exec.cjs.js');
10
+ var errors = require('@backstage/errors');
11
+ var stream = require('stream');
12
+ var promises = require('stream/promises');
13
+ var tar = require('tar');
14
+
15
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
16
+
17
+ var os__default = /*#__PURE__*/_interopDefaultCompat(os);
18
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
19
+ var tar__default = /*#__PURE__*/_interopDefaultCompat(tar);
20
+
21
+ const DEFAULT_REGISTRY_URL = "https://registry.npmjs.org";
22
+ const PATCH_GITIGNORE = [
23
+ // Avoid generating patches for source maps
24
+ "*.map",
25
+ // Patching package.json has no effect, so exclude
26
+ "package.json",
27
+ // No point patching docs
28
+ "/*.md",
29
+ "/docs"
30
+ ];
31
+ const GIT_ENV = {
32
+ GIT_CONFIG_NOSYSTEM: "1",
33
+ HOME: "",
34
+ XDG_CONFIG_HOME: "",
35
+ USERPROFILE: ""
36
+ };
37
+ var generatePatch = async (packageArg, opts) => {
38
+ const sourceRepo = await getPackages.getPackages(process.cwd());
39
+ const targetRepo = await getPackages.getPackages(opts.target);
40
+ const registryUrl = opts.registryUrl || DEFAULT_REGISTRY_URL;
41
+ if (targetRepo.tool !== "yarn") {
42
+ throw new Error(
43
+ `Unable to generate patch for target repo, tool is not supported: ${targetRepo.tool}`
44
+ );
45
+ }
46
+ if (sourceRepo.root.dir === targetRepo.root.dir) {
47
+ throw new Error(
48
+ `Unexpected workspace roots, source and target repo are the same: ${sourceRepo.root.dir}`
49
+ );
50
+ }
51
+ await verifyYarnVersion(sourceRepo.root.dir);
52
+ await verifyYarnVersion(targetRepo.root.dir);
53
+ const sourcePkg = sourceRepo.packages.find(
54
+ (pkg) => pkg.packageJson.name === packageArg || path.relative(sourceRepo.root.dir, pkg.dir) === packageArg
55
+ );
56
+ if (!sourcePkg) {
57
+ throw new Error(`Could not find package ${packageArg} in source repo`);
58
+ }
59
+ const tmpDir = await fs__default.default.mkdtemp(os__default.default.tmpdir());
60
+ const ctx = {
61
+ sourceRepo,
62
+ targetRepo,
63
+ sourcePkg,
64
+ packageName: sourcePkg.packageJson.name,
65
+ targetRoot: targetRepo.root.dir,
66
+ registryUrl,
67
+ workDir: tmpDir
68
+ };
69
+ try {
70
+ const updateTargetRootPkg = await loadTrimmedRootPkg(ctx, opts.query);
71
+ console.log(
72
+ `Building and packaging target package ${sourcePkg.packageJson.name}`
73
+ );
74
+ const targetArchive = await buildTargetArchive(ctx);
75
+ console.log(`Generating patch from ${sourcePkg.packageJson.version}`);
76
+ const patchEntry = await generatePatch$1(
77
+ ctx,
78
+ targetArchive,
79
+ opts.baseVersion || sourcePkg.packageJson.version
80
+ );
81
+ await updateTargetRootPkg(patchEntry);
82
+ if (!opts.skipInstall) {
83
+ console.log("Running 'yarn install' in target workspace");
84
+ await exec.exec("yarn", ["install"], {
85
+ cwd: ctx.targetRoot
86
+ }).catch(() => {
87
+ throw new Error(
88
+ "Failed to run 'yarn install' in target workspace, please run it manually to troubleshoot"
89
+ );
90
+ });
91
+ } else {
92
+ console.log("Skipped running 'yarn install'");
93
+ }
94
+ } finally {
95
+ fs__default.default.rmSync(tmpDir, { force: true, recursive: true, maxRetries: 3 });
96
+ }
97
+ };
98
+ async function loadTrimmedRootPkg(ctx, query) {
99
+ const newPkgJson = JSON.parse(
100
+ JSON.stringify(ctx.targetRepo.root.packageJson)
101
+ );
102
+ const resolutionsObj = newPkgJson.resolutions || (newPkgJson.resolutions = {});
103
+ const searchEntry = query ? `${ctx.packageName}@${query}` : ctx.packageName;
104
+ if (query || resolutionsObj[searchEntry]) {
105
+ const existingPatchFile = tryParsePatchResolution(
106
+ resolutionsObj[searchEntry]
107
+ );
108
+ if (existingPatchFile) {
109
+ await fs__default.default.rm(path.resolve(ctx.targetRoot, existingPatchFile), {
110
+ force: true
111
+ });
112
+ }
113
+ return async (patchEntry) => {
114
+ resolutionsObj[searchEntry] = patchEntry;
115
+ await fs__default.default.writeJson(
116
+ path.resolve(ctx.targetRoot, "package.json"),
117
+ newPkgJson,
118
+ {
119
+ spaces: 2
120
+ }
121
+ );
122
+ };
123
+ }
124
+ const resolutionMap = await readResolutionMap(ctx);
125
+ const entriesToRemove = Object.entries(resolutionsObj).filter(
126
+ ([key]) => key.startsWith(`${ctx.packageName}@`)
127
+ );
128
+ for (const [key, value] of entriesToRemove) {
129
+ delete resolutionsObj[key];
130
+ const existingPatchFile = tryParsePatchResolution(value);
131
+ if (existingPatchFile) {
132
+ await fs__default.default.rm(path.resolve(ctx.targetRoot, existingPatchFile), {
133
+ force: true
134
+ });
135
+ }
136
+ }
137
+ const descriptors = new Array();
138
+ for (const [descriptor, locator] of resolutionMap) {
139
+ if (!locator.includes("@npm:")) {
140
+ if (!locator.includes("@virtual:")) {
141
+ console.warn(`Skipping resolution for ${descriptor}, no version found`);
142
+ }
143
+ continue;
144
+ }
145
+ descriptors.push(descriptor);
146
+ }
147
+ return async (patchEntry) => {
148
+ for (const descriptor of descriptors) {
149
+ resolutionsObj[descriptor] = patchEntry;
150
+ }
151
+ await fs__default.default.writeJson(
152
+ path.resolve(ctx.targetRoot, "package.json"),
153
+ newPkgJson,
154
+ {
155
+ spaces: 2
156
+ }
157
+ );
158
+ };
159
+ }
160
+ async function verifyYarnVersion(cwd) {
161
+ const exists = await fs__default.default.pathExists(path.join(cwd, ".yarnrc.yml"));
162
+ if (!exists) {
163
+ throw new Error(
164
+ `Missing .yarnrc.yml in ${cwd}, Yarn v1 (classic) is not support by this command`
165
+ );
166
+ }
167
+ }
168
+ async function generatePatch$1(ctx, targetArchive, version) {
169
+ const baseArchive = await downloadArchive(ctx, version);
170
+ const patch = await generatePatchForArchives(ctx, baseArchive, targetArchive);
171
+ if (!patch) {
172
+ console.warn(`Generated patch for ${ctx.packageName} is empty`);
173
+ return void 0;
174
+ }
175
+ const cleanPackageName = ctx.packageName.replace("/", "-");
176
+ const describeResult = await exec.exec(
177
+ "git",
178
+ ["describe", "--always", "--dirty", "--exclude='*'"],
179
+ {
180
+ cwd: ctx.sourceRepo.root.dir,
181
+ env: { ...process.env, ...GIT_ENV }
182
+ }
183
+ );
184
+ const describe = describeResult.stdout.toString("utf8").trim();
185
+ const name = `${cleanPackageName}-${version}-${describe}.patch`;
186
+ const patchDir = path.join(ctx.targetRepo.root.dir, ".yarn", "patches");
187
+ await fs__default.default.ensureDir(patchDir);
188
+ await fs__default.default.writeFile(path.join(patchDir, name), patch, "utf8");
189
+ const locator = `${ctx.sourcePkg.packageJson.name}@npm:${version}`;
190
+ return `patch:${encodeURIComponent(locator)}#${path.posix.join(
191
+ ".",
192
+ ".yarn",
193
+ "patches",
194
+ name
195
+ )}`;
196
+ }
197
+ function tryParsePatchResolution(value) {
198
+ if (!value) {
199
+ return void 0;
200
+ }
201
+ if (!value.startsWith("patch:")) {
202
+ return void 0;
203
+ }
204
+ const patchFilePath = value.split("#")[1];
205
+ return patchFilePath;
206
+ }
207
+ async function readResolutionMap(ctx) {
208
+ const { stdout: whyOutput } = await exec.exec(
209
+ "yarn",
210
+ ["why", "--json", ctx.packageName],
211
+ {
212
+ cwd: ctx.targetRoot,
213
+ maxBuffer: 64 * 1024 * 1024
214
+ }
215
+ );
216
+ const resolutionMap = /* @__PURE__ */ new Map();
217
+ for (const line of whyOutput.toString("utf8").trim().split(/\r?\n/)) {
218
+ for (const { locator, descriptor } of Object.values(
219
+ JSON.parse(line).children
220
+ )) {
221
+ const existing = resolutionMap.get(descriptor);
222
+ if (existing) {
223
+ if (existing !== locator) {
224
+ throw new Error(
225
+ `Conflicting resolutions in target package for ${descriptor}: ${existing} vs ${locator}`
226
+ );
227
+ }
228
+ } else {
229
+ resolutionMap.set(descriptor, locator);
230
+ }
231
+ }
232
+ }
233
+ return resolutionMap;
234
+ }
235
+ async function buildTargetArchive(ctx) {
236
+ await exec.exec("yarn", ["build"], {
237
+ cwd: ctx.sourcePkg.dir
238
+ });
239
+ const archiveName = "target.tgz";
240
+ await exec.exec("yarn", ["pack", "--out", path.join(ctx.workDir, archiveName)], {
241
+ cwd: ctx.sourcePkg.dir
242
+ });
243
+ return archiveName;
244
+ }
245
+ async function downloadArchive(ctx, version) {
246
+ const nameWithoutScope = ctx.packageName.replace(/^@.+\//, "");
247
+ const tarName = `${nameWithoutScope}-${version}.tgz`;
248
+ if (await fs__default.default.pathExists(path.join(ctx.workDir, tarName))) {
249
+ return tarName;
250
+ }
251
+ try {
252
+ const url = `${ctx.registryUrl}/${ctx.packageName}/-/${tarName}`;
253
+ const res = await fetch(url);
254
+ if (!res.ok) {
255
+ throw new Error(
256
+ `Request to ${url} failed with status ${res.status} ${res.statusText}`
257
+ );
258
+ }
259
+ if (!res.body) {
260
+ throw new Error("Missing response body");
261
+ }
262
+ const write = fs__default.default.createWriteStream(path.join(ctx.workDir, tarName));
263
+ await promises.finished(stream.Readable.fromWeb(res.body).pipe(write));
264
+ return tarName;
265
+ } catch (error) {
266
+ throw new errors.ForwardedError(
267
+ `Failed to fetch tarball for ${ctx.packageName}@${version}`,
268
+ error
269
+ );
270
+ }
271
+ }
272
+ async function generatePatchForArchives(ctx, baseArchive, headArchive) {
273
+ const basePath = path.join(ctx.workDir, baseArchive);
274
+ const headPath = path.join(ctx.workDir, headArchive);
275
+ const patchDir = await fs__default.default.mkdtemp(path.join(ctx.workDir, "patch-"));
276
+ await tar__default.default.extract({ file: basePath, cwd: patchDir, strip: 1 });
277
+ await fs__default.default.writeFile(
278
+ path.join(patchDir, ".gitignore"),
279
+ PATCH_GITIGNORE.join(os__default.default.EOL)
280
+ );
281
+ await exec.exec("git", ["init"], {
282
+ cwd: patchDir,
283
+ env: { ...process.env, ...GIT_ENV }
284
+ });
285
+ await exec.exec("git", ["add", "."], {
286
+ cwd: patchDir,
287
+ env: { ...process.env, ...GIT_ENV }
288
+ });
289
+ for (const path$1 of await fs__default.default.readdir(patchDir)) {
290
+ if (path$1 !== ".git" && path$1 !== ".gitignore") {
291
+ await fs__default.default.rm(path.join(patchDir, path$1), {
292
+ recursive: true,
293
+ maxRetries: 3,
294
+ force: true
295
+ });
296
+ }
297
+ }
298
+ await tar__default.default.extract({ file: headPath, cwd: patchDir, strip: 1 });
299
+ const { stdout: patch } = await exec.exec(
300
+ "git",
301
+ [
302
+ "-c",
303
+ "core.safecrlf=false",
304
+ "diff",
305
+ "--src-prefix=a/",
306
+ "--dst-prefix=b/",
307
+ "--ignore-cr-at-eol",
308
+ "--full-index",
309
+ "--no-renames",
310
+ "--text"
311
+ ],
312
+ {
313
+ cwd: patchDir,
314
+ env: { ...process.env, ...GIT_ENV }
315
+ }
316
+ );
317
+ return patch.toString("utf8");
318
+ }
319
+
320
+ exports.default = generatePatch;
321
+ //# sourceMappingURL=generate-patch.cjs.js.map
@@ -133,6 +133,28 @@ function registerCommands(program) {
133
133
  )
134
134
  )
135
135
  );
136
+ program.command("generate-patch <package>").requiredOption(
137
+ "--target <target-repo>",
138
+ "The target repository to generate patches for"
139
+ ).option(
140
+ "--registry-url <registry-url>",
141
+ "The registry to use for downloading artifacts (default: https://registry.npmjs.org)"
142
+ ).option(
143
+ "--base-version <version>",
144
+ "Override the base version to generate the patch towards instead"
145
+ ).option(
146
+ "--query <query>",
147
+ "Only apply the patch for a specific version query in the target repository"
148
+ ).option(
149
+ "--skip-install",
150
+ "Skip dependency installation in the target repository after applying the patch"
151
+ ).description(
152
+ "Generate a patch for the selected package in the target repository"
153
+ ).action(
154
+ lazy(
155
+ () => Promise.resolve().then(function () { return require('./generate-patch/generate-patch.cjs.js'); }).then((m) => m.default)
156
+ )
157
+ );
136
158
  program.command("knip-reports [paths...]").option("--ci", "CI run checks that there is no changes on knip reports").description("Generate a knip report for selected packages").action(
137
159
  lazy(
138
160
  () => Promise.resolve().then(function () { return require('./knip-reports/knip-reports.cjs.js'); }).then((m) => m.buildKnipReports)
@@ -41,7 +41,7 @@ async function generate(outputDirectory, clientAdditionalProperties, abortSignal
41
41
  "-c",
42
42
  backendPluginApi.resolvePackagePath(
43
43
  "@backstage/repo-tools",
44
- "templates/typescript-backstage.yaml"
44
+ "templates/typescript-backstage-client.yaml"
45
45
  ),
46
46
  "--generator-key",
47
47
  "v3.0",
@@ -56,14 +56,18 @@ async function generate(outputDirectory, clientAdditionalProperties, abortSignal
56
56
  }
57
57
  }
58
58
  );
59
- await exec.exec(
60
- `yarn backstage-cli package lint --fix ${resolvedOutputDirectory}`,
61
- [],
62
- { signal: abortSignal?.signal }
59
+ const parentDirectory = path.resolve(resolvedOutputDirectory, "..");
60
+ await fs__default.default.writeFile(
61
+ path.resolve(parentDirectory, "index.ts"),
62
+ `//
63
+ export * from './generated';`
63
64
  );
65
+ await exec.exec(`yarn backstage-cli package lint --fix ${parentDirectory}`, [], {
66
+ signal: abortSignal?.signal
67
+ });
64
68
  const prettier = paths.paths.resolveTargetRoot("node_modules/.bin/prettier");
65
69
  if (prettier) {
66
- await exec.exec(`${prettier} --write ${resolvedOutputDirectory}`, [], {
70
+ await exec.exec(`${prettier} --write ${parentDirectory}`, [], {
67
71
  signal: abortSignal?.signal
68
72
  });
69
73
  }
@@ -1,25 +1,32 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs-extra');
4
- var YAML = require('js-yaml');
5
3
  var chalk = require('chalk');
6
- var paths = require('../../../../../lib/paths.cjs.js');
4
+ var path = require('path');
5
+ var YAML = require('js-yaml');
7
6
  var constants = require('../../../../../lib/openapi/constants.cjs.js');
8
- var util = require('util');
9
- var child_process = require('child_process');
7
+ var paths = require('../../../../../lib/paths.cjs.js');
8
+ var fs = require('fs-extra');
9
+ var exec = require('../../../../../lib/exec.cjs.js');
10
+ var backendPluginApi = require('@backstage/backend-plugin-api');
10
11
  var helpers = require('../../../../../lib/openapi/helpers.cjs.js');
11
12
 
12
13
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
13
14
 
14
- var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
15
- var YAML__default = /*#__PURE__*/_interopDefaultCompat(YAML);
16
15
  var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
16
+ var YAML__default = /*#__PURE__*/_interopDefaultCompat(YAML);
17
+ var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
17
18
 
18
- const exec = util.promisify(child_process.exec);
19
- async function generate(abortSignal) {
19
+ async function generateSpecFile() {
20
20
  const openapiPath = await helpers.getPathToCurrentOpenApiSpec();
21
21
  const yaml = YAML__default.default.load(await fs__default.default.readFile(openapiPath, "utf8"));
22
22
  const tsPath = paths.paths.resolveTarget(constants.TS_SCHEMA_PATH);
23
+ const schemaDir = path.dirname(tsPath);
24
+ await fs__default.default.mkdirp(schemaDir);
25
+ const oldTsPath = paths.paths.resolveTarget(constants.OLD_SCHEMA_PATH);
26
+ if (fs__default.default.existsSync(oldTsPath)) {
27
+ console.warn(`Removing old schema file at ${oldTsPath}`);
28
+ fs__default.default.removeSync(oldTsPath);
29
+ }
23
30
  await fs__default.default.writeFile(
24
31
  tsPath,
25
32
  `//
@@ -27,22 +34,82 @@ async function generate(abortSignal) {
27
34
  // ******************************************************************
28
35
  // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
29
36
  // ******************************************************************
30
- import {createValidatedOpenApiRouter} from '@backstage/backend-openapi-utils';
37
+ import {createValidatedOpenApiRouterFromGeneratedEndpointMap} from '@backstage/backend-openapi-utils';
38
+ import {EndpointMap} from './';
31
39
  export const spec = ${JSON.stringify(yaml, null, 2)} as const;
32
40
  export const createOpenApiRouter = async (
33
- options?: Parameters<typeof createValidatedOpenApiRouter>['1'],
34
- ) => createValidatedOpenApiRouter<typeof spec>(spec, options);
41
+ options?: Parameters<typeof createValidatedOpenApiRouterFromGeneratedEndpointMap>['1'],
42
+ ) => createValidatedOpenApiRouterFromGeneratedEndpointMap<EndpointMap>(spec, options);
35
43
  `
36
44
  );
37
- await exec(`yarn backstage-cli package lint --fix ${tsPath}`, {
38
- signal: abortSignal?.signal
39
- });
45
+ const indexFile = path.join(schemaDir, "..", "index.ts");
46
+ await fs__default.default.writeFile(
47
+ indexFile,
48
+ `//
49
+ export * from './generated';`
50
+ );
51
+ await exec.exec(`yarn backstage-cli package lint`, ["--fix", tsPath, indexFile]);
40
52
  if (await paths.paths.resolveTargetRoot("node_modules/.bin/prettier")) {
41
- await exec(`yarn prettier --write ${tsPath}`, {
42
- cwd: paths.paths.targetRoot,
53
+ await exec.exec(`yarn prettier`, ["--write", tsPath, indexFile], {
54
+ cwd: paths.paths.targetRoot
55
+ });
56
+ }
57
+ }
58
+ async function generate(abortSignal) {
59
+ const resolvedOpenapiPath = await helpers.getPathToCurrentOpenApiSpec();
60
+ const resolvedOutputDirectory = await helpers.getRelativePathToFile(constants.OUTPUT_PATH);
61
+ await fs__default.default.mkdirp(resolvedOutputDirectory);
62
+ await fs__default.default.writeFile(
63
+ path.resolve(resolvedOutputDirectory, ".openapi-generator-ignore"),
64
+ constants.OPENAPI_IGNORE_FILES.join("\n")
65
+ );
66
+ await exec.exec(
67
+ "node",
68
+ [
69
+ backendPluginApi.resolvePackagePath("@openapitools/openapi-generator-cli", "main.js"),
70
+ "generate",
71
+ "-i",
72
+ resolvedOpenapiPath,
73
+ "-o",
74
+ resolvedOutputDirectory,
75
+ "-g",
76
+ "typescript",
77
+ "-c",
78
+ backendPluginApi.resolvePackagePath(
79
+ "@backstage/repo-tools",
80
+ "templates/typescript-backstage-server.yaml"
81
+ ),
82
+ "--generator-key",
83
+ "v3.0"
84
+ ],
85
+ {
86
+ maxBuffer: Number.MAX_VALUE,
87
+ cwd: backendPluginApi.resolvePackagePath("@backstage/repo-tools"),
88
+ env: {
89
+ ...process.env
90
+ },
91
+ signal: abortSignal?.signal
92
+ }
93
+ );
94
+ await exec.exec(
95
+ `yarn backstage-cli package lint --fix ${resolvedOutputDirectory}`,
96
+ [],
97
+ {
98
+ signal: abortSignal?.signal
99
+ }
100
+ );
101
+ const prettier = paths.paths.resolveTargetRoot("node_modules/.bin/prettier");
102
+ if (prettier) {
103
+ await exec.exec(`${prettier} --write ${resolvedOutputDirectory}`, [], {
43
104
  signal: abortSignal?.signal
44
105
  });
45
106
  }
107
+ fs__default.default.removeSync(path.resolve(resolvedOutputDirectory, ".openapi-generator-ignore"));
108
+ fs__default.default.rmSync(path.resolve(resolvedOutputDirectory, ".openapi-generator"), {
109
+ recursive: true,
110
+ force: true
111
+ });
112
+ await generateSpecFile();
46
113
  }
47
114
  async function command({
48
115
  abortSignal,
@@ -22,11 +22,16 @@ async function verify(directoryPath) {
22
22
  return;
23
23
  }
24
24
  const yaml = await helpers.loadAndValidateOpenApiYaml(openapiPath);
25
- const schemaPath = path.join(directoryPath, constants.TS_SCHEMA_PATH);
26
- if (!await fs__default.default.pathExists(schemaPath)) {
25
+ let schemaPath = path.join(directoryPath, constants.TS_SCHEMA_PATH);
26
+ if (!await fs__default.default.pathExists(schemaPath) && !await fs__default.default.pathExists(path.join(directoryPath, constants.OLD_SCHEMA_PATH))) {
27
27
  throw new Error(`No \`${constants.TS_SCHEMA_PATH}\` file found.`);
28
+ } else if (await fs__default.default.pathExists(path.join(directoryPath, constants.OLD_SCHEMA_PATH))) {
29
+ console.warn(
30
+ `\`${constants.OLD_SCHEMA_PATH}\` is deprecated. Please re-run \`yarn backstage-repo-tools package schema openapi generate\` to update it.`
31
+ );
32
+ schemaPath = path.join(directoryPath, constants.OLD_SCHEMA_PATH);
28
33
  }
29
- const schema = await import(path.resolve(path.join(directoryPath, constants.TS_MODULE)));
34
+ const schema = await import(path.resolve(schemaPath));
30
35
  if (!schema.spec) {
31
36
  throw new Error(`\`${constants.TS_SCHEMA_PATH}\` needs to have a 'spec' export.`);
32
37
  }
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const YAML_SCHEMA_PATH = "src/schema/openapi.yaml";
4
- const TS_MODULE = "src/schema/openapi.generated";
4
+ const OUTPUT_PATH = "src/schema/openapi/generated";
5
+ const TS_MODULE = `${OUTPUT_PATH}/router`;
6
+ const OLD_SCHEMA_PATH = `src/schema/openapi.generated.ts`;
5
7
  const TS_SCHEMA_PATH = `${TS_MODULE}.ts`;
6
- const OUTPUT_PATH = "src/generated";
7
8
  const OPENAPI_IGNORE_FILES = [
8
9
  // Get rid of the default files.
9
10
  "*.md",
@@ -22,6 +23,7 @@ const OPENAPI_IGNORE_FILES = [
22
23
  // Override the created version.
23
24
  "apis/*.ts",
24
25
  "!apis/*.client.ts",
26
+ "!apis/*.server.ts",
25
27
  "models/*.ts",
26
28
  "!models/*.model.ts",
27
29
  // Always include index.ts files.
@@ -36,6 +38,7 @@ const OPENAPI_IGNORE_FILES = [
36
38
  "tsconfig.json"
37
39
  ];
38
40
 
41
+ exports.OLD_SCHEMA_PATH = OLD_SCHEMA_PATH;
39
42
  exports.OPENAPI_IGNORE_FILES = OPENAPI_IGNORE_FILES;
40
43
  exports.OUTPUT_PATH = OUTPUT_PATH;
41
44
  exports.TS_MODULE = TS_MODULE;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.11.0-next.0";
3
+ var version = "0.11.0-next.2";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/repo-tools",
3
- "version": "0.11.0-next.0",
3
+ "version": "0.11.0-next.2",
4
4
  "description": "CLI for Backstage repo tooling ",
5
5
  "backstage": {
6
6
  "role": "cli"
@@ -43,11 +43,11 @@
43
43
  "dependencies": {
44
44
  "@apidevtools/swagger-parser": "^10.1.0",
45
45
  "@apisyouwonthate/style-guide": "^1.4.0",
46
- "@backstage/backend-plugin-api": "1.0.2-next.0",
46
+ "@backstage/backend-plugin-api": "1.0.2-next.2",
47
47
  "@backstage/catalog-model": "1.7.0",
48
- "@backstage/cli-common": "0.1.14",
49
- "@backstage/cli-node": "0.2.9",
50
- "@backstage/config-loader": "1.9.1",
48
+ "@backstage/cli-common": "0.1.15-next.0",
49
+ "@backstage/cli-node": "0.2.10-next.0",
50
+ "@backstage/config-loader": "1.9.2-next.0",
51
51
  "@backstage/errors": "1.2.4",
52
52
  "@manypkg/get-packages": "^1.1.3",
53
53
  "@microsoft/api-documenter": "^7.25.7",
@@ -74,15 +74,16 @@
74
74
  "minimatch": "^9.0.0",
75
75
  "p-limit": "^3.0.2",
76
76
  "portfinder": "^1.0.32",
77
+ "tar": "^6.1.12",
77
78
  "ts-morph": "^23.0.0",
78
79
  "yaml-diff-patch": "^2.0.0"
79
80
  },
80
81
  "devDependencies": {
81
- "@backstage/backend-test-utils": "1.0.3-next.0",
82
- "@backstage/cli": "0.29.0-next.0",
82
+ "@backstage/backend-test-utils": "1.1.0-next.2",
83
+ "@backstage/cli": "0.29.0-next.2",
83
84
  "@backstage/types": "1.1.1",
84
85
  "@types/is-glob": "^4.0.2",
85
- "@types/node": "^18.17.8",
86
+ "@types/node": "^20.16.0",
86
87
  "@types/prettier": "^2.0.0"
87
88
  },
88
89
  "peerDependencies": {
@@ -29,8 +29,43 @@ export interface RequestOptions {
29
29
  token?: string;
30
30
  }
31
31
 
32
+ {{#operation}}
33
+ /**
34
+ * @public
35
+ */
36
+ export type {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}} = {
37
+ {{#hasPathParams}}
38
+ path: {
39
+ {{#pathParams}}
40
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
41
+ {{/pathParams}}
42
+ },
43
+ {{/hasPathParams}}
44
+ {{#hasBodyParam}}
45
+ {{#bodyParam}}
46
+ body: {{{dataType}}},
47
+ {{/bodyParam}}
48
+ {{/hasBodyParam}}
49
+ {{#hasQueryParams}}
50
+ query: {
51
+ {{#queryParams}}
52
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
53
+ {{/queryParams}}
54
+ },
55
+ {{/hasQueryParams}}
56
+ {{#hasHeaderParams}}
57
+ header: {
58
+ {{#headerParams}}
59
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
60
+ {{/headerParams}}
61
+ },
62
+ {{/hasHeaderParams}}
63
+ }
64
+ {{/operation}}
65
+
32
66
  /**
33
67
  * {{{description}}}{{^description}}no description{{/description}}
68
+ * @public
34
69
  */
35
70
  export class {{classname}}Client {
36
71
  private readonly discoveryApi: DiscoveryApi;
@@ -53,39 +88,12 @@ export class {{classname}}Client {
53
88
  * {{&summary}}
54
89
  {{/summary}}
55
90
  {{#allParams}}
56
- * @param {{paramName}} {{description}}
91
+ * @param {{paramName}} - {{description}}
57
92
  {{/allParams}}
58
93
  */
59
94
  public async {{nickname}}(
60
95
  // @ts-ignore
61
- request: {
62
- {{#hasPathParams}}
63
- path: {
64
- {{#pathParams}}
65
- {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
66
- {{/pathParams}}
67
- },
68
- {{/hasPathParams}}
69
- {{#hasBodyParam}}
70
- {{#bodyParam}}
71
- body: {{{dataType}}},
72
- {{/bodyParam}}
73
- {{/hasBodyParam}}
74
- {{#hasQueryParams}}
75
- query: {
76
- {{#queryParams}}
77
- {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
78
- {{/queryParams}}
79
- },
80
- {{/hasQueryParams}}
81
- {{#hasHeaderParams}}
82
- header: {
83
- {{#headerParams}}
84
- {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
85
- {{/headerParams}}
86
- },
87
- {{/hasHeaderParams}}
88
- },
96
+ request: {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}},
89
97
  options?: RequestOptions
90
98
  ): Promise<TypedResponse<{{{returnType}}} {{^returnType}}void{{/returnType}}>> {
91
99
  const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);
@@ -1,3 +1,6 @@
1
1
  {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelAlias.mustache }}
2
2
 
3
+ /**
4
+ * @public
5
+ */
3
6
  export type {{classname}} = {{dataType}};
@@ -1,6 +1,9 @@
1
1
  {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelEnum.mustache }}
2
2
 
3
3
  {{#stringEnums}}
4
+ /**
5
+ * @public
6
+ */
4
7
  export enum {{classname}} {
5
8
  {{#allowableValues}}
6
9
  {{#enumVars}}
@@ -10,8 +13,14 @@ export enum {{classname}} {
10
13
  }
11
14
  {{/stringEnums}}
12
15
  {{^stringEnums}}
16
+ /**
17
+ * @public
18
+ */
13
19
  export type {{classname}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}};
14
20
 
21
+ /**
22
+ * @public
23
+ */
15
24
  export const {{classname}} = {
16
25
  {{#allowableValues}}
17
26
  {{#enumVars}}
@@ -3,13 +3,14 @@
3
3
  {{#models}}
4
4
  {{#model}}
5
5
 
6
- {{#description}}
7
6
  /**
7
+ {{#description}}
8
8
  * {{{.}}}
9
- */
10
9
  {{/description}}
10
+ * @public
11
+ */
11
12
  {{^isEnum}}
12
- export interface {{classname}} {
13
+ export {{#isNullable}}type{{/isNullable}}{{^isNullable}}interface{{/isNullable}} {{classname}} {{#isNullable}}={{/isNullable}} {
13
14
  {{>modelGenericAdditionalProperties}}
14
15
  {{#vars}}
15
16
  {{#description}}
@@ -19,12 +20,15 @@ export interface {{classname}} {
19
20
  {{/description}}
20
21
  '{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}};
21
22
  {{/vars}}
22
- }
23
+ }{{#isNullable}} | null{{/isNullable}}
23
24
 
24
25
  {{#hasEnums}}
25
26
 
26
27
  {{#vars}}
27
28
  {{#isEnum}}
29
+ /**
30
+ * @public
31
+ */
28
32
  export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}};
29
33
  {{/isEnum}}
30
34
  {{/vars}}
@@ -32,6 +36,9 @@ export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {
32
36
  {{/hasEnums}}
33
37
  {{/isEnum}}
34
38
  {{#isEnum}}
39
+ /**
40
+ * @public
41
+ */
35
42
  export type {{classname}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}};
36
43
  {{/isEnum}}
37
44
  {{/model}}
@@ -3,11 +3,17 @@
3
3
  {{#hasEnums}}
4
4
 
5
5
  {{^stringEnums}}
6
+ /**
7
+ * @public
8
+ */
6
9
  export namespace {{classname}} {
7
10
  {{/stringEnums}}
8
11
  {{#vars}}
9
12
  {{#isEnum}}
10
13
  {{#stringEnums}}
14
+ /**
15
+ * @public
16
+ */
11
17
  export enum {{classname}}{{enumName}} {
12
18
  {{#allowableValues}}
13
19
  {{#enumVars}}
@@ -17,7 +23,14 @@ export enum {{classname}}{{enumName}} {
17
23
  };
18
24
  {{/stringEnums}}
19
25
  {{^stringEnums}}
26
+ /**
27
+ * @public
28
+ */
20
29
  export type {{enumName}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}};
30
+
31
+ /**
32
+ * @public
33
+ */
21
34
  export const {{enumName}} = {
22
35
  {{#allowableValues}}
23
36
  {{#enumVars}}
@@ -8,9 +8,10 @@ import {
8
8
  } from './';
9
9
 
10
10
  {{/hasImports}}
11
- {{#description}}
12
11
  /**
12
+ {{#description}}
13
13
  * {{{.}}}
14
- */
15
14
  {{/description}}
15
+ * @public
16
+ */
16
17
  export type {{classname}} = {{#oneOf}}{{{.}}}{{^-last}} | {{/-last}}{{/oneOf}};
@@ -0,0 +1,40 @@
1
+ templateDir: templates/typescript-backstage-client
2
+
3
+ files:
4
+ api.mustache:
5
+ templateType: API
6
+ # For some reason, they check for destinationFilename differences. We have to change the ending to override the file.
7
+ destinationFilename: .client.ts
8
+ model.mustache:
9
+ templateType: Model
10
+ destinationFilename: .model.ts
11
+ modelGeneric.mustache:
12
+ templateType: SupportingFiles
13
+ modelOneOf.mustache:
14
+ templateType: SupportingFiles
15
+ modelGenericAdditionalProperties.mustache:
16
+ templateType: SupportingFiles
17
+ modelGenericEnums.mustache:
18
+ templateType: SupportingFiles
19
+ modelAlias.mustache:
20
+ templateType: SupportingFiles
21
+ modelEnum.mustache:
22
+ templateType: SupportingFiles
23
+ modelTaggedUnion.mustache:
24
+ templateType: SupportingFiles
25
+ models/models_all.mustache:
26
+ templateType: SupportingFiles
27
+ destinationFilename: models/index.ts
28
+ types/fetch.ts:
29
+ destinationFilename: types/fetch.ts
30
+ types/discovery.ts:
31
+ destinationFilename: types/discovery.ts
32
+ apis/index.mustache:
33
+ templateType: SupportingFiles
34
+ destinationFilename: apis/index.ts
35
+ pluginId.mustache:
36
+ templateType: SupportingFiles
37
+ destinationFilename: pluginId.ts
38
+ index.mustache:
39
+ templateType: SupportingFiles
40
+ destinationFilename: index.ts
@@ -0,0 +1,54 @@
1
+ {{>licenseInfo}}
2
+ {{#imports}}
3
+ import { {{classname}} } from '{{filename}}.model{{importFileExtension}}';
4
+ {{/imports}}
5
+
6
+ {{#operations}}
7
+
8
+ {{#operation}}
9
+ /**
10
+ * @public
11
+ */
12
+ export type {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}} = {
13
+ {{#hasPathParams}}
14
+ path: {
15
+ {{#pathParams}}
16
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
17
+ {{/pathParams}}
18
+ },
19
+ {{/hasPathParams}}
20
+ {{#hasBodyParam}}
21
+ {{#bodyParam}}
22
+ body: {{{dataType}}},
23
+ {{/bodyParam}}
24
+ {{/hasBodyParam}}
25
+ {{#hasQueryParams}}
26
+ query: {
27
+ {{#queryParams}}
28
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
29
+ {{/queryParams}}
30
+ },
31
+ {{/hasQueryParams}}
32
+ {{#hasHeaderParams}}
33
+ header: {
34
+ {{#headerParams}}
35
+ {{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
36
+ {{/headerParams}}
37
+ },
38
+ {{/hasHeaderParams}}
39
+ response: {{#responses}} {{{dataType}}}{{^dataType}}void{{/dataType}} {{^-last}} | {{/-last}} {{/responses}}
40
+ }
41
+ {{/operation}}
42
+
43
+ /**
44
+ * {{{description}}}{{^description}}no description{{/description}}
45
+ */
46
+
47
+ export type EndpointMap = {
48
+ {{#operation}}
49
+
50
+ '#{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}|{{path}}': {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}},
51
+
52
+ {{/operation}}
53
+ }
54
+ {{/operations}}
@@ -0,0 +1,3 @@
1
+ //
2
+
3
+ export * from './DefaultApi.server';
@@ -0,0 +1,4 @@
1
+ //
2
+
3
+ export * from './apis';
4
+ export * from './router';
@@ -0,0 +1,5 @@
1
+ //
2
+
3
+ // ******************************************************************
4
+ // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
5
+ // ******************************************************************
@@ -0,0 +1,11 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/model.mustache#L17. }}
2
+ {{>licenseInfo}}
3
+ {{#models}}
4
+ {{#model}}
5
+ {{#tsImports}}
6
+ import { {{classname}} } from '{{filename}}.model';
7
+ {{/tsImports}}
8
+
9
+ {{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#isAlias}}{{>modelAlias}}{{/isAlias}}{{^isAlias}}{{#taggedUnions}}{{>modelTaggedUnion}}{{/taggedUnions}}{{^taggedUnions}}{{#oneOf}}{{#-first}}{{>modelOneOf}}{{/-first}}{{/oneOf}}{{^oneOf}}{{>modelGeneric}}{{/oneOf}}{{/taggedUnions}}{{/isAlias}}{{/isEnum}}
10
+ {{/model}}
11
+ {{/models}}
@@ -0,0 +1,6 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelAlias.mustache }}
2
+
3
+ /**
4
+ * @public
5
+ */
6
+ export type {{classname}} = {{dataType}};
@@ -0,0 +1,31 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelEnum.mustache }}
2
+
3
+ {{#stringEnums}}
4
+ /**
5
+ * @public
6
+ */
7
+ export enum {{classname}} {
8
+ {{#allowableValues}}
9
+ {{#enumVars}}
10
+ {{name}} = {{{value}}}{{^-last}},{{/-last}}
11
+ {{/enumVars}}
12
+ {{/allowableValues}}
13
+ }
14
+ {{/stringEnums}}
15
+ {{^stringEnums}}
16
+ /**
17
+ * @public
18
+ */
19
+ export type {{classname}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}};
20
+
21
+ /**
22
+ * @public
23
+ */
24
+ export const {{classname}} = {
25
+ {{#allowableValues}}
26
+ {{#enumVars}}
27
+ {{name}}: {{{value}}} as {{classname}}{{^-last}},{{/-last}}
28
+ {{/enumVars}}
29
+ {{/allowableValues}}
30
+ };
31
+ {{/stringEnums}}
@@ -0,0 +1,45 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelGeneric.mustache }}
2
+
3
+ {{#models}}
4
+ {{#model}}
5
+
6
+ /**
7
+ {{#description}}
8
+ * {{{.}}}
9
+ {{/description}}
10
+ * @public
11
+ */
12
+ {{^isEnum}}
13
+ export {{#isNullable}}type{{/isNullable}}{{^isNullable}}interface{{/isNullable}} {{classname}} {{#isNullable}}={{/isNullable}} {
14
+ {{>modelGenericAdditionalProperties}}
15
+ {{#vars}}
16
+ {{#description}}
17
+ /**
18
+ * {{{.}}}
19
+ */
20
+ {{/description}}
21
+ '{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}};
22
+ {{/vars}}
23
+ }{{#isNullable}} | null{{/isNullable}}
24
+
25
+ {{#hasEnums}}
26
+
27
+ {{#vars}}
28
+ {{#isEnum}}
29
+ /**
30
+ * @public
31
+ */
32
+ export type {{classname}}{{enumName}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}};
33
+ {{/isEnum}}
34
+ {{/vars}}
35
+
36
+ {{/hasEnums}}
37
+ {{/isEnum}}
38
+ {{#isEnum}}
39
+ /**
40
+ * @public
41
+ */
42
+ export type {{classname}} ={{#allowableValues}}{{#values}} "{{.}}" {{^-last}}|{{/-last}}{{/values}}{{/allowableValues}};
43
+ {{/isEnum}}
44
+ {{/model}}
45
+ {{/models}}
@@ -0,0 +1,5 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelGenericAdditionalProperties.mustache }}
2
+
3
+ {{#additionalPropertiesType}}
4
+ [key: string]: {{{additionalPropertiesType}}};
5
+ {{/additionalPropertiesType}}
@@ -0,0 +1,45 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelGenericEnums.mustache }}
2
+
3
+ {{#hasEnums}}
4
+
5
+ {{^stringEnums}}
6
+ /**
7
+ * @public
8
+ */
9
+ export namespace {{classname}} {
10
+ {{/stringEnums}}
11
+ {{#vars}}
12
+ {{#isEnum}}
13
+ {{#stringEnums}}
14
+ /**
15
+ * @public
16
+ */
17
+ export enum {{classname}}{{enumName}} {
18
+ {{#allowableValues}}
19
+ {{#enumVars}}
20
+ {{name}} = {{{value}}}{{^-last}},{{/-last}}
21
+ {{/enumVars}}
22
+ {{/allowableValues}}
23
+ };
24
+ {{/stringEnums}}
25
+ {{^stringEnums}}
26
+ /**
27
+ * @public
28
+ */
29
+ export type {{enumName}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}};
30
+
31
+ /**
32
+ * @public
33
+ */
34
+ export const {{enumName}} = {
35
+ {{#allowableValues}}
36
+ {{#enumVars}}
37
+ {{name}}: {{{value}}} as {{enumName}}{{^-last}},{{/-last}}
38
+ {{/enumVars}}
39
+ {{/allowableValues}}
40
+ };
41
+ {{/stringEnums}}
42
+ {{/isEnum}}
43
+ {{/vars}}
44
+ {{^stringEnums}}}{{/stringEnums}}
45
+ {{/hasEnums}}
@@ -0,0 +1,17 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelOneOf.mustache }}
2
+
3
+ {{#hasImports}}
4
+ import {
5
+ {{#imports}}
6
+ {{{.}}},
7
+ {{/imports}}
8
+ } from './';
9
+
10
+ {{/hasImports}}
11
+ /**
12
+ {{#description}}
13
+ * {{{.}}}
14
+ {{/description}}
15
+ * @public
16
+ */
17
+ export type {{classname}} = {{#oneOf}}{{{.}}}{{^-last}} | {{/-last}}{{/oneOf}};
@@ -0,0 +1,23 @@
1
+ {{! Sourced from https://github.com/OpenAPITools/openapi-generator/blob/7347daec61b2cb8d3d28e1ed06fe8b5e682090f8/modules/openapi-generator/src/main/resources/typescript-angular/modelTaggedUnion.mustache }}
2
+
3
+ {{#discriminator}}
4
+ export type {{classname}} = {{#children}}{{^-first}} | {{/-first}}{{classname}}{{/children}};
5
+ {{/discriminator}}
6
+ {{^discriminator}}
7
+ {{#parent}}
8
+ export interface {{classname}} { {{>modelGenericAdditionalProperties}}
9
+ {{#allVars}}
10
+ {{#description}}
11
+ /**
12
+ * {{{.}}}
13
+ */
14
+ {{/description}}
15
+ {{name}}{{^required}}?{{/required}}: {{#discriminatorValue}}'{{.}}'{{/discriminatorValue}}{{^discriminatorValue}}{{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{/discriminatorValue}}{{#isNullable}} | null{{/isNullable}};
16
+ {{/allVars}}
17
+ }
18
+ {{>modelGenericEnums}}
19
+ {{/parent}}
20
+ {{^parent}}
21
+ {{>modelGeneric}}
22
+ {{/parent}}
23
+ {{/discriminator}}
@@ -0,0 +1,7 @@
1
+ //
2
+
3
+ {{#models}}
4
+ {{#model}}
5
+ export * from '{{{ importPath }}}.model{{importFileExtension}}'
6
+ {{/model}}
7
+ {{/models}}
@@ -1,10 +1,16 @@
1
- templateDir: templates/typescript-backstage
1
+ templateDir: templates/typescript-backstage-server
2
2
 
3
3
  files:
4
4
  api.mustache:
5
5
  templateType: API
6
6
  # For some reason, they check for destinationFilename differences. We have to change the ending to override the file.
7
- destinationFilename: .client.ts
7
+ destinationFilename: .server.ts
8
+ apis/index.mustache:
9
+ templateType: SupportingFiles
10
+ destinationFilename: apis/index.ts
11
+ index.mustache:
12
+ templateType: SupportingFiles
13
+ destinationFilename: index.ts
8
14
  model.mustache:
9
15
  templateType: Model
10
16
  destinationFilename: .model.ts
@@ -24,12 +30,4 @@ files:
24
30
  templateType: SupportingFiles
25
31
  models/models_all.mustache:
26
32
  templateType: SupportingFiles
27
- destinationFilename: models/index.ts
28
- types/fetch.ts: {}
29
- types/discovery.ts: {}
30
- apis/index.mustache:
31
- templateType: SupportingFiles
32
- destinationFilename: apis/index.ts
33
- pluginId.mustache:
34
- templateType: SupportingFiles
35
- destinationFilename: pluginId.ts
33
+ destinationFilename: models/index.ts