@sasjs/cli 4.18.1 → 4.18.2
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/build/commands/compile/internal/compileTestFile.d.ts +18 -0
- package/build/commands/compile/internal/compileTestFile.js +33 -11
- package/build/commands/compile/internal/spec/compileTestFile.spec.js +117 -0
- package/build/commands/create/spec/create.spec.js +5 -2
- package/build/commands/docs/generateDocs.js +11 -3
- package/build/commands/docs/spec/generateDocs.spec.js +96 -0
- package/build/commands/init/spec/init.spec.js +5 -2
- package/build/commands/job/spec/jobCommand.spec.js +13 -13
- package/build/doxy/Doxyfile +1 -1
- package/build/types/command/spec/targetCommand.spec.d.ts +1 -0
- package/build/types/command/spec/targetCommand.spec.js +118 -0
- package/build/utils/spec/utils.spec.js +191 -0
- package/build/utils/utils.js +26 -10
- package/package.json +1 -1
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import { CompileTree, Target } from '@sasjs/utils';
|
|
2
2
|
import { TestFlow } from '../../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the relative destination fragment for a compiled test file inside
|
|
5
|
+
* `sasjsbuild/tests` - either just the file's basename (saveToRoot, used for
|
|
6
|
+
* testSetUp/testTearDown), or the path fragment following the build
|
|
7
|
+
* destination folder name (used for service/job test files).
|
|
8
|
+
*
|
|
9
|
+
* `filePath` for testSetUp/testTearDown comes straight from a user's
|
|
10
|
+
* sasjsconfig.json, which conventionally uses forward slashes for
|
|
11
|
+
* portability - it is not guaranteed to match the current OS's separator.
|
|
12
|
+
* Splitting on both `/` and `\` (instead of only `path.sep`) means this
|
|
13
|
+
* works whether the config was authored with POSIX-style paths and the CLI
|
|
14
|
+
* is running on Windows (`path.sep === '\\'`) or vice versa. Splitting on
|
|
15
|
+
* `path.sep` alone silently no-ops when the string contains none of that
|
|
16
|
+
* separator, leaving the whole config path intact and producing a nested
|
|
17
|
+
* `sasjsbuild/tests/sasjs/tests/testsetup.sas` instead of a flat
|
|
18
|
+
* `sasjsbuild/tests/testsetup.sas`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const getTestFileDestinationFragment: (filePath: string, buildDestinationFolderName: string | undefined, saveToRoot: boolean) => string;
|
|
3
21
|
export declare function compileTestFile(target: Target, filePath: string, testVar: string | undefined, saveToRoot: boolean | undefined, removeOriginalFile: boolean | undefined, compileTree: CompileTree, destinationPath?: string): Promise<void>;
|
|
4
22
|
export declare function copyTestMacroFiles(folderAbsolutePath: string): Promise<void>;
|
|
5
23
|
export declare const compileTestFlow: (target: Target) => Promise<TestFlow | undefined>;
|
|
@@ -64,7 +64,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
64
64
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
65
65
|
};
|
|
66
66
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
67
|
-
exports.compileTestFlow = exports.copyTestMacroFiles = exports.compileTestFile = void 0;
|
|
67
|
+
exports.compileTestFlow = exports.copyTestMacroFiles = exports.compileTestFile = exports.getTestFileDestinationFragment = void 0;
|
|
68
68
|
var utils_1 = require("@sasjs/utils");
|
|
69
69
|
var chalk_1 = __importDefault(require("chalk"));
|
|
70
70
|
var path_1 = __importDefault(require("path"));
|
|
@@ -73,6 +73,37 @@ var config_1 = require("../../../utils/config");
|
|
|
73
73
|
var file_1 = require("../../../utils/file");
|
|
74
74
|
var _1 = require("./");
|
|
75
75
|
var getFileName = function (filePath) { return path_1.default.parse(filePath).base; };
|
|
76
|
+
/**
|
|
77
|
+
* Resolves the relative destination fragment for a compiled test file inside
|
|
78
|
+
* `sasjsbuild/tests` - either just the file's basename (saveToRoot, used for
|
|
79
|
+
* testSetUp/testTearDown), or the path fragment following the build
|
|
80
|
+
* destination folder name (used for service/job test files).
|
|
81
|
+
*
|
|
82
|
+
* `filePath` for testSetUp/testTearDown comes straight from a user's
|
|
83
|
+
* sasjsconfig.json, which conventionally uses forward slashes for
|
|
84
|
+
* portability - it is not guaranteed to match the current OS's separator.
|
|
85
|
+
* Splitting on both `/` and `\` (instead of only `path.sep`) means this
|
|
86
|
+
* works whether the config was authored with POSIX-style paths and the CLI
|
|
87
|
+
* is running on Windows (`path.sep === '\\'`) or vice versa. Splitting on
|
|
88
|
+
* `path.sep` alone silently no-ops when the string contains none of that
|
|
89
|
+
* separator, leaving the whole config path intact and producing a nested
|
|
90
|
+
* `sasjsbuild/tests/sasjs/tests/testsetup.sas` instead of a flat
|
|
91
|
+
* `sasjsbuild/tests/testsetup.sas`.
|
|
92
|
+
*/
|
|
93
|
+
var getTestFileDestinationFragment = function (filePath, buildDestinationFolderName, saveToRoot) {
|
|
94
|
+
var segments = filePath.split(/[\\/]/);
|
|
95
|
+
var destinationFragment = saveToRoot
|
|
96
|
+
? segments.pop() || ''
|
|
97
|
+
: segments
|
|
98
|
+
.reduce(function (acc, item, i, arr) {
|
|
99
|
+
return acc.length
|
|
100
|
+
? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : arr[i - 1] === buildDestinationFolderName
|
|
101
|
+
? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : acc;
|
|
102
|
+
}, [])
|
|
103
|
+
.join(path_1.default.sep);
|
|
104
|
+
return destinationFragment;
|
|
105
|
+
};
|
|
106
|
+
exports.getTestFileDestinationFragment = getTestFileDestinationFragment;
|
|
76
107
|
function compileTestFile(target, filePath, testVar, saveToRoot, removeOriginalFile, compileTree, destinationPath) {
|
|
77
108
|
if (testVar === void 0) { testVar = ''; }
|
|
78
109
|
if (saveToRoot === void 0) { saveToRoot = true; }
|
|
@@ -100,16 +131,7 @@ function compileTestFile(target, filePath, testVar, saveToRoot, removeOriginalFi
|
|
|
100
131
|
.pop();
|
|
101
132
|
destinationPath =
|
|
102
133
|
destinationPath ||
|
|
103
|
-
path_1.default.join(buildDestinationTestFolder, saveToRoot
|
|
104
|
-
? filePath.split(path_1.default.sep).pop() || ''
|
|
105
|
-
: filePath
|
|
106
|
-
.split(path_1.default.sep)
|
|
107
|
-
.reduce(function (acc, item, i, arr) {
|
|
108
|
-
return acc.length
|
|
109
|
-
? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : arr[i - 1] === buildDestinationFolderName
|
|
110
|
-
? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : acc;
|
|
111
|
-
}, [])
|
|
112
|
-
.join(path_1.default.sep));
|
|
134
|
+
path_1.default.join(buildDestinationTestFolder, (0, exports.getTestFileDestinationFragment)(filePath, buildDestinationFolderName, saveToRoot));
|
|
113
135
|
return [4 /*yield*/, (0, utils_1.createFile)(destinationPath, dependencies)];
|
|
114
136
|
case 4:
|
|
115
137
|
_d.sent();
|
|
@@ -56,6 +56,31 @@ var test_1 = require("../../../../utils/test");
|
|
|
56
56
|
var path_1 = __importDefault(require("path"));
|
|
57
57
|
var compile_1 = require("../../compile");
|
|
58
58
|
var chalk_1 = __importDefault(require("chalk"));
|
|
59
|
+
describe('getTestFileDestinationFragment', function () {
|
|
60
|
+
// sasjsconfig.json testConfig paths (testSetUp/testTearDown) are conventionally
|
|
61
|
+
// forward-slash, regardless of the OS the CLI is running on - these tests pin
|
|
62
|
+
// that a Windows-style host separator doesn't break the flattening/reduce logic
|
|
63
|
+
// when the config value itself uses forward slashes (see PLAN-windows-testsetup-path.md).
|
|
64
|
+
describe('saveToRoot = true (testSetUp/testTearDown)', function () {
|
|
65
|
+
it('flattens a forward-slash config path to its basename', function () {
|
|
66
|
+
expect((0, __1.getTestFileDestinationFragment)('sasjs/tests/testsetup.sas', 'tests', true)).toEqual('testsetup.sas');
|
|
67
|
+
});
|
|
68
|
+
it('flattens a backslash (Windows-native) path to its basename', function () {
|
|
69
|
+
expect((0, __1.getTestFileDestinationFragment)('sasjs\\tests\\testsetup.sas', 'tests', true)).toEqual('testsetup.sas');
|
|
70
|
+
});
|
|
71
|
+
it('returns an empty string for a path ending in a separator', function () {
|
|
72
|
+
expect((0, __1.getTestFileDestinationFragment)('sasjs/tests/', 'tests', true)).toEqual('');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('saveToRoot = false (service/job test files)', function () {
|
|
76
|
+
it('keeps the path fragment after the build destination folder name, for a forward-slash path', function () {
|
|
77
|
+
expect((0, __1.getTestFileDestinationFragment)('sasjsbuild/tests/services/admin/random.test.sas', 'tests', false)).toEqual(['services', 'admin', 'random.test.sas'].join(path_1.default.sep));
|
|
78
|
+
});
|
|
79
|
+
it('keeps the path fragment after the build destination folder name, for a backslash path', function () {
|
|
80
|
+
expect((0, __1.getTestFileDestinationFragment)('sasjsbuild\\tests\\services\\admin\\random.test.sas', 'tests', false)).toEqual(['services', 'admin', 'random.test.sas'].join(path_1.default.sep));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
59
84
|
describe('compileTestFile', function () {
|
|
60
85
|
var appName = "cli-tests-compile-test-file-".concat((0, utils_1.generateTimestamp)());
|
|
61
86
|
var temp = (0, test_1.generateTestTarget)(appName, '/Public/app', {
|
|
@@ -159,6 +184,57 @@ describe('compileTestFile', function () {
|
|
|
159
184
|
}
|
|
160
185
|
});
|
|
161
186
|
}); });
|
|
187
|
+
it('should use default testVar/saveToRoot when omitted', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
188
|
+
var compileTree;
|
|
189
|
+
return __generator(this, function (_a) {
|
|
190
|
+
switch (_a.label) {
|
|
191
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
192
|
+
case 1:
|
|
193
|
+
_a.sent();
|
|
194
|
+
compileTree = (0, __1.getCompileTree)(target);
|
|
195
|
+
return [4 /*yield*/, expect((0, __1.compileTestFile)(target, target.testConfig.testSetUp, undefined, undefined, false, compileTree)).toResolve()];
|
|
196
|
+
case 2:
|
|
197
|
+
_a.sent();
|
|
198
|
+
return [2 /*return*/];
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}); });
|
|
202
|
+
it('should prepend a non-empty testVar to the compiled test file', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
203
|
+
var compileTree, testVar, compiledTestSetUpPath, compiledContent;
|
|
204
|
+
return __generator(this, function (_a) {
|
|
205
|
+
switch (_a.label) {
|
|
206
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
207
|
+
case 1:
|
|
208
|
+
_a.sent();
|
|
209
|
+
compileTree = (0, __1.getCompileTree)(target);
|
|
210
|
+
testVar = '%let some_var=some_value;';
|
|
211
|
+
return [4 /*yield*/, (0, __1.compileTestFile)(target, target.testConfig.testSetUp, testVar, true, false, compileTree)];
|
|
212
|
+
case 2:
|
|
213
|
+
_a.sent();
|
|
214
|
+
compiledTestSetUpPath = path_1.default.join(buildPath, 'tests', 'testsetup.sas');
|
|
215
|
+
return [4 /*yield*/, (0, utils_1.readFile)(compiledTestSetUpPath)];
|
|
216
|
+
case 3:
|
|
217
|
+
compiledContent = _a.sent();
|
|
218
|
+
expect(compiledContent.indexOf(testVar)).toEqual(0);
|
|
219
|
+
return [2 /*return*/];
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}); });
|
|
223
|
+
it('should skip copying a macro test file that is already present in the build folder', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
224
|
+
var macroFolderAbsolutePath;
|
|
225
|
+
return __generator(this, function (_a) {
|
|
226
|
+
switch (_a.label) {
|
|
227
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
228
|
+
case 1:
|
|
229
|
+
_a.sent();
|
|
230
|
+
macroFolderAbsolutePath = path_1.default.join(__dirname, appName, 'sasjs', 'macros');
|
|
231
|
+
return [4 /*yield*/, expect((0, __1.copyTestMacroFiles)(macroFolderAbsolutePath)).toResolve()];
|
|
232
|
+
case 2:
|
|
233
|
+
_a.sent();
|
|
234
|
+
return [2 /*return*/];
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}); });
|
|
162
238
|
});
|
|
163
239
|
describe('compileTestFlow', function () {
|
|
164
240
|
it('should compile test flow', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -198,6 +274,47 @@ describe('compileTestFile', function () {
|
|
|
198
274
|
}
|
|
199
275
|
});
|
|
200
276
|
}); });
|
|
277
|
+
it('should return no tests when the tests folder is empty', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
278
|
+
var testsFolderPath, testFlow;
|
|
279
|
+
return __generator(this, function (_a) {
|
|
280
|
+
switch (_a.label) {
|
|
281
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
282
|
+
case 1:
|
|
283
|
+
_a.sent();
|
|
284
|
+
testsFolderPath = path_1.default.join(buildPath, 'tests');
|
|
285
|
+
return [4 /*yield*/, (0, utils_1.deleteFolder)(testsFolderPath)];
|
|
286
|
+
case 2:
|
|
287
|
+
_a.sent();
|
|
288
|
+
return [4 /*yield*/, (0, utils_1.createFolder)(testsFolderPath)];
|
|
289
|
+
case 3:
|
|
290
|
+
_a.sent();
|
|
291
|
+
return [4 /*yield*/, (0, __1.compileTestFlow)(target)];
|
|
292
|
+
case 4:
|
|
293
|
+
testFlow = _a.sent();
|
|
294
|
+
expect(testFlow.tests).toEqual([]);
|
|
295
|
+
expect(testFlow.testSetUp).toBeUndefined();
|
|
296
|
+
expect(testFlow.testTearDown).toBeUndefined();
|
|
297
|
+
return [2 /*return*/];
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}); });
|
|
301
|
+
it('should not set testSetUp/testTearDown when the configured file is not among the compiled tests', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
302
|
+
var targetWithBogusSetup, testFlow;
|
|
303
|
+
return __generator(this, function (_a) {
|
|
304
|
+
switch (_a.label) {
|
|
305
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
306
|
+
case 1:
|
|
307
|
+
_a.sent();
|
|
308
|
+
targetWithBogusSetup = new utils_1.Target(__assign(__assign({}, target.toJson()), { testConfig: __assign(__assign({}, target.testConfig), { testSetUp: 'does-not-exist-setup.sas', testTearDown: 'does-not-exist-teardown.sas' }) }));
|
|
309
|
+
return [4 /*yield*/, (0, __1.compileTestFlow)(targetWithBogusSetup)];
|
|
310
|
+
case 2:
|
|
311
|
+
testFlow = _a.sent();
|
|
312
|
+
expect(testFlow.testSetUp).toBeUndefined();
|
|
313
|
+
expect(testFlow.testTearDown).toBeUndefined();
|
|
314
|
+
return [2 /*return*/];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}); });
|
|
201
318
|
it('should log coverage', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
202
319
|
var expectedHeader, expectedData;
|
|
203
320
|
return __generator(this, function (_a) {
|
|
@@ -68,10 +68,13 @@ describe('sasjs create', function () {
|
|
|
68
68
|
afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
69
69
|
return __generator(this, function (_a) {
|
|
70
70
|
switch (_a.label) {
|
|
71
|
-
case 0:
|
|
71
|
+
case 0:
|
|
72
|
+
if (!process.projectDir) return [3 /*break*/, 2];
|
|
73
|
+
return [4 /*yield*/, (0, utils_1.deleteFolder)(process.projectDir)];
|
|
72
74
|
case 1:
|
|
73
75
|
_a.sent();
|
|
74
|
-
|
|
76
|
+
_a.label = 2;
|
|
77
|
+
case 2: return [2 /*return*/];
|
|
75
78
|
}
|
|
76
79
|
});
|
|
77
80
|
}); });
|
|
@@ -95,7 +95,7 @@ var getDocConfig_1 = require("./internal/getDocConfig");
|
|
|
95
95
|
function generateDocs(target, config, outDirectory) {
|
|
96
96
|
var _a, _b;
|
|
97
97
|
return __awaiter(this, void 0, void 0, function () {
|
|
98
|
-
var _c, serverUrl, newOutDirectory, enableLineage, doxyContentFromConfig, _d, macroCoreFolders, macroFolders, programFolders, serviceFolders, jobFolders, combinedFolders, PROJECT_NAME, PROJECT_BRIEF, packageJsonContent, packageJson, e_1, doxyContent, layoutFilePath, LAYOUT_FILE, doxyParams, doxyConfigPath, spinner, pathExists, _e, stderr, code, foldersListForDot;
|
|
98
|
+
var _c, serverUrl, newOutDirectory, enableLineage, doxyContentFromConfig, _d, macroCoreFolders, macroFolders, programFolders, serviceFolders, jobFolders, combinedFolders, PROJECT_NAME, PROJECT_BRIEF, packageJsonContent, packageJson, e_1, doxyContent, layoutFilePath, LAYOUT_FILE, readMePath, doxyParams, doxyConfigPath, spinner, pathExists, _e, stderr, code, foldersListForDot;
|
|
99
99
|
var _this = this;
|
|
100
100
|
return __generator(this, function (_f) {
|
|
101
101
|
switch (_f.label) {
|
|
@@ -153,12 +153,20 @@ function generateDocs(target, config, outDirectory) {
|
|
|
153
153
|
return [2 /*return*/, tmpFilePath];
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
|
-
}); })
|
|
156
|
+
}); })
|
|
157
|
+
// Doxygen matches USE_MDFILE_AS_MAINPAGE against the file's path exactly as it
|
|
158
|
+
// appears in INPUT - a bare name like "README.md" no longer matches an absolute
|
|
159
|
+
// INPUT path on newer Doxygen versions (see doxygen/doxygen#10110), which silently
|
|
160
|
+
// drops the README content instead of using it as the main page. Passing the same
|
|
161
|
+
// absolute path to both keeps them in sync regardless of Doxygen version.
|
|
162
|
+
];
|
|
157
163
|
case 5:
|
|
158
164
|
LAYOUT_FILE = _f.sent();
|
|
165
|
+
readMePath = path_1.default.join(doxyContent.path, doxyContent.readMe);
|
|
159
166
|
doxyParams = setVariableCmd({
|
|
160
167
|
DOXY_HTML_OUTPUT: newOutDirectory,
|
|
161
|
-
DOXY_INPUT: "\"".concat(
|
|
168
|
+
DOXY_INPUT: "\"".concat(readMePath, "\" ").concat(combinedFolders),
|
|
169
|
+
DOXY_MAINPAGE: readMePath,
|
|
162
170
|
HTML_EXTRA_FILES: "\"".concat(path_1.default.join(doxyContent.path, doxyContent.favIcon), "\""),
|
|
163
171
|
HTML_EXTRA_STYLESHEET: "\"".concat(path_1.default.join(doxyContent.path, doxyContent.stylesheet), "\""),
|
|
164
172
|
HTML_FOOTER: path_1.default.join(doxyContent.path, doxyContent.footer),
|
|
@@ -51,6 +51,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
53
|
var path_1 = __importDefault(require("path"));
|
|
54
|
+
var shelljs_1 = __importDefault(require("shelljs"));
|
|
54
55
|
var test_1 = require("../../../utils/test");
|
|
55
56
|
var utils_1 = require("@sasjs/utils");
|
|
56
57
|
var generateDocs_1 = require("../generateDocs");
|
|
@@ -454,4 +455,99 @@ describe('sasjs doc', function () {
|
|
|
454
455
|
}
|
|
455
456
|
});
|
|
456
457
|
}); });
|
|
458
|
+
it('should throw when no macro/program/service/job folders are configured', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
459
|
+
var emptyTarget;
|
|
460
|
+
return __generator(this, function (_a) {
|
|
461
|
+
switch (_a.label) {
|
|
462
|
+
case 0:
|
|
463
|
+
emptyTarget = new utils_1.Target({
|
|
464
|
+
name: 'no-folders',
|
|
465
|
+
appLoc: '/Public/test/',
|
|
466
|
+
serverType: utils_1.ServerType.SasViya,
|
|
467
|
+
docConfig: { displayMacroCore: false }
|
|
468
|
+
});
|
|
469
|
+
return [4 /*yield*/, expect((0, generateDocs_1.generateDocs)(emptyTarget, {
|
|
470
|
+
docConfig: { displayMacroCore: false }
|
|
471
|
+
})).rejects.toThrow('Unable to locate folders for generating docs.')];
|
|
472
|
+
case 1:
|
|
473
|
+
_a.sent();
|
|
474
|
+
return [2 /*return*/];
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}); });
|
|
478
|
+
it('should not toggle the spinner when LOG_LEVEL is Debug', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
479
|
+
var originalLogLevel;
|
|
480
|
+
return __generator(this, function (_a) {
|
|
481
|
+
switch (_a.label) {
|
|
482
|
+
case 0:
|
|
483
|
+
originalLogLevel = process.env.LOG_LEVEL;
|
|
484
|
+
process.env.LOG_LEVEL = 'Debug';
|
|
485
|
+
return [4 /*yield*/, expect((0, generateDocs_1.generateDocs)(defaultTarget, defaultConfig)).resolves.toEqual({
|
|
486
|
+
outDirectory: docOutputDefault
|
|
487
|
+
})];
|
|
488
|
+
case 1:
|
|
489
|
+
_a.sent();
|
|
490
|
+
process.env.LOG_LEVEL = originalLogLevel;
|
|
491
|
+
return [2 /*return*/];
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}); });
|
|
495
|
+
it('should fall back to the default project name when package.json has none', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
496
|
+
var packageJsonPath, originalPackageJson, packageJson;
|
|
497
|
+
return __generator(this, function (_a) {
|
|
498
|
+
switch (_a.label) {
|
|
499
|
+
case 0:
|
|
500
|
+
packageJsonPath = path_1.default.join(__dirname, appName, 'package.json');
|
|
501
|
+
return [4 /*yield*/, (0, utils_1.readFile)(packageJsonPath)];
|
|
502
|
+
case 1:
|
|
503
|
+
originalPackageJson = _a.sent();
|
|
504
|
+
packageJson = JSON.parse(originalPackageJson);
|
|
505
|
+
delete packageJson.name;
|
|
506
|
+
return [4 /*yield*/, (0, utils_1.createFile)(packageJsonPath, JSON.stringify(packageJson))];
|
|
507
|
+
case 2:
|
|
508
|
+
_a.sent();
|
|
509
|
+
return [4 /*yield*/, expect((0, generateDocs_1.generateDocs)(defaultTarget, defaultConfig)).resolves.toEqual({
|
|
510
|
+
outDirectory: docOutputDefault
|
|
511
|
+
})];
|
|
512
|
+
case 3:
|
|
513
|
+
_a.sent();
|
|
514
|
+
return [4 /*yield*/, (0, utils_1.createFile)(packageJsonPath, originalPackageJson)];
|
|
515
|
+
case 4:
|
|
516
|
+
_a.sent();
|
|
517
|
+
return [2 /*return*/];
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}); });
|
|
521
|
+
it('should throw a Doxygen-specific error when the shell command fails with an "error: " stderr', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
522
|
+
return __generator(this, function (_a) {
|
|
523
|
+
switch (_a.label) {
|
|
524
|
+
case 0:
|
|
525
|
+
jest.spyOn(shelljs_1.default, 'exec').mockReturnValueOnce({
|
|
526
|
+
code: 1,
|
|
527
|
+
stderr: 'error: bad config',
|
|
528
|
+
stdout: ''
|
|
529
|
+
});
|
|
530
|
+
return [4 /*yield*/, expect((0, generateDocs_1.generateDocs)(defaultTarget, defaultConfig)).rejects.toThrow('\nerror: bad config')];
|
|
531
|
+
case 1:
|
|
532
|
+
_a.sent();
|
|
533
|
+
return [2 /*return*/];
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
}); });
|
|
537
|
+
it('should throw a generic Doxygen-not-installed error for any other shell failure', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
538
|
+
return __generator(this, function (_a) {
|
|
539
|
+
switch (_a.label) {
|
|
540
|
+
case 0:
|
|
541
|
+
jest.spyOn(shelljs_1.default, 'exec').mockReturnValueOnce({
|
|
542
|
+
code: 1,
|
|
543
|
+
stderr: 'command not found',
|
|
544
|
+
stdout: ''
|
|
545
|
+
});
|
|
546
|
+
return [4 /*yield*/, expect((0, generateDocs_1.generateDocs)(defaultTarget, defaultConfig)).rejects.toThrow("The Doxygen application is not installed or configured.")];
|
|
547
|
+
case 1:
|
|
548
|
+
_a.sent();
|
|
549
|
+
return [2 /*return*/];
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
}); });
|
|
457
553
|
});
|
|
@@ -54,10 +54,13 @@ describe('sasjs init', function () {
|
|
|
54
54
|
afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
55
55
|
return __generator(this, function (_a) {
|
|
56
56
|
switch (_a.label) {
|
|
57
|
-
case 0:
|
|
57
|
+
case 0:
|
|
58
|
+
if (!process.projectDir) return [3 /*break*/, 2];
|
|
59
|
+
return [4 /*yield*/, (0, utils_1.deleteFolder)(process.projectDir)];
|
|
58
60
|
case 1:
|
|
59
61
|
_a.sent();
|
|
60
|
-
|
|
62
|
+
_a.label = 2;
|
|
63
|
+
case 2: return [2 /*return*/];
|
|
61
64
|
}
|
|
62
65
|
});
|
|
63
66
|
}); });
|
|
@@ -392,6 +392,19 @@ describe('JobCommand', function () {
|
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
394
|
}); });
|
|
395
|
+
it('should log deprecation warning if returnStatusOnly flag is present', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
396
|
+
return __generator(this, function (_a) {
|
|
397
|
+
switch (_a.label) {
|
|
398
|
+
case 0:
|
|
399
|
+
jest.spyOn(process.logger, 'warn');
|
|
400
|
+
return [4 /*yield*/, executeCommandWrapper([jobPath, '--returnStatusOnly'])];
|
|
401
|
+
case 1:
|
|
402
|
+
_a.sent();
|
|
403
|
+
expect(process.logger.warn).toHaveBeenCalledWith('--returnStatusOnly (-r) flag is deprecated.');
|
|
404
|
+
return [2 /*return*/];
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}); });
|
|
395
408
|
});
|
|
396
409
|
describe('for server type sas9', function () {
|
|
397
410
|
beforeEach(function () {
|
|
@@ -549,19 +562,6 @@ describe('JobCommand', function () {
|
|
|
549
562
|
});
|
|
550
563
|
}); });
|
|
551
564
|
});
|
|
552
|
-
it('should log deprecation warning if returnStatusOnly flag is present', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
553
|
-
return __generator(this, function (_a) {
|
|
554
|
-
switch (_a.label) {
|
|
555
|
-
case 0:
|
|
556
|
-
jest.spyOn(process.logger, 'warn');
|
|
557
|
-
return [4 /*yield*/, executeCommandWrapper([jobPath, '--returnStatusOnly'])];
|
|
558
|
-
case 1:
|
|
559
|
-
_a.sent();
|
|
560
|
-
expect(process.logger.warn).toHaveBeenCalledWith('--returnStatusOnly (-r) flag is deprecated.');
|
|
561
|
-
return [2 /*return*/];
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
}); });
|
|
565
565
|
});
|
|
566
566
|
var setupMocksForViya = function () {
|
|
567
567
|
jest.resetAllMocks();
|
package/build/doxy/Doxyfile
CHANGED
|
@@ -22,7 +22,7 @@ INHERIT_DOCS = NO
|
|
|
22
22
|
INLINE_INFO = NO
|
|
23
23
|
INPUT = $(DOXY_INPUT)
|
|
24
24
|
LAYOUT_FILE = $(LAYOUT_FILE)
|
|
25
|
-
USE_MDFILE_AS_MAINPAGE =
|
|
25
|
+
USE_MDFILE_AS_MAINPAGE = $(DOXY_MAINPAGE)
|
|
26
26
|
MAX_INITIALIZER_LINES = 0
|
|
27
27
|
PROJECT_NAME = $(PROJECT_NAME)
|
|
28
28
|
PROJECT_LOGO = $(PROJECT_LOGO)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
35
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
36
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
37
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
38
|
+
function step(op) {
|
|
39
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
40
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
41
|
+
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;
|
|
42
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
43
|
+
switch (op[0]) {
|
|
44
|
+
case 0: case 1: t = op; break;
|
|
45
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
46
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
47
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
48
|
+
default:
|
|
49
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
50
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
51
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
52
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
53
|
+
if (t[2]) _.ops.pop();
|
|
54
|
+
_.trys.pop(); continue;
|
|
55
|
+
}
|
|
56
|
+
op = body.call(thisArg, _);
|
|
57
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
58
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
|
+
var utils_1 = require("@sasjs/utils");
|
|
63
|
+
var configUtils = __importStar(require("../../../utils/config"));
|
|
64
|
+
var loadEnvVariablesModule = __importStar(require("../../../utils/loadEnvVariables"));
|
|
65
|
+
var test_1 = require("../../../utils/test");
|
|
66
|
+
var targetCommand_1 = require("../targetCommand");
|
|
67
|
+
var returnCode_1 = require("../returnCode");
|
|
68
|
+
describe('TargetCommand.getTargetInfo', function () {
|
|
69
|
+
beforeEach(function () {
|
|
70
|
+
process.logger = new utils_1.Logger(utils_1.LogLevel.Off);
|
|
71
|
+
jest.spyOn(process.logger, 'error');
|
|
72
|
+
});
|
|
73
|
+
it('exits with an internal error when target env variables fail to load', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
74
|
+
var processExitSpy, command;
|
|
75
|
+
return __generator(this, function (_a) {
|
|
76
|
+
switch (_a.label) {
|
|
77
|
+
case 0:
|
|
78
|
+
processExitSpy = (0, test_1.mockProcessExit)();
|
|
79
|
+
jest
|
|
80
|
+
.spyOn(loadEnvVariablesModule, 'loadTargetEnvVariables')
|
|
81
|
+
.mockImplementation(function () { return Promise.reject(new Error('env file missing')); });
|
|
82
|
+
command = new targetCommand_1.TargetCommand(['node', 'sasjs', 'job'], {
|
|
83
|
+
strict: false
|
|
84
|
+
});
|
|
85
|
+
return [4 /*yield*/, command.getTargetInfo()];
|
|
86
|
+
case 1:
|
|
87
|
+
_a.sent();
|
|
88
|
+
expect(process.logger.error).toHaveBeenCalledWith(expect.stringContaining('Error loading environment variables'), expect.any(Error));
|
|
89
|
+
expect(processExitSpy).toHaveBeenCalledWith(returnCode_1.ReturnCode.InternalError);
|
|
90
|
+
return [2 /*return*/];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}); });
|
|
94
|
+
it('exits with an internal error when the target cannot be found in configuration', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
95
|
+
var processExitSpy, command;
|
|
96
|
+
return __generator(this, function (_a) {
|
|
97
|
+
switch (_a.label) {
|
|
98
|
+
case 0:
|
|
99
|
+
processExitSpy = (0, test_1.mockProcessExit)();
|
|
100
|
+
jest
|
|
101
|
+
.spyOn(loadEnvVariablesModule, 'loadTargetEnvVariables')
|
|
102
|
+
.mockImplementation(function () { return Promise.resolve(); });
|
|
103
|
+
jest
|
|
104
|
+
.spyOn(configUtils, 'findTargetInConfiguration')
|
|
105
|
+
.mockImplementation(function () { return Promise.reject(new Error('target not found')); });
|
|
106
|
+
command = new targetCommand_1.TargetCommand(['node', 'sasjs', 'job'], {
|
|
107
|
+
strict: false
|
|
108
|
+
});
|
|
109
|
+
return [4 /*yield*/, command.getTargetInfo()];
|
|
110
|
+
case 1:
|
|
111
|
+
_a.sent();
|
|
112
|
+
expect(process.logger.error).toHaveBeenCalledWith('Error reading target from configuration: ', expect.any(Error));
|
|
113
|
+
expect(processExitSpy).toHaveBeenCalledWith(returnCode_1.ReturnCode.InternalError);
|
|
114
|
+
return [2 /*return*/];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}); });
|
|
118
|
+
});
|
|
@@ -52,6 +52,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
53
|
var utils_1 = require("../utils");
|
|
54
54
|
var test_1 = require("../test");
|
|
55
|
+
var axios_1 = __importDefault(require("axios"));
|
|
55
56
|
var utils_2 = require("@sasjs/utils");
|
|
56
57
|
var node_1 = __importDefault(require("@sasjs/adapter/node"));
|
|
57
58
|
var path_1 = __importDefault(require("path"));
|
|
@@ -230,6 +231,27 @@ describe('utils', function () {
|
|
|
230
231
|
}
|
|
231
232
|
});
|
|
232
233
|
}); });
|
|
234
|
+
it('should populate all default rules when an existing .gitignore file is empty', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
235
|
+
var gitIgnoreContent;
|
|
236
|
+
return __generator(this, function (_a) {
|
|
237
|
+
switch (_a.label) {
|
|
238
|
+
case 0: return [4 /*yield*/, (0, utils_2.createFile)(gitFilePath, '')];
|
|
239
|
+
case 1:
|
|
240
|
+
_a.sent();
|
|
241
|
+
return [4 /*yield*/, expect((0, utils_1.setupGitIgnore)(folderPath)).toResolve()];
|
|
242
|
+
case 2:
|
|
243
|
+
_a.sent();
|
|
244
|
+
return [4 /*yield*/, (0, utils_2.readFile)(gitFilePath)];
|
|
245
|
+
case 3:
|
|
246
|
+
gitIgnoreContent = _a.sent();
|
|
247
|
+
expect(gitIgnoreContent).toEqual('node_modules\nsasjsbuild\nsasjsresults\n.env*\n');
|
|
248
|
+
return [4 /*yield*/, (0, utils_2.deleteFile)(gitFilePath)];
|
|
249
|
+
case 4:
|
|
250
|
+
_a.sent();
|
|
251
|
+
return [2 /*return*/];
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}); });
|
|
233
255
|
});
|
|
234
256
|
describe('chunk', function () {
|
|
235
257
|
it('should return an array with only one element that is equal to text itself if text size is less than max length', function () {
|
|
@@ -384,4 +406,173 @@ describe('utils', function () {
|
|
|
384
406
|
});
|
|
385
407
|
}); }, 600000);
|
|
386
408
|
});
|
|
409
|
+
describe('prefixAppLoc', function () {
|
|
410
|
+
it('should return null when path is falsy', function () {
|
|
411
|
+
expect((0, utils_1.prefixAppLoc)('/my/app', '')).toEqual(null);
|
|
412
|
+
});
|
|
413
|
+
it('should prepend a leading slash to appLoc if missing', function () {
|
|
414
|
+
expect((0, utils_1.prefixAppLoc)('my/app', 'program1')).toEqual('/my/app/program1');
|
|
415
|
+
});
|
|
416
|
+
it('should keep an already-absolute path unchanged', function () {
|
|
417
|
+
expect((0, utils_1.prefixAppLoc)('/my/app', '/absolute/path')).toEqual('/absolute/path');
|
|
418
|
+
});
|
|
419
|
+
it('should join an array path before prefixing each segment', function () {
|
|
420
|
+
expect((0, utils_1.prefixAppLoc)('/my/app', ['program1', 'program2'])).toEqual('/my/app/program1 /my/app/program2');
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
describe('isSASjsProject', function () {
|
|
424
|
+
it('should return true when sasjs/sasjsconfig.json exists under projectDir', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
425
|
+
var projectDir, originalProjectDir;
|
|
426
|
+
return __generator(this, function (_a) {
|
|
427
|
+
switch (_a.label) {
|
|
428
|
+
case 0:
|
|
429
|
+
projectDir = path_1.default.join(__dirname, "is-sasjs-project-".concat((0, utils_2.generateTimestamp)()));
|
|
430
|
+
originalProjectDir = process.projectDir;
|
|
431
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(path_1.default.join(projectDir, 'sasjs'))];
|
|
432
|
+
case 1:
|
|
433
|
+
_a.sent();
|
|
434
|
+
return [4 /*yield*/, (0, utils_2.createFile)(path_1.default.join(projectDir, 'sasjs', 'sasjsconfig.json'), '{}')];
|
|
435
|
+
case 2:
|
|
436
|
+
_a.sent();
|
|
437
|
+
process.projectDir = projectDir;
|
|
438
|
+
return [4 /*yield*/, expect((0, utils_1.isSASjsProject)()).resolves.toEqual(true)];
|
|
439
|
+
case 3:
|
|
440
|
+
_a.sent();
|
|
441
|
+
process.projectDir = originalProjectDir;
|
|
442
|
+
return [4 /*yield*/, (0, utils_2.deleteFolder)(projectDir)];
|
|
443
|
+
case 4:
|
|
444
|
+
_a.sent();
|
|
445
|
+
return [2 /*return*/];
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}); });
|
|
449
|
+
it('should return false when no sasjsconfig.json is found in any parent folder', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
450
|
+
var projectDir, originalProjectDir;
|
|
451
|
+
return __generator(this, function (_a) {
|
|
452
|
+
switch (_a.label) {
|
|
453
|
+
case 0:
|
|
454
|
+
projectDir = path_1.default.join(require('os').tmpdir(), "not-a-sasjs-project-".concat((0, utils_2.generateTimestamp)()));
|
|
455
|
+
originalProjectDir = process.projectDir;
|
|
456
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(projectDir)];
|
|
457
|
+
case 1:
|
|
458
|
+
_a.sent();
|
|
459
|
+
process.projectDir = projectDir;
|
|
460
|
+
return [4 /*yield*/, expect((0, utils_1.isSASjsProject)()).resolves.toEqual(false)];
|
|
461
|
+
case 2:
|
|
462
|
+
_a.sent();
|
|
463
|
+
process.projectDir = originalProjectDir;
|
|
464
|
+
return [4 /*yield*/, (0, utils_2.deleteFolder)(projectDir)];
|
|
465
|
+
case 3:
|
|
466
|
+
_a.sent();
|
|
467
|
+
return [2 /*return*/];
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}); });
|
|
471
|
+
});
|
|
472
|
+
describe('getNodeModulePath', function () {
|
|
473
|
+
it('should return the folder path of an installed module', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
474
|
+
var modulePath;
|
|
475
|
+
return __generator(this, function (_a) {
|
|
476
|
+
switch (_a.label) {
|
|
477
|
+
case 0: return [4 /*yield*/, (0, utils_1.getNodeModulePath)('@sasjs/utils')];
|
|
478
|
+
case 1:
|
|
479
|
+
modulePath = _a.sent();
|
|
480
|
+
expect(modulePath).not.toEqual('');
|
|
481
|
+
expect(modulePath.endsWith(path_1.default.join('@sasjs', 'utils'))).toEqual(true);
|
|
482
|
+
return [2 /*return*/];
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
}); });
|
|
486
|
+
it('should return an empty string when the module cannot be found', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
487
|
+
return __generator(this, function (_a) {
|
|
488
|
+
switch (_a.label) {
|
|
489
|
+
case 0: return [4 /*yield*/, expect((0, utils_1.getNodeModulePath)('sasjs-nonexistent-module-xyz')).resolves.toEqual('')];
|
|
490
|
+
case 1:
|
|
491
|
+
_a.sent();
|
|
492
|
+
return [2 /*return*/];
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}); });
|
|
496
|
+
});
|
|
497
|
+
describe('getUniqServicesObj', function () {
|
|
498
|
+
it('should return an empty object when services is falsy', function () {
|
|
499
|
+
expect((0, utils_1.getUniqServicesObj)(undefined)).toEqual({});
|
|
500
|
+
});
|
|
501
|
+
it('should key services by their basename, keeping the first of any duplicates', function () {
|
|
502
|
+
expect((0, utils_1.getUniqServicesObj)(['a/b/service1', 'x/service2', 'y/service1'])).toEqual({
|
|
503
|
+
service1: 'a/b/service1',
|
|
504
|
+
service2: 'x/service2'
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
describe('convertToSASStatements', function () {
|
|
509
|
+
it('should convert macroVars to %let statements', function () {
|
|
510
|
+
expect((0, utils_1.convertToSASStatements)({
|
|
511
|
+
macroVars: { var1: 'val1', var2: 'val2' }
|
|
512
|
+
})).toEqual('%let var1=val1;\n%let var2=val2;\n');
|
|
513
|
+
});
|
|
514
|
+
it('should return an empty string when there are no macroVars', function () {
|
|
515
|
+
expect((0, utils_1.convertToSASStatements)({ macroVars: {} })).toEqual('');
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
describe('terminateProcess', function () {
|
|
519
|
+
it('should exit the process with the given status code', function () {
|
|
520
|
+
var mockExit = (0, test_1.mockProcessExit)();
|
|
521
|
+
(0, utils_1.terminateProcess)(2);
|
|
522
|
+
expect(mockExit).toHaveBeenCalledWith(2);
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
describe('isSasJsServerInServerMode', function () {
|
|
526
|
+
var target = new utils_2.Target({
|
|
527
|
+
name: 'test',
|
|
528
|
+
appLoc: '/Public/test/',
|
|
529
|
+
serverType: utils_2.ServerType.Sasjs,
|
|
530
|
+
serverUrl: 'https://sasjsserver.com'
|
|
531
|
+
});
|
|
532
|
+
afterEach(function () {
|
|
533
|
+
jest.restoreAllMocks();
|
|
534
|
+
});
|
|
535
|
+
it('should return true when the server reports server mode', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
536
|
+
return __generator(this, function (_a) {
|
|
537
|
+
switch (_a.label) {
|
|
538
|
+
case 0:
|
|
539
|
+
jest
|
|
540
|
+
.spyOn(axios_1.default, 'get')
|
|
541
|
+
.mockImplementation(function () { return Promise.resolve({ data: { mode: 'server' } }); });
|
|
542
|
+
return [4 /*yield*/, expect((0, utils_1.isSasJsServerInServerMode)(target)).resolves.toEqual(true)];
|
|
543
|
+
case 1:
|
|
544
|
+
_a.sent();
|
|
545
|
+
return [2 /*return*/];
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}); });
|
|
549
|
+
it('should return false when the server does not report server mode', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
550
|
+
return __generator(this, function (_a) {
|
|
551
|
+
switch (_a.label) {
|
|
552
|
+
case 0:
|
|
553
|
+
jest
|
|
554
|
+
.spyOn(axios_1.default, 'get')
|
|
555
|
+
.mockImplementation(function () {
|
|
556
|
+
return Promise.resolve({ data: { mode: 'desktop' } });
|
|
557
|
+
});
|
|
558
|
+
return [4 /*yield*/, expect((0, utils_1.isSasJsServerInServerMode)(target)).resolves.toEqual(false)];
|
|
559
|
+
case 1:
|
|
560
|
+
_a.sent();
|
|
561
|
+
return [2 /*return*/];
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}); });
|
|
565
|
+
it('should throw when the server info request fails', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
566
|
+
return __generator(this, function (_a) {
|
|
567
|
+
switch (_a.label) {
|
|
568
|
+
case 0:
|
|
569
|
+
jest.spyOn(axios_1.default, 'get').mockImplementation(function () { return Promise.reject(); });
|
|
570
|
+
return [4 /*yield*/, expect((0, utils_1.isSasJsServerInServerMode)(target)).rejects.toThrow("An error occurred while fetching server info from ".concat(target.serverUrl, "/SASjsApi/info"))];
|
|
571
|
+
case 1:
|
|
572
|
+
_a.sent();
|
|
573
|
+
return [2 /*return*/];
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
}); });
|
|
577
|
+
});
|
|
387
578
|
});
|
package/build/utils/utils.js
CHANGED
|
@@ -182,16 +182,23 @@ function createTemplateApp(folderPath, template) {
|
|
|
182
182
|
var _this = this;
|
|
183
183
|
return __generator(this, function (_a) {
|
|
184
184
|
return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
|
|
185
|
-
var
|
|
185
|
+
var probeFile, _a, stderr, code;
|
|
186
186
|
return __generator(this, function (_b) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
switch (_b.label) {
|
|
188
|
+
case 0:
|
|
189
|
+
probeFile = 'response.txt';
|
|
190
|
+
_a = downloadFile("https://username:password@github.com/sasjs/template_".concat(template), probeFile), stderr = _a.stderr, code = _a.code;
|
|
191
|
+
return [4 /*yield*/, (0, utils_1.deleteFile)(probeFile).catch(function () { })];
|
|
192
|
+
case 1:
|
|
193
|
+
_b.sent();
|
|
194
|
+
if (stderr.includes('404: Not Found') || code) {
|
|
195
|
+
return [2 /*return*/, reject(new Error("Template \"".concat(template, "\" is not a SASjs template")))];
|
|
196
|
+
}
|
|
197
|
+
createApp(folderPath, "https://github.com/sasjs/template_".concat(template), 'https://github.com/sasjs/docs', function (err) {
|
|
198
|
+
return reject(new Error(err));
|
|
199
|
+
});
|
|
200
|
+
return [2 /*return*/, resolve()];
|
|
190
201
|
}
|
|
191
|
-
createApp(folderPath, "https://github.com/sasjs/template_".concat(template), 'https://github.com/sasjs/docs', function (err) {
|
|
192
|
-
return reject(new Error(err));
|
|
193
|
-
});
|
|
194
|
-
return [2 /*return*/, resolve()];
|
|
195
202
|
});
|
|
196
203
|
}); })];
|
|
197
204
|
});
|
|
@@ -274,14 +281,23 @@ var loadDocsSubmodule = function (docsUrl, folderPath, zipPath) { return __await
|
|
|
274
281
|
}); };
|
|
275
282
|
function downloadFile(url, filename) {
|
|
276
283
|
if ((0, utils_1.isLinux)()) {
|
|
277
|
-
|
|
284
|
+
// -O <filename> writes to the given name; without it, wget defaults to the
|
|
285
|
+
// remote URL's basename, which silently ignores the caller's `filename` and
|
|
286
|
+
// can leave an unexpectedly-named file behind (e.g. a repo-existence probe
|
|
287
|
+
// meant to be discarded as `response.txt` instead landing as the repo name).
|
|
288
|
+
return shelljs_1.default.exec("wget ".concat(url).concat(filename ? ' -O ' + filename : ''), {
|
|
289
|
+
silent: true
|
|
290
|
+
});
|
|
278
291
|
}
|
|
279
292
|
else if ((0, utils_1.isWindows)()) {
|
|
280
293
|
// First We set TLS12 & then we invoke request to download file.
|
|
281
294
|
return shelljs_1.default.exec("powershell.exe \"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Invoke-WebRequest ".concat(url, " ").concat(filename ? '-O ' + filename : '', "\""), { silent: true });
|
|
282
295
|
}
|
|
283
296
|
else {
|
|
284
|
-
|
|
297
|
+
// -o <filename> writes to the given name; -O (used previously) instead saves
|
|
298
|
+
// under the remote URL's basename, ignoring `filename` - see the wget comment
|
|
299
|
+
// above for the same issue.
|
|
300
|
+
return shelljs_1.default.exec("curl ".concat(url, " -L -f").concat(filename ? ' -o ' + filename : ' -O'), { silent: true });
|
|
285
301
|
}
|
|
286
302
|
}
|
|
287
303
|
function setupNpmProject(folderName) {
|
package/package.json
CHANGED