@sasjs/cli 6.29.0 → 6.30.1

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.
@@ -44,11 +44,9 @@ var path_1 = __importDefault(require("path"));
44
44
  var test_1 = require("../../../utils/test");
45
45
  var utils_1 = require("@sasjs/utils");
46
46
  var config_1 = require("../../../utils/config");
47
- var minimalAppFiles_1 = require("./minimalAppFiles");
48
- var reactAppFiles_1 = require("./reactAppFiles");
49
- var angularAppFiles_1 = require("./angularAppFiles");
50
47
  var create_1 = require("../create");
51
48
  var utils_2 = require("../../../utils");
49
+ var utils_3 = require("../../../utils/utils");
52
50
  describe('sasjs create', function () {
53
51
  beforeAll(function () {
54
52
  dotenv_1.default.config();
@@ -249,28 +247,34 @@ describe('sasjs create', function () {
249
247
  }); });
250
248
  });
251
249
  var verifyCreateWeb = function (appName, appType) { return __awaiter(void 0, void 0, void 0, function () {
252
- var fileStructure;
250
+ var template, docsCandidates, present;
253
251
  return __generator(this, function (_a) {
254
252
  switch (_a.label) {
255
- case 0:
256
- fileStructure = appType === 'minimal'
257
- ? minimalAppFiles_1.minimalAppFiles
258
- : appType === 'react'
259
- ? reactAppFiles_1.reactAppFiles
260
- : appType === 'angular'
261
- ? angularAppFiles_1.angularAppFiles
262
- : minimalAppFiles_1.minimalAppFiles;
263
- fileStructure.folderName = appName;
264
- return [4 /*yield*/, (0, test_1.verifyFolder)(fileStructure)];
253
+ case 0: return [4 /*yield*/, (0, test_1.getTemplateFileTree)(utils_3.seedAppUrls[appType])];
265
254
  case 1:
255
+ template = _a.sent();
256
+ template.folderName = appName;
257
+ return [4 /*yield*/, (0, test_1.verifyFolder)(template)];
258
+ case 2:
266
259
  _a.sent();
267
260
  return [4 /*yield*/, (0, test_1.verifyPackageJsonContent)(appName)
268
- // A seed app carries its dependencies in the template's package.json, so the
269
- // command create issues for it is a plain install - the same trade as above:
270
- // the stub writes what npm would, and this asserts the CLI asked for it.
261
+ // The docs are a submodule fetched after the archive, and the archive carries
262
+ // the folder empty - so the derived tree can only assert that the folder is
263
+ // there. A create whose docs download silently failed used to pass; assert
264
+ // the site itself arrived. Every template gets the docs (create routes all
265
+ // three through a create*App that passes the docs URL), and the path differs:
266
+ // react keeps them under `public`, the others at the root.
271
267
  ];
272
- case 2:
268
+ case 3:
273
269
  _a.sent();
270
+ docsCandidates = [
271
+ path_1.default.join(process.projectDir, appName, 'public', 'docs', 'index.html'),
272
+ path_1.default.join(process.projectDir, appName, 'docs', 'index.html')
273
+ ];
274
+ return [4 /*yield*/, Promise.all(docsCandidates.map(function (candidate) { return (0, utils_1.fileExists)(candidate); }))];
275
+ case 4:
276
+ present = _a.sent();
277
+ expect(present.some(Boolean)).toEqual(true);
274
278
  // A seed app carries its dependencies in the template's package.json, so the
275
279
  // command create issues for it is a plain install - the same trade as above:
276
280
  // the stub writes what npm would, and this asserts the CLI asked for it.
@@ -68,10 +68,38 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
68
68
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
69
  }
70
70
  };
71
+ var __read = (this && this.__read) || function (o, n) {
72
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
73
+ if (!m) return o;
74
+ var i = m.call(o), r, ar = [], e;
75
+ try {
76
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
77
+ }
78
+ catch (error) { e = { error: error }; }
79
+ finally {
80
+ try {
81
+ if (r && !r.done && (m = i["return"])) m.call(i);
82
+ }
83
+ finally { if (e) throw e.error; }
84
+ }
85
+ return ar;
86
+ };
87
+ var __values = (this && this.__values) || function(o) {
88
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
89
+ if (m) return m.call(o);
90
+ if (o && typeof o.length === "number") return {
91
+ next: function () {
92
+ if (o && i >= o.length) o = void 0;
93
+ return { value: o && o[i++], done: !o };
94
+ }
95
+ };
96
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
97
+ };
71
98
  var __importDefault = (this && this.__importDefault) || function (mod) {
72
99
  return (mod && mod.__esModule) ? mod : { "default": mod };
73
100
  };
74
101
  Object.defineProperty(exports, "__esModule", { value: true });
102
+ var fs_1 = __importDefault(require("fs"));
75
103
  var path_1 = __importDefault(require("path"));
76
104
  var node_1 = require("@sasjs/adapter/node");
77
105
  var js_base64_1 = require("js-base64");
@@ -85,6 +113,13 @@ var compile_1 = require("../../compile/compile");
85
113
  var deploy_1 = require("../deploy");
86
114
  var utils_2 = require("./utils");
87
115
  var config_1 = require("../../../utils/config");
116
+ /** Every file under a folder, recursively, as absolute paths. */
117
+ var listFiles = function (folderPath) {
118
+ return fs_1.default.readdirSync(folderPath, { withFileTypes: true }).flatMap(function (entry) {
119
+ var entryPath = path_1.default.join(folderPath, entry.name);
120
+ return entry.isDirectory() ? listFiles(entryPath) : [entryPath];
121
+ });
122
+ };
88
123
  describe('sasjs cbd with server type SASJS', function () {
89
124
  var target;
90
125
  var appName;
@@ -115,9 +150,10 @@ describe('sasjs cbd with server type SASJS', function () {
115
150
  });
116
151
  }); });
117
152
  it("should deploy compile and build to sasjs/server", function () { return __awaiter(void 0, void 0, void 0, function () {
118
- var deployMock, _a, customTarget, macroCorePath, mf_getuser, _b, mp_jsonout, ms_webout, webout, mocksPath, appinitJSPath, getdataJSPath, springsJSONPath, appinitJSContents, getdataJSContents, springsJSONContents, depsInserts, appinit, getdata, getCode;
119
- return __generator(this, function (_c) {
120
- switch (_c.label) {
153
+ var deployMock, _a, customTarget, macroCorePath, mf_getuser, _b, mp_jsonout, ms_webout, webout, depsInserts, getCode, _c, payload, deployed, indexMembers, projectRoot, mocksRoot, mockFiles, mockFiles_1, mockFiles_1_1, filePath, relative, _d, _e, _f, e_1_1, serviceFiles, serviceFiles_1, serviceFiles_1_1, filePath, name_1, contents, member, e_2_1;
154
+ var e_1, _g, _h, e_2, _j;
155
+ return __generator(this, function (_k) {
156
+ switch (_k.label) {
121
157
  case 0:
122
158
  jest.spyOn(fileModule, 'fileExists').mockImplementation(function (filePath) {
123
159
  if (filePath.endsWith('.zip'))
@@ -141,7 +177,7 @@ describe('sasjs cbd with server type SASJS', function () {
141
177
  }
142
178
  })];
143
179
  case 1:
144
- _c.sent();
180
+ _k.sent();
145
181
  return [4 /*yield*/, (0, utils_2.updateLocalTarget)(target.name, {
146
182
  jobConfig: undefined,
147
183
  serviceConfig: undefined,
@@ -151,101 +187,139 @@ describe('sasjs cbd with server type SASJS', function () {
151
187
  }
152
188
  })];
153
189
  case 2:
154
- _c.sent();
190
+ _k.sent();
155
191
  _a = process;
156
192
  return [4 /*yield*/, (0, config_1.getLocalConfig)()];
157
193
  case 3:
158
- _a.sasjsConfig = _c.sent();
194
+ _a.sasjsConfig = _k.sent();
159
195
  return [4 /*yield*/, (0, config_1.findTargetInConfiguration)(target.name, types_1.TargetScope.Local)];
160
196
  case 4:
161
- customTarget = (_c.sent()).target;
197
+ customTarget = (_k.sent()).target;
162
198
  return [4 /*yield*/, (0, compile_1.compile)(customTarget)];
163
199
  case 5:
164
- _c.sent();
200
+ _k.sent();
165
201
  return [4 /*yield*/, expect((0, build_1.build)(customTarget)).toResolve()];
166
202
  case 6:
167
- _c.sent();
203
+ _k.sent();
168
204
  return [4 /*yield*/, (0, deploy_1.deploy)(customTarget, true)];
169
205
  case 7:
170
- _c.sent();
206
+ _k.sent();
171
207
  macroCorePath = process.sasjsConstants.macroCorePath;
172
208
  _b = utils_1.removeHeader;
173
209
  return [4 /*yield*/, (0, utils_1.readFile)("".concat(macroCorePath, "/base/mf_getuser.sas"))];
174
210
  case 8:
175
- mf_getuser = _b.apply(void 0, [_c.sent()]);
211
+ mf_getuser = _b.apply(void 0, [_k.sent()]);
176
212
  return [4 /*yield*/, (0, utils_1.readFile)("".concat(macroCorePath, "/base/mp_jsonout.sas"))];
177
213
  case 9:
178
- mp_jsonout = _c.sent();
214
+ mp_jsonout = _k.sent();
179
215
  return [4 /*yield*/, (0, utils_1.readFile)("".concat(macroCorePath, "/server/ms_webout.sas"))];
180
216
  case 10:
181
- ms_webout = _c.sent();
217
+ ms_webout = _k.sent();
182
218
  webout = "%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO,maxobs=MAX);\n %ms_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt\n ,missing=&missing\n ,showmeta=&showmeta\n ,maxobs=&maxobs\n )\n%mend;\n";
183
- mocksPath = path_1.default.join(__dirname, appName, 'sasjs', 'mocks');
184
- appinitJSPath = path_1.default.join(mocksPath, 'services', 'common', 'appinit.js');
185
- getdataJSPath = path_1.default.join(mocksPath, 'services', 'common', 'getdata.js');
186
- springsJSONPath = path_1.default.join(mocksPath, 'services', 'common', 'springs.json');
187
- return [4 /*yield*/, (0, utils_1.readFile)(appinitJSPath)];
188
- case 11:
189
- appinitJSContents = _c.sent();
190
- return [4 /*yield*/, (0, utils_1.readFile)(getdataJSPath)];
191
- case 12:
192
- getdataJSContents = _c.sent();
193
- return [4 /*yield*/, (0, utils_1.readFile)(springsJSONPath)];
194
- case 13:
195
- springsJSONContents = _c.sent();
196
219
  depsInserts = "\n\n* Service Variables start;\n\n\n* Service Variables end;\n* SAS Macros start;\n\n\n\n* SAS Macros end;\n* SAS Includes start;\n\n* SAS Includes end;\n* Binary Files start;\n\n* Binary Files end;\n\n\n* Service start;\n";
197
- appinit = "/**\n @file appinit.sas\n @brief Initialisation service - runs on app startup\n @details This is always the first service called when the app is opened.\n\n <h4> SAS Macros </h4>\n\n**/\n\nproc sql;\ncreate table areas as select distinct area\n from mydb.springs;\n\n%webout(OPEN)\n%webout(OBJ,areas)\n%webout(CLOSE)\n\n";
198
- getdata = "/**\n @file getdata.sas\n @brief Get Data service - runs on app startup\n @details This is always the first service called when the app is opened.\n\n <h4> SAS Macros </h4>\n\n**/\n\n%webout(FETCH)\n\nproc sql;\ncreate table springs as select * from mydb.springs\n where area in (select area from work.areas);\n\n%webout(OPEN)\n%webout(OBJ,springs)\n%webout(CLOSE)\n\n";
199
220
  getCode = function (file) {
200
221
  return "".concat(mf_getuser).concat(mp_jsonout).concat(ms_webout).concat(webout, "/* provide additional debug info */\n%global _program;\n%put &=syscc;\n%put user=%mf_getuser();\n%put pgm=&_program;\n%put timestamp=%sysfunc(datetime(),datetime19.);").concat(depsInserts).concat(file, "* Service end;");
201
222
  };
202
- expect(deployMock).toHaveBeenCalledWith({
203
- appLoc: target.appLoc,
204
- fileTree: {
205
- members: [
206
- {
207
- name: 'services',
208
- type: 'folder',
209
- members: [
210
- {
211
- name: 'common',
212
- type: 'folder',
213
- members: [
214
- {
215
- name: 'appinit.js',
216
- type: 'file',
217
- encoding: 'base64',
218
- code: (0, js_base64_1.encode)(appinitJSContents)
219
- },
220
- {
221
- name: 'appinit',
222
- type: 'service',
223
- code: getCode((0, utils_1.removeHeader)(appinit))
224
- },
225
- {
226
- name: 'getdata.js',
227
- type: 'file',
228
- encoding: 'base64',
229
- code: (0, js_base64_1.encode)(getdataJSContents)
230
- },
231
- {
232
- name: 'getdata',
233
- type: 'service',
234
- code: getCode((0, utils_1.removeHeader)(getdata))
235
- },
236
- {
237
- name: 'springs.json',
238
- type: 'file',
239
- encoding: 'base64',
240
- code: (0, js_base64_1.encode)(springsJSONContents)
241
- }
242
- ]
243
- }
244
- ]
245
- }
246
- ]
247
- }
248
- }, target.appLoc, undefined);
223
+ // The payload is derived from the project the command created rather than
224
+ // listed by hand. A hand-kept list turned this spec red when the seed app
225
+ // gained a data file beside its services - a file the CLI deploys correctly
226
+ // - so the reference here is the project itself. What stays explicit is the
227
+ // CLI's own contribution: the wrapper, built by `getCode` above.
228
+ expect(deployMock).toHaveBeenCalledTimes(1);
229
+ _c = __read(deployMock.mock.calls[0], 1), payload = _c[0];
230
+ expect(payload.appLoc).toEqual(target.appLoc);
231
+ deployed = new Map();
232
+ indexMembers = function (members, prefix) {
233
+ if (members === void 0) { members = []; }
234
+ if (prefix === void 0) { prefix = ''; }
235
+ return members.forEach(function (member) {
236
+ var memberPath = prefix ? "".concat(prefix, "/").concat(member.name) : member.name;
237
+ if (member.type === 'folder')
238
+ indexMembers(member.members, memberPath);
239
+ else
240
+ deployed.set(memberPath, member);
241
+ });
242
+ };
243
+ indexMembers(payload.fileTree.members);
244
+ projectRoot = path_1.default.join(__dirname, appName);
245
+ mocksRoot = path_1.default.join(projectRoot, 'sasjs', 'mocks');
246
+ mockFiles = listFiles(mocksRoot);
247
+ _k.label = 11;
248
+ case 11:
249
+ _k.trys.push([11, 16, 17, 18]);
250
+ mockFiles_1 = __values(mockFiles), mockFiles_1_1 = mockFiles_1.next();
251
+ _k.label = 12;
252
+ case 12:
253
+ if (!!mockFiles_1_1.done) return [3 /*break*/, 15];
254
+ filePath = mockFiles_1_1.value;
255
+ relative = path_1.default
256
+ .relative(mocksRoot, filePath)
257
+ .split(path_1.default.sep)
258
+ .join('/');
259
+ _e = (_d = expect(deployed.get(relative))).toEqual;
260
+ _h = {
261
+ name: path_1.default.basename(filePath),
262
+ type: 'file',
263
+ encoding: 'base64'
264
+ };
265
+ _f = js_base64_1.encode;
266
+ return [4 /*yield*/, (0, utils_1.readFile)(filePath)];
267
+ case 13:
268
+ _e.apply(_d, [(_h.code = _f.apply(void 0, [_k.sent()]),
269
+ _h)]);
270
+ _k.label = 14;
271
+ case 14:
272
+ mockFiles_1_1 = mockFiles_1.next();
273
+ return [3 /*break*/, 12];
274
+ case 15: return [3 /*break*/, 18];
275
+ case 16:
276
+ e_1_1 = _k.sent();
277
+ e_1 = { error: e_1_1 };
278
+ return [3 /*break*/, 18];
279
+ case 17:
280
+ try {
281
+ if (mockFiles_1_1 && !mockFiles_1_1.done && (_g = mockFiles_1.return)) _g.call(mockFiles_1);
282
+ }
283
+ finally { if (e_1) throw e_1.error; }
284
+ return [7 /*endfinally*/];
285
+ case 18:
286
+ serviceFiles = listFiles(path_1.default.join(projectRoot, 'sasjs', 'services', 'common')).filter(function (filePath) { return filePath.endsWith('.sas'); });
287
+ _k.label = 19;
288
+ case 19:
289
+ _k.trys.push([19, 24, 25, 26]);
290
+ serviceFiles_1 = __values(serviceFiles), serviceFiles_1_1 = serviceFiles_1.next();
291
+ _k.label = 20;
292
+ case 20:
293
+ if (!!serviceFiles_1_1.done) return [3 /*break*/, 23];
294
+ filePath = serviceFiles_1_1.value;
295
+ name_1 = path_1.default.basename(filePath, '.sas');
296
+ return [4 /*yield*/, (0, utils_1.readFile)(filePath)];
297
+ case 21:
298
+ contents = _k.sent();
299
+ member = deployed.get("services/common/".concat(name_1));
300
+ expect(member).toMatchObject({ name: name_1, type: 'service' });
301
+ // the compiled service ends its text with a blank line before the end
302
+ // marker, whatever trailing whitespace the source file carries
303
+ expect(member.code).toEqual(getCode((0, utils_1.removeHeader)(contents).trimEnd() + '\n\n'));
304
+ _k.label = 22;
305
+ case 22:
306
+ serviceFiles_1_1 = serviceFiles_1.next();
307
+ return [3 /*break*/, 20];
308
+ case 23: return [3 /*break*/, 26];
309
+ case 24:
310
+ e_2_1 = _k.sent();
311
+ e_2 = { error: e_2_1 };
312
+ return [3 /*break*/, 26];
313
+ case 25:
314
+ try {
315
+ if (serviceFiles_1_1 && !serviceFiles_1_1.done && (_j = serviceFiles_1.return)) _j.call(serviceFiles_1);
316
+ }
317
+ finally { if (e_2) throw e_2.error; }
318
+ return [7 /*endfinally*/];
319
+ case 26:
320
+ // and nothing else: a member the CLI gains or loses shows as a difference
321
+ // in the count, rather than silently passing inside a hand-written tree
322
+ expect(deployed.size).toEqual(mockFiles.length + serviceFiles.length);
249
323
  return [2 /*return*/];
250
324
  }
251
325
  });
@@ -50,6 +50,18 @@ export declare const generateTestTarget: (targetName: string, appLoc: string, se
50
50
  export declare const createTestGlobalTarget: (targetName: string, appLoc: string, serviceConfig?: ServiceConfig, serverType?: ServerType) => Promise<Target>;
51
51
  export declare const verifyStep: (step?: "db" | "compile" | "build", buildFileName?: string, customFiles?: "custom" | "no") => Promise<void>;
52
52
  export declare const mockProcessExit: () => jest.SpyInstance<never, [code?: string | number | null | undefined], any>;
53
+ /**
54
+ * The file tree of a seed app, read from the archive `sasjs create` downloads.
55
+ *
56
+ * A created project used to be compared against a hand-kept list of the files
57
+ * each template ships, so every seed release that added or removed one turned
58
+ * this suite red with no change to the CLI - twice in one afternoon, for
59
+ * `springs.json` and for the angular template's component specs. The template
60
+ * is what the command copies, so it is what the test compares against: the same
61
+ * repository, fetched the same way, with the copy's own normalisations applied
62
+ * where the command makes them.
63
+ */
64
+ export declare const getTemplateFileTree: (repoUrl: string) => Promise<Folder>;
53
65
  export declare const verifyFolder: (folder: Folder, parentFolderName?: string) => Promise<boolean>;
54
66
  export declare const verifyPackageJsonContent: (parentFolderName?: string) => Promise<void>;
55
67
  export declare const removeAllTargetsFromConfigs: () => Promise<void>;
@@ -108,8 +108,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
108
108
  return (mod && mod.__esModule) ? mod : { "default": mod };
109
109
  };
110
110
  Object.defineProperty(exports, "__esModule", { value: true });
111
- exports.verifyGitNotPresent = exports.verifyCompiledJob = exports.verifyCompiledService = exports.verifyDotFilesNotGenerated = exports.verifyDotFiles = exports.verifyDocs = exports.updateConfig = exports.updateTarget = exports.removeAllTargetsFromConfigs = exports.verifyPackageJsonContent = exports.verifyFolder = exports.mockProcessExit = exports.verifyStep = exports.createTestGlobalTarget = exports.generateTestTarget = exports.removeTestServerFolder = exports.removeTestApp = exports.createTestMinimalApp = exports.createTestJobsApp = exports.createTestApp = exports.stubNpm = exports.npmCommands = exports.generateUniqueTimestamp = void 0;
111
+ exports.verifyGitNotPresent = exports.verifyCompiledJob = exports.verifyCompiledService = exports.verifyDotFilesNotGenerated = exports.verifyDotFiles = exports.verifyDocs = exports.updateConfig = exports.updateTarget = exports.removeAllTargetsFromConfigs = exports.verifyPackageJsonContent = exports.verifyFolder = exports.getTemplateFileTree = exports.mockProcessExit = exports.verifyStep = exports.createTestGlobalTarget = exports.generateTestTarget = exports.removeTestServerFolder = exports.removeTestApp = exports.createTestMinimalApp = exports.createTestJobsApp = exports.createTestApp = exports.stubNpm = exports.npmCommands = exports.generateUniqueTimestamp = void 0;
112
112
  var fs_1 = __importDefault(require("fs"));
113
+ var os_1 = __importDefault(require("os"));
113
114
  var path_1 = __importDefault(require("path"));
114
115
  var dotenv_1 = __importDefault(require("dotenv"));
115
116
  var utils_1 = require("@sasjs/utils");
@@ -122,6 +123,8 @@ var compiledFilesCustom1_1 = require("./fileStructures/compiledFilesCustom1");
122
123
  var builtFiles_1 = require("./fileStructures/builtFiles");
123
124
  var builtFilesCustom1_1 = require("./fileStructures/builtFilesCustom1");
124
125
  var create_1 = require("../commands/create/create");
126
+ var utils_2 = require("./utils");
127
+ var zip_1 = require("./zip");
125
128
  var setConstants_1 = require("./setConstants");
126
129
  var shell = __importStar(require("./shell"));
127
130
  /**
@@ -524,6 +527,68 @@ var verifyBuildJson = function (folders, buildJson, buildSas) {
524
527
  });
525
528
  return true;
526
529
  };
530
+ /**
531
+ * The file tree of a seed app, read from the archive `sasjs create` downloads.
532
+ *
533
+ * A created project used to be compared against a hand-kept list of the files
534
+ * each template ships, so every seed release that added or removed one turned
535
+ * this suite red with no change to the CLI - twice in one afternoon, for
536
+ * `springs.json` and for the angular template's component specs. The template
537
+ * is what the command copies, so it is what the test compares against: the same
538
+ * repository, fetched the same way, with the copy's own normalisations applied
539
+ * where the command makes them.
540
+ */
541
+ var getTemplateFileTree = function (repoUrl) { return __awaiter(void 0, void 0, void 0, function () {
542
+ var workspace, archive, main_1, root;
543
+ return __generator(this, function (_a) {
544
+ switch (_a.label) {
545
+ case 0:
546
+ if (!repoUrl) {
547
+ throw new Error("No seed app URL for that template - add it to seedAppUrls in src/utils/utils.ts");
548
+ }
549
+ workspace = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'sasjs-template-'));
550
+ _a.label = 1;
551
+ case 1:
552
+ _a.trys.push([1, , 3, 4]);
553
+ archive = path_1.default.join(workspace, 'main.zip');
554
+ main_1 = (0, utils_2.downloadFile)("".concat(repoUrl, "/archive/refs/heads/main.zip"), archive);
555
+ // the seed repos are on `main`, but the command falls back to `master` and
556
+ // the reference has to be taken from whatever it would have downloaded
557
+ if (main_1.code || main_1.stderr.includes('404')) {
558
+ (0, utils_2.downloadFile)("".concat(repoUrl, "/archive/refs/heads/master.zip"), archive);
559
+ }
560
+ return [4 /*yield*/, (0, zip_1.extractZip)(archive, workspace, true)];
561
+ case 2:
562
+ _a.sent();
563
+ root = fs_1.default
564
+ .readdirSync(workspace, { withFileTypes: true })
565
+ .find(function (entry) { return entry.isDirectory(); });
566
+ if (!root) {
567
+ throw new Error("Could not find the unzipped folder for ".concat(repoUrl));
568
+ }
569
+ return [2 /*return*/, toFileTree(path_1.default.join(workspace, root.name), root.name)];
570
+ case 3:
571
+ fs_1.default.rmSync(workspace, { recursive: true, force: true });
572
+ return [7 /*endfinally*/];
573
+ case 4: return [2 /*return*/];
574
+ }
575
+ });
576
+ }); };
577
+ exports.getTemplateFileTree = getTemplateFileTree;
578
+ var toFileTree = function (folderPath, folderName) {
579
+ var entries = fs_1.default.readdirSync(folderPath, { withFileTypes: true });
580
+ return {
581
+ folderName: folderName,
582
+ // `create` removes this once the docs have been fetched into the folder, so
583
+ // it is the one file the project is not expected to carry
584
+ files: entries
585
+ .filter(function (entry) { return entry.isFile() && entry.name !== '.gitmodules'; })
586
+ .map(function (entry) { return ({ fileName: entry.name }); }),
587
+ subFolders: entries
588
+ .filter(function (entry) { return entry.isDirectory(); })
589
+ .map(function (entry) { return toFileTree(path_1.default.join(folderPath, entry.name), entry.name); })
590
+ };
591
+ };
527
592
  var verifyFolder = function (folder_1) {
528
593
  var args_1 = [];
529
594
  for (var _i = 1; _i < arguments.length; _i++) {
@@ -4,6 +4,14 @@ import SASjs from '@sasjs/adapter/node';
4
4
  import { LogJson } from '../types';
5
5
  export declare function inExistingProject(folderPath: string): Promise<boolean>;
6
6
  export declare function diff(a: any[], b: any[]): any[];
7
+ /**
8
+ * The seed apps `sasjs create` downloads, by template name.
9
+ *
10
+ * One map for the commands that fetch them and the specs that compare their
11
+ * output, so a template added here is covered by both rather than downloaded
12
+ * by one and unknown to the other.
13
+ */
14
+ export declare const seedAppUrls: Record<string, string>;
7
15
  export declare function createReactApp(folderPath: string): Promise<void>;
8
16
  export declare function createAngularApp(folderPath: string): Promise<void>;
9
17
  export declare function createMinimalApp(folderPath: string): Promise<void>;
@@ -90,7 +90,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
90
90
  return (mod && mod.__esModule) ? mod : { "default": mod };
91
91
  };
92
92
  Object.defineProperty(exports, "__esModule", { value: true });
93
- exports.isSasJsServerInServerMode = exports.getNodeModulePath = exports.isSASjsProject = exports.terminateProcess = exports.loadEnvVariables = exports.millisecondsToDdHhMmSs = exports.arrToObj = void 0;
93
+ exports.isSasJsServerInServerMode = exports.getNodeModulePath = exports.isSASjsProject = exports.terminateProcess = exports.loadEnvVariables = exports.millisecondsToDdHhMmSs = exports.arrToObj = exports.seedAppUrls = void 0;
94
94
  exports.inExistingProject = inExistingProject;
95
95
  exports.diff = diff;
96
96
  exports.createReactApp = createReactApp;
@@ -147,6 +147,18 @@ function diff(a, b) {
147
147
  });
148
148
  return __spreadArray(__spreadArray([], __read(notInA), false), __read(notInB), false);
149
149
  }
150
+ /**
151
+ * The seed apps `sasjs create` downloads, by template name.
152
+ *
153
+ * One map for the commands that fetch them and the specs that compare their
154
+ * output, so a template added here is covered by both rather than downloaded
155
+ * by one and unknown to the other.
156
+ */
157
+ exports.seedAppUrls = {
158
+ angular: 'https://github.com/sasjs/angular-seed-app',
159
+ minimal: 'https://github.com/sasjs/minimal-seed-app',
160
+ react: 'https://github.com/sasjs/react-seed-app'
161
+ };
150
162
  function createReactApp(folderPath) {
151
163
  return __awaiter(this, void 0, void 0, function () {
152
164
  var _this = this;
@@ -154,7 +166,7 @@ function createReactApp(folderPath) {
154
166
  return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
155
167
  return __generator(this, function (_a) {
156
168
  switch (_a.label) {
157
- case 0: return [4 /*yield*/, createApp(folderPath, 'https://github.com/sasjs/react-seed-app', 'https://github.com/sasjs/docs', function (err) {
169
+ case 0: return [4 /*yield*/, createApp(folderPath, exports.seedAppUrls.react, 'https://github.com/sasjs/docs', function (err) {
158
170
  return reject(new Error(err));
159
171
  })];
160
172
  case 1:
@@ -173,7 +185,7 @@ function createAngularApp(folderPath) {
173
185
  return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
174
186
  return __generator(this, function (_a) {
175
187
  switch (_a.label) {
176
- case 0: return [4 /*yield*/, createApp(folderPath, 'https://github.com/sasjs/angular-seed-app', 'https://github.com/sasjs/docs', function (err) {
188
+ case 0: return [4 /*yield*/, createApp(folderPath, exports.seedAppUrls.angular, 'https://github.com/sasjs/docs', function (err) {
177
189
  return reject(new Error(err));
178
190
  })];
179
191
  case 1:
@@ -192,7 +204,7 @@ function createMinimalApp(folderPath) {
192
204
  return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
193
205
  return __generator(this, function (_a) {
194
206
  switch (_a.label) {
195
- case 0: return [4 /*yield*/, createApp(folderPath, 'https://github.com/sasjs/minimal-seed-app', 'https://github.com/sasjs/docs', function (err) {
207
+ case 0: return [4 /*yield*/, createApp(folderPath, exports.seedAppUrls.minimal, 'https://github.com/sasjs/docs', function (err) {
196
208
  return reject(new Error(err));
197
209
  })];
198
210
  case 1:
package/package.json CHANGED
@@ -71,7 +71,7 @@
71
71
  },
72
72
  "dependencies": {
73
73
  "@sasjs/adapter": "6.0.2",
74
- "@sasjs/api": "0.28.0",
74
+ "@sasjs/api": "0.38.0",
75
75
  "@sasjs/core": "7.1.12",
76
76
  "@sasjs/lint": "5.3.0",
77
77
  "@sasjs/utils": "4.11.0",
@@ -125,5 +125,5 @@
125
125
  "ws": "8.21.0",
126
126
  "nanoid": "3.3.18"
127
127
  },
128
- "version": "6.29.0"
128
+ "version": "6.30.1"
129
129
  }
@@ -1,2 +0,0 @@
1
- import { Folder } from '../../../types';
2
- export declare const angularAppFiles: Folder;