@superblocksteam/cli 1.9.2 → 1.10.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/README.md +1 -1
- package/assets/custom-components/setup/package.json +1 -1
- package/assets/injectedReactShim17.jsx +15 -0
- package/assets/injectedReactShim18.jsx +16 -0
- package/assets/injectedReactShimShared.jsx +140 -0
- package/dist/appendHotReloadEventPlugin.d.ts +2 -0
- package/dist/appendHotReloadEventPlugin.js +48 -0
- package/dist/commands/components/upload.js +4 -4
- package/dist/commands/components/watch.js +4 -4
- package/dist/commands/init.js +7 -3
- package/dist/commands/migrate.js +5 -5
- package/dist/commands/pull.js +4 -2
- package/dist/common/version-control.d.ts +13 -6
- package/dist/common/version-control.js +500 -120
- package/dist/productionCssPlugin.d.ts +2 -0
- package/dist/productionCssPlugin.js +56 -0
- package/dist/reactShimPlugin.d.ts +2 -0
- package/dist/reactShimPlugin.js +134 -0
- package/oclif.manifest.json +1 -1
- package/package.json +5 -7
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
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;
|
|
3
|
+
exports.deleteResourcesAndUpdateRootConfig = exports.validateLocalResource = exports.writeAppApi = exports.extractApiName = exports.isGitRepoDirty = exports.isCI = exports.getHeadCommit = exports.getCurrentGitBranch = exports.getCurrentGitBranchIfGit = exports.getLocalGitRepoState = exports.sortByKey = exports.getMode = exports.removeResourceFromDisk = exports.addExistingFilePathsForApi = exports.writeMultiPageApplicationToDisk = exports.writeResourceToDisk = exports.readApiFromDisk = exports.readMultiPageApplicationFromDisk = exports.readApplicationFromDisk = exports.getFileStructureType = exports.readAppApiYamlFile = exports.getApiRepresentation = 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
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const https = tslib_1.__importStar(require("https"));
|
|
6
6
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
7
|
const path_1 = require("path");
|
|
8
|
+
const sdk_1 = require("@superblocksteam/sdk");
|
|
8
9
|
const util_1 = require("@superblocksteam/util");
|
|
9
|
-
const util_2 = require("@superblocksteam/util");
|
|
10
10
|
const colorette_1 = require("colorette");
|
|
11
11
|
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
12
12
|
const lodash_1 = require("lodash");
|
|
13
13
|
const lodash_2 = tslib_1.__importDefault(require("lodash"));
|
|
14
|
+
const semver = tslib_1.__importStar(require("semver"));
|
|
14
15
|
const simple_git_1 = require("simple-git");
|
|
15
16
|
const slugify_1 = tslib_1.__importDefault(require("slugify"));
|
|
16
17
|
const yaml_1 = require("yaml");
|
|
@@ -18,6 +19,10 @@ exports.LATEST_EDITS_MODE = "latest-edits";
|
|
|
18
19
|
exports.MOST_RECENT_COMMIT_MODE = "most-recent-commit";
|
|
19
20
|
exports.DEPLOYED_MODE = "deployed";
|
|
20
21
|
exports.DEFAULT_BRANCH = "main";
|
|
22
|
+
const LANGUAGE_STEP_EXTENSIONS = {
|
|
23
|
+
javascript: "js",
|
|
24
|
+
python: "py",
|
|
25
|
+
};
|
|
21
26
|
exports.modeFlagValuesMap = {
|
|
22
27
|
[exports.LATEST_EDITS_MODE]: "Latest edits",
|
|
23
28
|
[exports.MOST_RECENT_COMMIT_MODE]: "Most recent commit",
|
|
@@ -50,6 +55,34 @@ const atLeastOneSelection = (value) => {
|
|
|
50
55
|
return true;
|
|
51
56
|
};
|
|
52
57
|
exports.atLeastOneSelection = atLeastOneSelection;
|
|
58
|
+
const DEFAULT_FILE_VERSION = "0.1.0";
|
|
59
|
+
const SPLIT_LARGE_API_STEPS_VERSION = "0.2.0";
|
|
60
|
+
const LATEST_FILE_VERSION = SPLIT_LARGE_API_STEPS_VERSION;
|
|
61
|
+
function getApiRepresentation(featureFlags, resourceConfig) {
|
|
62
|
+
var _a;
|
|
63
|
+
const linesForLargeSteps = (_a = featureFlags.linesForLargeSteps()) !== null && _a !== void 0 ? _a : sdk_1.DEFAULT_LINES_FOR_LARGE_STEPS;
|
|
64
|
+
if (featureFlags.splitLargeApiStepsEnabled() &&
|
|
65
|
+
isPostSplitLargeApiSteps(resourceConfig)) {
|
|
66
|
+
return {
|
|
67
|
+
extractLargeSourceFiles: true,
|
|
68
|
+
minLinesForExtraction: linesForLargeSteps,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Return the default
|
|
72
|
+
return {
|
|
73
|
+
extractLargeSourceFiles: false,
|
|
74
|
+
minLinesForExtraction: linesForLargeSteps,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
exports.getApiRepresentation = getApiRepresentation;
|
|
78
|
+
function isPostSplitLargeApiSteps(resourceConfig) {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
if (!resourceConfig) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const version = (_b = (_a = resourceConfig.metadata) === null || _a === void 0 ? void 0 : _a.fileVersion) !== null && _b !== void 0 ? _b : DEFAULT_FILE_VERSION;
|
|
84
|
+
return semver.compare(version, SPLIT_LARGE_API_STEPS_VERSION) >= 0;
|
|
85
|
+
}
|
|
53
86
|
function slugifyName(originalName) {
|
|
54
87
|
return (0, slugify_1.default)(originalName, {
|
|
55
88
|
replacement: "_",
|
|
@@ -95,6 +128,95 @@ async function downloadFile(rootDirectory, filepath, url) {
|
|
|
95
128
|
}
|
|
96
129
|
return Promise.resolve("");
|
|
97
130
|
}
|
|
131
|
+
async function readAppApiYamlFile(parentDirectory, apiName) {
|
|
132
|
+
var _a;
|
|
133
|
+
// The API is either stored in its entirety in a single YAML file, or
|
|
134
|
+
// or in a subdirectory containing the YAML file and zero or more language-specific files.
|
|
135
|
+
const apiNameSlug = slugifyName(apiName !== null && apiName !== void 0 ? apiName : "api");
|
|
136
|
+
const singularApiYamlPath = `${parentDirectory}/${apiNameSlug}.yaml`;
|
|
137
|
+
const apiDirPath = `${parentDirectory}/${apiNameSlug}`;
|
|
138
|
+
const nestedApiYamlPath = `${apiDirPath}/${apiNameSlug}.yaml`;
|
|
139
|
+
// Read the YAML file
|
|
140
|
+
let yamlPath;
|
|
141
|
+
let yamlParentPath;
|
|
142
|
+
if (await fs.pathExists(singularApiYamlPath)) {
|
|
143
|
+
// The API YAML file is in the parent directory
|
|
144
|
+
yamlPath = singularApiYamlPath;
|
|
145
|
+
yamlParentPath = parentDirectory;
|
|
146
|
+
}
|
|
147
|
+
else if (await fs.pathExists(nestedApiYamlPath)) {
|
|
148
|
+
// The API YAML file is nested in an API-specific directory
|
|
149
|
+
yamlPath = nestedApiYamlPath;
|
|
150
|
+
yamlParentPath = apiDirPath;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
throw new Error(`API ${apiName !== null && apiName !== void 0 ? apiName : ""} not found at ${parentDirectory}`);
|
|
154
|
+
}
|
|
155
|
+
// That is nested in an API-specific directory
|
|
156
|
+
const apiDefn = (await readYamlFile(yamlPath));
|
|
157
|
+
// The API YAML file may or may not have language-specific content in separate files.
|
|
158
|
+
// Replace any file references with the actual content
|
|
159
|
+
await resolveLanguageSpecificStepContentFromBlocks(yamlParentPath, (_a = apiDefn.blocks) !== null && _a !== void 0 ? _a : []);
|
|
160
|
+
return apiDefn;
|
|
161
|
+
}
|
|
162
|
+
exports.readAppApiYamlFile = readAppApiYamlFile;
|
|
163
|
+
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
|
+
for (const block of blocks) {
|
|
166
|
+
// Handle language-specific step content
|
|
167
|
+
if (block.step) {
|
|
168
|
+
const step = block.step;
|
|
169
|
+
await resolveLanguageSpecificStepContentFromStep(parentPath, step);
|
|
170
|
+
}
|
|
171
|
+
// Handle conditional blocks
|
|
172
|
+
if (block.conditional) {
|
|
173
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_b = (_a = block.conditional.if) === null || _a === void 0 ? void 0 : _a.blocks) !== null && _b !== void 0 ? _b : []);
|
|
174
|
+
for (const elseIfBlock of block.conditional.elseIf) {
|
|
175
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, elseIfBlock.blocks);
|
|
176
|
+
}
|
|
177
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_d = (_c = block.conditional.else) === null || _c === void 0 ? void 0 : _c.blocks) !== null && _d !== void 0 ? _d : []);
|
|
178
|
+
}
|
|
179
|
+
// Handle loop blocks
|
|
180
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_f = (_e = block.loop) === null || _e === void 0 ? void 0 : _e.blocks) !== null && _f !== void 0 ? _f : []);
|
|
181
|
+
// Handle try-catch blocks
|
|
182
|
+
if (block.tryCatch) {
|
|
183
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_h = (_g = block.tryCatch.try) === null || _g === void 0 ? void 0 : _g.blocks) !== null && _h !== void 0 ? _h : []);
|
|
184
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_k = (_j = block.tryCatch.catch) === null || _j === void 0 ? void 0 : _j.blocks) !== null && _k !== void 0 ? _k : []);
|
|
185
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_m = (_l = block.tryCatch.finally) === null || _l === void 0 ? void 0 : _l.blocks) !== null && _m !== void 0 ? _m : []);
|
|
186
|
+
}
|
|
187
|
+
// Handle parallel blocks
|
|
188
|
+
if (block.parallel) {
|
|
189
|
+
for (const path of Object.values((_q = (_p = (_o = block.parallel) === null || _o === void 0 ? void 0 : _o.static) === null || _p === void 0 ? void 0 : _p.paths) !== null && _q !== void 0 ? _q : {})) {
|
|
190
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, path.blocks);
|
|
191
|
+
}
|
|
192
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_t = (_s = (_r = block.parallel) === null || _r === void 0 ? void 0 : _r.dynamic) === null || _s === void 0 ? void 0 : _s.blocks) !== null && _t !== void 0 ? _t : []);
|
|
193
|
+
}
|
|
194
|
+
// Handle stream blocks
|
|
195
|
+
if (block.stream) {
|
|
196
|
+
await resolveLanguageSpecificStepContentFromBlocks(parentPath, (_v = (_u = block.stream.process) === null || _u === void 0 ? void 0 : _u.blocks) !== null && _v !== void 0 ? _v : []);
|
|
197
|
+
await resolveLanguageSpecificStepContentFromStep(parentPath, (_x = (_w = block.stream.trigger) === null || _w === void 0 ? void 0 : _w.step) !== null && _x !== void 0 ? _x : {});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function resolveLanguageSpecificStepContentFromStep(parentPath, step) {
|
|
202
|
+
// Handle language-specific step content
|
|
203
|
+
if (!(step === null || step === void 0 ? void 0 : step.integration) || !LANGUAGE_STEP_EXTENSIONS[step.integration]) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const languageContent = step[step.integration];
|
|
207
|
+
if (languageContent.body &&
|
|
208
|
+
typeof languageContent.body === "object" &&
|
|
209
|
+
"path" in languageContent.body) {
|
|
210
|
+
const languageFilePath = `${parentPath}/${languageContent.body.path}`;
|
|
211
|
+
if (await fs.pathExists(languageFilePath)) {
|
|
212
|
+
// Read the file content
|
|
213
|
+
const stepBodyContent = await fs.readFile(languageFilePath, "utf8");
|
|
214
|
+
if (stepBodyContent && languageContent) {
|
|
215
|
+
languageContent.body = stepBodyContent;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
98
220
|
async function readYamlFile(path) {
|
|
99
221
|
return (0, yaml_1.parse)(await fs.readFile(path, "utf8"));
|
|
100
222
|
}
|
|
@@ -120,7 +242,7 @@ async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
|
|
|
120
242
|
if (await fs.pathExists(apisDirName)) {
|
|
121
243
|
const apiFiles = await fs.readdir(apisDirName);
|
|
122
244
|
for (const apiFile of apiFiles) {
|
|
123
|
-
const apiContent = await
|
|
245
|
+
const apiContent = await readAppApiYamlFile(apisDirName, apiFile);
|
|
124
246
|
// This mimics the shape of the ApiV3Dto object
|
|
125
247
|
apis.push({
|
|
126
248
|
id: apiContent.metadata.id,
|
|
@@ -145,12 +267,16 @@ async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocati
|
|
|
145
267
|
const pages = [];
|
|
146
268
|
if (await fs.pathExists(pagesDirName)) {
|
|
147
269
|
for (const page of Object.values((_a = superblocksApplicationConfig.pages) !== null && _a !== void 0 ? _a : {})) {
|
|
270
|
+
// Read in the page definition
|
|
148
271
|
const pageContent = await readYamlFile(`${pagesDirName}/${slugifyName(page.name)}/page.yaml`);
|
|
272
|
+
// Read in the API definitions for this page
|
|
149
273
|
const pageApisDirName = `${pagesDirName}/${slugifyName(page.name)}/apis`;
|
|
150
274
|
const apis = [];
|
|
151
275
|
if (await fs.pathExists(pageApisDirName)) {
|
|
152
|
-
|
|
153
|
-
|
|
276
|
+
// Get the API names from pageApis if it exists, or from apis if it doesn't
|
|
277
|
+
const pageApiNames = getApiNamesFromPageConfig(page);
|
|
278
|
+
for (const apiName of pageApiNames) {
|
|
279
|
+
const apiContent = await readAppApiYamlFile(pageApisDirName, apiName);
|
|
154
280
|
// This mimics the shape of the ApiV3Dto object
|
|
155
281
|
apis.push({
|
|
156
282
|
id: apiContent.metadata.id,
|
|
@@ -172,8 +298,11 @@ async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocati
|
|
|
172
298
|
const appApisDirName = `${rootPath}/${existingRelativeLocation}/apis`;
|
|
173
299
|
const apis = [];
|
|
174
300
|
if (await fs.pathExists(appApisDirName)) {
|
|
175
|
-
|
|
176
|
-
|
|
301
|
+
// Get the API names from appApis if it exists, or from apis if it doesn't
|
|
302
|
+
const appConfig = superblocksApplicationConfig;
|
|
303
|
+
const apiNames = getApiNamesFromApplicationConfig(appConfig);
|
|
304
|
+
for (const apiName of apiNames) {
|
|
305
|
+
const apiContent = await readAppApiYamlFile(appApisDirName, apiName);
|
|
177
306
|
// This mimics the shape of the ApiV3Dto object
|
|
178
307
|
apis.push({
|
|
179
308
|
id: apiContent.metadata.id,
|
|
@@ -188,15 +317,29 @@ async function readMultiPageApplicationFromDisk(rootPath, existingRelativeLocati
|
|
|
188
317
|
};
|
|
189
318
|
}
|
|
190
319
|
exports.readMultiPageApplicationFromDisk = readMultiPageApplicationFromDisk;
|
|
320
|
+
function getApiNamesFromApplicationConfig(applicationConfig) {
|
|
321
|
+
var _a;
|
|
322
|
+
return applicationConfig.appApis
|
|
323
|
+
? Object.values(applicationConfig.appApis).map((api) => api.name)
|
|
324
|
+
: Object.values((_a = applicationConfig.apis) !== null && _a !== void 0 ? _a : {});
|
|
325
|
+
}
|
|
326
|
+
function getApiNamesFromPageConfig(pageConfig) {
|
|
327
|
+
var _a;
|
|
328
|
+
return pageConfig.pageApis
|
|
329
|
+
? Object.values(pageConfig.pageApis).map((api) => api.name)
|
|
330
|
+
: Object.values((_a = pageConfig.apis) !== null && _a !== void 0 ? _a : {});
|
|
331
|
+
}
|
|
191
332
|
async function readApiFromDisk(rootPath, existingRelativeLocation) {
|
|
333
|
+
const path = `${rootPath}/${existingRelativeLocation}`;
|
|
334
|
+
const apiContent = await readAppApiYamlFile(path);
|
|
192
335
|
return {
|
|
193
|
-
apiPb:
|
|
336
|
+
apiPb: apiContent,
|
|
194
337
|
};
|
|
195
338
|
}
|
|
196
339
|
exports.readApiFromDisk = readApiFromDisk;
|
|
197
340
|
// NOTE: If a change is made to how applications are written to disk, please update
|
|
198
341
|
// logic to read applications from disk in the "readApplicationFromDisk" function accordingly.
|
|
199
|
-
async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, existingRelativeLocation) {
|
|
342
|
+
async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, featureFlags, existingRelativeLocation, preferredApiRepresentation) {
|
|
200
343
|
var _a, _b, _c;
|
|
201
344
|
switch (resourceType) {
|
|
202
345
|
case "APPLICATION": {
|
|
@@ -221,43 +364,39 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
221
364
|
const apiPromises = [];
|
|
222
365
|
const apisDirName = `${appDirName}/apis`;
|
|
223
366
|
await fs.ensureDir(apisDirName);
|
|
367
|
+
const existingApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigIfExists)(appDirName);
|
|
368
|
+
const existingFilePaths = getExistingFilePathsForApplicationApi(existingApplicationConfig, appDirName);
|
|
224
369
|
const newApplicationConfig = {
|
|
225
370
|
configType: "APPLICATION",
|
|
226
|
-
apis: {},
|
|
227
371
|
defaultPageId: (_a = resource.page) === null || _a === void 0 ? void 0 : _a.id,
|
|
228
372
|
id: resource.application.id,
|
|
373
|
+
metadata: getResourceConfigMetadata(featureFlags, existingApplicationConfig),
|
|
229
374
|
};
|
|
375
|
+
const apiRepresentation = preferredApiRepresentation !== null && preferredApiRepresentation !== void 0 ? preferredApiRepresentation : getApiRepresentation(featureFlags, newApplicationConfig);
|
|
230
376
|
if (resource.apis) {
|
|
231
377
|
for (const api of resource.apis) {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
378
|
+
const apiInfo = await writeAppApi(api, appDirName, existingFilePaths, apiPromises, apiRepresentation);
|
|
379
|
+
if (apiRepresentation.extractLargeSourceFiles) {
|
|
380
|
+
if (!newApplicationConfig.appApis) {
|
|
381
|
+
newApplicationConfig.appApis = {};
|
|
382
|
+
}
|
|
383
|
+
newApplicationConfig.appApis[api.apiPb.metadata.id] = apiInfo;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
if (!newApplicationConfig.apis) {
|
|
387
|
+
newApplicationConfig.apis = {};
|
|
388
|
+
}
|
|
389
|
+
newApplicationConfig.apis[api.apiPb.metadata.id] = apiInfo.name;
|
|
390
|
+
}
|
|
243
391
|
}
|
|
244
392
|
await Promise.all(apiPromises);
|
|
245
393
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
}
|
|
394
|
+
// Delete any existing files that were not overwritten
|
|
395
|
+
for (const filePath of existingFilePaths) {
|
|
396
|
+
await fs.remove(filePath);
|
|
258
397
|
}
|
|
259
|
-
await fs.ensureDir(`${appDirName}/${
|
|
260
|
-
await fs.writeFile(`${appDirName}/${
|
|
398
|
+
await fs.ensureDir(`${appDirName}/${util_1.SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
399
|
+
await fs.writeFile(`${appDirName}/${util_1.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
|
|
261
400
|
const createdFiles = await Promise.resolve(
|
|
262
401
|
// Defensive check for when application settings are missing componentFiles
|
|
263
402
|
(_c = (_b = resource.componentFiles) === null || _b === void 0 ? void 0 : _b.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _c !== void 0 ? _c : []);
|
|
@@ -281,17 +420,26 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
281
420
|
if (!(await fs.pathExists(backendDirName))) {
|
|
282
421
|
await fs.mkdir(backendDirName, { recursive: true });
|
|
283
422
|
}
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
blockQuote: "literal",
|
|
287
|
-
});
|
|
288
|
-
await fs.outputFile(`${backendDirName}/api.yaml`, backendContent);
|
|
423
|
+
const existingBackendConfig = await (0, util_1.getSuperblocksBackendConfigIfExists)(backendDirName);
|
|
424
|
+
const existingFilePaths = getExistingFilePathsForBackendApi(existingBackendConfig, backendDirName);
|
|
289
425
|
const backendConfig = {
|
|
290
426
|
id: resourceId,
|
|
291
427
|
configType: "BACKEND",
|
|
428
|
+
metadata: getResourceConfigMetadata(featureFlags, existingBackendConfig),
|
|
292
429
|
};
|
|
293
|
-
|
|
294
|
-
|
|
430
|
+
const apiRepresentation = preferredApiRepresentation !== null && preferredApiRepresentation !== void 0 ? preferredApiRepresentation : getApiRepresentation(featureFlags, backendConfig);
|
|
431
|
+
// Write the API file(s)
|
|
432
|
+
const apiInfo = await writeBackendApi(resource, backendDirName, [], apiRepresentation, existingFilePaths);
|
|
433
|
+
if (apiRepresentation.extractLargeSourceFiles) {
|
|
434
|
+
backendConfig.sourceFiles = apiInfo.sourceFiles;
|
|
435
|
+
}
|
|
436
|
+
// Write the backend config file
|
|
437
|
+
await fs.ensureDir(`${backendDirName}/${util_1.SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
438
|
+
await fs.writeFile(`${backendDirName}/${util_1.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(backendConfig), null, 2));
|
|
439
|
+
// Delete any existing files that were not overwritten
|
|
440
|
+
for (const filePath of existingFilePaths) {
|
|
441
|
+
await fs.remove(filePath);
|
|
442
|
+
}
|
|
295
443
|
return {
|
|
296
444
|
location: relativeLocation,
|
|
297
445
|
resourceType: "BACKEND",
|
|
@@ -305,8 +453,8 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
|
|
|
305
453
|
exports.writeResourceToDisk = writeResourceToDisk;
|
|
306
454
|
// NOTE: If a change is made to how applications are written to disk, please update
|
|
307
455
|
// logic to read applications from disk in the "readMultiPageApplicationFromDisk" function accordingly.
|
|
308
|
-
async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelativeLocation, migrateFromSinglePage) {
|
|
309
|
-
var _a, _b, _c
|
|
456
|
+
async function writeMultiPageApplicationToDisk(resource, rootPath, featureFlags, existingRelativeLocation, migrateFromSinglePage, preferredApiRepresentation) {
|
|
457
|
+
var _a, _b, _c;
|
|
310
458
|
const parentDirName = "apps";
|
|
311
459
|
const newRelativeLocation = `${parentDirName}/${slugifyName(resource.application.name)}`;
|
|
312
460
|
const relativeLocation = existingRelativeLocation !== null && existingRelativeLocation !== void 0 ? existingRelativeLocation : newRelativeLocation;
|
|
@@ -318,11 +466,15 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelat
|
|
|
318
466
|
sortMapEntries: true,
|
|
319
467
|
});
|
|
320
468
|
await fs.outputFile(`${appDirName}/application.yaml`, applicationContent);
|
|
469
|
+
// Find the existing application config and existing file paths
|
|
470
|
+
const existingApplicationConfig = await (0, util_1.getSuperblocksApplicationConfigIfExists)(appDirName);
|
|
471
|
+
const existingFilePaths = getExistingFilePathsForApplicationApi(existingApplicationConfig, appDirName);
|
|
321
472
|
const newApplicationConfig = {
|
|
322
473
|
configType: "APPLICATION",
|
|
323
|
-
apis: {},
|
|
324
474
|
id: resource.application.id,
|
|
475
|
+
metadata: getResourceConfigMetadata(featureFlags, existingApplicationConfig),
|
|
325
476
|
};
|
|
477
|
+
const apiRepresentation = preferredApiRepresentation !== null && preferredApiRepresentation !== void 0 ? preferredApiRepresentation : getApiRepresentation(featureFlags, newApplicationConfig);
|
|
326
478
|
newApplicationConfig.pages = {};
|
|
327
479
|
const apiPromises = [];
|
|
328
480
|
for (const page of Object.values(resource.pages)) {
|
|
@@ -334,8 +486,8 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelat
|
|
|
334
486
|
newApplicationConfig.pages[pageId] = {
|
|
335
487
|
id: page.id,
|
|
336
488
|
name: page.name,
|
|
337
|
-
apis: {},
|
|
338
489
|
};
|
|
490
|
+
const pageConfig = newApplicationConfig.pages[pageId];
|
|
339
491
|
const pageContent = (0, yaml_1.stringify)({
|
|
340
492
|
id: page.id,
|
|
341
493
|
name: page.name,
|
|
@@ -346,79 +498,63 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelat
|
|
|
346
498
|
sortMapEntries: true,
|
|
347
499
|
blockQuote: "literal",
|
|
348
500
|
});
|
|
349
|
-
|
|
350
|
-
|
|
501
|
+
const pageFilePath = `${pageDirName}/page.yaml`;
|
|
502
|
+
await fs.outputFile(pageFilePath, pageContent);
|
|
503
|
+
existingFilePaths.delete(pageFilePath);
|
|
351
504
|
for (const api of page.apis) {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
505
|
+
const apiInfo = await writeAppApi(api, pageDirName, existingFilePaths, apiPromises, apiRepresentation);
|
|
506
|
+
// Update the page config with the new api info
|
|
507
|
+
const apiId = api.apiPb.metadata.id;
|
|
508
|
+
if (apiRepresentation.extractLargeSourceFiles) {
|
|
509
|
+
// Add the new pageApis field whenever large source files might be extracted
|
|
510
|
+
if (!pageConfig.pageApis) {
|
|
511
|
+
pageConfig.pageApis = {};
|
|
512
|
+
}
|
|
513
|
+
pageConfig.pageApis[apiId] = {
|
|
514
|
+
name: apiInfo.name,
|
|
515
|
+
sourceFiles: (_a = apiInfo.sourceFiles) === null || _a === void 0 ? void 0 : _a.sort(),
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
if (!pageConfig.apis) {
|
|
520
|
+
pageConfig.apis = {};
|
|
521
|
+
}
|
|
522
|
+
pageConfig.apis[apiId] = apiInfo.name;
|
|
523
|
+
}
|
|
355
524
|
}
|
|
356
525
|
}
|
|
357
|
-
const
|
|
526
|
+
const appApis = {};
|
|
358
527
|
if (resource.apis && resource.apis.length) {
|
|
359
|
-
await fs.ensureDir(apisDirName);
|
|
360
528
|
for (const api of resource.apis) {
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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);
|
|
529
|
+
const apiInfo = await writeAppApi(api, appDirName, existingFilePaths, apiPromises, apiRepresentation);
|
|
530
|
+
const apiId = api.apiPb.metadata.id;
|
|
531
|
+
if (apiRepresentation.extractLargeSourceFiles) {
|
|
532
|
+
if (!newApplicationConfig.appApis) {
|
|
533
|
+
newApplicationConfig.appApis = {};
|
|
404
534
|
}
|
|
535
|
+
newApplicationConfig.appApis[apiId] = apiInfo;
|
|
405
536
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
for (const existingApiName of Object.values(existingPage.apis)) {
|
|
412
|
-
const existingApiPath = `${existingPageDir}/apis/${slugifyName(existingApiName)}.yaml`;
|
|
413
|
-
await fs.remove(existingApiPath);
|
|
537
|
+
else {
|
|
538
|
+
if (!newApplicationConfig.apis) {
|
|
539
|
+
newApplicationConfig.apis = {};
|
|
540
|
+
}
|
|
541
|
+
newApplicationConfig.apis[apiId] = apiInfo.name;
|
|
414
542
|
}
|
|
415
543
|
}
|
|
544
|
+
await Promise.all(apiPromises);
|
|
545
|
+
}
|
|
546
|
+
if (apiRepresentation.extractLargeSourceFiles) {
|
|
547
|
+
newApplicationConfig.appApis = appApis;
|
|
416
548
|
}
|
|
417
|
-
|
|
418
|
-
|
|
549
|
+
// Delete any existing files that were not overwritten
|
|
550
|
+
for (const filePath of existingFilePaths) {
|
|
551
|
+
await fs.remove(filePath);
|
|
552
|
+
}
|
|
553
|
+
await fs.ensureDir(`${appDirName}/${util_1.SUPERBLOCKS_HOME_FOLDER_NAME}`);
|
|
554
|
+
await fs.writeFile(`${appDirName}/${util_1.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(newApplicationConfig), null, 2));
|
|
419
555
|
const createdFiles = await Promise.resolve(
|
|
420
556
|
// Defensive check for when application settings are missing componentFiles
|
|
421
|
-
(
|
|
557
|
+
(_c = (_b = resource.componentFiles) === null || _b === void 0 ? void 0 : _b.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _c !== void 0 ? _c : []);
|
|
422
558
|
// print out failed downloads synchronously here
|
|
423
559
|
createdFiles
|
|
424
560
|
.filter((createdFiles) => createdFiles.length)
|
|
@@ -439,6 +575,95 @@ async function writeMultiPageApplicationToDisk(resource, rootPath, existingRelat
|
|
|
439
575
|
};
|
|
440
576
|
}
|
|
441
577
|
exports.writeMultiPageApplicationToDisk = writeMultiPageApplicationToDisk;
|
|
578
|
+
function getExistingFilePathsForApplicationApi(superblocksApplicationConfig, location) {
|
|
579
|
+
const paths = new Set();
|
|
580
|
+
if (!superblocksApplicationConfig) {
|
|
581
|
+
return paths;
|
|
582
|
+
}
|
|
583
|
+
// Pages
|
|
584
|
+
if (superblocksApplicationConfig.pages) {
|
|
585
|
+
for (const page of Object.values(superblocksApplicationConfig.pages)) {
|
|
586
|
+
// Page YAML
|
|
587
|
+
const pageNameSlug = slugifyName(page.name);
|
|
588
|
+
const pagePath = `${location}/pages/${pageNameSlug}`;
|
|
589
|
+
paths.add(`${pagePath}/page.yaml`);
|
|
590
|
+
// Page APIs
|
|
591
|
+
if (page.pageApis) {
|
|
592
|
+
for (const api of Object.values(page.pageApis)) {
|
|
593
|
+
addExistingFilePathsForApi(api, `${pagePath}/apis`, paths, true);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
else if (page.apis) {
|
|
597
|
+
for (const apiName of Object.values(page.apis)) {
|
|
598
|
+
addExistingFilePathsForApi({ name: apiName }, `${pagePath}/apis`, paths, true);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
// APIs
|
|
604
|
+
if (superblocksApplicationConfig.appApis) {
|
|
605
|
+
// For file version >= 0.2.0, there are API files either the 'apis' folder or in an API-specific folder
|
|
606
|
+
for (const api of Object.values(superblocksApplicationConfig.appApis)) {
|
|
607
|
+
addExistingFilePathsForApi(api, `${location}/apis`, paths, true);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
else if (superblocksApplicationConfig.apis) {
|
|
611
|
+
// For file version < 0.2.0, there are only API file
|
|
612
|
+
for (const apiName of Object.values(superblocksApplicationConfig.apis)) {
|
|
613
|
+
addExistingFilePathsForApi({ name: apiName }, `${location}/apis`, paths, true);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
return paths;
|
|
617
|
+
}
|
|
618
|
+
function getExistingFilePathsForBackendApi(superblocksBackendConfig, location) {
|
|
619
|
+
const paths = new Set();
|
|
620
|
+
if (!superblocksBackendConfig) {
|
|
621
|
+
return paths;
|
|
622
|
+
}
|
|
623
|
+
// Pages
|
|
624
|
+
if (superblocksBackendConfig.sourceFiles) {
|
|
625
|
+
addExistingFilePathsForApi({ name: "api", sourceFiles: superblocksBackendConfig.sourceFiles }, location, paths, false);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
addExistingFilePathsForApi({ name: "api" }, location, paths, false);
|
|
629
|
+
}
|
|
630
|
+
return paths;
|
|
631
|
+
}
|
|
632
|
+
function addExistingFilePathsForApi(api, location, paths, useNestedFolder) {
|
|
633
|
+
var _a, _b;
|
|
634
|
+
const apiNameSlug = slugifyName(api.name);
|
|
635
|
+
if ((_a = api.sourceFiles) === null || _a === void 0 ? void 0 : _a.length) {
|
|
636
|
+
// API files are in an API-specific folder
|
|
637
|
+
const apiDirPath = useNestedFolder
|
|
638
|
+
? `${location}/${apiNameSlug}`
|
|
639
|
+
: location;
|
|
640
|
+
paths.add(`${apiDirPath}/${apiNameSlug}.yaml`);
|
|
641
|
+
// And there are source files
|
|
642
|
+
for (const sourceFile of (_b = api.sourceFiles) !== null && _b !== void 0 ? _b : []) {
|
|
643
|
+
paths.add(`${apiDirPath}/${sourceFile}`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
// API file is in the 'apis' folder with no separate source files
|
|
648
|
+
paths.add(`${location}/${apiNameSlug}.yaml`);
|
|
649
|
+
}
|
|
650
|
+
return paths;
|
|
651
|
+
}
|
|
652
|
+
exports.addExistingFilePathsForApi = addExistingFilePathsForApi;
|
|
653
|
+
function getResourceConfigMetadata(featureFlags, existingResourceConfig) {
|
|
654
|
+
if (!existingResourceConfig) {
|
|
655
|
+
// This is a new application, and we may need to add a metadata field to the application config
|
|
656
|
+
if (featureFlags.splitLargeApiStepsInNewEnabled()) {
|
|
657
|
+
return {
|
|
658
|
+
fileVersion: LATEST_FILE_VERSION,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
else if (existingResourceConfig.metadata) {
|
|
663
|
+
return existingResourceConfig.metadata;
|
|
664
|
+
}
|
|
665
|
+
return undefined;
|
|
666
|
+
}
|
|
442
667
|
async function removeResourceFromDisk(rootPath, resourceRelativeLocation) {
|
|
443
668
|
const resourceLocation = node_path_1.default.resolve(rootPath, resourceRelativeLocation);
|
|
444
669
|
await fs.remove(resourceLocation);
|
|
@@ -593,21 +818,161 @@ function extractApiName(api) {
|
|
|
593
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";
|
|
594
819
|
}
|
|
595
820
|
exports.extractApiName = extractApiName;
|
|
596
|
-
function
|
|
597
|
-
const
|
|
598
|
-
const
|
|
821
|
+
async function writeAppApi(api, directoryPath, existingFilePaths, apiPromises, apiRepresentation) {
|
|
822
|
+
const originalApiName = extractApiName(api);
|
|
823
|
+
const additionalStepFiles = [];
|
|
824
|
+
await writeApiFiles(api, slugifyName(originalApiName), `${directoryPath}/apis`, true, apiPromises, additionalStepFiles, apiRepresentation, existingFilePaths);
|
|
825
|
+
return {
|
|
826
|
+
name: originalApiName,
|
|
827
|
+
sourceFiles: additionalStepFiles.map((file) => file.relativePath).sort(),
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
exports.writeAppApi = writeAppApi;
|
|
831
|
+
async function writeBackendApi(api, directoryPath, apiPromises, apiRepresentation, existingFilePaths) {
|
|
832
|
+
const originalApiName = extractApiName(api);
|
|
833
|
+
const additionalStepFiles = [];
|
|
834
|
+
await writeApiFiles(api, "api", directoryPath, false, apiPromises, additionalStepFiles, apiRepresentation, existingFilePaths);
|
|
835
|
+
return {
|
|
836
|
+
name: originalApiName,
|
|
837
|
+
sourceFiles: additionalStepFiles.map((file) => file.relativePath).sort(),
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
async function writeApiFiles(api, apiNameSlug, directoryPath, nestedApiFiles, apiPromises, additionalStepFiles, apiRepresentation, existingFilePaths) {
|
|
841
|
+
let pathForApiFile = directoryPath;
|
|
842
|
+
// Determine whether to extract into separate files the source code from the steps
|
|
843
|
+
const updatedApi = extractAdditionalStepFiles(api.apiPb, additionalStepFiles, apiRepresentation);
|
|
844
|
+
if (additionalStepFiles.length > 0) {
|
|
845
|
+
if (nestedApiFiles) {
|
|
846
|
+
// This API has at least one large step code file, so we need a nested directory
|
|
847
|
+
pathForApiFile = `${pathForApiFile}/${apiNameSlug}`;
|
|
848
|
+
}
|
|
849
|
+
// Make sure the directory exists
|
|
850
|
+
await fs.ensureDir(pathForApiFile);
|
|
851
|
+
// Write any additional step source code files to the disk
|
|
852
|
+
for (const stepFile of additionalStepFiles) {
|
|
853
|
+
const sourceFilePath = `${pathForApiFile}/${stepFile.relativePath}`;
|
|
854
|
+
const handleApi = async () => {
|
|
855
|
+
await fs.outputFile(sourceFilePath, stepFile.contents);
|
|
856
|
+
};
|
|
857
|
+
apiPromises.push(handleApi());
|
|
858
|
+
// Mark the existing source file as being reused
|
|
859
|
+
existingFilePaths === null || existingFilePaths === void 0 ? void 0 : existingFilePaths.delete(sourceFilePath);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
// No additional step files to write, so mark the API directory as existing so that it will be removed later.
|
|
864
|
+
// Do this even if the current representation does not extract large source files, in case they were previously
|
|
865
|
+
existingFilePaths === null || existingFilePaths === void 0 ? void 0 : existingFilePaths.add(`${directoryPath}/${apiNameSlug}`);
|
|
866
|
+
}
|
|
867
|
+
// Convert the updated API to YAML and write it to disk
|
|
868
|
+
const apiContent = (0, yaml_1.stringify)(updatedApi, {
|
|
599
869
|
sortMapEntries: true,
|
|
600
870
|
blockQuote: "literal",
|
|
601
871
|
});
|
|
872
|
+
const yamlFilePath = `${pathForApiFile}/${apiNameSlug}.yaml`;
|
|
602
873
|
const handleApi = async () => {
|
|
603
|
-
await fs.outputFile(
|
|
874
|
+
await fs.outputFile(yamlFilePath, apiContent);
|
|
604
875
|
};
|
|
605
|
-
|
|
876
|
+
apiPromises.push(handleApi());
|
|
877
|
+
// Mark the existing source file as being reused
|
|
878
|
+
existingFilePaths === null || existingFilePaths === void 0 ? void 0 : existingFilePaths.delete(yamlFilePath);
|
|
879
|
+
}
|
|
880
|
+
function extractAdditionalStepFiles(api, additionalStepFiles, apiRepresentation) {
|
|
881
|
+
var _a, _b;
|
|
882
|
+
if (!api.blocks || !(apiRepresentation === null || apiRepresentation === void 0 ? void 0 : apiRepresentation.extractLargeSourceFiles)) {
|
|
883
|
+
return api;
|
|
884
|
+
}
|
|
885
|
+
const apiClone = lodash_2.default.cloneDeep(api);
|
|
886
|
+
const minLinesForExtraction = (_a = apiRepresentation === null || apiRepresentation === void 0 ? void 0 : apiRepresentation.minLinesForExtraction) !== null && _a !== void 0 ? _a : sdk_1.DEFAULT_LINES_FOR_LARGE_STEPS;
|
|
887
|
+
const existingFilePaths = new Set();
|
|
888
|
+
extractAdditionalStepFilesFromBlocks((_b = apiClone.blocks) !== null && _b !== void 0 ? _b : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
889
|
+
return apiClone;
|
|
890
|
+
}
|
|
891
|
+
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
|
+
for (const block of blocks) {
|
|
894
|
+
// Handle language step files
|
|
895
|
+
if (block.step) {
|
|
896
|
+
extractAdditionalStepFilesFromStep(block.step, block.name, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
897
|
+
}
|
|
898
|
+
// Handle loops
|
|
899
|
+
extractAdditionalStepFilesFromBlocks((_b = (_a = block.loop) === null || _a === void 0 ? void 0 : _a.blocks) !== null && _b !== void 0 ? _b : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
900
|
+
// Handle try/catch
|
|
901
|
+
if (block.tryCatch) {
|
|
902
|
+
extractAdditionalStepFilesFromBlocks((_d = (_c = block.tryCatch.try) === null || _c === void 0 ? void 0 : _c.blocks) !== null && _d !== void 0 ? _d : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
903
|
+
extractAdditionalStepFilesFromBlocks((_f = (_e = block.tryCatch.catch) === null || _e === void 0 ? void 0 : _e.blocks) !== null && _f !== void 0 ? _f : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
904
|
+
extractAdditionalStepFilesFromBlocks((_h = (_g = block.tryCatch.finally) === null || _g === void 0 ? void 0 : _g.blocks) !== null && _h !== void 0 ? _h : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
905
|
+
}
|
|
906
|
+
// Handle conditional
|
|
907
|
+
if (block.conditional) {
|
|
908
|
+
extractAdditionalStepFilesFromBlocks((_k = (_j = block.conditional.if) === null || _j === void 0 ? void 0 : _j.blocks) !== null && _k !== void 0 ? _k : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
909
|
+
for (const elseIfBlock of (_l = block.conditional.elseIf) !== null && _l !== void 0 ? _l : []) {
|
|
910
|
+
extractAdditionalStepFilesFromBlocks(elseIfBlock.blocks, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
911
|
+
}
|
|
912
|
+
extractAdditionalStepFilesFromBlocks((_o = (_m = block.conditional.else) === null || _m === void 0 ? void 0 : _m.blocks) !== null && _o !== void 0 ? _o : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
913
|
+
}
|
|
914
|
+
// Handle Parallel API
|
|
915
|
+
if (block.parallel) {
|
|
916
|
+
for (const path of Object.values((_r = (_q = (_p = block.parallel) === null || _p === void 0 ? void 0 : _p.static) === null || _q === void 0 ? void 0 : _q.paths) !== null && _r !== void 0 ? _r : {})) {
|
|
917
|
+
extractAdditionalStepFilesFromBlocks(path.blocks, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
918
|
+
}
|
|
919
|
+
extractAdditionalStepFilesFromBlocks((_u = (_t = (_s = block.parallel) === null || _s === void 0 ? void 0 : _s.dynamic) === null || _t === void 0 ? void 0 : _t.blocks) !== null && _u !== void 0 ? _u : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
920
|
+
}
|
|
921
|
+
// Handle stream
|
|
922
|
+
if (block.stream) {
|
|
923
|
+
const trigger = block.stream.trigger;
|
|
924
|
+
if (trigger && trigger.step) {
|
|
925
|
+
extractAdditionalStepFilesFromStep(trigger.step, trigger.name, additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
926
|
+
}
|
|
927
|
+
extractAdditionalStepFilesFromBlocks((_w = (_v = block.stream.process) === null || _v === void 0 ? void 0 : _v.blocks) !== null && _w !== void 0 ? _w : [], additionalStepFiles, existingFilePaths, minLinesForExtraction);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function extractAdditionalStepFilesFromStep(step, name, additionalStepFiles, existingFilePaths, minLinesForExtraction) {
|
|
932
|
+
// Handle language step files
|
|
933
|
+
if (step && "integration" in step) {
|
|
934
|
+
const integration = step.integration;
|
|
935
|
+
const extension = LANGUAGE_STEP_EXTENSIONS[integration];
|
|
936
|
+
if (extension) {
|
|
937
|
+
const languageContent = step[integration];
|
|
938
|
+
if (languageContent) {
|
|
939
|
+
const blockBody = languageContent.body;
|
|
940
|
+
if (blockBody && typeof blockBody === "string") {
|
|
941
|
+
const lines = blockBody === null || blockBody === void 0 ? void 0 : blockBody.split("\n");
|
|
942
|
+
const linesNum = lines === null || lines === void 0 ? void 0 : lines.length;
|
|
943
|
+
if (linesNum && linesNum > minLinesForExtraction) {
|
|
944
|
+
// Record the separate file is needed, with the language contents
|
|
945
|
+
const relativePath = findUnusedFilePath(slugifyName(name), extension, existingFilePaths);
|
|
946
|
+
additionalStepFiles.push({
|
|
947
|
+
relativePath: relativePath,
|
|
948
|
+
contents: blockBody,
|
|
949
|
+
language: integration,
|
|
950
|
+
});
|
|
951
|
+
// Replace the body with a reference to the separate file
|
|
952
|
+
languageContent.body = {
|
|
953
|
+
path: `./${relativePath}`,
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
function findUnusedFilePath(filename, extension, existingFilePaths) {
|
|
962
|
+
let proposedFilename = `${filename}.${extension}`;
|
|
963
|
+
let i = 1;
|
|
964
|
+
while (existingFilePaths.has(proposedFilename)) {
|
|
965
|
+
proposedFilename = `${filename}_${i}.${extension}`;
|
|
966
|
+
i++;
|
|
967
|
+
}
|
|
968
|
+
existingFilePaths.add(proposedFilename);
|
|
969
|
+
return proposedFilename;
|
|
606
970
|
}
|
|
607
971
|
async function validateMultiPageApplication(applicationConfig, superblocksRootPath, location) {
|
|
608
972
|
var _a;
|
|
609
973
|
// validate app level APIs
|
|
610
|
-
|
|
974
|
+
const apiNames = getApiNamesFromApplicationConfig(applicationConfig);
|
|
975
|
+
for (const apiName of apiNames) {
|
|
611
976
|
const apiPath = node_path_1.default.resolve(superblocksRootPath, location, "apis", `${slugifyName(apiName)}.yaml`);
|
|
612
977
|
const validateApiError = await validateYamlFile(apiPath);
|
|
613
978
|
if (validateApiError) {
|
|
@@ -622,11 +987,26 @@ async function validateMultiPageApplication(applicationConfig, superblocksRootPa
|
|
|
622
987
|
return validatePageError;
|
|
623
988
|
}
|
|
624
989
|
// validate page level APIs
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
990
|
+
const pageApiNames = getApiNamesFromPageConfig(page);
|
|
991
|
+
for (const apiName of pageApiNames) {
|
|
992
|
+
const apisPath = node_path_1.default.resolve(superblocksRootPath, location, "pages", slugifyName(page.name), "apis");
|
|
993
|
+
// Try the API path not in a nested directory
|
|
994
|
+
const apiPath = node_path_1.default.resolve(apisPath, `${slugifyName(apiName)}.yaml`);
|
|
995
|
+
if (fs.pathExistsSync(apiPath)) {
|
|
996
|
+
const validateApiError = await validateYamlFile(apiPath);
|
|
997
|
+
if (validateApiError) {
|
|
998
|
+
return validateApiError;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
else {
|
|
1002
|
+
// Try the API path in a nested directory
|
|
1003
|
+
const nestedApiPath = node_path_1.default.resolve(apisPath, slugifyName(apiName), "api.yaml");
|
|
1004
|
+
if (fs.pathExistsSync(nestedApiPath)) {
|
|
1005
|
+
const validateApiError = await validateYamlFile(nestedApiPath);
|
|
1006
|
+
if (validateApiError) {
|
|
1007
|
+
return validateApiError;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
630
1010
|
}
|
|
631
1011
|
}
|
|
632
1012
|
}
|
|
@@ -636,7 +1016,7 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
636
1016
|
switch (resource.resourceType) {
|
|
637
1017
|
case "APPLICATION": {
|
|
638
1018
|
// make sure application config exists
|
|
639
|
-
const applicationConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location,
|
|
1019
|
+
const applicationConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location, util_1.RESOURCE_CONFIG_PATH);
|
|
640
1020
|
if (!(await fs.pathExists(applicationConfigPath))) {
|
|
641
1021
|
return `File ${relativeToCurrentDir(applicationConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
|
|
642
1022
|
}
|
|
@@ -667,7 +1047,7 @@ async function validateLocalResource(superblocksRootPath, resource) {
|
|
|
667
1047
|
}
|
|
668
1048
|
case "BACKEND": {
|
|
669
1049
|
// make sure the backend config exists
|
|
670
|
-
const backendConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location,
|
|
1050
|
+
const backendConfigPath = node_path_1.default.resolve(superblocksRootPath, resource.location, util_1.RESOURCE_CONFIG_PATH);
|
|
671
1051
|
if (!(await fs.pathExists(backendConfigPath))) {
|
|
672
1052
|
return `File ${relativeToCurrentDir(backendConfigPath)} not found. Superblocks CLI commands cannot function without it.`;
|
|
673
1053
|
}
|