@superblocksteam/cli 1.9.3 → 1.12.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 (59) hide show
  1. package/LICENSE.txt +87 -0
  2. package/README.md +6 -6
  3. package/assets/custom-components/setup/package.json +1 -1
  4. package/assets/custom-components/setup/tsconfig.json +0 -1
  5. package/assets/injectedReactShim17.jsx +15 -0
  6. package/assets/injectedReactShim18.jsx +16 -0
  7. package/assets/injectedReactShimShared.jsx +140 -0
  8. package/bin/dev +5 -7
  9. package/bin/run +1 -3
  10. package/dist/appendHotReloadEventPlugin.d.mts +2 -0
  11. package/dist/appendHotReloadEventPlugin.mjs +43 -0
  12. package/dist/commands/commits.d.mts +18 -0
  13. package/dist/commands/{commits.js → commits.mjs} +59 -67
  14. package/dist/commands/components/{create.d.ts → create.d.mts} +2 -2
  15. package/dist/commands/components/{create.js → create.mjs} +84 -93
  16. package/dist/commands/components/{register.d.ts → register.d.mts} +1 -1
  17. package/dist/commands/components/register.mjs +12 -0
  18. package/dist/commands/components/{upload.d.ts → upload.d.mts} +2 -2
  19. package/dist/commands/components/{upload.js → upload.mjs} +39 -43
  20. package/dist/commands/components/{watch.d.ts → watch.d.mts} +1 -1
  21. package/dist/commands/components/{watch.js → watch.mjs} +29 -36
  22. package/dist/commands/config/{set.d.ts → set.d.mts} +2 -2
  23. package/dist/commands/config/{set.js → set.mjs} +28 -32
  24. package/dist/commands/{init.d.ts → init.d.mts} +4 -4
  25. package/dist/commands/{init.js → init.mjs} +63 -65
  26. package/dist/commands/{login.d.ts → login.d.mts} +1 -1
  27. package/dist/commands/login.mjs +55 -0
  28. package/dist/commands/{migrate.d.ts → migrate.d.mts} +1 -1
  29. package/dist/commands/{migrate.js → migrate.mjs} +38 -46
  30. package/dist/commands/pull.d.mts +17 -0
  31. package/dist/commands/{pull.js → pull.mjs} +74 -80
  32. package/dist/commands/push.d.mts +15 -0
  33. package/dist/commands/{push.js → push.mjs} +81 -90
  34. package/dist/commands/{rm.d.ts → rm.d.mts} +2 -2
  35. package/dist/commands/{rm.js → rm.mjs} +34 -40
  36. package/dist/common/{authenticated-command.js → authenticated-command.mjs} +65 -75
  37. package/dist/common/defaults/{create-component-defaults.js → create-component-defaults.mjs} +2 -7
  38. package/dist/common/{version-control.d.ts → version-control.d.mts} +13 -6
  39. package/dist/common/version-control.mjs +1064 -0
  40. package/dist/index.js +1 -5
  41. package/dist/productionCssPlugin.d.mts +2 -0
  42. package/dist/productionCssPlugin.mjs +50 -0
  43. package/dist/reactShimPlugin.d.mts +2 -0
  44. package/dist/reactShimPlugin.mjs +127 -0
  45. package/dist/util/migrationWarningsForApplications.mjs +47 -0
  46. package/dist/util/{migrationsForDotfiles.js → migrationsForDotfiles.mjs} +10 -17
  47. package/oclif.manifest.json +274 -161
  48. package/package.json +45 -45
  49. package/dist/commands/commits.d.ts +0 -18
  50. package/dist/commands/components/register.js +0 -15
  51. package/dist/commands/login.js +0 -61
  52. package/dist/commands/pull.d.ts +0 -17
  53. package/dist/commands/push.d.ts +0 -15
  54. package/dist/common/version-control.js +0 -716
  55. package/dist/util/migrationWarningsForApplications.js +0 -52
  56. /package/dist/common/{authenticated-command.d.ts → authenticated-command.d.mts} +0 -0
  57. /package/dist/common/defaults/{create-component-defaults.d.ts → create-component-defaults.d.mts} +0 -0
  58. /package/dist/util/{migrationWarningsForApplications.d.ts → migrationWarningsForApplications.d.mts} +0 -0
  59. /package/dist/util/{migrationsForDotfiles.d.ts → migrationsForDotfiles.d.mts} +0 -0
