@sasjs/cli 3.13.4 → 3.14.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.
@@ -97,6 +97,7 @@ var compile_1 = require("../compile/compile");
97
97
  var config_2 = require("./internal/config");
98
98
  var getLaunchPageCode_1 = require("./internal/getLaunchPageCode");
99
99
  var types_1 = require("@sasjs/utils/types");
100
+ var compressAndSave_1 = require("../../utils/compressAndSave");
100
101
  function build(target) {
101
102
  return __awaiter(this, void 0, void 0, function () {
102
103
  return __generator(this, function (_a) {
@@ -114,47 +115,48 @@ function build(target) {
114
115
  }
115
116
  exports.build = build;
116
117
  function createFinalSasFiles(target) {
117
- var _a, _b, _c, _d, _e, _f, _g;
118
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
118
119
  return __awaiter(this, void 0, void 0, function () {
119
- var streamConfig, streamWeb, buildConfig, serverType, name, macroFolders, buildOutputFileName, buildDestinationFolder, finalSasFileContent, finalFilePath, finalFilePathJSON, buildInfo, buildInit, buildTerm, macroCorePath, dependencyFilePaths, dependenciesContent, _h, folderContent, folderContentJSON, servicePackSASjs, servicePack;
120
- return __generator(this, function (_j) {
121
- switch (_j.label) {
120
+ var streamConfig, streamWeb, buildConfig, serverType, name, macroFolders, buildOutputFileName, buildDestinationFolder, finalSasFileContent, finalFilePath, finalFilePathJSON, finalFilePathZipped, buildInfo, buildInit, buildTerm, macroCorePath, dependencyFilePaths, dependenciesContent, _k, folderContent, folderContentJSON, servicePackSASjs, servicePack;
121
+ return __generator(this, function (_l) {
122
+ switch (_l.label) {
122
123
  case 0:
123
124
  (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info('Creating output SAS and JSON files.');
124
125
  return [4 /*yield*/, (0, config_1.getStreamConfig)(target)];
125
126
  case 1:
126
- streamConfig = _j.sent();
127
+ streamConfig = _l.sent();
127
128
  streamWeb = (_b = streamConfig.streamWeb) !== null && _b !== void 0 ? _b : false;
128
129
  buildConfig = target.buildConfig, serverType = target.serverType, name = target.name;
129
130
  return [4 /*yield*/, (0, config_1.getMacroFolders)(target)];
130
131
  case 2:
131
- macroFolders = _j.sent();
132
+ macroFolders = _l.sent();
132
133
  buildOutputFileName = (_c = buildConfig === null || buildConfig === void 0 ? void 0 : buildConfig.buildOutputFileName) !== null && _c !== void 0 ? _c : "".concat(name, ".sas");
133
134
  buildDestinationFolder = process.sasjsConstants.buildDestinationFolder;
134
135
  finalSasFileContent = '';
135
136
  finalFilePath = path_1.default.join(buildDestinationFolder, buildOutputFileName);
136
137
  finalFilePathJSON = path_1.default.join(buildDestinationFolder, "".concat(name, ".json"));
138
+ finalFilePathZipped = path_1.default.join(buildDestinationFolder, "".concat(name, ".json.zip"));
137
139
  return [4 /*yield*/, getBuildInfo(target, streamWeb)];
138
140
  case 3:
139
- buildInfo = _j.sent();
141
+ buildInfo = _l.sent();
140
142
  finalSasFileContent += "\n".concat(buildInfo);
141
143
  return [4 /*yield*/, (0, config_2.getBuildInit)(target)];
142
144
  case 4:
143
- buildInit = _j.sent();
145
+ buildInit = _l.sent();
144
146
  return [4 /*yield*/, (0, config_2.getBuildTerm)(target)];
145
147
  case 5:
146
- buildTerm = _j.sent();
148
+ buildTerm = _l.sent();
147
149
  macroCorePath = process.sasjsConstants.macroCorePath;
148
150
  return [4 /*yield*/, (0, utils_1.getDependencyPaths)("".concat(buildTerm, "\n").concat(buildInit), macroFolders, macroCorePath)];
149
151
  case 6:
150
- dependencyFilePaths = _j.sent();
152
+ dependencyFilePaths = _l.sent();
151
153
  return [4 /*yield*/, getDependencies(dependencyFilePaths)];
152
154
  case 7:
153
- dependenciesContent = _j.sent();
155
+ dependenciesContent = _l.sent();
154
156
  finalSasFileContent += "\n".concat(dependenciesContent, "\n\n").concat(buildInit, "\n");
155
157
  return [4 /*yield*/, getFolderContent(serverType)];
156
158
  case 8:
157
- _h = _j.sent(), folderContent = _h.folderContent, folderContentJSON = _h.folderContentJSON;
159
+ _k = _l.sent(), folderContent = _k.folderContent, folderContentJSON = _k.folderContentJSON;
158
160
  servicePackSASjs = {
159
161
  appLoc: target.appLoc,
160
162
  fileTree: folderContentJSON
@@ -176,7 +178,7 @@ function createFinalSasFiles(target) {
176
178
  (_d = process.logger) === null || _d === void 0 ? void 0 : _d.debug("Creating file ".concat(finalFilePath, " ."));
177
179
  return [4 /*yield*/, (0, utils_1.createFile)(finalFilePath, finalSasFileContent)];
178
180
  case 9:
179
- _j.sent();
181
+ _l.sent();
180
182
  (_e = process.logger) === null || _e === void 0 ? void 0 : _e.success("File ".concat(finalFilePath, " has been created."));
181
183
  (_f = process.logger) === null || _f === void 0 ? void 0 : _f.debug("Creating file ".concat(finalFilePathJSON, " ."));
182
184
  servicePack = target.serverType === utils_1.ServerType.Sasjs
@@ -184,8 +186,13 @@ function createFinalSasFiles(target) {
184
186
  : folderContentJSON;
185
187
  return [4 /*yield*/, (0, utils_1.createFile)(finalFilePathJSON, JSON.stringify(servicePack, null, 1))];
186
188
  case 10:
187
- _j.sent();
189
+ _l.sent();
188
190
  (_g = process.logger) === null || _g === void 0 ? void 0 : _g.success("File ".concat(finalFilePathJSON, " has been created."));
191
+ (_h = process.logger) === null || _h === void 0 ? void 0 : _h.debug("Creating file ".concat(finalFilePathZipped, " ."));
192
+ return [4 /*yield*/, (0, compressAndSave_1.compressAndSave)(finalFilePathZipped, JSON.stringify(servicePack, null, 1))];
193
+ case 11:
194
+ _l.sent();
195
+ (_j = process.logger) === null || _j === void 0 ? void 0 : _j.success("File ".concat(finalFilePathZipped, " has been created."));
189
196
  return [2 /*return*/];
190
197
  }
191
198
  });
@@ -329,7 +329,7 @@ function recreateBuildFolder() {
329
329
  }
330
330
  // REFACTOR: combine compileServiceFolder and compileJobFolder
331
331
  var compileServiceFolder = function (target, serviceFolder, macroFolders, programFolders, compileTree) { return __awaiter(void 0, void 0, void 0, function () {
332
- var destinationPath, subFolders, filesNamesInPath;
332
+ var destinationPath, subFolders, sourceFiles;
333
333
  return __generator(this, function (_a) {
334
334
  switch (_a.label) {
335
335
  case 0:
@@ -337,21 +337,21 @@ var compileServiceFolder = function (target, serviceFolder, macroFolders, progra
337
337
  return [4 /*yield*/, (0, utils_1.listSubFoldersInFolder)(destinationPath)];
338
338
  case 1:
339
339
  subFolders = _a.sent();
340
- return [4 /*yield*/, (0, utils_1.listFilesInFolder)(destinationPath)
340
+ return [4 /*yield*/, (0, utils_1.listFilesInFolder)(serviceFolder)
341
341
  // Checks if file in sasjsbuild folder exists in source folder.
342
342
  // If not, it means that the file shouldn't be compiled.
343
343
  ];
344
344
  case 2:
345
- filesNamesInPath = _a.sent();
345
+ sourceFiles = _a.sent();
346
346
  // Checks if file in sasjsbuild folder exists in source folder.
347
347
  // If not, it means that the file shouldn't be compiled.
348
- return [4 /*yield*/, (0, utils_1.asyncForEach)(filesNamesInPath, function (fileName, i) { return __awaiter(void 0, void 0, void 0, function () {
348
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName, i) { return __awaiter(void 0, void 0, void 0, function () {
349
349
  return __generator(this, function (_a) {
350
350
  switch (_a.label) {
351
351
  case 0: return [4 /*yield*/, (0, utils_1.fileExists)(path_1.default.join(serviceFolder, fileName))];
352
352
  case 1:
353
353
  if (!(_a.sent())) {
354
- filesNamesInPath.splice(i, 1);
354
+ sourceFiles.splice(i, 1);
355
355
  }
356
356
  return [2 /*return*/];
357
357
  }
@@ -361,7 +361,7 @@ var compileServiceFolder = function (target, serviceFolder, macroFolders, progra
361
361
  // Checks if file in sasjsbuild folder exists in source folder.
362
362
  // If not, it means that the file shouldn't be compiled.
363
363
  _a.sent();
364
- return [4 /*yield*/, (0, utils_1.asyncForEach)(filesNamesInPath, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
364
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
365
365
  var filePath;
366
366
  return __generator(this, function (_a) {
367
367
  switch (_a.label) {
@@ -383,15 +383,15 @@ var compileServiceFolder = function (target, serviceFolder, macroFolders, progra
383
383
  case 4:
384
384
  _a.sent();
385
385
  return [4 /*yield*/, (0, utils_1.asyncForEach)(subFolders, function (subFolder) { return __awaiter(void 0, void 0, void 0, function () {
386
- var sourceFolder, fileNames;
386
+ var sourceFolder, sourceFiles;
387
387
  return __generator(this, function (_a) {
388
388
  switch (_a.label) {
389
389
  case 0:
390
390
  sourceFolder = path_1.default.join(serviceFolder, subFolder);
391
391
  return [4 /*yield*/, (0, utils_1.listFilesInFolder)(sourceFolder)];
392
392
  case 1:
393
- fileNames = _a.sent();
394
- return [4 /*yield*/, (0, utils_1.asyncForEach)(fileNames, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
393
+ sourceFiles = _a.sent();
394
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
395
395
  var filePath;
396
396
  return __generator(this, function (_a) {
397
397
  switch (_a.label) {
@@ -424,7 +424,7 @@ var compileServiceFolder = function (target, serviceFolder, macroFolders, progra
424
424
  });
425
425
  }); };
426
426
  var compileJobFolder = function (target, jobFolder, macroFolders, programFolders, compileTree) { return __awaiter(void 0, void 0, void 0, function () {
427
- var destinationPath, subFolders, filesNamesInPath;
427
+ var destinationPath, subFolders, sourceFiles;
428
428
  return __generator(this, function (_a) {
429
429
  switch (_a.label) {
430
430
  case 0:
@@ -437,16 +437,16 @@ var compileJobFolder = function (target, jobFolder, macroFolders, programFolders
437
437
  // If not, it means that the file shouldn't be compiled.
438
438
  ];
439
439
  case 2:
440
- filesNamesInPath = _a.sent();
440
+ sourceFiles = _a.sent();
441
441
  // Checks if file in sasjsbuild folder exists in source folder.
442
442
  // If not, it means that the file shouldn't be compiled.
443
- return [4 /*yield*/, (0, utils_1.asyncForEach)(filesNamesInPath, function (fileName, i) { return __awaiter(void 0, void 0, void 0, function () {
443
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName, i) { return __awaiter(void 0, void 0, void 0, function () {
444
444
  return __generator(this, function (_a) {
445
445
  switch (_a.label) {
446
446
  case 0: return [4 /*yield*/, (0, utils_1.fileExists)(path_1.default.join(jobFolder, fileName))];
447
447
  case 1:
448
448
  if (!(_a.sent())) {
449
- filesNamesInPath.splice(i, 1);
449
+ sourceFiles.splice(i, 1);
450
450
  }
451
451
  return [2 /*return*/];
452
452
  }
@@ -456,7 +456,7 @@ var compileJobFolder = function (target, jobFolder, macroFolders, programFolders
456
456
  // Checks if file in sasjsbuild folder exists in source folder.
457
457
  // If not, it means that the file shouldn't be compiled.
458
458
  _a.sent();
459
- return [4 /*yield*/, (0, utils_1.asyncForEach)(filesNamesInPath, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
459
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
460
460
  var filePath;
461
461
  return __generator(this, function (_a) {
462
462
  switch (_a.label) {
@@ -478,15 +478,15 @@ var compileJobFolder = function (target, jobFolder, macroFolders, programFolders
478
478
  case 4:
479
479
  _a.sent();
480
480
  return [4 /*yield*/, (0, utils_1.asyncForEach)(subFolders, function (subFolder) { return __awaiter(void 0, void 0, void 0, function () {
481
- var sourcePath, fileNames;
481
+ var sourcePath, sourceFiles;
482
482
  return __generator(this, function (_a) {
483
483
  switch (_a.label) {
484
484
  case 0:
485
485
  sourcePath = path_1.default.join(jobFolder, subFolder);
486
- return [4 /*yield*/, (0, utils_1.listFilesInFolder)(path_1.default.join(jobFolder, subFolder))];
486
+ return [4 /*yield*/, (0, utils_1.listFilesInFolder)(sourcePath)];
487
487
  case 1:
488
- fileNames = _a.sent();
489
- return [4 /*yield*/, (0, utils_1.asyncForEach)(fileNames, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
488
+ sourceFiles = _a.sent();
489
+ return [4 /*yield*/, (0, utils_1.asyncForEach)(sourceFiles, function (fileName) { return __awaiter(void 0, void 0, void 0, function () {
490
490
  var filePath;
491
491
  return __generator(this, function (_a) {
492
492
  switch (_a.label) {
@@ -1,4 +1,15 @@
1
1
  import { CompileTree } from '@sasjs/utils';
2
2
  import { Target, ServerType, SASJsFileType } from '@sasjs/utils/types';
3
+ /**
4
+ * Compiles file dependencies.
5
+ * @param {Target} target - SAS server configuration.
6
+ * @param {string} filePath - file path of the file to be compiled.
7
+ * @param {string[]} macroFolders - macro folders paths.
8
+ * @param {string[]} programFolders - program folders paths.
9
+ * @param {string} programVar - program variable.
10
+ * @param {object} compileTree - compilation tree that stores used compilation assets.
11
+ * @param {SASJsFileType} fileType - sasjs file type.
12
+ * @param {string} sourceFolder - folder path of the source folder.
13
+ */
3
14
  export declare function compileFile(target: Target, filePath: string, macroFolders: string[], programFolders: string[], programVar: string | undefined, compileTree: CompileTree, fileType: SASJsFileType, sourceFolder: string): Promise<void>;
4
15
  export declare function getPreCodeForServicePack(serverType: ServerType): Promise<string>;
@@ -46,6 +46,17 @@ var error_1 = require("@sasjs/utils/error");
46
46
  var loadDependencies_1 = require("./loadDependencies");
47
47
  var getServerType_1 = require("./getServerType");
48
48
  var path_1 = __importDefault(require("path"));
49
+ /**
50
+ * Compiles file dependencies.
51
+ * @param {Target} target - SAS server configuration.
52
+ * @param {string} filePath - file path of the file to be compiled.
53
+ * @param {string[]} macroFolders - macro folders paths.
54
+ * @param {string[]} programFolders - program folders paths.
55
+ * @param {string} programVar - program variable.
56
+ * @param {object} compileTree - compilation tree that stores used compilation assets.
57
+ * @param {SASJsFileType} fileType - sasjs file type.
58
+ * @param {string} sourceFolder - folder path of the source folder.
59
+ */
49
60
  function compileFile(target, filePath, macroFolders, programFolders, programVar, compileTree, fileType, sourceFolder) {
50
61
  if (programVar === void 0) { programVar = ''; }
51
62
  return __awaiter(this, void 0, void 0, function () {
@@ -298,11 +298,12 @@ function printHelpText() {
298
298
  title: 'test',
299
299
  description: [
300
300
  "Triggers SAS unit tests.",
301
- "[2spaces]command example: sasjs test <filteringString> --source <testFlowPath> --outDirectory <folderPath> -t <targetName>",
301
+ "[2spaces]command example: sasjs test <filteringString> --source <testFlowPath> --outDirectory <folderPath> -t <targetName> --force",
302
302
  "",
303
303
  "[2spaces]NOTE: Providing <filteringString> is optional. If not present, all tests mentioned in test flow file will be executed.",
304
304
  "[2spaces]NOTE: Providing source flag is optional. If not present, CLI will use test flow located at sasjsbuild/testFlow.json.",
305
- "[2spaces]NOTE: Providing outDirectory flag is optional. If not present, CLI will use save outputs into sasjsresults folder."
305
+ "[2spaces]NOTE: Providing outDirectory flag is optional. If not present, CLI will use save outputs into sasjsresults folder.",
306
+ "[2spaces]NOTE: Providing force (--force or -f) flag is optional. If present, CLI will force command to finish running all tests and will not return an error code even when some are failing. Useful when the requirement is not to make CI Pipeline fail."
306
307
  ]
307
308
  }
308
309
  ];
@@ -127,7 +127,8 @@ describe('TestCommand', function () {
127
127
  '--outDirectory',
128
128
  'path-to-out',
129
129
  '--source',
130
- 'path-to-source'
130
+ 'path-to-source',
131
+ '--force'
131
132
  ], false);
132
133
  command = new testCommand_1.TestCommand(args);
133
134
  return [4 /*yield*/, command.getTargetInfo()];
@@ -155,7 +156,8 @@ describe('TestCommand', function () {
155
156
  '--out',
156
157
  'path-to-out',
157
158
  '-s',
158
- 'path-to-source'
159
+ 'path-to-source',
160
+ '-f'
159
161
  ], false);
160
162
  command = new testCommand_1.TestCommand(args);
161
163
  return [4 /*yield*/, command.getTargetInfo()];
@@ -179,7 +181,7 @@ describe('TestCommand', function () {
179
181
  return [4 /*yield*/, command.execute()];
180
182
  case 1:
181
183
  _a.sent();
182
- expect(testModule.runTest).toHaveBeenCalledWith(target, undefined, undefined, undefined);
184
+ expect(testModule.runTest).toHaveBeenCalledWith(target, undefined, undefined, undefined, false);
183
185
  return [2 /*return*/];
184
186
  }
185
187
  });
@@ -217,7 +217,7 @@ describe('sasjs test', function () {
217
217
  ]
218
218
  };
219
219
  expectedResultsCsv = "test_target,test_loc,sasjs_test_id,test_suite_result,test_description,test_url\ntestsetup,tests/testsetup.sas,sasjs_test_id,not provided,,".concat(testUrlLink('testsetup'), "\nexampleprogram,tests/jobs/jobs/exampleprogram.test.sas,sasjs_test_id,not provided,,").concat(testUrlLink('jobs/jobs/exampleprogram.test'), "\nstandalone,tests/jobs/jobs/standalone.test.sas,sasjs_test_id,not provided,,").concat(testUrlLink('jobs/jobs/standalone.test'), "\nexamplemacro,tests/macros/examplemacro.test.sas,sasjs_test_id,PASS,examplemacro test.1 description,").concat(testUrlLink('macros/examplemacro.test'), "\ndostuff,tests/services/admin/dostuff.test.0.sas,sasjs_test_id,FAIL,dostuff 0 test description,").concat(testUrlLink('services/admin/dostuff.test.0'), "\ndostuff,tests/services/admin/dostuff.test.1.sas,sasjs_test_id,PASS,dostuff 1 test description,").concat(testUrlLink('services/admin/dostuff.test.1'), "\ntestteardown,tests/testteardown.sas,sasjs_test_id,not provided,,").concat(testUrlLink('testteardown'), "\n");
220
- return [4 /*yield*/, (0, test_1.runTest)(target)];
220
+ return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined, true)];
221
221
  case 1:
222
222
  _a.sent();
223
223
  resultsFolderPath = path_1.default.join(__dirname, target.name, 'sasjsresults');
@@ -330,7 +330,7 @@ describe('sasjs test', function () {
330
330
  return [4 /*yield*/, (0, utils_1.copy)(path_1.default.join(__dirname, target.name, 'sasjsbuild', 'testFlow.json'), path_1.default.join(__dirname, target.name, movedTestFlow))];
331
331
  case 1:
332
332
  _a.sent();
333
- return [4 /*yield*/, (0, test_1.runTest)(target, ['jobs/standalone', 'shouldFail', 'services/admin/dostuff.test.0'], outputFolder, movedTestFlow)];
333
+ return [4 /*yield*/, (0, test_1.runTest)(target, ['jobs/standalone', 'shouldFail', 'services/admin/dostuff.test.0'], outputFolder, movedTestFlow, true)];
334
334
  case 2:
335
335
  _a.sent();
336
336
  resultsFolderPath = path_1.default.join(__dirname, target.name, outputFolder);
@@ -531,7 +531,7 @@ describe('sasjs test', function () {
531
531
  ]
532
532
  };
533
533
  expectedResultsCsv = "test_target,test_loc,sasjs_test_id,test_suite_result,test_description,test_url\ntestsetup,tests/testsetup.sas,sasjs_test_id,not provided,,".concat(testUrlLink('testsetup'), "\nexampleprogram,tests/jobs/jobs/exampleprogram.test.sas,sasjs_test_id,not provided,,").concat(testUrlLink('jobs/jobs/exampleprogram.test'), "\nstandalone,tests/jobs/jobs/standalone.test.sas,sasjs_test_id,not provided,,").concat(testUrlLink('jobs/jobs/standalone.test'), "\nexamplemacro,tests/macros/examplemacro.test.sas,sasjs_test_id,PASS,examplemacro test.1 description,").concat(testUrlLink('macros/examplemacro.test'), "\nshouldFail,tests/macros/shouldFail.test.sas,sasjs_test_id,not provided,,").concat(testUrlLink('macros/shouldFail.test'), "\ndostuff,tests/services/admin/dostuff.test.0.sas,sasjs_test_id,FAIL,dostuff 0 test description,").concat(testUrlLink('services/admin/dostuff.test.0'), "\ndostuff,tests/services/admin/dostuff.test.1.sas,sasjs_test_id,PASS,dostuff 1 test description,").concat(testUrlLink('services/admin/dostuff.test.1'), "\ntestteardown,tests/testteardown.sas,sasjs_test_id,not provided,,").concat(testUrlLink('testteardown'), "\n");
534
- return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined)];
534
+ return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined, true)];
535
535
  case 1:
536
536
  _a.sent();
537
537
  resultsFolderPath = path_1.default.join(__dirname, target.name, 'sasjsresults');
@@ -591,7 +591,7 @@ describe('sasjs test', function () {
591
591
  jest.spyOn(fileModule, 'readFile').mockImplementation(function () {
592
592
  return Promise.resolve("{\n \"tests\": [\n \"tests/macros/".concat(testService, ".test.sas\"\n ],\n \"testSetUp\": \"\",\n \"testTearDown\": \"\"\n}"));
593
593
  });
594
- return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined)];
594
+ return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined, true)];
595
595
  case 1:
596
596
  _a.sent();
597
597
  expect(process.logger.table).toHaveBeenCalledWith([['uuidv4', testService, chalk_1.default.redBright(types_1.TestResultStatus.fail)]], { head: ['SASjs Test ID', 'Test Target', 'Test Suite Result'] });
@@ -599,6 +599,34 @@ describe('sasjs test', function () {
599
599
  }
600
600
  });
601
601
  }); });
602
+ it('should fail on tests failing', function () { return __awaiter(void 0, void 0, void 0, function () {
603
+ var error;
604
+ return __generator(this, function (_a) {
605
+ switch (_a.label) {
606
+ case 0: return [4 /*yield*/, (0, test_1.runTest)(target).catch(function (err) {
607
+ return err;
608
+ })];
609
+ case 1:
610
+ error = _a.sent();
611
+ expect(error).toEqual('6 tests completed with failures!');
612
+ return [2 /*return*/];
613
+ }
614
+ });
615
+ }); });
616
+ it('should not throw error on tests failing', function () { return __awaiter(void 0, void 0, void 0, function () {
617
+ var error;
618
+ return __generator(this, function (_a) {
619
+ switch (_a.label) {
620
+ case 0: return [4 /*yield*/, (0, test_1.runTest)(target, undefined, undefined, undefined, true).catch(function (err) {
621
+ return err;
622
+ })];
623
+ case 1:
624
+ error = _a.sent();
625
+ expect(error).toBeUndefined();
626
+ return [2 /*return*/];
627
+ }
628
+ });
629
+ }); });
602
630
  });
603
631
  });
604
632
  function generateTarget(serverType) {
@@ -1,3 +1,3 @@
1
1
  import { Target } from '@sasjs/utils';
2
- export declare function runTest(target: Target, testRegExps?: string[], outDirectory?: string, flowSourcePath?: string): Promise<undefined>;
2
+ export declare function runTest(target: Target, testRegExps?: string[], outDirectory?: string, flowSourcePath?: string, force?: boolean): Promise<undefined>;
3
3
  export declare const getTestUrl: (target: Target, jobLocation: string) => string;
@@ -87,11 +87,11 @@ var chalk_1 = __importDefault(require("chalk"));
87
87
  var utils_2 = require("../../utils/utils");
88
88
  var createSASjsInstance_1 = require("../../utils/createSASjsInstance");
89
89
  // interface
90
- function runTest(target, testRegExps, outDirectory, flowSourcePath) {
90
+ function runTest(target, testRegExps, outDirectory, flowSourcePath, force) {
91
91
  var _a, _b;
92
92
  if (testRegExps === void 0) { testRegExps = []; }
93
93
  return __awaiter(this, void 0, void 0, function () {
94
- var testFlowData, testFlow, flow, sasjs, authConfig, username, password, _c, sas9CredentialsError, e_1, result, isCodeExamplePrinted, printCodeExample, jsonPath, xmlPath, _d, csvData, csvPath, coverageReportPath, resultTable, testSuites, testsCount, passedTestsCount, testsWithResultsCount;
94
+ var testFlowData, testFlow, flow, sasjs, authConfig, username, password, _c, sas9CredentialsError, e_1, result, isCodeExamplePrinted, printCodeExample, jsonPath, xmlPath, _d, csvData, csvPath, coverageReportPath, resultTable, testSuites, testsCount, passedTestsCount, testsWithResultsCount, failedTestsCount, testsWithoutResultCount, errorMessage;
95
95
  var _this = this;
96
96
  return __generator(this, function (_e) {
97
97
  switch (_e.label) {
@@ -394,6 +394,17 @@ function runTest(target, testRegExps, outDirectory, flowSourcePath) {
394
394
  (_b = process.logger) === null || _b === void 0 ? void 0 : _b.info("Tests provided results: ".concat(testsWithResultsCount + '/' + testsCount, " (").concat(chalk_1.default.greenBright(Math.round((testsWithResultsCount / testsCount) * 100 || 0) + '%'), ")\n Tests that pass: ").concat(passedTestsCount + '/' + testsWithResultsCount, " (").concat(chalk_1.default.greenBright(Math.round((passedTestsCount / testsWithResultsCount) * 100 || 0) + '%'), ")\n "));
395
395
  (0, displayResult_1.displaySuccess)("Tests execution finished. The results are stored at:\n ".concat(jsonPath, "\n ").concat(csvPath, "\n ").concat(xmlPath));
396
396
  (0, displayResult_1.displaySuccess)("Tests coverage report:\n ".concat(coverageReportPath));
397
+ if (!force) {
398
+ failedTestsCount = testsWithResultsCount - passedTestsCount;
399
+ testsWithoutResultCount = testsCount - testsWithResultsCount;
400
+ errorMessage = '';
401
+ if (testsWithoutResultCount > 0)
402
+ errorMessage = "".concat(testsWithoutResultCount, " ").concat(testsWithoutResultCount === 1 ? 'test' : 'tests', " failed to complete!\n");
403
+ if (failedTestsCount > 0)
404
+ errorMessage += "".concat(failedTestsCount, " ").concat(failedTestsCount === 1 ? 'test' : 'tests', " completed with failures!");
405
+ if (errorMessage)
406
+ return [2 /*return*/, Promise.reject(errorMessage)];
407
+ }
397
408
  return [2 /*return*/];
398
409
  }
399
410
  });
@@ -57,15 +57,15 @@ var targetCommand_1 = require("../../types/command/targetCommand");
57
57
  var utils_1 = require("../../utils");
58
58
  var test_1 = require("./test");
59
59
  var syntax = 'test [filteringString..]';
60
- var usage = 'Usage: sasjs test [filtering-strings..] --source <test-flow-path> --outDirectory <folder-path> --target <target-name>';
60
+ var usage = 'Usage: sasjs test [filtering-strings..] --source <test-flow-path> --outDirectory <folder-path> --target <target-name> --force';
61
61
  var description = 'Triggers SAS unit tests.';
62
62
  var examples = [
63
63
  {
64
- command: 'sasjs test jobs/standalone1 jobs/standalone2 --source <test-flow-path> --outDirectory <folder-path> --target <target-name>',
64
+ command: 'sasjs test jobs/standalone1 jobs/standalone2 --source <test-flow-path> --outDirectory <folder-path> --target <target-name> --force',
65
65
  description: ''
66
66
  },
67
67
  {
68
- command: 'sasjs test jobs/standalone1 jobs/standalone2 -s <test-flow-path> --out <folder-path> --t <target-name>',
68
+ command: 'sasjs test jobs/standalone1 jobs/standalone2 -s <test-flow-path> --out <folder-path> -t <target-name> -f',
69
69
  description: ''
70
70
  }
71
71
  ];
@@ -77,12 +77,18 @@ var TestCommand = /** @class */ (function (_super) {
77
77
  outDirectory: {
78
78
  type: 'string',
79
79
  alias: 'out',
80
- description: 'Path to output folder for tests resuls.'
80
+ description: 'Path to output folder for tests results.'
81
81
  },
82
82
  source: {
83
83
  type: 'string',
84
84
  alias: 's',
85
85
  description: 'Test flow located at source will be executed.'
86
+ },
87
+ force: {
88
+ type: 'boolean',
89
+ default: false,
90
+ alias: 'f',
91
+ description: 'If present, CLI will force command to finish running all tests and will not return an error code even when some are failing.'
86
92
  }
87
93
  },
88
94
  syntax: syntax,
@@ -93,14 +99,14 @@ var TestCommand = /** @class */ (function (_super) {
93
99
  }
94
100
  TestCommand.prototype.execute = function () {
95
101
  return __awaiter(this, void 0, void 0, function () {
96
- var target, _a, filteringString, outDirectory, source;
102
+ var target, _a, filteringString, outDirectory, source, force;
97
103
  return __generator(this, function (_b) {
98
104
  switch (_b.label) {
99
105
  case 0: return [4 /*yield*/, this.getTargetInfo()];
100
106
  case 1:
101
107
  target = (_b.sent()).target;
102
- _a = this.parsed, filteringString = _a.filteringString, outDirectory = _a.outDirectory, source = _a.source;
103
- return [4 /*yield*/, (0, test_1.runTest)(target, filteringString, outDirectory, source)
108
+ _a = this.parsed, filteringString = _a.filteringString, outDirectory = _a.outDirectory, source = _a.source, force = _a.force;
109
+ return [4 /*yield*/, (0, test_1.runTest)(target, filteringString, outDirectory, source, force)
104
110
  .then(function () {
105
111
  return command_1.ReturnCode.Success;
106
112
  })
@@ -1 +1 @@
1
- export declare const sasjsout = "\n%macro sasjsout(type,fref=sasjs);\n%global sysprocessmode SYS_JES_JOB_URI;\n%if \"&sysprocessmode\"=\"SAS Compute Server\" %then %do;\n %if &type=HTML %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name=\"_webout.json\"\n contenttype=\"text/html\";\n %end;\n %else %if &type=JS or &type=JS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.js'\n contenttype='application/javascript';\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.css'\n contenttype='text/css';\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n name=\"_webout.%lowcase(&type)\"\n contenttype=\"image/%lowcase(&type)\" lrecl=2000000 recfm=n;\n %end;\n %else %if &type=ICO %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ico'\n contenttype='image/vnd.microsoft.icon' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=JSON %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.json'\n contenttype='application/json' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=MP3 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.mp3'\n contenttype='audio/mpeg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WAV %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.wav'\n contenttype='audio/x-wav' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=OGG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ogg'\n contenttype='audio/ogg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"font/%lowcase(&type)\";\n %end;\n %else %if &type=MP4 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"video/mp4\";\n %end;\n%end;\n%else %do;\n %if &type=JS or &type=JS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(\n Content-type,application/javascript%str(;)charset=UTF-8\n ));\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,text/css));\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/%lowcase(&type)));\n %end;\n %else %if &type=ICO %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/vnd.microsoft.icon));\n %end;\n %else %if &type=JSON %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,application/json));\n %end;\n %else %if &type=MP3 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/mpeg));\n %end;\n %else %if &type=WAV %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/x-wav));\n %end;\n %else %if &type=OGG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/ogg));\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,font/%lowcase(&type)));\n %end;\n %else %if &type=MP4 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,video/mp4));\n %end;\n%end;\n%if &type=HTML %then %do;\n /*\n We need to perform some substitutions -eg to get the APPLOC and SERVERTYPE.\n Therefore the developer should avoid writing lines that exceed 32k\n characters (eg base64 encoded images) as they will get truncated when passing\n through the datastep. This could of course be re-written using LUA, removing\n the length restriction. Pull requests are welcome!\n */\n filename _sjs temp;\n data _null_;\n file _sjs lrecl=32767 encoding='utf-8';\n infile &fref lrecl=32767;\n input;\n length appLoc expanded_path $1048;\n if _n_=1 then do;\n retain pgm \"&_program\" appLoc expanded_path;\n /* index is deployed in the /services/ folder under the appLoc */\n appLoc=substr(pgm,1,find(pgm,'/services/')-1);\n expanded_path=cats('?_PROGRAM=',appLoc,'/services/');\n end;\n if find(_infile_,' appLoc: ') then put ' appLoc: ' apploc:$quote1048. ',';\n else if find(_infile_,' serverType: ') then do;\n if symexist('_metaperson') then put ' serverType: \"SAS9\" ,';\n else put ' serverType: \"SASVIYA\" ,';\n end;\n else if find(_infile_,' hostUrl: ') then do;\n /* nothing - we are streaming, so remove to default as hostname */\n end;\n else do;\n length newline $32767;\n /* during SAS9 compilation, dependencies are assigned three slashes /// */\n newline=tranwrd(_infile_,'?_PROGRAM=///',cats(expanded_path));\n put newline;\n end;\n run;\n %let fref=_sjs;\n%end;\n\n/**\n * In SAS9, JS & CSS files are base64 encoded to avoid UTF8 issues in WLATIN1\n * metadata - so in this case, decode and stream byte by byte.\n * */\n%if &type=GIF or &type=PNG or &type=JPG or &type=JPEG or &type=ICO or &type=MP3\nor &type=JS64 or &type=CSS64 or &type=WAV or &type=OGG or &type=WOFF\nor &type=WOFF2 or &type=TTF or &type=MP4\n%then %do;\n data _null_;\n length filein 8 fileout 8;\n filein = fopen(\"&fref\",'I',4,'B');\n fileout = fopen(\"_webout\",'A',1,'B');\n char= '20'x;\n do while(fread(filein)=0);\n length raw $4 ;\n do i=1 to 4;\n rc=fget(filein,char,1);\n substr(raw,i,1)=char;\n end;\n rc = fput(fileout, input(raw,$base64X4.));\n rc =fwrite(fileout);\n end;\n rc = fclose(filein);\n rc = fclose(fileout);\n run;\n%end;\n%else %do;\n data _null_;\n length filein 8 fileid 8;\n filein = fopen(\"&fref\",'I',1,'B');\n fileid = fopen(\"_webout\",'A',1,'B');\n rec = '20'x;\n do while(fread(filein)=0);\n rc = fget(filein,rec,1);\n rc = fput(fileid, rec);\n rc =fwrite(fileid);\n end;\n rc = fclose(filein);\n rc = fclose(fileid);\n run;\n%end;\n%mend;";
1
+ export declare const sasjsout = "\n%macro sasjsout(type,fref=sasjs);\n%global sysprocessmode SYS_JES_JOB_URI;\n%if \"&sysprocessmode\"=\"SAS Compute Server\" %then %do;\n %if &type=HTML %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name=\"_webout.json\"\n contenttype=\"text/html\";\n %end;\n %else %if &type=JS or &type=JS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.js'\n contenttype='application/javascript';\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.css'\n contenttype='text/css';\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n name=\"_webout.%lowcase(&type)\"\n contenttype=\"image/%lowcase(&type)\" lrecl=2000000 recfm=n;\n %end;\n %else %if &type=ICO %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ico'\n contenttype='image/vnd.microsoft.icon' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=JSON %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.json'\n contenttype='application/json' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=MP3 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.mp3'\n contenttype='audio/mpeg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WAV %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.wav'\n contenttype='audio/x-wav' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=OGG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ogg'\n contenttype='audio/ogg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"font/%lowcase(&type)\";\n %end;\n %else %if &type=MP4 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"video/mp4\";\n %end;\n%end;\n%else %do;\n %if &type=JS or &type=JS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(\n Content-type,application/javascript%str(;)charset=UTF-8\n ));\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,text/css));\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/%lowcase(&type)));\n %end;\n %else %if &type=ICO %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/vnd.microsoft.icon));\n %end;\n %else %if &type=JSON %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,application/json));\n %end;\n %else %if &type=MP3 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/mpeg));\n %end;\n %else %if &type=WAV %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/x-wav));\n %end;\n %else %if &type=OGG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/ogg));\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,font/%lowcase(&type)));\n %end;\n %else %if &type=MP4 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,video/mp4));\n %end;\n%end;\n%if &type=HTML %then %do;\n /*\n We need to perform some substitutions -eg to get the APPLOC and SERVERTYPE.\n Therefore the developer should avoid writing lines that exceed 32k\n characters (eg base64 encoded images) as they will get truncated when passing\n through the datastep. This could of course be re-written using LUA, removing\n the length restriction. Pull requests are welcome!\n */\n filename _sjs temp;\n data _null_;\n file _sjs lrecl=32767 encoding='utf-8';\n infile &fref lrecl=32767;\n input;\n length appLoc expanded_path $1048;\n if _n_=1 then do;\n retain pgm \"&_program\" appLoc expanded_path;\n /* index is deployed in the /services/ folder under the appLoc */\n appLoc=substr(pgm,1,find(pgm,'/services/')-1);\n expanded_path=cats('?_PROGRAM=',appLoc,'/services/');\n end;\n if find(_infile_,' appLoc: ') then put ' appLoc: ' apploc:$quote1048. ',';\n else if find(_infile_,' serverType: ') then do;\n if symexist('_metaperson') then put ' serverType: \"SAS9\" ,';\n else put ' serverType: \"SASVIYA\" ,';\n end;\n else if find(_infile_,' serverUrl: ') then do;\n /* nothing - we are streaming, so remove to default as hostname */\n end;\n else do;\n /* More recently, SASjs apps avoid inline JS to allow strict CSP */\n length infile in1 in2 $32767;\n infile=cats(_infile_);\n spos1=index(upcase(infile),'APPLOC=\"');\n if spos1>0 then do;\n in1=substr(infile,1,spos1+7);\n in2=subpad(infile,spos1+8);\n in2=substr(in2,index(in2,'\"'));\n infile=cats(in1,appLoc,in2);\n putlog \"new apploc: \" infile=;\n end;\n /* find & replace serverType in HTML attributes */\n spos2=index(upcase(infile),'SERVERTYPE=\"');\n if spos2>0 then do;\n in1=substr(infile,1,spos2+11);\n in2=subpad(infile,spos2+12);\n in2=substr(in2,index(in2,'\"'));\n if symexist('sasjsprocessmode') then infile=cats(in1,\"SASJS\",in2);\n else if \"&sysprocessmode\"=\"SAS Object Server\"\n or \"&sysprocessmode\"= \"SAS Compute Server\"\n then infile=cats(in1,\"SASVIYA\",in2);\n else infile=cats(in1,\"SAS9\",in2);\n putlog \"new servertype: \" infile=;\n end;\n /* find & replace serverUrl in HTML attributes */\n spos3=index(upcase(infile),'SERVERURL=\"');\n if spos3>0 then do;\n in1=substr(infile,1,spos3+10);\n in2=subpad(infile,spos3+11);\n in2=substr(in2,index(in2,'\"'));\n infile=cats(in1,in2);\n putlog \"new serverUrl: \" infile=;\n end;\n if sum(spos1,spos2,spos3)>0 then put infile;\n else do;\n /* during SAS9 sasjs compile, dependencies get three slashes /// */\n infile=tranwrd(_infile_,'?_PROGRAM=///',cats(expanded_path));\n put infile;\n end;\n end;\n run;\n %let fref=_sjs;\n%end;\n\n/**\n * In SAS9, JS & CSS files are base64 encoded to avoid UTF8 issues in WLATIN1\n * metadata - so in this case, decode and stream byte by byte.\n * */\n%if &type=GIF or &type=PNG or &type=JPG or &type=JPEG or &type=ICO or &type=MP3\nor &type=JS64 or &type=CSS64 or &type=WAV or &type=OGG or &type=WOFF\nor &type=WOFF2 or &type=TTF or &type=MP4\n%then %do;\n data _null_;\n length filein 8 fileout 8;\n filein = fopen(\"&fref\",'I',4,'B');\n fileout = fopen(\"_webout\",'A',1,'B');\n char= '20'x;\n do while(fread(filein)=0);\n length raw $4 ;\n do i=1 to 4;\n rc=fget(filein,char,1);\n substr(raw,i,1)=char;\n end;\n rc = fput(fileout, input(raw,$base64X4.));\n rc =fwrite(fileout);\n end;\n rc = fclose(filein);\n rc = fclose(fileout);\n run;\n%end;\n%else %do;\n data _null_;\n length filein 8 fileid 8;\n filein = fopen(\"&fref\",'I',1,'B');\n fileid = fopen(\"_webout\",'A',1,'B');\n rec = '20'x;\n do while(fread(filein)=0);\n rc = fget(filein,rec,1);\n rc = fput(fileid, rec);\n rc =fwrite(fileid);\n end;\n rc = fclose(filein);\n rc = fclose(fileid);\n run;\n%end;\n%mend;";
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.sasjsout = void 0;
4
- exports.sasjsout = "\n%macro sasjsout(type,fref=sasjs);\n%global sysprocessmode SYS_JES_JOB_URI;\n%if \"&sysprocessmode\"=\"SAS Compute Server\" %then %do;\n %if &type=HTML %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name=\"_webout.json\"\n contenttype=\"text/html\";\n %end;\n %else %if &type=JS or &type=JS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.js'\n contenttype='application/javascript';\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.css'\n contenttype='text/css';\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n name=\"_webout.%lowcase(&type)\"\n contenttype=\"image/%lowcase(&type)\" lrecl=2000000 recfm=n;\n %end;\n %else %if &type=ICO %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ico'\n contenttype='image/vnd.microsoft.icon' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=JSON %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.json'\n contenttype='application/json' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=MP3 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.mp3'\n contenttype='audio/mpeg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WAV %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.wav'\n contenttype='audio/x-wav' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=OGG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ogg'\n contenttype='audio/ogg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"font/%lowcase(&type)\";\n %end;\n %else %if &type=MP4 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"video/mp4\";\n %end;\n%end;\n%else %do;\n %if &type=JS or &type=JS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(\n Content-type,application/javascript%str(;)charset=UTF-8\n ));\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,text/css));\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/%lowcase(&type)));\n %end;\n %else %if &type=ICO %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/vnd.microsoft.icon));\n %end;\n %else %if &type=JSON %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,application/json));\n %end;\n %else %if &type=MP3 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/mpeg));\n %end;\n %else %if &type=WAV %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/x-wav));\n %end;\n %else %if &type=OGG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/ogg));\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,font/%lowcase(&type)));\n %end;\n %else %if &type=MP4 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,video/mp4));\n %end;\n%end;\n%if &type=HTML %then %do;\n /*\n We need to perform some substitutions -eg to get the APPLOC and SERVERTYPE.\n Therefore the developer should avoid writing lines that exceed 32k\n characters (eg base64 encoded images) as they will get truncated when passing\n through the datastep. This could of course be re-written using LUA, removing\n the length restriction. Pull requests are welcome!\n */\n filename _sjs temp;\n data _null_;\n file _sjs lrecl=32767 encoding='utf-8';\n infile &fref lrecl=32767;\n input;\n length appLoc expanded_path $1048;\n if _n_=1 then do;\n retain pgm \"&_program\" appLoc expanded_path;\n /* index is deployed in the /services/ folder under the appLoc */\n appLoc=substr(pgm,1,find(pgm,'/services/')-1);\n expanded_path=cats('?_PROGRAM=',appLoc,'/services/');\n end;\n if find(_infile_,' appLoc: ') then put ' appLoc: ' apploc:$quote1048. ',';\n else if find(_infile_,' serverType: ') then do;\n if symexist('_metaperson') then put ' serverType: \"SAS9\" ,';\n else put ' serverType: \"SASVIYA\" ,';\n end;\n else if find(_infile_,' hostUrl: ') then do;\n /* nothing - we are streaming, so remove to default as hostname */\n end;\n else do;\n length newline $32767;\n /* during SAS9 compilation, dependencies are assigned three slashes /// */\n newline=tranwrd(_infile_,'?_PROGRAM=///',cats(expanded_path));\n put newline;\n end;\n run;\n %let fref=_sjs;\n%end;\n\n/**\n * In SAS9, JS & CSS files are base64 encoded to avoid UTF8 issues in WLATIN1\n * metadata - so in this case, decode and stream byte by byte.\n * */\n%if &type=GIF or &type=PNG or &type=JPG or &type=JPEG or &type=ICO or &type=MP3\nor &type=JS64 or &type=CSS64 or &type=WAV or &type=OGG or &type=WOFF\nor &type=WOFF2 or &type=TTF or &type=MP4\n%then %do;\n data _null_;\n length filein 8 fileout 8;\n filein = fopen(\"&fref\",'I',4,'B');\n fileout = fopen(\"_webout\",'A',1,'B');\n char= '20'x;\n do while(fread(filein)=0);\n length raw $4 ;\n do i=1 to 4;\n rc=fget(filein,char,1);\n substr(raw,i,1)=char;\n end;\n rc = fput(fileout, input(raw,$base64X4.));\n rc =fwrite(fileout);\n end;\n rc = fclose(filein);\n rc = fclose(fileout);\n run;\n%end;\n%else %do;\n data _null_;\n length filein 8 fileid 8;\n filein = fopen(\"&fref\",'I',1,'B');\n fileid = fopen(\"_webout\",'A',1,'B');\n rec = '20'x;\n do while(fread(filein)=0);\n rc = fget(filein,rec,1);\n rc = fput(fileid, rec);\n rc =fwrite(fileid);\n end;\n rc = fclose(filein);\n rc = fclose(fileid);\n run;\n%end;\n%mend;";
4
+ exports.sasjsout = "\n%macro sasjsout(type,fref=sasjs);\n%global sysprocessmode SYS_JES_JOB_URI;\n%if \"&sysprocessmode\"=\"SAS Compute Server\" %then %do;\n %if &type=HTML %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name=\"_webout.json\"\n contenttype=\"text/html\";\n %end;\n %else %if &type=JS or &type=JS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.js'\n contenttype='application/javascript';\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.css'\n contenttype='text/css';\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n name=\"_webout.%lowcase(&type)\"\n contenttype=\"image/%lowcase(&type)\" lrecl=2000000 recfm=n;\n %end;\n %else %if &type=ICO %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ico'\n contenttype='image/vnd.microsoft.icon' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=JSON %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.json'\n contenttype='application/json' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=MP3 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.mp3'\n contenttype='audio/mpeg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WAV %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.wav'\n contenttype='audio/x-wav' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=OGG %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\" name='_webout.ogg'\n contenttype='audio/ogg' lrecl=2000000 recfm=n;\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"font/%lowcase(&type)\";\n %end;\n %else %if &type=MP4 %then %do;\n filename _webout filesrvc parenturi=\"&SYS_JES_JOB_URI\"\n contenttype=\"video/mp4\";\n %end;\n%end;\n%else %do;\n %if &type=JS or &type=JS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(\n Content-type,application/javascript%str(;)charset=UTF-8\n ));\n %end;\n %else %if &type=CSS or &type=CSS64 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,text/css));\n %end;\n %else %if &type=PNG or &type=GIF or &type=JPEG or &type=JPG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/%lowcase(&type)));\n %end;\n %else %if &type=ICO %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,image/vnd.microsoft.icon));\n %end;\n %else %if &type=JSON %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,application/json));\n %end;\n %else %if &type=MP3 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/mpeg));\n %end;\n %else %if &type=WAV %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/x-wav));\n %end;\n %else %if &type=OGG %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,audio/ogg));\n %end;\n %else %if &type=WOFF or &type=WOFF2 or &type=TTF %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,font/%lowcase(&type)));\n %end;\n %else %if &type=MP4 %then %do;\n %let rc=%sysfunc(stpsrv_header(Content-type,video/mp4));\n %end;\n%end;\n%if &type=HTML %then %do;\n /*\n We need to perform some substitutions -eg to get the APPLOC and SERVERTYPE.\n Therefore the developer should avoid writing lines that exceed 32k\n characters (eg base64 encoded images) as they will get truncated when passing\n through the datastep. This could of course be re-written using LUA, removing\n the length restriction. Pull requests are welcome!\n */\n filename _sjs temp;\n data _null_;\n file _sjs lrecl=32767 encoding='utf-8';\n infile &fref lrecl=32767;\n input;\n length appLoc expanded_path $1048;\n if _n_=1 then do;\n retain pgm \"&_program\" appLoc expanded_path;\n /* index is deployed in the /services/ folder under the appLoc */\n appLoc=substr(pgm,1,find(pgm,'/services/')-1);\n expanded_path=cats('?_PROGRAM=',appLoc,'/services/');\n end;\n if find(_infile_,' appLoc: ') then put ' appLoc: ' apploc:$quote1048. ',';\n else if find(_infile_,' serverType: ') then do;\n if symexist('_metaperson') then put ' serverType: \"SAS9\" ,';\n else put ' serverType: \"SASVIYA\" ,';\n end;\n else if find(_infile_,' serverUrl: ') then do;\n /* nothing - we are streaming, so remove to default as hostname */\n end;\n else do;\n /* More recently, SASjs apps avoid inline JS to allow strict CSP */\n length infile in1 in2 $32767;\n infile=cats(_infile_);\n spos1=index(upcase(infile),'APPLOC=\"');\n if spos1>0 then do;\n in1=substr(infile,1,spos1+7);\n in2=subpad(infile,spos1+8);\n in2=substr(in2,index(in2,'\"'));\n infile=cats(in1,appLoc,in2);\n putlog \"new apploc: \" infile=;\n end;\n /* find & replace serverType in HTML attributes */\n spos2=index(upcase(infile),'SERVERTYPE=\"');\n if spos2>0 then do;\n in1=substr(infile,1,spos2+11);\n in2=subpad(infile,spos2+12);\n in2=substr(in2,index(in2,'\"'));\n if symexist('sasjsprocessmode') then infile=cats(in1,\"SASJS\",in2);\n else if \"&sysprocessmode\"=\"SAS Object Server\"\n or \"&sysprocessmode\"= \"SAS Compute Server\"\n then infile=cats(in1,\"SASVIYA\",in2);\n else infile=cats(in1,\"SAS9\",in2);\n putlog \"new servertype: \" infile=;\n end;\n /* find & replace serverUrl in HTML attributes */\n spos3=index(upcase(infile),'SERVERURL=\"');\n if spos3>0 then do;\n in1=substr(infile,1,spos3+10);\n in2=subpad(infile,spos3+11);\n in2=substr(in2,index(in2,'\"'));\n infile=cats(in1,in2);\n putlog \"new serverUrl: \" infile=;\n end;\n if sum(spos1,spos2,spos3)>0 then put infile;\n else do;\n /* during SAS9 sasjs compile, dependencies get three slashes /// */\n infile=tranwrd(_infile_,'?_PROGRAM=///',cats(expanded_path));\n put infile;\n end;\n end;\n run;\n %let fref=_sjs;\n%end;\n\n/**\n * In SAS9, JS & CSS files are base64 encoded to avoid UTF8 issues in WLATIN1\n * metadata - so in this case, decode and stream byte by byte.\n * */\n%if &type=GIF or &type=PNG or &type=JPG or &type=JPEG or &type=ICO or &type=MP3\nor &type=JS64 or &type=CSS64 or &type=WAV or &type=OGG or &type=WOFF\nor &type=WOFF2 or &type=TTF or &type=MP4\n%then %do;\n data _null_;\n length filein 8 fileout 8;\n filein = fopen(\"&fref\",'I',4,'B');\n fileout = fopen(\"_webout\",'A',1,'B');\n char= '20'x;\n do while(fread(filein)=0);\n length raw $4 ;\n do i=1 to 4;\n rc=fget(filein,char,1);\n substr(raw,i,1)=char;\n end;\n rc = fput(fileout, input(raw,$base64X4.));\n rc =fwrite(fileout);\n end;\n rc = fclose(filein);\n rc = fclose(fileout);\n run;\n%end;\n%else %do;\n data _null_;\n length filein 8 fileid 8;\n filein = fopen(\"&fref\",'I',1,'B');\n fileid = fopen(\"_webout\",'A',1,'B');\n rec = '20'x;\n do while(fread(filein)=0);\n rc = fget(filein,rec,1);\n rc = fput(fileid, rec);\n rc =fwrite(fileid);\n end;\n rc = fclose(filein);\n rc = fclose(fileid);\n run;\n%end;\n%mend;";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Creates a zip file.
3
+ * Having single JSON file in it.
4
+ * @param {string} saveTo - full path to save the file.
5
+ * @param {string} contents - contents of JSON file.
6
+ */
7
+ export declare const compressAndSave: (saveTo: string, contents: string) => Promise<void>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.compressAndSave = void 0;
43
+ var path_1 = __importDefault(require("path"));
44
+ var adm_zip_1 = __importDefault(require("adm-zip"));
45
+ /**
46
+ * Creates a zip file.
47
+ * Having single JSON file in it.
48
+ * @param {string} saveTo - full path to save the file.
49
+ * @param {string} contents - contents of JSON file.
50
+ */
51
+ var compressAndSave = function (saveTo, contents) { return __awaiter(void 0, void 0, void 0, function () {
52
+ var zip, filenameInZip;
53
+ return __generator(this, function (_a) {
54
+ switch (_a.label) {
55
+ case 0:
56
+ zip = new adm_zip_1.default();
57
+ filenameInZip = path_1.default.basename(saveTo, path_1.default.extname(saveTo));
58
+ // add file directly
59
+ zip.addFile(filenameInZip, Buffer.from(contents, 'utf8'), 'entry comment goes here');
60
+ return [4 /*yield*/, zip.writeZipPromise(saveTo, { overwrite: true })];
61
+ case 1:
62
+ _a.sent();
63
+ return [2 /*return*/];
64
+ }
65
+ });
66
+ }); };
67
+ exports.compressAndSave = compressAndSave;
@@ -6,7 +6,8 @@ var builtFiles = function (buildFileName) {
6
6
  folderName: 'sasjsbuild',
7
7
  files: [
8
8
  { fileName: "".concat(buildFileName, ".sas") },
9
- { fileName: "".concat(buildFileName, ".json") }
9
+ { fileName: "".concat(buildFileName, ".json") },
10
+ { fileName: "".concat(buildFileName, ".json.zip") }
10
11
  ],
11
12
  subFolders: [
12
13
  {
@@ -6,7 +6,8 @@ var builtFilesCustom1 = function (buildFileName) {
6
6
  folderName: 'sasjsbuild',
7
7
  files: [
8
8
  { fileName: "".concat(buildFileName, ".sas") },
9
- { fileName: "".concat(buildFileName, ".json") }
9
+ { fileName: "".concat(buildFileName, ".json") },
10
+ { fileName: "".concat(buildFileName, ".json.zip") }
10
11
  ],
11
12
  subFolders: [
12
13
  {
@@ -3,7 +3,7 @@ export * from './config';
3
3
  export * from './displayResult';
4
4
  export * from './file';
5
5
  export * from './loadEnvVariables';
6
- export * from './setProjectDir';
7
6
  export * from './setConstants';
7
+ export * from './setProjectDir';
8
8
  export * from './utils';
9
9
  export * from './validateTargetName';
@@ -15,7 +15,7 @@ __exportStar(require("./config"), exports);
15
15
  __exportStar(require("./displayResult"), exports);
16
16
  __exportStar(require("./file"), exports);
17
17
  __exportStar(require("./loadEnvVariables"), exports);
18
- __exportStar(require("./setProjectDir"), exports);
19
18
  __exportStar(require("./setConstants"), exports);
19
+ __exportStar(require("./setProjectDir"), exports);
20
20
  __exportStar(require("./utils"), exports);
21
21
  __exportStar(require("./validateTargetName"), exports);
package/package.json CHANGED
@@ -51,6 +51,7 @@
51
51
  "@sasjs/core": "4.23.4",
52
52
  "@sasjs/lint": "1.11.2",
53
53
  "@sasjs/utils": "2.44.0",
54
+ "adm-zip": "0.5.9",
54
55
  "chalk": "4.1.2",
55
56
  "csv-stringify": "5.6.5",
56
57
  "dotenv": "10.0.0",
@@ -65,13 +66,14 @@
65
66
  "ora": "5.4.1",
66
67
  "rimraf": "3.0.2",
67
68
  "shelljs": "0.8.5",
68
- "ssl-root-cas": "^1.3.1",
69
+ "ssl-root-cas": "1.3.1",
69
70
  "xml": "1.0.1",
70
71
  "yargs": "17.2.1"
71
72
  },
72
73
  "devDependencies": {
73
74
  "@babel/preset-env": "7.15.6",
74
75
  "@babel/preset-typescript": "7.15.0",
76
+ "@types/adm-zip": "0.5.0",
75
77
  "@types/find": "0.2.1",
76
78
  "@types/jest": "27.0.2",
77
79
  "@types/jsdom": "16.2.13",
@@ -87,11 +89,12 @@
87
89
  "jest-cli": "27.4.7",
88
90
  "jest-extended": "1.1.0",
89
91
  "nodemon": "2.0.15",
92
+ "prettier": "2.6.2",
90
93
  "ts-jest": "27.1.2",
91
94
  "ts-node": "10.4.0",
92
95
  "tslib": "2.3.1",
93
96
  "typescript": "4.5.4",
94
97
  "util": "0.12.4"
95
98
  },
96
- "version": "3.13.4"
99
+ "version": "3.14.0"
97
100
  }