@superblocksteam/cli 1.10.0 → 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.
- package/LICENSE.txt +87 -0
- package/README.md +6 -6
- package/assets/custom-components/setup/tsconfig.json +0 -1
- package/bin/dev +5 -7
- package/bin/run +1 -3
- package/dist/appendHotReloadEventPlugin.mjs +43 -0
- package/dist/commands/commits.d.mts +18 -0
- package/dist/commands/{commits.js → commits.mjs} +59 -67
- package/dist/commands/components/{create.d.ts → create.d.mts} +2 -2
- package/dist/commands/components/{create.js → create.mjs} +84 -93
- package/dist/commands/components/{register.d.ts → register.d.mts} +1 -1
- package/dist/commands/components/register.mjs +12 -0
- package/dist/commands/components/{upload.d.ts → upload.d.mts} +2 -2
- package/dist/commands/components/{upload.js → upload.mjs} +39 -43
- package/dist/commands/components/{watch.d.ts → watch.d.mts} +1 -1
- package/dist/commands/components/{watch.js → watch.mjs} +29 -36
- package/dist/commands/config/{set.d.ts → set.d.mts} +2 -2
- package/dist/commands/config/{set.js → set.mjs} +28 -32
- package/dist/commands/{init.d.ts → init.d.mts} +4 -4
- package/dist/commands/{init.js → init.mjs} +58 -64
- package/dist/commands/{login.d.ts → login.d.mts} +1 -1
- package/dist/commands/login.mjs +55 -0
- package/dist/commands/{migrate.d.ts → migrate.d.mts} +1 -1
- package/dist/commands/{migrate.js → migrate.mjs} +34 -42
- package/dist/commands/pull.d.mts +17 -0
- package/dist/commands/{pull.js → pull.mjs} +72 -80
- package/dist/commands/push.d.mts +15 -0
- package/dist/commands/{push.js → push.mjs} +81 -90
- package/dist/commands/{rm.d.ts → rm.d.mts} +2 -2
- package/dist/commands/{rm.js → rm.mjs} +34 -40
- package/dist/common/{authenticated-command.js → authenticated-command.mjs} +65 -75
- package/dist/common/defaults/{create-component-defaults.js → create-component-defaults.mjs} +2 -7
- package/dist/common/{version-control.d.ts → version-control.d.mts} +1 -1
- package/dist/common/{version-control.js → version-control.mjs} +170 -202
- package/dist/index.js +1 -5
- package/dist/{productionCssPlugin.js → productionCssPlugin.mjs} +4 -10
- package/dist/{reactShimPlugin.js → reactShimPlugin.mjs} +17 -24
- package/dist/util/migrationWarningsForApplications.mjs +47 -0
- package/dist/util/{migrationsForDotfiles.js → migrationsForDotfiles.mjs} +10 -17
- package/oclif.manifest.json +274 -161
- package/package.json +43 -41
- package/dist/appendHotReloadEventPlugin.js +0 -48
- package/dist/commands/commits.d.ts +0 -18
- package/dist/commands/components/register.js +0 -15
- package/dist/commands/login.js +0 -61
- package/dist/commands/pull.d.ts +0 -17
- package/dist/commands/push.d.ts +0 -15
- package/dist/util/migrationWarningsForApplications.js +0 -52
- /package/dist/{appendHotReloadEventPlugin.d.ts → appendHotReloadEventPlugin.d.mts} +0 -0
- /package/dist/common/{authenticated-command.d.ts → authenticated-command.d.mts} +0 -0
- /package/dist/common/defaults/{create-component-defaults.d.ts → create-component-defaults.d.mts} +0 -0
- /package/dist/{productionCssPlugin.d.ts → productionCssPlugin.d.mts} +0 -0
- /package/dist/{reactShimPlugin.d.ts → reactShimPlugin.d.mts} +0 -0
- /package/dist/util/{migrationWarningsForApplications.d.ts → migrationWarningsForApplications.d.mts} +0 -0
- /package/dist/util/{migrationsForDotfiles.d.ts → migrationsForDotfiles.d.mts} +0 -0
|
@@ -1,66 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const yaml_1 = require("yaml");
|
|
18
|
-
exports.LATEST_EDITS_MODE = "latest-edits";
|
|
19
|
-
exports.MOST_RECENT_COMMIT_MODE = "most-recent-commit";
|
|
20
|
-
exports.DEPLOYED_MODE = "deployed";
|
|
21
|
-
exports.DEFAULT_BRANCH = "main";
|
|
1
|
+
import * as https from "https";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { DEFAULT_LINES_FOR_LARGE_STEPS, } from "@superblocksteam/sdk";
|
|
5
|
+
import { RESOURCE_CONFIG_PATH, SUPERBLOCKS_HOME_FOLDER_NAME, getSuperblocksApplicationConfigIfExists, getSuperblocksApplicationConfigJson, getSuperblocksBackendConfigIfExists, } from "@superblocksteam/util";
|
|
6
|
+
import { bold } from "colorette";
|
|
7
|
+
import fs from "fs-extra";
|
|
8
|
+
import { isEmpty, isArray, isObject, get, cloneDeep } from "lodash-es";
|
|
9
|
+
import * as semver from "semver";
|
|
10
|
+
import { simpleGit } from "simple-git";
|
|
11
|
+
import slugify from "slugify";
|
|
12
|
+
import { parse, stringify as ymlstringify } from "yaml";
|
|
13
|
+
export const LATEST_EDITS_MODE = "latest-edits";
|
|
14
|
+
export const MOST_RECENT_COMMIT_MODE = "most-recent-commit";
|
|
15
|
+
export const DEPLOYED_MODE = "deployed";
|
|
16
|
+
export const DEFAULT_BRANCH = "main";
|
|
22
17
|
const LANGUAGE_STEP_EXTENSIONS = {
|
|
23
18
|
javascript: "js",
|
|
24
19
|
python: "py",
|
|
25
20
|
};
|
|
26
|
-
|
|
27
|
-
[
|
|
28
|
-
[
|
|
29
|
-
[
|
|
21
|
+
export const modeFlagValuesMap = {
|
|
22
|
+
[LATEST_EDITS_MODE]: "Latest edits",
|
|
23
|
+
[MOST_RECENT_COMMIT_MODE]: "Most recent commit",
|
|
24
|
+
[DEPLOYED_MODE]: "Deployed",
|
|
30
25
|
};
|
|
31
|
-
var FileStructureType;
|
|
26
|
+
export var FileStructureType;
|
|
32
27
|
(function (FileStructureType) {
|
|
33
28
|
FileStructureType["SINGLE_PAGE"] = "single-page";
|
|
34
29
|
FileStructureType["MULTI_PAGE"] = "multi-page";
|
|
35
|
-
})(FileStructureType || (
|
|
36
|
-
function modeFlagToViewMode(modeFlag) {
|
|
30
|
+
})(FileStructureType || (FileStructureType = {}));
|
|
31
|
+
export function modeFlagToViewMode(modeFlag) {
|
|
37
32
|
switch (modeFlag) {
|
|
38
|
-
case
|
|
33
|
+
case LATEST_EDITS_MODE:
|
|
39
34
|
return "export-live";
|
|
40
|
-
case
|
|
35
|
+
case MOST_RECENT_COMMIT_MODE:
|
|
41
36
|
return "export-latest";
|
|
42
|
-
case
|
|
37
|
+
case DEPLOYED_MODE:
|
|
43
38
|
return "export-deployed";
|
|
44
39
|
default:
|
|
45
40
|
throw new Error(`Unsupported mode flag: ${modeFlag}`);
|
|
46
41
|
}
|
|
47
42
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return `Please select at least one item ${(0, colorette_1.bold)("by pressing space")}`;
|
|
43
|
+
export const SELECT_PROMPT_HELP = "Use ↑/↓ arrow keys, Enter to confirm";
|
|
44
|
+
export const MULTI_SELECT_PROMPT_HELP = "Type to filter, Use ↑/↓ arrow keys, Space to select, Enter to confirm";
|
|
45
|
+
export const atLeastOneSelection = (value) => {
|
|
46
|
+
if (isEmpty(value)) {
|
|
47
|
+
return `Please select at least one item ${bold("by pressing space")}`;
|
|
54
48
|
}
|
|
55
49
|
return true;
|
|
56
50
|
};
|
|
57
|
-
exports.atLeastOneSelection = atLeastOneSelection;
|
|
58
51
|
const DEFAULT_FILE_VERSION = "0.1.0";
|
|
59
52
|
const SPLIT_LARGE_API_STEPS_VERSION = "0.2.0";
|
|
60
53
|
const LATEST_FILE_VERSION = SPLIT_LARGE_API_STEPS_VERSION;
|
|
61
|
-
function getApiRepresentation(featureFlags, resourceConfig) {
|
|
62
|
-
|
|
63
|
-
const linesForLargeSteps = (_a = featureFlags.linesForLargeSteps()) !== null && _a !== void 0 ? _a : sdk_1.DEFAULT_LINES_FOR_LARGE_STEPS;
|
|
54
|
+
export function getApiRepresentation(featureFlags, resourceConfig) {
|
|
55
|
+
const linesForLargeSteps = featureFlags.linesForLargeSteps() ?? DEFAULT_LINES_FOR_LARGE_STEPS;
|
|
64
56
|
if (featureFlags.splitLargeApiStepsEnabled() &&
|
|
65
57
|
isPostSplitLargeApiSteps(resourceConfig)) {
|
|
66
58
|
return {
|
|
@@ -74,17 +66,15 @@ function getApiRepresentation(featureFlags, resourceConfig) {
|
|
|
74
66
|
minLinesForExtraction: linesForLargeSteps,
|
|
75
67
|
};
|
|
76
68
|
}
|
|
77
|
-
exports.getApiRepresentation = getApiRepresentation;
|
|
78
69
|
function isPostSplitLargeApiSteps(resourceConfig) {
|
|
79
|
-
var _a, _b;
|
|
80
70
|
if (!resourceConfig) {
|
|
81
71
|
return false;
|
|
82
72
|
}
|
|
83
|
-
const version =
|
|
73
|
+
const version = resourceConfig.metadata?.fileVersion ?? DEFAULT_FILE_VERSION;
|
|
84
74
|
return semver.compare(version, SPLIT_LARGE_API_STEPS_VERSION) >= 0;
|
|
85
75
|
}
|
|
86
76
|
function slugifyName(originalName) {
|
|
87
|
-
return (
|
|
77
|
+
return slugify(originalName, {
|
|
88
78
|
replacement: "_",
|
|
89
79
|
lower: true,
|
|
90
80
|
});
|
|
@@ -97,7 +87,7 @@ async function downloadFile(rootDirectory, filepath, url) {
|
|
|
97
87
|
try {
|
|
98
88
|
// create directory path if it doesn't exist yet
|
|
99
89
|
if (!(await fs.pathExists(fullPath))) {
|
|
100
|
-
await fs.mkdir(
|
|
90
|
+
await fs.mkdir(dirname(fullPath), { recursive: true });
|
|
101
91
|
}
|
|
102
92
|
const file = fs.createWriteStream(fullPath);
|
|
103
93
|
https.get(url, (resp) => {
|
|
@@ -112,7 +102,7 @@ async function downloadFile(rootDirectory, filepath, url) {
|
|
|
112
102
|
});
|
|
113
103
|
});
|
|
114
104
|
}
|
|
115
|
-
catch
|
|
105
|
+
catch {
|
|
116
106
|
return resolve(false);
|
|
117
107
|
}
|
|
118
108
|
});
|
|
@@ -121,21 +111,20 @@ async function downloadFile(rootDirectory, filepath, url) {
|
|
|
121
111
|
try {
|
|
122
112
|
await fs.unlink(fullPath);
|
|
123
113
|
}
|
|
124
|
-
catch
|
|
114
|
+
catch {
|
|
125
115
|
console.log("Failed to delete file", fullPath);
|
|
126
116
|
}
|
|
127
117
|
return Promise.resolve(fullPath);
|
|
128
118
|
}
|
|
129
119
|
return Promise.resolve("");
|
|
130
120
|
}
|
|
131
|
-
async function readAppApiYamlFile(parentDirectory, apiName) {
|
|
132
|
-
var _a;
|
|
121
|
+
export async function readAppApiYamlFile(parentDirectory, apiName) {
|
|
133
122
|
// The API is either stored in its entirety in a single YAML file, or
|
|
134
123
|
// or in a subdirectory containing the YAML file and zero or more language-specific files.
|
|
135
|
-
const apiNameSlug = slugifyName(apiName
|
|
124
|
+
const apiNameSlug = slugifyName(apiName ?? "api");
|
|
136
125
|
const singularApiYamlPath = `${parentDirectory}/${apiNameSlug}.yaml`;
|
|
137
126
|
const apiDirPath = `${parentDirectory}/${apiNameSlug}`;
|
|
138
|
-
const nestedApiYamlPath = `${apiDirPath}
|
|
127
|
+
const nestedApiYamlPath = `${apiDirPath}/api.yaml`;
|
|
139
128
|
// Read the YAML file
|
|
140
129
|
let yamlPath;
|
|
141
130
|
let yamlParentPath;
|
|
@@ -150,18 +139,16 @@ async function readAppApiYamlFile(parentDirectory, apiName) {
|
|
|
150
139
|
yamlParentPath = apiDirPath;
|
|
151
140
|
}
|
|
152
141
|
else {
|
|
153
|
-
throw new Error(`API ${apiName
|
|
142
|
+
throw new Error(`API ${apiName ?? ""} not found at ${parentDirectory}`);
|
|
154
143
|
}
|
|
155
144
|
// That is nested in an API-specific directory
|
|
156
145
|
const apiDefn = (await readYamlFile(yamlPath));
|
|
157
146
|
// The API YAML file may or may not have language-specific content in separate files.
|
|
158
147
|
// Replace any file references with the actual content
|
|
159
|
-
await resolveLanguageSpecificStepContentFromBlocks(yamlParentPath,
|
|
148
|
+
await resolveLanguageSpecificStepContentFromBlocks(yamlParentPath, apiDefn.blocks ?? []);
|
|
160
149
|
return apiDefn;
|
|
161
150
|
}
|
|
162
|
-
exports.readAppApiYamlFile = readAppApiYamlFile;
|
|
163
151
|
async function resolveLanguageSpecificStepContentFromBlocks(parentPath, blocks) {
|
|
164
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
165
152
|
for (const block of blocks) {
|
|
166
153
|
// Handle language-specific step content
|
|
167
154
|
if (block.step) {
|
|
@@ -170,37 +157,37 @@ async function resolveLanguageSpecificStepContentFromBlocks(parentPath, blocks)
|
|
|
170
157
|
}
|
|
171
158
|
// Handle conditional blocks
|
|
172
159
|
if (block.conditional) {
|
|
173
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
160
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.conditional.if?.blocks ?? []);
|
|
174
161
|
for (const elseIfBlock of block.conditional.elseIf) {
|
|
175
162
|
await resolveLanguageSpecificStepContentFromBlocks(parentPath, elseIfBlock.blocks);
|
|
176
163
|
}
|
|
177
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
164
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.conditional.else?.blocks ?? []);
|
|
178
165
|
}
|
|
179
166
|
// Handle loop blocks
|
|
180
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
167
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.loop?.blocks ?? []);
|
|
181
168
|
// Handle try-catch blocks
|
|
182
169
|
if (block.tryCatch) {
|
|
183
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
184
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
185
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
170
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.tryCatch.try?.blocks ?? []);
|
|
171
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.tryCatch.catch?.blocks ?? []);
|
|
172
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.tryCatch.finally?.blocks ?? []);
|
|
186
173
|
}
|
|
187
174
|
// Handle parallel blocks
|
|
188
175
|
if (block.parallel) {
|
|
189
|
-
for (const path of Object.values(
|
|
176
|
+
for (const path of Object.values(block.parallel?.static?.paths ?? {})) {
|
|
190
177
|
await resolveLanguageSpecificStepContentFromBlocks(parentPath, path.blocks);
|
|
191
178
|
}
|
|
192
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
179
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.parallel?.dynamic?.blocks ?? []);
|
|
193
180
|
}
|
|
194
181
|
// Handle stream blocks
|
|
195
182
|
if (block.stream) {
|
|
196
|
-
await resolveLanguageSpecificStepContentFromBlocks(parentPath,
|
|
197
|
-
await resolveLanguageSpecificStepContentFromStep(parentPath,
|
|
183
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, block.stream.process?.blocks ?? []);
|
|
184
|
+
await resolveLanguageSpecificStepContentFromStep(parentPath, block.stream.trigger?.step ?? {});
|
|
198
185
|
}
|
|
199
186
|
}
|
|
200
187
|
}
|
|
201
188
|
async function resolveLanguageSpecificStepContentFromStep(parentPath, step) {
|
|
202
189
|
// Handle language-specific step content
|
|
203
|
-
if (!
|
|
190
|
+
if (!step?.integration || !LANGUAGE_STEP_EXTENSIONS[step.integration]) {
|
|
204
191
|
return;
|
|
205
192
|
}
|
|
206
193
|
const languageContent = step[step.integration];
|
|
@@ -218,7 +205,7 @@ async function resolveLanguageSpecificStepContentFromStep(parentPath, step) {
|
|
|
218
205
|
}
|
|
219
206
|
}
|
|
220
207
|
async function readYamlFile(path) {
|
|
221
|
-
return
|
|
208
|
+
return parse(await fs.readFile(path, "utf8"));
|
|
222
209
|
}
|
|
223
210
|
function getFileStructureTypeFromResourceConfig(superblocksConfig) {
|
|
224
211
|
if (superblocksConfig.pages) {
|
|
@@ -226,15 +213,14 @@ function getFileStructureTypeFromResourceConfig(superblocksConfig) {
|
|
|
226
213
|
}
|
|
227
214
|
return FileStructureType.SINGLE_PAGE;
|
|
228
215
|
}
|
|
229
|
-
async function getFileStructureType(rootPath, existingRelativeLocation) {
|
|
230
|
-
const superblocksConfig = await
|
|
216
|
+
export async function getFileStructureType(rootPath, existingRelativeLocation) {
|
|
217
|
+
const superblocksConfig = await getSuperblocksApplicationConfigJson(`${rootPath}/${existingRelativeLocation}`);
|
|
231
218
|
return getFileStructureTypeFromResourceConfig(superblocksConfig);
|
|
232
219
|
}
|
|
233
|
-
exports.getFileStructureType = getFileStructureType;
|
|
234
220
|
// NOTE: If a change is made to how applications are read from disk, please update
|
|
235
221
|
// logic to write applications to disk in the "writeResourceToDisk" function accordingly.
|
|
236
222
|
// @deprecated this can be removed once all customers move to multi page applications
|
|
237
|
-
async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
223
|
+
export async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
238
224
|
const application = await readYamlFile(`${rootPath}/${existingRelativeLocation}/application.yaml`);
|
|
239
225
|
const page = await readYamlFile(`${rootPath}/${existingRelativeLocation}/page.yaml`);
|
|
240
226
|
const apisDirName = `${rootPath}/${existingRelativeLocation}/apis`;
|
|
@@ -256,17 +242,15 @@ async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
|
256
242
|
page,
|
|
257
243
|
};
|
|
258
244
|
}
|
|
259
|
-
exports.readApplicationFromDisk = readApplicationFromDisk;
|
|
260
245
|
// NOTE: If a change is made to how applications are read from disk, please update
|
|
261
246
|
// logic to write applications to disk in the "writeResourceToDisk" function accordingly.
|
|
262
|
-
async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
263
|
-
|
|
264
|
-
const superblocksApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigJson)(`${rootPath}/${existingRelativeLocation}`);
|
|
247
|
+
export async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
248
|
+
const superblocksApplicationConfig = await getSuperblocksApplicationConfigJson(`${rootPath}/${existingRelativeLocation}`);
|
|
265
249
|
const application = await readYamlFile(`${rootPath}/${existingRelativeLocation}/application.yaml`);
|
|
266
250
|
const pagesDirName = `${rootPath}/${existingRelativeLocation}/pages`;
|
|
267
251
|
const pages = [];
|
|
268
252
|
if (await fs.pathExists(pagesDirName)) {
|
|
269
|
-
for (const page of Object.values(
|
|
253
|
+
for (const page of Object.values(superblocksApplicationConfig.pages ?? {})) {
|
|
270
254
|
// Read in the page definition
|
|
271
255
|
const pageContent = await readYamlFile(`${pagesDirName}/${slugifyName(page.name)}/page.yaml`);
|
|
272
256
|
// Read in the API definitions for this page
|
|
@@ -280,7 +264,7 @@ async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocati
|
|
|
280
264
|
// This mimics the shape of the ApiV3Dto object
|
|
281
265
|
apis.push({
|
|
282
266
|
id: apiContent.metadata.id,
|
|
283
|
-
pageId: page.id,
|
|
267
|
+
pageId: page.id, // Alternatively, pageId is also stored in apiPb.trigger.application.pageId
|
|
284
268
|
apiPb: apiContent,
|
|
285
269
|
});
|
|
286
270
|
}
|
|
@@ -316,46 +300,41 @@ async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocati
|
|
|
316
300
|
pages,
|
|
317
301
|
};
|
|
318
302
|
}
|
|
319
|
-
exports.readMultiPageApplicationFromDisk = readMultiPageApplicationFromDisk;
|
|
320
303
|
function getApiNamesFromApplicationConfig(applicationConfig) {
|
|
321
|
-
var _a;
|
|
322
304
|
return applicationConfig.appApis
|
|
323
305
|
? Object.values(applicationConfig.appApis).map((api) => api.name)
|
|
324
|
-
: Object.values(
|
|
306
|
+
: Object.values(applicationConfig.apis ?? {});
|
|
325
307
|
}
|
|
326
308
|
function getApiNamesFromPageConfig(pageConfig) {
|
|
327
|
-
var _a;
|
|
328
309
|
return pageConfig.pageApis
|
|
329
310
|
? Object.values(pageConfig.pageApis).map((api) => api.name)
|
|
330
|
-
: Object.values(
|
|
311
|
+
: Object.values(pageConfig.apis ?? {});
|
|
331
312
|
}
|
|
332
|
-
async function readApiFromDisk(rootPath, existingRelativeLocation) {
|
|
313
|
+
export async function readApiFromDisk(rootPath, existingRelativeLocation) {
|
|
333
314
|
const path = `${rootPath}/${existingRelativeLocation}`;
|
|
334
315
|
const apiContent = await readAppApiYamlFile(path);
|
|
335
316
|
return {
|
|
336
317
|
apiPb: apiContent,
|
|
337
318
|
};
|
|
338
319
|
}
|
|
339
|
-
exports.readApiFromDisk = readApiFromDisk;
|
|
340
320
|
// NOTE: If a change is made to how applications are written to disk, please update
|
|
341
321
|
// logic to read applications from disk in the "readApplicationFromDisk" function accordingly.
|
|
342
|
-
async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, featureFlags, existingRelativeLocation, preferredApiRepresentation) {
|
|
343
|
-
var _a, _b, _c;
|
|
322
|
+
export async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, featureFlags, existingRelativeLocation, preferredApiRepresentation) {
|
|
344
323
|
switch (resourceType) {
|
|
345
324
|
case "APPLICATION": {
|
|
346
325
|
const parentDirName = "apps";
|
|
347
326
|
const newRelativeLocation = `${parentDirName}/${slugifyName(resource.application.name)}`;
|
|
348
|
-
const relativeLocation = existingRelativeLocation
|
|
349
|
-
const appDirName =
|
|
327
|
+
const relativeLocation = existingRelativeLocation ?? newRelativeLocation;
|
|
328
|
+
const appDirName = path.resolve(rootPath, relativeLocation);
|
|
350
329
|
if (!(await fs.pathExists(appDirName))) {
|
|
351
330
|
await fs.mkdir(appDirName, { recursive: true });
|
|
352
331
|
}
|
|
353
|
-
const applicationContent = (
|
|
332
|
+
const applicationContent = ymlstringify(resource.application, {
|
|
354
333
|
sortMapEntries: true,
|
|
355
334
|
});
|
|
356
335
|
await fs.outputFile(`${appDirName}/application.yaml`, applicationContent);
|
|
357
336
|
if (resource.page) {
|
|
358
|
-
const pageContent = (
|
|
337
|
+
const pageContent = ymlstringify(resource.page, {
|
|
359
338
|
sortMapEntries: true,
|
|
360
339
|
blockQuote: "literal",
|
|
361
340
|
});
|
|
@@ -364,15 +343,16 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
364
343
|
const apiPromises = [];
|
|
365
344
|
const apisDirName = `${appDirName}/apis`;
|
|
366
345
|
await fs.ensureDir(apisDirName);
|
|
367
|
-
const existingApplicationConfig = await
|
|
346
|
+
const existingApplicationConfig = await getSuperblocksApplicationConfigIfExists(appDirName);
|
|
368
347
|
const existingFilePaths = getExistingFilePathsForApplicationApi(existingApplicationConfig, appDirName);
|
|
369
348
|
const newApplicationConfig = {
|
|
370
349
|
configType: "APPLICATION",
|
|
371
|
-
defaultPageId:
|
|
350
|
+
defaultPageId: resource.page?.id,
|
|
372
351
|
id: resource.application.id,
|
|
373
352
|
metadata: getResourceConfigMetadata(featureFlags, existingApplicationConfig),
|
|
374
353
|
};
|
|
375
|
-
const apiRepresentation = preferredApiRepresentation
|
|
354
|
+
const apiRepresentation = preferredApiRepresentation ??
|
|
355
|
+
getApiRepresentation(featureFlags, newApplicationConfig);
|
|
376
356
|
if (resource.apis) {
|
|
377
357
|
for (const api of resource.apis) {
|
|
378
358
|
const apiInfo = await writeAppApi(api, appDirName, existingFilePaths, apiPromises, apiRepresentation);
|
|
@@ -395,11 +375,11 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
395
375
|
for (const filePath of existingFilePaths) {
|
|
396
376
|
await fs.remove(filePath);
|
|
397
377
|
}
|
|
398
|
-
await fs.ensureDir(`${appDirName}/${
|
|
399
|
-
await fs.writeFile(`${appDirName}/${
|
|
378
|
+
await fs.ensureDir(`${appDirName}/${SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
379
|
+
await fs.writeFile(`${appDirName}/${RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
|
|
400
380
|
const createdFiles = await Promise.resolve(
|
|
401
381
|
// Defensive check for when application settings are missing componentFiles
|
|
402
|
-
|
|
382
|
+
resource.componentFiles?.map((file) => downloadFile(appDirName, file.filename, file.url)) ?? []);
|
|
403
383
|
// print out failed downloads synchronously here
|
|
404
384
|
createdFiles
|
|
405
385
|
.filter((createdFiles) => createdFiles.length)
|
|
@@ -415,27 +395,28 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
415
395
|
const parentDirName = "backends";
|
|
416
396
|
const apiName = slugifyName(extractApiName(resource));
|
|
417
397
|
const newRelativeLocation = `${parentDirName}/${apiName}`;
|
|
418
|
-
const relativeLocation = existingRelativeLocation
|
|
419
|
-
const backendDirName =
|
|
398
|
+
const relativeLocation = existingRelativeLocation ?? newRelativeLocation;
|
|
399
|
+
const backendDirName = path.resolve(rootPath, relativeLocation);
|
|
420
400
|
if (!(await fs.pathExists(backendDirName))) {
|
|
421
401
|
await fs.mkdir(backendDirName, { recursive: true });
|
|
422
402
|
}
|
|
423
|
-
const existingBackendConfig = await
|
|
403
|
+
const existingBackendConfig = await getSuperblocksBackendConfigIfExists(backendDirName);
|
|
424
404
|
const existingFilePaths = getExistingFilePathsForBackendApi(existingBackendConfig, backendDirName);
|
|
425
405
|
const backendConfig = {
|
|
426
406
|
id: resourceId,
|
|
427
407
|
configType: "BACKEND",
|
|
428
408
|
metadata: getResourceConfigMetadata(featureFlags, existingBackendConfig),
|
|
429
409
|
};
|
|
430
|
-
const apiRepresentation = preferredApiRepresentation
|
|
410
|
+
const apiRepresentation = preferredApiRepresentation ??
|
|
411
|
+
getApiRepresentation(featureFlags, backendConfig);
|
|
431
412
|
// Write the API file(s)
|
|
432
413
|
const apiInfo = await writeBackendApi(resource, backendDirName, [], apiRepresentation, existingFilePaths);
|
|
433
414
|
if (apiRepresentation.extractLargeSourceFiles) {
|
|
434
415
|
backendConfig.sourceFiles = apiInfo.sourceFiles;
|
|
435
416
|
}
|
|
436
417
|
// Write the backend config file
|
|
437
|
-
await fs.ensureDir(`${backendDirName}/${
|
|
438
|
-
await fs.writeFile(`${backendDirName}/${
|
|
418
|
+
await fs.ensureDir(`${backendDirName}/${SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
419
|
+
await fs.writeFile(`${backendDirName}/${RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(backendConfig), null, 2));
|
|
439
420
|
// Delete any existing files that were not overwritten
|
|
440
421
|
for (const filePath of existingFilePaths) {
|
|
441
422
|
await fs.remove(filePath);
|
|
@@ -450,31 +431,30 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
450
431
|
}
|
|
451
432
|
}
|
|
452
433
|
}
|
|
453
|
-
exports.writeResourceToDisk = writeResourceToDisk;
|
|
454
434
|
// NOTE: If a change is made to how applications are written to disk, please update
|
|
455
435
|
// logic to read applications from disk in the "readMultiPageApplicationFromDisk" function accordingly.
|
|
456
|
-
async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags, existingRelativeLocation, migrateFromSinglePage, preferredApiRepresentation) {
|
|
457
|
-
var _a, _b, _c;
|
|
436
|
+
export async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags, existingRelativeLocation, migrateFromSinglePage, preferredApiRepresentation) {
|
|
458
437
|
const parentDirName = "apps";
|
|
459
438
|
const newRelativeLocation = `${parentDirName}/${slugifyName(resource.application.name)}`;
|
|
460
|
-
const relativeLocation = existingRelativeLocation
|
|
461
|
-
const appDirName =
|
|
439
|
+
const relativeLocation = existingRelativeLocation ?? newRelativeLocation;
|
|
440
|
+
const appDirName = path.resolve(rootPath, relativeLocation);
|
|
462
441
|
if (!(await fs.pathExists(appDirName))) {
|
|
463
442
|
await fs.mkdir(appDirName, { recursive: true });
|
|
464
443
|
}
|
|
465
|
-
const applicationContent = (
|
|
444
|
+
const applicationContent = ymlstringify(resource.application, {
|
|
466
445
|
sortMapEntries: true,
|
|
467
446
|
});
|
|
468
447
|
await fs.outputFile(`${appDirName}/application.yaml`, applicationContent);
|
|
469
448
|
// Find the existing application config and existing file paths
|
|
470
|
-
const existingApplicationConfig = await
|
|
449
|
+
const existingApplicationConfig = await getSuperblocksApplicationConfigIfExists(appDirName);
|
|
471
450
|
const existingFilePaths = getExistingFilePathsForApplicationApi(existingApplicationConfig, appDirName);
|
|
472
451
|
const newApplicationConfig = {
|
|
473
452
|
configType: "APPLICATION",
|
|
474
453
|
id: resource.application.id,
|
|
475
454
|
metadata: getResourceConfigMetadata(featureFlags, existingApplicationConfig),
|
|
476
455
|
};
|
|
477
|
-
const apiRepresentation = preferredApiRepresentation
|
|
456
|
+
const apiRepresentation = preferredApiRepresentation ??
|
|
457
|
+
getApiRepresentation(featureFlags, newApplicationConfig);
|
|
478
458
|
newApplicationConfig.pages = {};
|
|
479
459
|
const apiPromises = [];
|
|
480
460
|
for (const page of Object.values(resource.pages)) {
|
|
@@ -488,7 +468,7 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags,
|
|
|
488
468
|
name: page.name,
|
|
489
469
|
};
|
|
490
470
|
const pageConfig = newApplicationConfig.pages[pageId];
|
|
491
|
-
const pageContent = (
|
|
471
|
+
const pageContent = ymlstringify({
|
|
492
472
|
id: page.id,
|
|
493
473
|
name: page.name,
|
|
494
474
|
applicationId: page.applicationId,
|
|
@@ -512,7 +492,7 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags,
|
|
|
512
492
|
}
|
|
513
493
|
pageConfig.pageApis[apiId] = {
|
|
514
494
|
name: apiInfo.name,
|
|
515
|
-
sourceFiles:
|
|
495
|
+
sourceFiles: apiInfo.sourceFiles?.sort(),
|
|
516
496
|
};
|
|
517
497
|
}
|
|
518
498
|
else {
|
|
@@ -546,15 +526,19 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags,
|
|
|
546
526
|
if (apiRepresentation.extractLargeSourceFiles) {
|
|
547
527
|
newApplicationConfig.appApis = appApis;
|
|
548
528
|
}
|
|
529
|
+
else if (!newApplicationConfig.apis) {
|
|
530
|
+
// Make sure there is an empty object even if there are no APIs
|
|
531
|
+
newApplicationConfig.apis = {};
|
|
532
|
+
}
|
|
549
533
|
// Delete any existing files that were not overwritten
|
|
550
534
|
for (const filePath of existingFilePaths) {
|
|
551
535
|
await fs.remove(filePath);
|
|
552
536
|
}
|
|
553
|
-
await fs.ensureDir(`${appDirName}/${
|
|
554
|
-
await fs.writeFile(`${appDirName}/${
|
|
537
|
+
await fs.ensureDir(`${appDirName}/${SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
538
|
+
await fs.writeFile(`${appDirName}/${RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
|
|
555
539
|
const createdFiles = await Promise.resolve(
|
|
556
540
|
// Defensive check for when application settings are missing componentFiles
|
|
557
|
-
|
|
541
|
+
resource.componentFiles?.map((file) => downloadFile(appDirName, file.filename, file.url)) ?? []);
|
|
558
542
|
// print out failed downloads synchronously here
|
|
559
543
|
createdFiles
|
|
560
544
|
.filter((createdFiles) => createdFiles.length)
|
|
@@ -574,7 +558,6 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags,
|
|
|
574
558
|
resourceType: "APPLICATION",
|
|
575
559
|
};
|
|
576
560
|
}
|
|
577
|
-
exports.writeMultiPageApplicationToDisk = writeMultiPageApplicationToDisk;
|
|
578
561
|
function getExistingFilePathsForApplicationApi(superblocksApplicationConfig, location) {
|
|
579
562
|
const paths = new Set();
|
|
580
563
|
if (!superblocksApplicationConfig) {
|
|
@@ -629,17 +612,16 @@ function getExistingFilePathsForBackendApi(superblocksBackendConfig, location) {
|
|
|
629
612
|
}
|
|
630
613
|
return paths;
|
|
631
614
|
}
|
|
632
|
-
function addExistingFilePathsForApi(api, location, paths, useNestedFolder) {
|
|
633
|
-
var _a, _b;
|
|
615
|
+
export function addExistingFilePathsForApi(api, location, paths, useNestedFolder) {
|
|
634
616
|
const apiNameSlug = slugifyName(api.name);
|
|
635
|
-
if (
|
|
617
|
+
if (api.sourceFiles?.length) {
|
|
636
618
|
// API files are in an API-specific folder
|
|
637
619
|
const apiDirPath = useNestedFolder
|
|
638
620
|
? `${location}/${apiNameSlug}`
|
|
639
621
|
: location;
|
|
640
622
|
paths.add(`${apiDirPath}/${apiNameSlug}.yaml`);
|
|
641
623
|
// And there are source files
|
|
642
|
-
for (const sourceFile of
|
|
624
|
+
for (const sourceFile of api.sourceFiles ?? []) {
|
|
643
625
|
paths.add(`${apiDirPath}/${sourceFile}`);
|
|
644
626
|
}
|
|
645
627
|
}
|
|
@@ -649,7 +631,6 @@ function addExistingFilePathsForApi(api, location, paths, useNestedFolder) {
|
|
|
649
631
|
}
|
|
650
632
|
return paths;
|
|
651
633
|
}
|
|
652
|
-
exports.addExistingFilePathsForApi = addExistingFilePathsForApi;
|
|
653
634
|
function getResourceConfigMetadata(featureFlags, existingResourceConfig) {
|
|
654
635
|
if (!existingResourceConfig) {
|
|
655
636
|
// This is a new application, and we may need to add a metadata field to the application config
|
|
@@ -664,12 +645,11 @@ function getResourceConfigMetadata(featureFlags, existingResourceConfig) {
|
|
|
664
645
|
}
|
|
665
646
|
return undefined;
|
|
666
647
|
}
|
|
667
|
-
async function removeResourceFromDisk(rootPath, resourceRelativeLocation) {
|
|
668
|
-
const resourceLocation =
|
|
648
|
+
export async function removeResourceFromDisk(rootPath, resourceRelativeLocation) {
|
|
649
|
+
const resourceLocation = path.resolve(rootPath, resourceRelativeLocation);
|
|
669
650
|
await fs.remove(resourceLocation);
|
|
670
651
|
}
|
|
671
|
-
|
|
672
|
-
async function getMode(task, mode) {
|
|
652
|
+
export async function getMode(task, mode) {
|
|
673
653
|
if (mode) {
|
|
674
654
|
return modeFlagToViewMode(mode);
|
|
675
655
|
}
|
|
@@ -677,10 +657,10 @@ async function getMode(task, mode) {
|
|
|
677
657
|
{
|
|
678
658
|
type: "Select",
|
|
679
659
|
name: "mode",
|
|
680
|
-
message: `Select which version of a resource you would like to fetch (${
|
|
681
|
-
choices: Object.keys(
|
|
660
|
+
message: `Select which version of a resource you would like to fetch (${SELECT_PROMPT_HELP})`,
|
|
661
|
+
choices: Object.keys(modeFlagValuesMap).map((mode) => ({
|
|
682
662
|
name: mode,
|
|
683
|
-
message:
|
|
663
|
+
message: modeFlagValuesMap[mode],
|
|
684
664
|
})),
|
|
685
665
|
initial: 0,
|
|
686
666
|
multiple: false,
|
|
@@ -688,25 +668,22 @@ async function getMode(task, mode) {
|
|
|
688
668
|
]);
|
|
689
669
|
return modeFlagToViewMode(selectedMode);
|
|
690
670
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (lodash_2.default.isArray(obj)) {
|
|
671
|
+
export function sortByKey(obj) {
|
|
672
|
+
if (isArray(obj)) {
|
|
694
673
|
return obj.map((item) => sortByKey(item));
|
|
695
674
|
}
|
|
696
|
-
if (
|
|
675
|
+
if (isObject(obj)) {
|
|
697
676
|
const sortedKeys = Object.keys(obj).sort();
|
|
698
677
|
const sortedObj = {};
|
|
699
678
|
for (const key of sortedKeys) {
|
|
700
|
-
sortedObj[key] = sortByKey(
|
|
679
|
+
sortedObj[key] = sortByKey(get(obj, key));
|
|
701
680
|
}
|
|
702
681
|
return sortedObj;
|
|
703
682
|
}
|
|
704
683
|
return obj;
|
|
705
684
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
var _a, _b, _c;
|
|
709
|
-
const git = (0, simple_git_1.simpleGit)();
|
|
685
|
+
export async function getLocalGitRepoState(overrideLocalBranch) {
|
|
686
|
+
const git = simpleGit();
|
|
710
687
|
let status;
|
|
711
688
|
try {
|
|
712
689
|
// do not return untracked files which can be slow, we only care about the branch info
|
|
@@ -729,15 +706,18 @@ async function getLocalGitRepoState(overrideLocalBranch) {
|
|
|
729
706
|
}
|
|
730
707
|
localBranchName = status.current;
|
|
731
708
|
}
|
|
732
|
-
const remoteName = (
|
|
709
|
+
const remoteName = (await git.getConfig(`branch.${localBranchName}.remote`))
|
|
710
|
+
?.value;
|
|
733
711
|
if (!remoteName) {
|
|
734
712
|
return { status: "IN_A_BRANCH", localBranchName };
|
|
735
713
|
}
|
|
736
|
-
const remoteFetchUrl = (
|
|
714
|
+
const remoteFetchUrl = (await git.getConfig(`remote.${remoteName}.url`))
|
|
715
|
+
?.value;
|
|
737
716
|
if (!remoteFetchUrl) {
|
|
738
717
|
return { status: "IN_A_BRANCH", localBranchName };
|
|
739
718
|
}
|
|
740
|
-
const remotePushUrl = (
|
|
719
|
+
const remotePushUrl = (await git.getConfig(`remote.${remoteName}.pushurl`))
|
|
720
|
+
?.value;
|
|
741
721
|
let upstreamBranchName = (await git.revparse(["--abbrev-ref", "--symbolic-full-name", "@{u}"])).split("\n", 1)[0];
|
|
742
722
|
if (upstreamBranchName.startsWith(`${remoteName}/`)) {
|
|
743
723
|
// `upstreamBranchName` is in the form `$remoteName/$branchName`, so we need to remove the `$remoteName/` part
|
|
@@ -754,12 +734,11 @@ async function getLocalGitRepoState(overrideLocalBranch) {
|
|
|
754
734
|
},
|
|
755
735
|
};
|
|
756
736
|
}
|
|
757
|
-
exports.getLocalGitRepoState = getLocalGitRepoState;
|
|
758
737
|
/**
|
|
759
738
|
* Returns the current git branch, or undefined if not in a git repo
|
|
760
739
|
*/
|
|
761
|
-
async function getCurrentGitBranchIfGit() {
|
|
762
|
-
const git =
|
|
740
|
+
export async function getCurrentGitBranchIfGit() {
|
|
741
|
+
const git = simpleGit();
|
|
763
742
|
try {
|
|
764
743
|
// do not return untracked files which can be slow, we only care about the branch info
|
|
765
744
|
const status = await git.status(["--untracked-files=no"]);
|
|
@@ -771,20 +750,18 @@ async function getCurrentGitBranchIfGit() {
|
|
|
771
750
|
}
|
|
772
751
|
return null;
|
|
773
752
|
}
|
|
774
|
-
exports.getCurrentGitBranchIfGit = getCurrentGitBranchIfGit;
|
|
775
753
|
/**
|
|
776
754
|
* Returns the current git branch, or throws if not in a git repo
|
|
777
755
|
*/
|
|
778
|
-
async function getCurrentGitBranch() {
|
|
756
|
+
export async function getCurrentGitBranch() {
|
|
779
757
|
const currentBranch = await getCurrentGitBranchIfGit();
|
|
780
758
|
if (!currentBranch) {
|
|
781
759
|
throw new Error("No git repository found");
|
|
782
760
|
}
|
|
783
761
|
return currentBranch;
|
|
784
762
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const git = (0, simple_git_1.simpleGit)();
|
|
763
|
+
export async function getHeadCommit(branch) {
|
|
764
|
+
const git = simpleGit();
|
|
788
765
|
let headCommitId;
|
|
789
766
|
let headCommitMessage;
|
|
790
767
|
const logResponse = await git.show(["--no-patch", "--format=%H%n%s", branch]);
|
|
@@ -798,27 +775,22 @@ async function getHeadCommit(branch) {
|
|
|
798
775
|
}
|
|
799
776
|
return [headCommitId, headCommitMessage];
|
|
800
777
|
}
|
|
801
|
-
|
|
802
|
-
function isCI() {
|
|
778
|
+
export function isCI() {
|
|
803
779
|
return process.env.CI === "true";
|
|
804
780
|
}
|
|
805
|
-
|
|
806
|
-
async function isGitRepoDirty() {
|
|
781
|
+
export async function isGitRepoDirty() {
|
|
807
782
|
if (isCI()) {
|
|
808
783
|
// Skip dirtiness check in CI environments
|
|
809
784
|
return false;
|
|
810
785
|
}
|
|
811
|
-
const git =
|
|
786
|
+
const git = simpleGit();
|
|
812
787
|
const status = await git.status();
|
|
813
788
|
return !status.isClean();
|
|
814
789
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
var _a, _b, _c, _d;
|
|
818
|
-
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";
|
|
790
|
+
export function extractApiName(api) {
|
|
791
|
+
return api.apiPb?.metadata?.name ?? api?.name ?? "Unknown";
|
|
819
792
|
}
|
|
820
|
-
|
|
821
|
-
async function writeAppApi(api, directoryPath, existingFilePaths, apiPromises, apiRepresentation) {
|
|
793
|
+
export async function writeAppApi(api, directoryPath, existingFilePaths, apiPromises, apiRepresentation) {
|
|
822
794
|
const originalApiName = extractApiName(api);
|
|
823
795
|
const additionalStepFiles = [];
|
|
824
796
|
await writeApiFiles(api, slugifyName(originalApiName), `${directoryPath}/apis`, true, apiPromises, additionalStepFiles, apiRepresentation, existingFilePaths);
|
|
@@ -827,7 +799,6 @@ async function writeAppApi(api, directoryPath, existingFilePaths, apiPromises, a
|
|
|
827
799
|
sourceFiles: additionalStepFiles.map((file) => file.relativePath).sort(),
|
|
828
800
|
};
|
|
829
801
|
}
|
|
830
|
-
exports.writeAppApi = writeAppApi;
|
|
831
802
|
async function writeBackendApi(api, directoryPath, apiPromises, apiRepresentation, existingFilePaths) {
|
|
832
803
|
const originalApiName = extractApiName(api);
|
|
833
804
|
const additionalStepFiles = [];
|
|
@@ -839,12 +810,14 @@ async function writeBackendApi(api, directoryPath, apiPromises, apiRepresentatio
|
|
|
839
810
|
}
|
|
840
811
|
async function writeApiFiles(api, apiNameSlug, directoryPath, nestedApiFiles, apiPromises, additionalStepFiles, apiRepresentation, existingFilePaths) {
|
|
841
812
|
let pathForApiFile = directoryPath;
|
|
813
|
+
let yamlFileName = `${apiNameSlug}.yaml`;
|
|
842
814
|
// Determine whether to extract into separate files the source code from the steps
|
|
843
815
|
const updatedApi = extractAdditionalStepFiles(api.apiPb, additionalStepFiles, apiRepresentation);
|
|
844
|
-
if (
|
|
816
|
+
if (apiRepresentation?.extractLargeSourceFiles) {
|
|
845
817
|
if (nestedApiFiles) {
|
|
846
818
|
// This API has at least one large step code file, so we need a nested directory
|
|
847
819
|
pathForApiFile = `${pathForApiFile}/${apiNameSlug}`;
|
|
820
|
+
yamlFileName = "api.yaml";
|
|
848
821
|
}
|
|
849
822
|
// Make sure the directory exists
|
|
850
823
|
await fs.ensureDir(pathForApiFile);
|
|
@@ -856,67 +829,65 @@ async function writeApiFiles(api, apiNameSlug, directoryPath, nestedApiFiles, ap
|
|
|
856
829
|
};
|
|
857
830
|
apiPromises.push(handleApi());
|
|
858
831
|
// Mark the existing source file as being reused
|
|
859
|
-
existingFilePaths
|
|
832
|
+
existingFilePaths?.delete(sourceFilePath);
|
|
860
833
|
}
|
|
861
834
|
}
|
|
862
835
|
else {
|
|
863
836
|
// No additional step files to write, so mark the API directory as existing so that it will be removed later.
|
|
864
837
|
// Do this even if the current representation does not extract large source files, in case they were previously
|
|
865
|
-
existingFilePaths
|
|
838
|
+
existingFilePaths?.add(`${directoryPath}/${apiNameSlug}`);
|
|
866
839
|
}
|
|
867
840
|
// Convert the updated API to YAML and write it to disk
|
|
868
|
-
const apiContent = (
|
|
841
|
+
const apiContent = ymlstringify(updatedApi, {
|
|
869
842
|
sortMapEntries: true,
|
|
870
843
|
blockQuote: "literal",
|
|
871
844
|
});
|
|
872
|
-
const yamlFilePath = `${pathForApiFile}/${
|
|
845
|
+
const yamlFilePath = `${pathForApiFile}/${yamlFileName}`;
|
|
873
846
|
const handleApi = async () => {
|
|
874
847
|
await fs.outputFile(yamlFilePath, apiContent);
|
|
875
848
|
};
|
|
876
849
|
apiPromises.push(handleApi());
|
|
877
850
|
// Mark the existing source file as being reused
|
|
878
|
-
existingFilePaths
|
|
851
|
+
existingFilePaths?.delete(yamlFilePath);
|
|
879
852
|
}
|
|
880
853
|
function extractAdditionalStepFiles(api, additionalStepFiles, apiRepresentation) {
|
|
881
|
-
|
|
882
|
-
if (!api.blocks || !(apiRepresentation === null || apiRepresentation === void 0 ? void 0 : apiRepresentation.extractLargeSourceFiles)) {
|
|
854
|
+
if (!api.blocks || !apiRepresentation?.extractLargeSourceFiles) {
|
|
883
855
|
return api;
|
|
884
856
|
}
|
|
885
|
-
const apiClone =
|
|
886
|
-
const minLinesForExtraction =
|
|
857
|
+
const apiClone = cloneDeep(api);
|
|
858
|
+
const minLinesForExtraction = apiRepresentation?.minLinesForExtraction ?? DEFAULT_LINES_FOR_LARGE_STEPS;
|
|
887
859
|
const existingFilePaths = new Set();
|
|
888
|
-
extractAdditionalStepFilesFromBlocks(
|
|
860
|
+
extractAdditionalStepFilesFromBlocks(apiClone.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
889
861
|
return apiClone;
|
|
890
862
|
}
|
|
891
863
|
function extractAdditionalStepFilesFromBlocks(blocks, additionalStepFiles, existingFilePaths, minLinesForExtraction) {
|
|
892
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
893
864
|
for (const block of blocks) {
|
|
894
865
|
// Handle language step files
|
|
895
866
|
if (block.step) {
|
|
896
867
|
extractAdditionalStepFilesFromStep(block.step, block.name, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
897
868
|
}
|
|
898
869
|
// Handle loops
|
|
899
|
-
extractAdditionalStepFilesFromBlocks(
|
|
870
|
+
extractAdditionalStepFilesFromBlocks(block.loop?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
900
871
|
// Handle try/catch
|
|
901
872
|
if (block.tryCatch) {
|
|
902
|
-
extractAdditionalStepFilesFromBlocks(
|
|
903
|
-
extractAdditionalStepFilesFromBlocks(
|
|
904
|
-
extractAdditionalStepFilesFromBlocks(
|
|
873
|
+
extractAdditionalStepFilesFromBlocks(block.tryCatch.try?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
874
|
+
extractAdditionalStepFilesFromBlocks(block.tryCatch.catch?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
875
|
+
extractAdditionalStepFilesFromBlocks(block.tryCatch.finally?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
905
876
|
}
|
|
906
877
|
// Handle conditional
|
|
907
878
|
if (block.conditional) {
|
|
908
|
-
extractAdditionalStepFilesFromBlocks(
|
|
909
|
-
for (const elseIfBlock of
|
|
879
|
+
extractAdditionalStepFilesFromBlocks(block.conditional.if?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
880
|
+
for (const elseIfBlock of block.conditional.elseIf ?? []) {
|
|
910
881
|
extractAdditionalStepFilesFromBlocks(elseIfBlock.blocks, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
911
882
|
}
|
|
912
|
-
extractAdditionalStepFilesFromBlocks(
|
|
883
|
+
extractAdditionalStepFilesFromBlocks(block.conditional.else?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
913
884
|
}
|
|
914
885
|
// Handle Parallel API
|
|
915
886
|
if (block.parallel) {
|
|
916
|
-
for (const path of Object.values(
|
|
887
|
+
for (const path of Object.values(block.parallel?.static?.paths ?? {})) {
|
|
917
888
|
extractAdditionalStepFilesFromBlocks(path.blocks, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
918
889
|
}
|
|
919
|
-
extractAdditionalStepFilesFromBlocks(
|
|
890
|
+
extractAdditionalStepFilesFromBlocks(block.parallel?.dynamic?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
920
891
|
}
|
|
921
892
|
// Handle stream
|
|
922
893
|
if (block.stream) {
|
|
@@ -924,7 +895,7 @@ function extractAdditionalStepFilesFromBlocks(blocks, additionalStepFiles, exist
|
|
|
924
895
|
if (trigger && trigger.step) {
|
|
925
896
|
extractAdditionalStepFilesFromStep(trigger.step, trigger.name, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
926
897
|
}
|
|
927
|
-
extractAdditionalStepFilesFromBlocks(
|
|
898
|
+
extractAdditionalStepFilesFromBlocks(block.stream.process?.blocks ?? [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
928
899
|
}
|
|
929
900
|
}
|
|
930
901
|
}
|
|
@@ -938,8 +909,8 @@ function extractAdditionalStepFilesFromStep(step, name, additionalStepFiles, exi
|
|
|
938
909
|
if (languageContent) {
|
|
939
910
|
const blockBody = languageContent.body;
|
|
940
911
|
if (blockBody && typeof blockBody === "string") {
|
|
941
|
-
const lines = blockBody
|
|
942
|
-
const linesNum = lines
|
|
912
|
+
const lines = blockBody?.split("\n");
|
|
913
|
+
const linesNum = lines?.length;
|
|
943
914
|
if (linesNum && linesNum > minLinesForExtraction) {
|
|
944
915
|
// Record the separate file is needed, with the language contents
|
|
945
916
|
const relativePath = findUnusedFilePath(slugifyName(name), extension, existingFilePaths);
|
|
@@ -969,19 +940,18 @@ function findUnusedFilePath(filename, extension, existingFilePaths) {
|
|
|
969
940
|
return proposedFilename;
|
|
970
941
|
}
|
|
971
942
|
async function validateMultiPageApplication(applicationConfig, superblocksRootPath, location) {
|
|
972
|
-
var _a;
|
|
973
943
|
// validate app level APIs
|
|
974
944
|
const apiNames = getApiNamesFromApplicationConfig(applicationConfig);
|
|
975
945
|
for (const apiName of apiNames) {
|
|
976
|
-
const apiPath =
|
|
946
|
+
const apiPath = path.resolve(superblocksRootPath, location, "apis", `${slugifyName(apiName)}.yaml`);
|
|
977
947
|
const validateApiError = await validateYamlFile(apiPath);
|
|
978
948
|
if (validateApiError) {
|
|
979
949
|
return validateApiError;
|
|
980
950
|
}
|
|
981
951
|
}
|
|
982
952
|
// validate pages
|
|
983
|
-
for (const page of Object.values(
|
|
984
|
-
const pagePath =
|
|
953
|
+
for (const page of Object.values(applicationConfig.pages ?? {})) {
|
|
954
|
+
const pagePath = path.resolve(superblocksRootPath, location, "pages", slugifyName(page.name), "page.yaml");
|
|
985
955
|
const validatePageError = await validateYamlFile(pagePath);
|
|
986
956
|
if (validatePageError) {
|
|
987
957
|
return validatePageError;
|
|
@@ -989,9 +959,9 @@ async function validateMultiPageApplication(applicationConfig, superblocksRootPa
|
|
|
989
959
|
// validate page level APIs
|
|
990
960
|
const pageApiNames = getApiNamesFromPageConfig(page);
|
|
991
961
|
for (const apiName of pageApiNames) {
|
|
992
|
-
const apisPath =
|
|
962
|
+
const apisPath = path.resolve(superblocksRootPath, location, "pages", slugifyName(page.name), "apis");
|
|
993
963
|
// Try the API path not in a nested directory
|
|
994
|
-
const apiPath =
|
|
964
|
+
const apiPath = path.resolve(apisPath, `${slugifyName(apiName)}.yaml`);
|
|
995
965
|
if (fs.pathExistsSync(apiPath)) {
|
|
996
966
|
const validateApiError = await validateYamlFile(apiPath);
|
|
997
967
|
if (validateApiError) {
|
|
@@ -1000,7 +970,7 @@ async function validateMultiPageApplication(applicationConfig, superblocksRootPa
|
|
|
1000
970
|
}
|
|
1001
971
|
else {
|
|
1002
972
|
// Try the API path in a nested directory
|
|
1003
|
-
const nestedApiPath =
|
|
973
|
+
const nestedApiPath = path.resolve(apisPath, slugifyName(apiName), "api.yaml");
|
|
1004
974
|
if (fs.pathExistsSync(nestedApiPath)) {
|
|
1005
975
|
const validateApiError = await validateYamlFile(nestedApiPath);
|
|
1006
976
|
if (validateApiError) {
|
|
@@ -1012,11 +982,11 @@ async function validateMultiPageApplication(applicationConfig, superblocksRootPa
|
|
|
1012
982
|
}
|
|
1013
983
|
return undefined;
|
|
1014
984
|
}
|
|
1015
|
-
async function validateLocalResource(superblocksRootPath, resource) {
|
|
985
|
+
export async function validateLocalResource(superblocksRootPath, resource) {
|
|
1016
986
|
switch (resource.resourceType) {
|
|
1017
987
|
case "APPLICATION": {
|
|
1018
988
|
// make sure application config exists
|
|
1019
|
-
const applicationConfigPath =
|
|
989
|
+
const applicationConfigPath = path.resolve(superblocksRootPath, resource.location, RESOURCE_CONFIG_PATH);
|
|
1020
990
|
if (!(await fs.pathExists(applicationConfigPath))) {
|
|
1021
991
|
return `File ${relativeToCurrentDir(applicationConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
|
|
1022
992
|
}
|
|
@@ -1031,7 +1001,7 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
1031
1001
|
catch {
|
|
1032
1002
|
return `File ${relativeToCurrentDir(applicationConfigPath)} is not a valid JSON file. Please be sure it's valid JSON and rerun the command.`;
|
|
1033
1003
|
}
|
|
1034
|
-
const applicationYamlPath =
|
|
1004
|
+
const applicationYamlPath = path.resolve(superblocksRootPath, resource.location, "application.yaml");
|
|
1035
1005
|
// make sure application.yaml is a well-formed yaml file
|
|
1036
1006
|
try {
|
|
1037
1007
|
await readYamlFile(applicationYamlPath);
|
|
@@ -1047,7 +1017,7 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
1047
1017
|
}
|
|
1048
1018
|
case "BACKEND": {
|
|
1049
1019
|
// make sure the backend config exists
|
|
1050
|
-
const backendConfigPath =
|
|
1020
|
+
const backendConfigPath = path.resolve(superblocksRootPath, resource.location, RESOURCE_CONFIG_PATH);
|
|
1051
1021
|
if (!(await fs.pathExists(backendConfigPath))) {
|
|
1052
1022
|
return `File ${relativeToCurrentDir(backendConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
|
|
1053
1023
|
}
|
|
@@ -1059,7 +1029,7 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
1059
1029
|
return `File ${relativeToCurrentDir(backendConfigPath)} is not a valid JSON file. Please be sure it's valid JSON and rerun the command.`;
|
|
1060
1030
|
}
|
|
1061
1031
|
// make sure that api.yaml exists
|
|
1062
|
-
const apiYamlPath =
|
|
1032
|
+
const apiYamlPath = path.resolve(superblocksRootPath, resource.location, "api.yaml");
|
|
1063
1033
|
const validateYamlFileError = await validateYamlFile(apiYamlPath);
|
|
1064
1034
|
if (validateYamlFileError) {
|
|
1065
1035
|
return validateYamlFileError;
|
|
@@ -1069,10 +1039,9 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
1069
1039
|
}
|
|
1070
1040
|
return undefined;
|
|
1071
1041
|
}
|
|
1072
|
-
|
|
1073
|
-
async function deleteResourcesAndUpdateRootConfig(removedResourceIds, existingSuperblocksRootConfig, superblocksRootPath, superblocksRootConfigPath) {
|
|
1042
|
+
export async function deleteResourcesAndUpdateRootConfig(removedResourceIds, existingSuperblocksRootConfig, superblocksRootPath, superblocksRootConfigPath) {
|
|
1074
1043
|
for (const resourceId of removedResourceIds) {
|
|
1075
|
-
const resource = existingSuperblocksRootConfig
|
|
1044
|
+
const resource = existingSuperblocksRootConfig?.resources[resourceId];
|
|
1076
1045
|
await removeResourceFromDisk(superblocksRootPath, resource.location);
|
|
1077
1046
|
}
|
|
1078
1047
|
for (const removedResourceId of removedResourceIds) {
|
|
@@ -1081,7 +1050,6 @@ async function deleteResourcesAndUpdateRootConfig(removedResourceIds, existingSu
|
|
|
1081
1050
|
// update superblocks.json file with removed resources
|
|
1082
1051
|
await fs.writeFile(superblocksRootConfigPath, JSON.stringify(sortByKey(existingSuperblocksRootConfig), null, 2));
|
|
1083
1052
|
}
|
|
1084
|
-
exports.deleteResourcesAndUpdateRootConfig = deleteResourcesAndUpdateRootConfig;
|
|
1085
1053
|
async function validateYamlFile(yamlPath) {
|
|
1086
1054
|
// make sure a yaml file is well-formed
|
|
1087
1055
|
try {
|
|
@@ -1092,5 +1060,5 @@ async function validateYamlFile(yamlPath) {
|
|
|
1092
1060
|
}
|
|
1093
1061
|
}
|
|
1094
1062
|
function relativeToCurrentDir(applicationConfigPath) {
|
|
1095
|
-
return `./${
|
|
1063
|
+
return `./${path.relative(process.cwd(), applicationConfigPath)}`;
|
|
1096
1064
|
}
|