@@ -1,716 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteResourcesAndUpdateRootConfig = exports.validateLocalResource = exports.extractApiName = exports.isGitRepoDirty = exports.isCI = exports.getHeadCommit = exports.getCurrentGitBranch = exports.getCurrentGitBranchIfGit = exports.getLocalGitRepoState = exports.sortByKey = exports.getMode = exports.removeResourceFromDisk = exports.writeMultiPageApplicationToDisk = exports.writeResourceToDisk = exports.readApiFromDisk = exports.readMultiPageApplicationFromDisk = exports.readApplicationFromDisk = exports.getFileStructureType = exports.atLeastOneSelection = exports.MULTI_SELECT_PROMPT_HELP = exports.SELECT_PROMPT_HELP = exports.modeFlagToViewMode = exports.FileStructureType = exports.modeFlagValuesMap = exports.DEFAULT_BRANCH = exports.DEPLOYED_MODE = exports.MOST_RECENT_COMMIT_MODE = exports.LATEST_EDITS_MODE = void 0;
4
- const tslib_1 = require("tslib");
5
- const https = tslib_1.__importStar(require("https"));
6
- const node_path_1 = tslib_1.__importDefault(require("node:path"));
7
- const path_1 = require("path");
8
- const util_1 = require("@superblocksteam/util");
9
- const util_2 = require("@superblocksteam/util");
10
- const colorette_1 = require("colorette");
11
- const fs = tslib_1.__importStar(require("fs-extra"));
12
- const lodash_1 = require("lodash");
13
- const lodash_2 = tslib_1.__importDefault(require("lodash"));
14
- const simple_git_1 = require("simple-git");
15
- const slugify_1 = tslib_1.__importDefault(require("slugify"));
16
- const yaml_1 = require("yaml");
17
- exports.LATEST_EDITS_MODE = "latest-edits";
18
- exports.MOST_RECENT_COMMIT_MODE = "most-recent-commit";
19
- exports.DEPLOYED_MODE = "deployed";
20
- exports.DEFAULT_BRANCH = "main";
21
- exports.modeFlagValuesMap = {
22
- [exports.LATEST_EDITS_MODE]: "Latest edits",
23
- [exports.MOST_RECENT_COMMIT_MODE]: "Most recent commit",
24
- [exports.DEPLOYED_MODE]: "Deployed",
25
- };
26
- var FileStructureType;
27
- (function (FileStructureType) {
28
- FileStructureType["SINGLE_PAGE"] = "single-page";
29
- FileStructureType["MULTI_PAGE"] = "multi-page";
30
- })(FileStructureType || (exports.FileStructureType = FileStructureType = {}));
31
- function modeFlagToViewMode(modeFlag) {
32
- switch (modeFlag) {
33
- case exports.LATEST_EDITS_MODE:
34
- return "export-live";
35
- case exports.MOST_RECENT_COMMIT_MODE:
36
- return "export-latest";
37
- case exports.DEPLOYED_MODE:
38
- return "export-deployed";
39
- default:
40
- throw new Error(`Unsupported mode flag: ${modeFlag}`);
41
- }
42
- }
43
- exports.modeFlagToViewMode = modeFlagToViewMode;
44
- exports.SELECT_PROMPT_HELP = "Use ↑/↓ arrow keys, Enter to confirm";
45
- exports.MULTI_SELECT_PROMPT_HELP = "Type to filter, Use ↑/↓ arrow keys, Space to select, Enter to confirm";
46
- const atLeastOneSelection = (value) => {
47
- if ((0, lodash_1.isEmpty)(value)) {
48
- return `Please select at least one item ${(0, colorette_1.bold)("by pressing space")}`;
49
- }
50
- return true;
51
- };
52
- exports.atLeastOneSelection = atLeastOneSelection;
53
- function slugifyName(originalName) {
54
- return (0, slugify_1.default)(originalName, {
55
- replacement: "_",
56
- lower: true,
57
- });
58
- }
59
- // resolves a true promise when download is complete. If there's an error, resolve false
60
- async function downloadFile(rootDirectory, filepath, url) {
61
- const fullPath = `${rootDirectory}/${filepath}`;
62
- // eslint-disable-next-line no-async-promise-executor
63
- const result = await new Promise(async (resolve) => {
64
- try {
65
- // create directory path if it doesn't exist yet
66
- if (!(await fs.pathExists(fullPath))) {
67
- await fs.mkdir((0, path_1.dirname)(fullPath), { recursive: true });
68
- }
69
- const file = fs.createWriteStream(fullPath);
70
- https.get(url, (resp) => {
71
- resp.pipe(file);
72
- file
73
- .on("finish", () => {
74
- file.end(() => resolve(true));
75
- })
76
- .on("error", () => {
77
- fs.unlink(filepath);
78
- resolve(false);
79
- });
80
- });
81
- }
82
- catch (e) {
83
- return resolve(false);
84
- }
85
- });
86
- // failed to download correctly, attempt to clean up file
87
- if (!result) {
88
- try {
89
- await fs.unlink(fullPath);
90
- }
91
- catch (e) {
92
- console.log("Failed to delete file", fullPath);
93
- }
94
- return Promise.resolve(fullPath);
95
- }
96
- return Promise.resolve("");
97
- }
98
- async function readYamlFile(path) {
99
- return (0, yaml_1.parse)(await fs.readFile(path, "utf8"));
100
- }
101
- function getFileStructureTypeFromResourceConfig(superblocksConfig) {
102
- if (superblocksConfig.pages) {
103
- return FileStructureType.MULTI_PAGE;
104
- }
105
- return FileStructureType.SINGLE_PAGE;
106
- }
107
- async function getFileStructureType(rootPath, existingRelativeLocation) {
108
- const superblocksConfig = await (0, util_1.getSuperblocksApplicationConfigJson)(`${rootPath}/${existingRelativeLocation}`);
109
- return getFileStructureTypeFromResourceConfig(superblocksConfig);
110
- }
111
- exports.getFileStructureType = getFileStructureType;
112
- // NOTE: If a change is made to how applications are read from disk, please update
113
- // logic to write applications to disk in the "writeResourceToDisk" function accordingly.
114
- // @deprecated this can be removed once all customers move to multi page applications
115
- async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
116
- const application = await readYamlFile(`${rootPath}/${existingRelativeLocation}/application.yaml`);
117
- const page = await readYamlFile(`${rootPath}/${existingRelativeLocation}/page.yaml`);
118
- const apisDirName = `${rootPath}/${existingRelativeLocation}/apis`;
119
- const apis = [];
120
- if (await fs.pathExists(apisDirName)) {
121
- const apiFiles = await fs.readdir(apisDirName);
122
- for (const apiFile of apiFiles) {
123
- const apiContent = await readYamlFile(`${apisDirName}/${apiFile}`);
124
- // This mimics the shape of the ApiV3Dto object
125
- apis.push({
126
- id: apiContent.metadata.id,
127
- apiPb: apiContent,
128
- });
129
- }
130
- }
131
- return {
132
- application,
133
- apis,
134
- page,
135
- };
136
- }
137
- exports.readApplicationFromDisk = readApplicationFromDisk;
138
- // NOTE: If a change is made to how applications are read from disk, please update
139
- // logic to write applications to disk in the "writeResourceToDisk" function accordingly.
140
- async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocation) {
141
- var _a;
142
- const superblocksApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigJson)(`${rootPath}/${existingRelativeLocation}`);
143
- const application = await readYamlFile(`${rootPath}/${existingRelativeLocation}/application.yaml`);
144
- const pagesDirName = `${rootPath}/${existingRelativeLocation}/pages`;
145
- const pages = [];
146
- if (await fs.pathExists(pagesDirName)) {
147
- for (const page of Object.values((_a = superblocksApplicationConfig.pages) !== null && _a !== void 0 ? _a : {})) {
148
- const pageContent = await readYamlFile(`${pagesDirName}/${slugifyName(page.name)}/page.yaml`);
149
- const pageApisDirName = `${pagesDirName}/${slugifyName(page.name)}/apis`;
150
- const apis = [];
151
- if (await fs.pathExists(pageApisDirName)) {
152
- for (const apiName of Object.values(page.apis)) {
153
- const apiContent = await readYamlFile(`${pageApisDirName}/${slugifyName(apiName)}.yaml`);
154
- // This mimics the shape of the ApiV3Dto object
155
- apis.push({
156
- id: apiContent.metadata.id,
157
- pageId: page.id,
158
- apiPb: apiContent,
159
- });
160
- }
161
- }
162
- pages.push({
163
- id: pageContent.id,
164
- name: pageContent.name,
165
- applicationId: pageContent.applicationId,
166
- isHidden: pageContent.isHidden,
167
- layouts: pageContent.layouts,
168
- apis,
169
- });
170
- }
171
- }
172
- const appApisDirName = `${rootPath}/${existingRelativeLocation}/apis`;
173
- const apis = [];
174
- if (await fs.pathExists(appApisDirName)) {
175
- for (const apiName of Object.values(superblocksApplicationConfig.apis)) {
176
- const apiContent = await readYamlFile(`${appApisDirName}/${slugifyName(apiName)}.yaml`);
177
- // This mimics the shape of the ApiV3Dto object
178
- apis.push({
179
- id: apiContent.metadata.id,
180
- apiPb: apiContent,
181
- });
182
- }
183
- }
184
- return {
185
- application,
186
- apis,
187
- pages,
188
- };
189
- }
190
- exports.readMultiPageApplicationFromDisk = readMultiPageApplicationFromDisk;
191
- async function readApiFromDisk(rootPath, existingRelativeLocation) {
192
- return {
193
- apiPb: await readYamlFile(`${rootPath}/${existingRelativeLocation}/api.yaml`),
194
- };
195
- }
196
- exports.readApiFromDisk = readApiFromDisk;
197
- // NOTE: If a change is made to how applications are written to disk, please update
198
- // logic to read applications from disk in the "readApplicationFromDisk" function accordingly.
199
- async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, existingRelativeLocation) {
200
- var _a, _b, _c;
201
- switch (resourceType) {
202
- case "APPLICATION": {
203
- const parentDirName = "apps";
204
- const newRelativeLocation = `${parentDirName}/${slugifyName(resource.application.name)}`;
205
- const relativeLocation = existingRelativeLocation !== null && existingRelativeLocation !== void 0 ? existingRelativeLocation : newRelativeLocation;
206
- const appDirName = node_path_1.default.resolve(rootPath, relativeLocation);
207
- if (!(await fs.pathExists(appDirName))) {
208
- await fs.mkdir(appDirName, { recursive: true });
209
- }
210
- const applicationContent = (0, yaml_1.stringify)(resource.application, {
211
- sortMapEntries: true,
212
- });
213
- await fs.outputFile(`${appDirName}/application.yaml`, applicationContent);
214
- if (resource.page) {
215
- const pageContent = (0, yaml_1.stringify)(resource.page, {
216
- sortMapEntries: true,
217
- blockQuote: "literal",
218
- });
219
- await fs.outputFile(`${appDirName}/page.yaml`, pageContent);
220
- }
221
- const apiPromises = [];
222
- const apisDirName = `${appDirName}/apis`;
223
- await fs.ensureDir(apisDirName);
224
- const newApplicationConfig = {
225
- configType: "APPLICATION",
226
- apis: {},
227
- defaultPageId: (_a = resource.page) === null || _a === void 0 ? void 0 : _a.id,
228
- id: resource.application.id,
229
- };
230
- if (resource.apis) {
231
- for (const api of resource.apis) {
232
- const originalApiName = extractApiName(api);
233
- const apiName = slugifyName(originalApiName);
234
- const apiContent = (0, yaml_1.stringify)(api.apiPb, {
235
- sortMapEntries: true,
236
- blockQuote: "literal",
237
- });
238
- const handleApi = async () => {
239
- await fs.outputFile(`${apisDirName}/${apiName}.yaml`, apiContent);
240
- };
241
- apiPromises.push(handleApi());
242
- newApplicationConfig.apis[api.id] = originalApiName;
243
- }
244
- await Promise.all(apiPromises);
245
- }
246
- const existingApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigIfExists)(appDirName);
247
- // iterate through existing apis and remove from disk any that are no longer present
248
- if (existingApplicationConfig === null || existingApplicationConfig === void 0 ? void 0 : existingApplicationConfig.apis) {
249
- for (const existingApiId of Object.keys(existingApplicationConfig.apis)) {
250
- const existingApiName = existingApplicationConfig.apis[existingApiId];
251
- const existingApiPath = `${apisDirName}/${slugifyName(existingApiName)}.yaml`;
252
- const newApiName = newApplicationConfig.apis[existingApiId];
253
- if (!(existingApiId in newApplicationConfig.apis) ||
254
- slugifyName(newApiName) !== slugifyName(existingApiName)) {
255
- await fs.remove(existingApiPath);
256
- }
257
- }
258
- }
259
- await fs.ensureDir(`${appDirName}/${util_2.SUPERBLOCKS_HOME_FOLDER_NAME}`);
260
- await fs.writeFile(`${appDirName}/${util_2.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
261
- const createdFiles = await Promise.resolve(
262
- // Defensive check for when application settings are missing componentFiles
263
- (_c = (_b = resource.componentFiles) === null || _b === void 0 ? void 0 : _b.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _c !== void 0 ? _c : []);
264
- // print out failed downloads synchronously here
265
- createdFiles
266
- .filter((createdFiles) => createdFiles.length)
267
- .forEach((createdFile) => {
268
- console.log(`Unable to download ${createdFile}`);
269
- });
270
- return {
271
- location: relativeLocation,
272
- resourceType: "APPLICATION",
273
- };
274
- }
275
- case "BACKEND": {
276
- const parentDirName = "backends";
277
- const apiName = slugifyName(extractApiName(resource));
278
- const newRelativeLocation = `${parentDirName}/${apiName}`;
279
- const relativeLocation = existingRelativeLocation !== null && existingRelativeLocation !== void 0 ? existingRelativeLocation : newRelativeLocation;
280
- const backendDirName = node_path_1.default.resolve(rootPath, relativeLocation);
281
- if (!(await fs.pathExists(backendDirName))) {
282
- await fs.mkdir(backendDirName, { recursive: true });
283
- }
284
- const backendContent = (0, yaml_1.stringify)(resource.apiPb, {
285
- sortMapEntries: true,
286
- blockQuote: "literal",
287
- });
288
- await fs.outputFile(`${backendDirName}/api.yaml`, backendContent);
289
- const backendConfig = {
290
- id: resourceId,
291
- configType: "BACKEND",
292
- };
293
- await fs.ensureDir(`${backendDirName}/${util_2.SUPERBLOCKS_HOME_FOLDER_NAME}`);
294
- await fs.writeFile(`${backendDirName}/${util_2.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(backendConfig), null, 2));
295
- return {
296
- location: relativeLocation,
297
- resourceType: "BACKEND",
298
- };
299
- }
300
- default: {
301
- throw new Error(`Unsupported resource type: ${resourceType}`);
302
- }
303
- }
304
- }
305
- exports.writeResourceToDisk = writeResourceToDisk;
306
- // NOTE: If a change is made to how applications are written to disk, please update
307
- // logic to read applications from disk in the "readMultiPageApplicationFromDisk" function accordingly.
308
- async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelativeLocation, migrateFromSinglePage) {
309
- var _a, _b, _c, _d;
310
- const parentDirName = "apps";
311
- const newRelativeLocation = `${parentDirName}/${slugifyName(resource.application.name)}`;
312
- const relativeLocation = existingRelativeLocation !== null && existingRelativeLocation !== void 0 ? existingRelativeLocation : newRelativeLocation;
313
- const appDirName = node_path_1.default.resolve(rootPath, relativeLocation);
314
- if (!(await fs.pathExists(appDirName))) {
315
- await fs.mkdir(appDirName, { recursive: true });
316
- }
317
- const applicationContent = (0, yaml_1.stringify)(resource.application, {
318
- sortMapEntries: true,
319
- });
320
- await fs.outputFile(`${appDirName}/application.yaml`, applicationContent);
321
- const newApplicationConfig = {
322
- configType: "APPLICATION",
323
- apis: {},
324
- id: resource.application.id,
325
- };
326
- newApplicationConfig.pages = {};
327
- const apiPromises = [];
328
- for (const page of Object.values(resource.pages)) {
329
- const pageId = page.id;
330
- const pageDirName = `${appDirName}/pages/${slugifyName(page.name)}`;
331
- if (!(await fs.pathExists(pageDirName))) {
332
- await fs.mkdir(pageDirName, { recursive: true });
333
- }
334
- newApplicationConfig.pages[pageId] = {
335
- id: page.id,
336
- name: page.name,
337
- apis: {},
338
- };
339
- const pageContent = (0, yaml_1.stringify)({
340
- id: page.id,
341
- name: page.name,
342
- applicationId: page.applicationId,
343
- isHidden: page.isHidden,
344
- layouts: page.layouts,
345
- }, {
346
- sortMapEntries: true,
347
- blockQuote: "literal",
348
- });
349
- await fs.outputFile(`${pageDirName}/page.yaml`, pageContent);
350
- const pageApisDirName = `${pageDirName}/apis`;
351
- for (const api of page.apis) {
352
- const originalApiName = extractApiName(api);
353
- apiPromises.push(writeApi(api, originalApiName, pageApisDirName));
354
- newApplicationConfig.pages[pageId].apis[api.id] = originalApiName;
355
- }
356
- }
357
- const apisDirName = `${appDirName}/apis`;
358
- if (resource.apis && resource.apis.length) {
359
- await fs.ensureDir(apisDirName);
360
- for (const api of resource.apis) {
361
- const originalApiName = extractApiName(api);
362
- apiPromises.push(writeApi(api, originalApiName, apisDirName));
363
- newApplicationConfig.apis[api.id] = originalApiName;
364
- }
365
- await Promise.all(apiPromises);
366
- }
367
- const existingApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigIfExists)(appDirName);
368
- // iterate through existing app-level apis and remove from disk any that are no longer present
369
- for (const existingApiId of Object.keys((_a = existingApplicationConfig === null || existingApplicationConfig === void 0 ? void 0 : existingApplicationConfig.apis) !== null && _a !== void 0 ? _a : {})) {
370
- const existingApiName = existingApplicationConfig === null || existingApplicationConfig === void 0 ? void 0 : existingApplicationConfig.apis[existingApiId];
371
- const existingApiPath = `${apisDirName}/${slugifyName(existingApiName)}.yaml`;
372
- const newApiName = newApplicationConfig.apis[existingApiId];
373
- if (!(existingApiId in newApplicationConfig.apis) ||
374
- slugifyName(newApiName) !== slugifyName(existingApiName)) {
375
- await fs.remove(existingApiPath);
376
- }
377
- }
378
- // iterate through existing pages and remove from disk any that are no longer present
379
- for (const existingPage of Object.values((_b = existingApplicationConfig === null || existingApplicationConfig === void 0 ? void 0 : existingApplicationConfig.pages) !== null && _b !== void 0 ? _b : {})) {
380
- const existingPageId = existingPage.id;
381
- const existingPageDir = `${appDirName}/pages/${slugifyName(existingPage.name)}`;
382
- if (existingPageId in newApplicationConfig.pages) {
383
- // page still exists
384
- const currentPage = newApplicationConfig.pages[existingPageId];
385
- const newPageName = currentPage.name;
386
- if (slugifyName(newPageName) !== slugifyName(existingPage.name)) {
387
- // page was renamed
388
- await fs.remove(existingPageDir);
389
- }
390
- // iterate through existing page-level apis and remove from disk any that are no longer present
391
- for (const [existingApiId, existingApiName] of Object.entries(existingPage.apis)) {
392
- const existingApiPath = `${existingPageDir}/apis/${slugifyName(existingApiName)}.yaml`;
393
- if (existingApiId in currentPage.apis) {
394
- // api still exists
395
- const newApiName = newApplicationConfig.pages[existingPageId].apis[existingApiId];
396
- if (slugifyName(newApiName) !== slugifyName(existingApiName)) {
397
- // api was renamed
398
- await fs.remove(existingApiPath);
399
- }
400
- }
401
- else {
402
- // api was removed
403
- await fs.remove(existingApiPath);
404
- }
405
- }
406
- }
407
- else {
408
- // page was removed
409
- await fs.remove(existingPageDir);
410
- // remove all page-level apis
411
- for (const existingApiName of Object.values(existingPage.apis)) {
412
- const existingApiPath = `${existingPageDir}/apis/${slugifyName(existingApiName)}.yaml`;
413
- await fs.remove(existingApiPath);
414
- }
415
- }
416
- }
417
- await fs.ensureDir(`${appDirName}/${util_2.SUPERBLOCKS_HOME_FOLDER_NAME}`);
418
- await fs.writeFile(`${appDirName}/${util_2.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
419
- const createdFiles = await Promise.resolve(
420
- // Defensive check for when application settings are missing componentFiles
421
- (_d = (_c = resource.componentFiles) === null || _c === void 0 ? void 0 : _c.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _d !== void 0 ? _d : []);
422
- // print out failed downloads synchronously here
423
- createdFiles
424
- .filter((createdFiles) => createdFiles.length)
425
- .forEach((createdFile) => {
426
- console.log(`Unable to download ${createdFile}`);
427
- });
428
- // do a post-migration cleanup if necessary
429
- if (migrateFromSinglePage) {
430
- await fs.remove(`${appDirName}/page.yaml`);
431
- // delete app-level apis if they are not present in the new application config
432
- if (!resource.apis || !resource.apis.length) {
433
- await fs.remove(`${appDirName}/apis`);
434
- }
435
- }
436
- return {
437
- location: relativeLocation,
438
- resourceType: "APPLICATION",
439
- };
440
- }
441
- exports.writeMultiPageApplicationToDisk = writeMultiPageApplicationToDisk;
442
- async function removeResourceFromDisk(rootPath, resourceRelativeLocation) {
443
- const resourceLocation = node_path_1.default.resolve(rootPath, resourceRelativeLocation);
444
- await fs.remove(resourceLocation);
445
- }
446
- exports.removeResourceFromDisk = removeResourceFromDisk;
447
- async function getMode(task, mode) {
448
- if (mode) {
449
- return modeFlagToViewMode(mode);
450
- }
451
- const selectedMode = await task.prompt([
452
- {
453
- type: "Select",
454
- name: "mode",
455
- message: `Select which version of a resource you would like to fetch (${exports.SELECT_PROMPT_HELP})`,
456
- choices: Object.keys(exports.modeFlagValuesMap).map((mode) => ({
457
- name: mode,
458
- message: exports.modeFlagValuesMap[mode],
459
- })),
460
- initial: 0,
461
- multiple: false,
462
- },
463
- ]);
464
- return modeFlagToViewMode(selectedMode);
465
- }
466
- exports.getMode = getMode;
467
- function sortByKey(obj) {
468
- if (lodash_2.default.isArray(obj)) {
469
- return obj.map((item) => sortByKey(item));
470
- }
471
- if (lodash_2.default.isObject(obj)) {
472
- const sortedKeys = Object.keys(obj).sort();
473
- const sortedObj = {};
474
- for (const key of sortedKeys) {
475
- sortedObj[key] = sortByKey(lodash_2.default.get(obj, key));
476
- }
477
- return sortedObj;
478
- }
479
- return obj;
480
- }
481
- exports.sortByKey = sortByKey;
482
- async function getLocalGitRepoState(overrideLocalBranch) {
483
- var _a, _b, _c;
484
- const git = (0, simple_git_1.simpleGit)();
485
- let status;
486
- try {
487
- // do not return untracked files which can be slow, we only care about the branch info
488
- status = await git.status(["--untracked-files=no"]);
489
- }
490
- catch {
491
- return { status: "NO_GIT" };
492
- }
493
- let localBranchName;
494
- if (overrideLocalBranch) {
495
- const branches = await git.branch();
496
- if (!branches.all.includes(overrideLocalBranch)) {
497
- throw new Error(`There is no branch named ${overrideLocalBranch}`);
498
- }
499
- localBranchName = overrideLocalBranch;
500
- }
501
- else {
502
- if (status.detached || !status.current) {
503
- return { status: "DETACHED" };
504
- }
505
- localBranchName = status.current;
506
- }
507
- const remoteName = (_a = (await git.getConfig(`branch.${localBranchName}.remote`))) === null || _a === void 0 ? void 0 : _a.value;
508
- if (!remoteName) {
509
- return { status: "IN_A_BRANCH", localBranchName };
510
- }
511
- const remoteFetchUrl = (_b = (await git.getConfig(`remote.${remoteName}.url`))) === null || _b === void 0 ? void 0 : _b.value;
512
- if (!remoteFetchUrl) {
513
- return { status: "IN_A_BRANCH", localBranchName };
514
- }
515
- const remotePushUrl = (_c = (await git.getConfig(`remote.${remoteName}.pushurl`))) === null || _c === void 0 ? void 0 : _c.value;
516
- let upstreamBranchName = (await git.revparse(["--abbrev-ref", "--symbolic-full-name", "@{u}"])).split("\n", 1)[0];
517
- if (upstreamBranchName.startsWith(`${remoteName}/`)) {
518
- // `upstreamBranchName` is in the form `$remoteName/$branchName`, so we need to remove the `$remoteName/` part
519
- upstreamBranchName = upstreamBranchName.substring(remoteName.length + 1);
520
- }
521
- return {
522
- status: "IN_A_BRANCH",
523
- localBranchName,
524
- upstream: {
525
- branchName: upstreamBranchName,
526
- remoteName,
527
- url: remoteFetchUrl,
528
- pushUrl: remotePushUrl,
529
- },
530
- };
531
- }
532
- exports.getLocalGitRepoState = getLocalGitRepoState;
533
- /**
534
- * Returns the current git branch, or undefined if not in a git repo
535
- */
536
- async function getCurrentGitBranchIfGit() {
537
- const git = (0, simple_git_1.simpleGit)();
538
- try {
539
- // do not return untracked files which can be slow, we only care about the branch info
540
- const status = await git.status(["--untracked-files=no"]);
541
- const currentBranch = status.current;
542
- return currentBranch;
543
- }
544
- catch {
545
- // ignore
546
- }
547
- return null;
548
- }
549
- exports.getCurrentGitBranchIfGit = getCurrentGitBranchIfGit;
550
- /**
551
- * Returns the current git branch, or throws if not in a git repo
552
- */
553
- async function getCurrentGitBranch() {
554
- const currentBranch = await getCurrentGitBranchIfGit();
555
- if (!currentBranch) {
556
- throw new Error("No git repository found");
557
- }
558
- return currentBranch;
559
- }
560
- exports.getCurrentGitBranch = getCurrentGitBranch;
561
- async function getHeadCommit(branch) {
562
- const git = (0, simple_git_1.simpleGit)();
563
- let headCommitId;
564
- let headCommitMessage;
565
- const logResponse = await git.show(["--no-patch", "--format=%H%n%s", branch]);
566
- const logLines = logResponse.split("\n");
567
- if (logLines.length > 1) {
568
- headCommitId = logLines[0];
569
- headCommitMessage = logLines[1];
570
- }
571
- if (!headCommitId || !headCommitMessage) {
572
- throw new Error(`Failed to get head commit for branch '${branch}'`);
573
- }
574
- return [headCommitId, headCommitMessage];
575
- }
576
- exports.getHeadCommit = getHeadCommit;
577
- function isCI() {
578
- return process.env.CI === "true";
579
- }
580
- exports.isCI = isCI;
581
- async function isGitRepoDirty() {
582
- if (isCI()) {
583
- // Skip dirtiness check in CI environments
584
- return false;
585
- }
586
- const git = (0, simple_git_1.simpleGit)();
587
- const status = await git.status();
588
- return !status.isClean();
589
- }
590
- exports.isGitRepoDirty = isGitRepoDirty;
591
- function extractApiName(api) {
592
- var _a, _b, _c, _d;
593
- return (_d = (_c = (_b = (_a = api.apiPb) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : api === null || api === void 0 ? void 0 : api.name) !== null && _d !== void 0 ? _d : "Unknown";
594
- }
595
- exports.extractApiName = extractApiName;
596
- function writeApi(api, originalApiName, appDirName) {
597
- const apiName = slugifyName(originalApiName);
598
- const apiContent = (0, yaml_1.stringify)(api.apiPb, {
599
- sortMapEntries: true,
600
- blockQuote: "literal",
601
- });
602
- const handleApi = async () => {
603
- await fs.outputFile(`${appDirName}/${apiName}.yaml`, apiContent);
604
- };
605
- return handleApi();
606
- }
607
- async function validateMultiPageApplication(applicationConfig, superblocksRootPath, location) {
608
- var _a;
609
- // validate app level APIs
610
- for (const apiName of Object.values(applicationConfig.apis)) {
611
- const apiPath = node_path_1.default.resolve(superblocksRootPath, location, "apis", `${slugifyName(apiName)}.yaml`);
612
- const validateApiError = await validateYamlFile(apiPath);
613
- if (validateApiError) {
614
- return validateApiError;
615
- }
616
- }
617
- // validate pages
618
- for (const page of Object.values((_a = applicationConfig.pages) !== null && _a !== void 0 ? _a : {})) {
619
- const pagePath = node_path_1.default.resolve(superblocksRootPath, location, "pages", slugifyName(page.name), "page.yaml");
620
- const validatePageError = await validateYamlFile(pagePath);
621
- if (validatePageError) {
622
- return validatePageError;
623
- }
624
- // validate page level APIs
625
- for (const apiName of Object.values(page.apis)) {
626
- const apiPath = node_path_1.default.resolve(superblocksRootPath, location, "pages", slugifyName(page.name), "apis", `${slugifyName(apiName)}.yaml`);
627
- const validateApiError = await validateYamlFile(apiPath);
628
- if (validateApiError) {
629
- return validateApiError;
630
- }
631
- }
632
- }
633
- return undefined;
634
- }
635
- async function validateLocalResource(superblocksRootPath, resource) {
636
- switch (resource.resourceType) {
637
- case "APPLICATION": {
638
- // make sure application config exists
639
- const applicationConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location, util_2.RESOURCE_CONFIG_PATH);
640
- if (!(await fs.pathExists(applicationConfigPath))) {
641
- return `File ${relativeToCurrentDir(applicationConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
642
- }
643
- let applicationConfig = undefined;
644
- try {
645
- // make sure it's a well-formed application config
646
- applicationConfig = await fs.readJSON(applicationConfigPath);
647
- if (!applicationConfig) {
648
- throw new Error();
649
- }
650
- }
651
- catch {
652
- return `File ${relativeToCurrentDir(applicationConfigPath)} is not a valid JSON file. Please be sure it's valid JSON and rerun the command.`;
653
- }
654
- const applicationYamlPath = node_path_1.default.resolve(superblocksRootPath, resource.location, "application.yaml");
655
- // make sure application.yaml is a well-formed yaml file
656
- try {
657
- await readYamlFile(applicationYamlPath);
658
- }
659
- catch {
660
- return `File ${relativeToCurrentDir(applicationYamlPath)} is not a valid YAML file. Please be sure it's valid YAML and rerun the command.`;
661
- }
662
- const validationError = validateMultiPageApplication(applicationConfig, superblocksRootPath, resource.location);
663
- if (validationError) {
664
- return validationError;
665
- }
666
- break;
667
- }
668
- case "BACKEND": {
669
- // make sure the backend config exists
670
- const backendConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location, util_2.RESOURCE_CONFIG_PATH);
671
- if (!(await fs.pathExists(backendConfigPath))) {
672
- return `File ${relativeToCurrentDir(backendConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
673
- }
674
- // make sure it's a well-formed backend config
675
- try {
676
- await fs.readJSON(backendConfigPath);
677
- }
678
- catch {
679
- return `File ${relativeToCurrentDir(backendConfigPath)} is not a valid JSON file. Please be sure it's valid JSON and rerun the command.`;
680
- }
681
- // make sure that api.yaml exists
682
- const apiYamlPath = node_path_1.default.resolve(superblocksRootPath, resource.location, "api.yaml");
683
- const validateYamlFileError = await validateYamlFile(apiYamlPath);
684
- if (validateYamlFileError) {
685
- return validateYamlFileError;
686
- }
687
- break;
688
- }
689
- }
690
- return undefined;
691
- }
692
- exports.validateLocalResource = validateLocalResource;
693
- async function deleteResourcesAndUpdateRootConfig(removedResourceIds, existingSuperblocksRootConfig, superblocksRootPath, superblocksRootConfigPath) {
694
- for (const resourceId of removedResourceIds) {
695
- const resource = existingSuperblocksRootConfig === null || existingSuperblocksRootConfig === void 0 ? void 0 : existingSuperblocksRootConfig.resources[resourceId];
696
- await removeResourceFromDisk(superblocksRootPath, resource.location);
697
- }
698
- for (const removedResourceId of removedResourceIds) {
699
- delete existingSuperblocksRootConfig.resources[removedResourceId];
700
- }
701
- // update superblocks.json file with removed resources
702
- await fs.writeFile(superblocksRootConfigPath, JSON.stringify(sortByKey(existingSuperblocksRootConfig), null, 2));
703
- }
704
- exports.deleteResourcesAndUpdateRootConfig = deleteResourcesAndUpdateRootConfig;
705
- async function validateYamlFile(yamlPath) {
706
- // make sure a yaml file is well-formed
707
- try {
708
- await readYamlFile(yamlPath);
709
- }
710
- catch {
711
- return `File ${relativeToCurrentDir(yamlPath)} is not a valid YAML file. Please be sure it's valid YAML and rerun the command.`;
712
- }
713
- }
714
- function relativeToCurrentDir(applicationConfigPath) {
715
- return `./${node_path_1.default.relative(process.cwd(), applicationConfigPath)}`;
716
- }