@sasjs/cli 6.5.0 → 6.7.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.
Files changed (53) hide show
  1. package/README.md +2 -1
  2. package/build/commands/build/build.js +66 -29
  3. package/build/commands/build/spec/build.spec.js +31 -1
  4. package/build/commands/compile/compile.js +168 -33
  5. package/build/commands/compile/compileCommand.js +1 -1
  6. package/build/commands/compile/internal/checkCompileStatus.js +30 -11
  7. package/build/commands/compile/internal/compileFile.js +16 -7
  8. package/build/commands/compile/internal/compileManifest.d.ts +36 -0
  9. package/build/commands/compile/internal/compileManifest.js +610 -0
  10. package/build/commands/compile/internal/index.d.ts +2 -0
  11. package/build/commands/compile/internal/index.js +2 -0
  12. package/build/commands/compile/internal/passThrough.d.ts +12 -0
  13. package/build/commands/compile/internal/passThrough.js +17 -0
  14. package/build/commands/compile/internal/spec/compileTestFile.spec.js +9 -6
  15. package/build/commands/compile/spec/checkCompileStatus.spec.d.ts +1 -0
  16. package/build/commands/compile/spec/checkCompileStatus.spec.js +221 -0
  17. package/build/commands/compile/spec/compileCommand.spec.js +9 -2
  18. package/build/commands/compile/spec/compileManifest.spec.d.ts +1 -0
  19. package/build/commands/compile/spec/compileManifest.spec.js +401 -0
  20. package/build/commands/compile/spec/passThrough.spec.d.ts +1 -0
  21. package/build/commands/compile/spec/passThrough.spec.js +160 -0
  22. package/build/commands/deploy/spec/cbd.spec.js +11 -7
  23. package/build/commands/help/help.js +10 -0
  24. package/build/commands/index.d.ts +1 -0
  25. package/build/commands/index.js +3 -1
  26. package/build/commands/logcheck/collectLogs.d.ts +60 -0
  27. package/build/commands/logcheck/collectLogs.js +386 -0
  28. package/build/commands/logcheck/logCheckConfig.d.ts +72 -0
  29. package/build/commands/logcheck/logCheckConfig.js +283 -0
  30. package/build/commands/logcheck/logcheckCommand.d.ts +6 -0
  31. package/build/commands/logcheck/logcheckCommand.js +200 -0
  32. package/build/commands/logcheck/processLogCheck.d.ts +44 -0
  33. package/build/commands/logcheck/processLogCheck.js +242 -0
  34. package/build/commands/logcheck/renderLogCheck.d.ts +128 -0
  35. package/build/commands/logcheck/renderLogCheck.js +423 -0
  36. package/build/commands/logcheck/spec/collectLogs.spec.d.ts +1 -0
  37. package/build/commands/logcheck/spec/collectLogs.spec.js +477 -0
  38. package/build/commands/logcheck/spec/logCheckConfig.spec.d.ts +1 -0
  39. package/build/commands/logcheck/spec/logCheckConfig.spec.js +323 -0
  40. package/build/commands/logcheck/spec/logcheckCommand.spec.d.ts +1 -0
  41. package/build/commands/logcheck/spec/logcheckCommand.spec.js +360 -0
  42. package/build/commands/logcheck/spec/processLogCheck.spec.d.ts +1 -0
  43. package/build/commands/logcheck/spec/processLogCheck.spec.js +354 -0
  44. package/build/commands/logcheck/spec/renderLogCheck.spec.d.ts +1 -0
  45. package/build/commands/logcheck/spec/renderLogCheck.spec.js +426 -0
  46. package/build/commands/logcheck/types.d.ts +98 -0
  47. package/build/commands/logcheck/types.js +14 -0
  48. package/build/commands/testing/spec/testing.spec.js +8 -2
  49. package/build/types/command/commandAliases.js +1 -0
  50. package/build/types/command/commandFactory.js +2 -0
  51. package/build/types/command/returnCode.d.ts +2 -1
  52. package/build/types/command/returnCode.js +4 -0
  53. package/package.json +3 -3
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ 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;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var path_1 = __importDefault(require("path"));
54
+ var os_1 = __importDefault(require("os"));
55
+ var fs_1 = require("fs");
56
+ var logCheckConfig_1 = require("../logCheckConfig");
57
+ var types_1 = require("../types");
58
+ var tempFolder = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
59
+ switch (_a.label) {
60
+ case 0: return [4 /*yield*/, fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'sasjs-logcheck-config-'))];
61
+ case 1: return [2 /*return*/, _a.sent()];
62
+ }
63
+ }); }); };
64
+ describe('parseLogCheckSection', function () {
65
+ it('returns the defaults when the section is absent', function () {
66
+ expect((0, logCheckConfig_1.parseLogCheckSection)(undefined)).toEqual(types_1.defaultLogCheckConfig);
67
+ expect((0, logCheckConfig_1.parseLogCheckSection)(null)).toEqual(types_1.defaultLogCheckConfig);
68
+ });
69
+ it('returns the defaults when the section is empty', function () {
70
+ expect((0, logCheckConfig_1.parseLogCheckSection)({})).toEqual(types_1.defaultLogCheckConfig);
71
+ });
72
+ it('reads every supported setting', function () {
73
+ var config = (0, logCheckConfig_1.parseLogCheckSection)({
74
+ failOn: 'warning',
75
+ maxWarnings: 4,
76
+ ignoreCodes: ['49-169'],
77
+ ignorePaths: ['sasjsresults/legacy'],
78
+ folder: 'logs'
79
+ });
80
+ expect(config).toEqual({
81
+ failOn: 'warning',
82
+ maxWarnings: 4,
83
+ ignoreCodes: ['49-169'],
84
+ ignorePaths: ['sasjsresults/legacy'],
85
+ folder: 'logs'
86
+ });
87
+ });
88
+ it('refuses a failOn that is not one of the four policies', function () {
89
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ failOn: 'warnings' }); }).toThrow('must be one of error, warning, note, never');
90
+ });
91
+ it('refuses a maxWarnings that is not a whole number of zero or more', function () {
92
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ maxWarnings: -1 }); }).toThrow('whole number of zero or more');
93
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ maxWarnings: 1.5 }); }).toThrow('whole number of zero or more');
94
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ maxWarnings: '3' }); }).toThrow('whole number of zero or more');
95
+ });
96
+ it('refuses a suppressions list that is not an array of strings', function () {
97
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ ignoreCodes: '49-169' }); }).toThrow('must be an array of strings');
98
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ ignorePaths: [1] }); }).toThrow('must be an array of strings');
99
+ });
100
+ it('refuses an empty folder name', function () {
101
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ folder: ' ' }); }).toThrow('must be a non-empty string');
102
+ });
103
+ it('refuses a section that is not an object', function () {
104
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)(['failOn'], 'sasjsconfig.json'); }).toThrow('must be an object');
105
+ expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)('error', 'sasjsconfig.json'); }).toThrow('must be an object');
106
+ });
107
+ it('trims and de-duplicates the suppressions', function () {
108
+ var config = (0, logCheckConfig_1.parseLogCheckSection)({
109
+ ignoreCodes: [' 49-169 ', '49-169', ''],
110
+ ignorePaths: ['a', 'a']
111
+ });
112
+ expect(config.ignoreCodes).toEqual(['49-169']);
113
+ expect(config.ignorePaths).toEqual(['a']);
114
+ });
115
+ });
116
+ describe('readLogCheckConfig', function () {
117
+ var originalProjectDir = process.projectDir;
118
+ afterEach(function () {
119
+ process.projectDir = originalProjectDir;
120
+ });
121
+ var withConfig = function (contents) { return __awaiter(void 0, void 0, void 0, function () {
122
+ var folder;
123
+ return __generator(this, function (_a) {
124
+ switch (_a.label) {
125
+ case 0: return [4 /*yield*/, tempFolder()];
126
+ case 1:
127
+ folder = _a.sent();
128
+ process.projectDir = folder;
129
+ if (!(contents !== undefined)) return [3 /*break*/, 3];
130
+ return [4 /*yield*/, fs_1.promises.writeFile(path_1.default.join(folder, 'sasjsconfig.json'), typeof contents === 'string' ? contents : JSON.stringify(contents))];
131
+ case 2:
132
+ _a.sent();
133
+ _a.label = 3;
134
+ case 3: return [2 /*return*/, folder];
135
+ }
136
+ });
137
+ }); };
138
+ it('returns the defaults when the project has no sasjsconfig.json', function () { return __awaiter(void 0, void 0, void 0, function () {
139
+ var _a;
140
+ return __generator(this, function (_b) {
141
+ switch (_b.label) {
142
+ case 0: return [4 /*yield*/, withConfig(undefined)];
143
+ case 1:
144
+ _b.sent();
145
+ _a = expect;
146
+ return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
147
+ case 2:
148
+ _a.apply(void 0, [_b.sent()]).toEqual(types_1.defaultLogCheckConfig);
149
+ return [2 /*return*/];
150
+ }
151
+ });
152
+ }); });
153
+ it('reads the section from the top level of the config', function () { return __awaiter(void 0, void 0, void 0, function () {
154
+ var _a;
155
+ return __generator(this, function (_b) {
156
+ switch (_b.label) {
157
+ case 0: return [4 /*yield*/, withConfig({ logCheck: { failOn: 'note' } })];
158
+ case 1:
159
+ _b.sent();
160
+ _a = expect;
161
+ return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
162
+ case 2:
163
+ _a.apply(void 0, [(_b.sent()).failOn]).toEqual('note');
164
+ return [2 /*return*/];
165
+ }
166
+ });
167
+ }); });
168
+ it('reads the section from a wrapped config', function () { return __awaiter(void 0, void 0, void 0, function () {
169
+ var _a;
170
+ return __generator(this, function (_b) {
171
+ switch (_b.label) {
172
+ case 0: return [4 /*yield*/, withConfig({ config: { logCheck: { failOn: 'never' } } })];
173
+ case 1:
174
+ _b.sent();
175
+ _a = expect;
176
+ return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
177
+ case 2:
178
+ _a.apply(void 0, [(_b.sent()).failOn]).toEqual('never');
179
+ return [2 /*return*/];
180
+ }
181
+ });
182
+ }); });
183
+ it('follows the project results folder a config names', function () { return __awaiter(void 0, void 0, void 0, function () {
184
+ var _a;
185
+ return __generator(this, function (_b) {
186
+ switch (_b.label) {
187
+ case 0: return [4 /*yield*/, withConfig({ sasjsResultsFolder: 'build-output/results' })];
188
+ case 1:
189
+ _b.sent();
190
+ _a = expect;
191
+ return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
192
+ case 2:
193
+ _a.apply(void 0, [(_b.sent()).folder]).toEqual('build-output/results');
194
+ return [2 /*return*/];
195
+ }
196
+ });
197
+ }); });
198
+ it('prefers the folder the logCheck section names', function () { return __awaiter(void 0, void 0, void 0, function () {
199
+ var _a;
200
+ return __generator(this, function (_b) {
201
+ switch (_b.label) {
202
+ case 0: return [4 /*yield*/, withConfig({
203
+ sasjsResultsFolder: 'build-output/results',
204
+ logCheck: { folder: 'logs' }
205
+ })];
206
+ case 1:
207
+ _b.sent();
208
+ _a = expect;
209
+ return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
210
+ case 2:
211
+ _a.apply(void 0, [(_b.sent()).folder]).toEqual('logs');
212
+ return [2 /*return*/];
213
+ }
214
+ });
215
+ }); });
216
+ it('fails loudly on a config that is not valid JSON', function () { return __awaiter(void 0, void 0, void 0, function () {
217
+ return __generator(this, function (_a) {
218
+ switch (_a.label) {
219
+ case 0: return [4 /*yield*/, withConfig('{ "logCheck": ')];
220
+ case 1:
221
+ _a.sent();
222
+ return [4 /*yield*/, expect((0, logCheckConfig_1.readLogCheckConfig)()).rejects.toThrow('Could not parse')];
223
+ case 2:
224
+ _a.sent();
225
+ return [2 /*return*/];
226
+ }
227
+ });
228
+ }); });
229
+ });
230
+ describe('mergeConfig', function () {
231
+ var base = __assign(__assign({}, types_1.defaultLogCheckConfig), { ignoreCodes: ['49-169'], ignorePaths: ['legacy'] });
232
+ it('prefers the command line over the file', function () {
233
+ var merged = (0, logCheckConfig_1.mergeConfig)(__assign(__assign({}, base), { failOn: 'error' }), { failOn: 'note' });
234
+ expect(merged.failOn).toEqual('note');
235
+ });
236
+ it('returns the config unchanged when there are no overrides', function () {
237
+ expect((0, logCheckConfig_1.mergeConfig)(__assign(__assign({}, base), { failOn: 'note' })).failOn).toEqual('note');
238
+ });
239
+ it('keeps the file value when the flag is absent', function () {
240
+ expect((0, logCheckConfig_1.mergeConfig)(__assign(__assign({}, base), { maxWarnings: 5 }), {}).maxWarnings).toEqual(5);
241
+ });
242
+ it('adds suppressions instead of replacing them', function () {
243
+ var merged = (0, logCheckConfig_1.mergeConfig)(base, {
244
+ ignoreCodes: ['22-322'],
245
+ ignorePaths: ['build.log']
246
+ });
247
+ expect(merged.ignoreCodes).toEqual(['49-169', '22-322']);
248
+ expect(merged.ignorePaths).toEqual(['legacy', 'build.log']);
249
+ });
250
+ it('does not mutate the config it was given', function () {
251
+ var config = __assign(__assign({}, base), { ignoreCodes: ['49-169'] });
252
+ (0, logCheckConfig_1.mergeConfig)(config, { ignoreCodes: ['22-322'] });
253
+ expect(config.ignoreCodes).toEqual(['49-169']);
254
+ });
255
+ it('treats an empty override list as no override', function () {
256
+ expect((0, logCheckConfig_1.mergeConfig)(base, { ignoreCodes: [] }).ignoreCodes).toEqual([
257
+ '49-169'
258
+ ]);
259
+ });
260
+ });
261
+ describe('matchesPath', function () {
262
+ it('matches a plain entry as whole path segments', function () {
263
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/legacy/run.log', 'sasjsresults/legacy')).toBe(true);
264
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/run.log', 'sasjsresults/legacy')).toBe(false);
265
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/legacy', 'sasjsresults/legacy')).toBe(true);
266
+ });
267
+ it('does not let a fragment of a name silence a file', function () {
268
+ // The reviewer's case: `test` silencing `latest.log`, and `logs` silencing
269
+ // anything that merely contains it.
270
+ expect((0, logCheckConfig_1.matchesPath)('latest.log', 'test')).toBe(false);
271
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/nested-logs/run.log', 'logs')).toBe(false);
272
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/run.log', 'run')).toBe(false);
273
+ });
274
+ it('matches at any depth, on a segment boundary', function () {
275
+ expect((0, logCheckConfig_1.matchesPath)('test/run.log', 'test')).toBe(true);
276
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/test/run.log', 'test')).toBe(true);
277
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/latest-test/run.log', 'test')).toBe(false);
278
+ });
279
+ it('ignores a leading `./` and a trailing separator', function () {
280
+ expect((0, logCheckConfig_1.matchesPath)('logs/run.log', './logs/')).toBe(true);
281
+ });
282
+ it('matches a single wildcard without crossing folders', function () {
283
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/build.log', 'sasjsresults/*.log')).toBe(true);
284
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/nested/build.log', 'sasjsresults/*.log')).toBe(false);
285
+ });
286
+ it('lets a leading double wildcard match the folder itself', function () {
287
+ expect((0, logCheckConfig_1.matchesPath)('build.log', '**/build.log')).toBe(true);
288
+ expect((0, logCheckConfig_1.matchesPath)('a/b/build.log', '**/build.log')).toBe(true);
289
+ });
290
+ it('matches a single character wildcard', function () {
291
+ expect((0, logCheckConfig_1.matchesPath)('logs/a1.log', 'logs/a?.log')).toBe(true);
292
+ expect((0, logCheckConfig_1.matchesPath)('logs/a12.log', 'logs/a?.log')).toBe(false);
293
+ });
294
+ it('ignores an empty pattern', function () {
295
+ expect((0, logCheckConfig_1.matchesPath)('sasjsresults/run.log', ' ')).toBe(false);
296
+ });
297
+ it('reads a Windows path the same way as a POSIX one', function () {
298
+ var windowsPath = ['sasjsresults', 'run.log'].join(path_1.default.sep);
299
+ expect((0, logCheckConfig_1.matchesPath)(windowsPath, 'sasjsresults/run.log')).toBe(true);
300
+ });
301
+ it('reports whether any pattern covers the path', function () {
302
+ expect((0, logCheckConfig_1.isIgnoredPath)('a/b.log', ['x', '**/b.log'])).toBe(true);
303
+ expect((0, logCheckConfig_1.isIgnoredPath)('a/c.log', ['x', '**/b.log'])).toBe(false);
304
+ });
305
+ });
306
+ describe('globToRegExp', function () {
307
+ it('escapes the regular-expression characters of a literal pattern', function () {
308
+ expect((0, logCheckConfig_1.globToRegExp)('logs/a+b.log').test('logs/a+b.log')).toBe(true);
309
+ expect((0, logCheckConfig_1.globToRegExp)('logs/a+b.log').test('logs/aab.log')).toBe(false);
310
+ });
311
+ it('anchors the pattern at both ends', function () {
312
+ expect((0, logCheckConfig_1.globToRegExp)('run.log').test('myrun.log')).toBe(false);
313
+ });
314
+ it('treats a double wildcard anywhere as any characters', function () {
315
+ expect((0, logCheckConfig_1.globToRegExp)('logs/**/x.log').test('logs/x.log')).toBe(true);
316
+ expect((0, logCheckConfig_1.globToRegExp)('logs/**/x.log').test('logs/a/b/x.log')).toBe(true);
317
+ });
318
+ });
319
+ describe('toPosix', function () {
320
+ it('uses forward slashes on every platform', function () {
321
+ expect((0, logCheckConfig_1.toPosix)(['a', 'b.log'].join(path_1.default.sep))).toEqual('a/b.log');
322
+ });
323
+ });