@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,477 @@
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 __values = (this && this.__values) || function(o) {
50
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
+ if (m) return m.call(o);
52
+ if (o && typeof o.length === "number") return {
53
+ next: function () {
54
+ if (o && i >= o.length) o = void 0;
55
+ return { value: o && o[i++], done: !o };
56
+ }
57
+ };
58
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
+ };
60
+ var __read = (this && this.__read) || function (o, n) {
61
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
62
+ if (!m) return o;
63
+ var i = m.call(o), r, ar = [], e;
64
+ try {
65
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
+ }
67
+ catch (error) { e = { error: error }; }
68
+ finally {
69
+ try {
70
+ if (r && !r.done && (m = i["return"])) m.call(i);
71
+ }
72
+ finally { if (e) throw e.error; }
73
+ }
74
+ return ar;
75
+ };
76
+ var __importDefault = (this && this.__importDefault) || function (mod) {
77
+ return (mod && mod.__esModule) ? mod : { "default": mod };
78
+ };
79
+ Object.defineProperty(exports, "__esModule", { value: true });
80
+ var path_1 = __importDefault(require("path"));
81
+ var os_1 = __importDefault(require("os"));
82
+ var fs_1 = require("fs");
83
+ var collectLogs_1 = require("../collectLogs");
84
+ var types_1 = require("../types");
85
+ var sasLog = "NOTE: Copyright (c) 2016 by SAS Institute Inc., Cary, NC, USA.\nNOTE: SAS (r) Proprietary Software 9.4 (TS1M9)\n\n1 data work.x;\n2 set work.y;\n3 run;\nERROR 22-322: Syntax error, expecting one of the following: ;, RUN, QUIT.\nWARNING: Apparent symbolic reference X not resolved.\nNOTE: Variable flag is uninitialized.\nNOTE: The data set WORK.X has 5 observations and 2 variables.\n";
86
+ var cleanLog = "NOTE: Copyright (c) 2016 by SAS Institute Inc., Cary, NC, USA.\n\n1 data work.x;\n2 x = 1;\n3 run;\nNOTE: The data set WORK.X has 1 observations and 1 variables.\n";
87
+ var buildLog = "> tsc -p .\nERROR: Cannot find module './config'\nERROR: Command failed with exit code 2\n";
88
+ var tempFolder = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
89
+ switch (_a.label) {
90
+ case 0: return [4 /*yield*/, fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'sasjs-logcheck-collect-'))];
91
+ case 1: return [2 /*return*/, _a.sent()];
92
+ }
93
+ }); }); };
94
+ var writeFiles = function (folder, files) { return __awaiter(void 0, void 0, void 0, function () {
95
+ var _a, _b, _c, name_1, contents, filePath, e_1_1;
96
+ var e_1, _d;
97
+ return __generator(this, function (_e) {
98
+ switch (_e.label) {
99
+ case 0:
100
+ _e.trys.push([0, 6, 7, 8]);
101
+ _a = __values(Object.entries(files)), _b = _a.next();
102
+ _e.label = 1;
103
+ case 1:
104
+ if (!!_b.done) return [3 /*break*/, 5];
105
+ _c = __read(_b.value, 2), name_1 = _c[0], contents = _c[1];
106
+ filePath = path_1.default.join(folder, name_1);
107
+ return [4 /*yield*/, fs_1.promises.mkdir(path_1.default.dirname(filePath), { recursive: true })];
108
+ case 2:
109
+ _e.sent();
110
+ return [4 /*yield*/, fs_1.promises.writeFile(filePath, contents)];
111
+ case 3:
112
+ _e.sent();
113
+ _e.label = 4;
114
+ case 4:
115
+ _b = _a.next();
116
+ return [3 /*break*/, 1];
117
+ case 5: return [3 /*break*/, 8];
118
+ case 6:
119
+ e_1_1 = _e.sent();
120
+ e_1 = { error: e_1_1 };
121
+ return [3 /*break*/, 8];
122
+ case 7:
123
+ try {
124
+ if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
125
+ }
126
+ finally { if (e_1) throw e_1.error; }
127
+ return [7 /*endfinally*/];
128
+ case 8: return [2 /*return*/];
129
+ }
130
+ });
131
+ }); };
132
+ describe('collectLogFiles', function () {
133
+ it('returns a single file as it was given', function () { return __awaiter(void 0, void 0, void 0, function () {
134
+ var folder, _a, files, missing;
135
+ return __generator(this, function (_b) {
136
+ switch (_b.label) {
137
+ case 0: return [4 /*yield*/, tempFolder()];
138
+ case 1:
139
+ folder = _b.sent();
140
+ return [4 /*yield*/, writeFiles(folder, { 'run.log': sasLog })];
141
+ case 2:
142
+ _b.sent();
143
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([
144
+ path_1.default.join(folder, 'run.log')
145
+ ])];
146
+ case 3:
147
+ _a = _b.sent(), files = _a.files, missing = _a.missing;
148
+ expect(files).toEqual([path_1.default.join(folder, 'run.log')]);
149
+ expect(missing).toEqual([]);
150
+ return [2 /*return*/];
151
+ }
152
+ });
153
+ }); });
154
+ it('walks a folder, and the folders under it', function () { return __awaiter(void 0, void 0, void 0, function () {
155
+ var folder, files;
156
+ return __generator(this, function (_a) {
157
+ switch (_a.label) {
158
+ case 0: return [4 /*yield*/, tempFolder()];
159
+ case 1:
160
+ folder = _a.sent();
161
+ return [4 /*yield*/, writeFiles(folder, {
162
+ 'a.log': sasLog,
163
+ 'nested/b.log': sasLog,
164
+ 'nested/deep/c.log': sasLog
165
+ })];
166
+ case 2:
167
+ _a.sent();
168
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([folder])];
169
+ case 3:
170
+ files = (_a.sent()).files;
171
+ expect(files.map(function (file) { return path_1.default.relative(folder, file); })).toEqual(expect.arrayContaining([
172
+ 'a.log',
173
+ path_1.default.join('nested', 'b.log'),
174
+ path_1.default.join('nested', 'deep', 'c.log')
175
+ ]));
176
+ expect(files).toHaveLength(3);
177
+ return [2 /*return*/];
178
+ }
179
+ });
180
+ }); });
181
+ it('does not walk into node_modules', function () { return __awaiter(void 0, void 0, void 0, function () {
182
+ var folder, files;
183
+ return __generator(this, function (_a) {
184
+ switch (_a.label) {
185
+ case 0: return [4 /*yield*/, tempFolder()];
186
+ case 1:
187
+ folder = _a.sent();
188
+ return [4 /*yield*/, writeFiles(folder, {
189
+ 'a.log': sasLog,
190
+ 'node_modules/pkg/b.log': sasLog
191
+ })];
192
+ case 2:
193
+ _a.sent();
194
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([folder])];
195
+ case 3:
196
+ files = (_a.sent()).files;
197
+ expect(files).toHaveLength(1);
198
+ expect(files[0]).toEqual(path_1.default.join(folder, 'a.log'));
199
+ return [2 /*return*/];
200
+ }
201
+ });
202
+ }); });
203
+ it('reports a folder it cannot list instead of treating it as empty', function () { return __awaiter(void 0, void 0, void 0, function () {
204
+ var folder, readdir, _a, files, unreadable;
205
+ return __generator(this, function (_b) {
206
+ switch (_b.label) {
207
+ case 0: return [4 /*yield*/, tempFolder()];
208
+ case 1:
209
+ folder = _b.sent();
210
+ return [4 /*yield*/, writeFiles(folder, { 'logs/a.log': sasLog })];
211
+ case 2:
212
+ _b.sent();
213
+ readdir = jest
214
+ .spyOn(require('fs/promises'), 'readdir')
215
+ .mockRejectedValue(Object.assign(new Error('denied'), { code: 'EACCES' }));
216
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([
217
+ path_1.default.join(folder, 'logs')
218
+ ])];
219
+ case 3:
220
+ _a = _b.sent(), files = _a.files, unreadable = _a.unreadable;
221
+ readdir.mockRestore();
222
+ expect(files).toEqual([]);
223
+ expect(unreadable).toHaveLength(1);
224
+ expect(unreadable[0].reason).toEqual('could not be listed (EACCES)');
225
+ return [2 /*return*/];
226
+ }
227
+ });
228
+ }); });
229
+ it('reports a path that does not exist instead of failing', function () { return __awaiter(void 0, void 0, void 0, function () {
230
+ var folder, _a, files, missing;
231
+ return __generator(this, function (_b) {
232
+ switch (_b.label) {
233
+ case 0: return [4 /*yield*/, tempFolder()];
234
+ case 1:
235
+ folder = _b.sent();
236
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([
237
+ path_1.default.join(folder, 'nope.log')
238
+ ])];
239
+ case 2:
240
+ _a = _b.sent(), files = _a.files, missing = _a.missing;
241
+ expect(files).toEqual([]);
242
+ expect(missing).toEqual([path_1.default.join(folder, 'nope.log')]);
243
+ return [2 /*return*/];
244
+ }
245
+ });
246
+ }); });
247
+ it('lists the same file once when a file and its folder are both named', function () { return __awaiter(void 0, void 0, void 0, function () {
248
+ var folder, files;
249
+ return __generator(this, function (_a) {
250
+ switch (_a.label) {
251
+ case 0: return [4 /*yield*/, tempFolder()];
252
+ case 1:
253
+ folder = _a.sent();
254
+ return [4 /*yield*/, writeFiles(folder, { 'a.log': sasLog })];
255
+ case 2:
256
+ _a.sent();
257
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([
258
+ folder,
259
+ path_1.default.join(folder, 'a.log')
260
+ ])];
261
+ case 3:
262
+ files = (_a.sent()).files;
263
+ expect(files).toEqual([path_1.default.join(folder, 'a.log')]);
264
+ return [2 /*return*/];
265
+ }
266
+ });
267
+ }); });
268
+ it('sorts the files so two runs produce the same report', function () { return __awaiter(void 0, void 0, void 0, function () {
269
+ var folder, files;
270
+ return __generator(this, function (_a) {
271
+ switch (_a.label) {
272
+ case 0: return [4 /*yield*/, tempFolder()];
273
+ case 1:
274
+ folder = _a.sent();
275
+ return [4 /*yield*/, writeFiles(folder, { 'b.log': sasLog, 'a.log': sasLog })];
276
+ case 2:
277
+ _a.sent();
278
+ return [4 /*yield*/, (0, collectLogs_1.collectLogFiles)([folder])];
279
+ case 3:
280
+ files = (_a.sent()).files;
281
+ expect(files.map(function (file) { return path_1.default.basename(file); })).toEqual(['a.log', 'b.log']);
282
+ return [2 /*return*/];
283
+ }
284
+ });
285
+ }); });
286
+ });
287
+ describe('toDisplayPath', function () {
288
+ var originalProjectDir = process.projectDir;
289
+ afterEach(function () {
290
+ process.projectDir = originalProjectDir;
291
+ });
292
+ it('is relative to the project folder', function () {
293
+ process.projectDir = path_1.default.join('project', 'root');
294
+ expect((0, collectLogs_1.toDisplayPath)(path_1.default.join('project', 'root', 'sasjsresults', 'run.log'))).toEqual('sasjsresults/run.log');
295
+ });
296
+ it('is absolute for a file outside the project folder', function () {
297
+ process.projectDir = path_1.default.join(os_1.default.tmpdir(), 'sasjs-logcheck-project');
298
+ var outside = path_1.default.join(os_1.default.tmpdir(), 'elsewhere', 'run.log');
299
+ expect((0, collectLogs_1.toDisplayPath)(outside)).toEqual(outside.split(path_1.default.sep).join('/'));
300
+ });
301
+ });
302
+ describe('scanLogFile', function () {
303
+ it('reports the issues a SAS log carries', function () { return __awaiter(void 0, void 0, void 0, function () {
304
+ var folder, filePath, log;
305
+ return __generator(this, function (_a) {
306
+ switch (_a.label) {
307
+ case 0: return [4 /*yield*/, tempFolder()];
308
+ case 1:
309
+ folder = _a.sent();
310
+ filePath = path_1.default.join(folder, 'run.log');
311
+ return [4 /*yield*/, fs_1.promises.writeFile(filePath, sasLog)];
312
+ case 2:
313
+ _a.sent();
314
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(filePath, types_1.defaultLogCheckConfig)];
315
+ case 3:
316
+ log = _a.sent();
317
+ expect(log.skippedReason).toBeUndefined();
318
+ expect(log.counts).toEqual({ errors: 1, warnings: 1, notes: 1 });
319
+ expect(log.issues.map(function (issue) { return issue.severity; })).toEqual([
320
+ 'error',
321
+ 'warning',
322
+ 'note'
323
+ ]);
324
+ return [2 /*return*/];
325
+ }
326
+ });
327
+ }); });
328
+ it('reports a clean log as checked, with nothing in it', function () { return __awaiter(void 0, void 0, void 0, function () {
329
+ var folder, filePath, log;
330
+ return __generator(this, function (_a) {
331
+ switch (_a.label) {
332
+ case 0: return [4 /*yield*/, tempFolder()];
333
+ case 1:
334
+ folder = _a.sent();
335
+ filePath = path_1.default.join(folder, 'clean.log');
336
+ return [4 /*yield*/, fs_1.promises.writeFile(filePath, cleanLog)];
337
+ case 2:
338
+ _a.sent();
339
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(filePath, types_1.defaultLogCheckConfig)];
340
+ case 3:
341
+ log = _a.sent();
342
+ expect(log.skippedReason).toBeUndefined();
343
+ expect(log.counts).toEqual({ errors: 0, warnings: 0, notes: 0 });
344
+ return [2 /*return*/];
345
+ }
346
+ });
347
+ }); });
348
+ it('skips a log another tool wrote', function () { return __awaiter(void 0, void 0, void 0, function () {
349
+ var folder, filePath, log;
350
+ return __generator(this, function (_a) {
351
+ switch (_a.label) {
352
+ case 0: return [4 /*yield*/, tempFolder()];
353
+ case 1:
354
+ folder = _a.sent();
355
+ filePath = path_1.default.join(folder, 'build.log');
356
+ return [4 /*yield*/, fs_1.promises.writeFile(filePath, buildLog)];
357
+ case 2:
358
+ _a.sent();
359
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(filePath, types_1.defaultLogCheckConfig)];
360
+ case 3:
361
+ log = _a.sent();
362
+ expect(log.skippedReason).toEqual('not a SAS log');
363
+ expect(log.issues).toEqual([]);
364
+ return [2 /*return*/];
365
+ }
366
+ });
367
+ }); });
368
+ it('reports a path that is not a file', function () { return __awaiter(void 0, void 0, void 0, function () {
369
+ var folder, log;
370
+ return __generator(this, function (_a) {
371
+ switch (_a.label) {
372
+ case 0: return [4 /*yield*/, tempFolder()];
373
+ case 1:
374
+ folder = _a.sent();
375
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(folder, types_1.defaultLogCheckConfig)];
376
+ case 2:
377
+ log = _a.sent();
378
+ expect(log.skippedReason).toEqual('not a file');
379
+ return [2 /*return*/];
380
+ }
381
+ });
382
+ }); });
383
+ it('reports a file that vanished before it could be read', function () { return __awaiter(void 0, void 0, void 0, function () {
384
+ var folder, log;
385
+ return __generator(this, function (_a) {
386
+ switch (_a.label) {
387
+ case 0: return [4 /*yield*/, tempFolder()];
388
+ case 1:
389
+ folder = _a.sent();
390
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(path_1.default.join(folder, 'missing.log'), types_1.defaultLogCheckConfig)];
391
+ case 2:
392
+ log = _a.sent();
393
+ expect(log.skippedReason).toEqual('could not be read');
394
+ return [2 /*return*/];
395
+ }
396
+ });
397
+ }); });
398
+ it('sets a suppressed issue aside instead of reporting it', function () { return __awaiter(void 0, void 0, void 0, function () {
399
+ var folder, filePath, log;
400
+ return __generator(this, function (_a) {
401
+ switch (_a.label) {
402
+ case 0: return [4 /*yield*/, tempFolder()];
403
+ case 1:
404
+ folder = _a.sent();
405
+ filePath = path_1.default.join(folder, 'run.log');
406
+ return [4 /*yield*/, fs_1.promises.writeFile(filePath, sasLog)];
407
+ case 2:
408
+ _a.sent();
409
+ return [4 /*yield*/, (0, collectLogs_1.scanLogFile)(filePath, __assign(__assign({}, types_1.defaultLogCheckConfig), { ignoreCodes: ['22-322'] }))];
410
+ case 3:
411
+ log = _a.sent();
412
+ expect(log.issues.map(function (issue) { return issue.severity; })).toEqual([
413
+ 'warning',
414
+ 'note'
415
+ ]);
416
+ expect(log.suppressed).toHaveLength(1);
417
+ expect(log.suppressed[0].code).toEqual('22-322');
418
+ expect(log.counts).toEqual({ errors: 0, warnings: 1, notes: 1 });
419
+ return [2 /*return*/];
420
+ }
421
+ });
422
+ }); });
423
+ });
424
+ describe('partitionIssues', function () {
425
+ var issues = [
426
+ {
427
+ line: 0,
428
+ endLine: 0,
429
+ column: 0,
430
+ endColumn: 5,
431
+ severity: 'error',
432
+ code: '22-322',
433
+ message: 'Syntax error'
434
+ },
435
+ {
436
+ line: 1,
437
+ endLine: 1,
438
+ column: 0,
439
+ endColumn: 5,
440
+ severity: 'warning',
441
+ message: 'Apparent symbolic reference'
442
+ },
443
+ {
444
+ line: 2,
445
+ endLine: 2,
446
+ column: 0,
447
+ endColumn: 5,
448
+ severity: 'note',
449
+ code: '49-169',
450
+ message: 'Line was truncated'
451
+ }
452
+ ];
453
+ it('keeps every issue when nothing is suppressed', function () {
454
+ var _a = (0, collectLogs_1.partitionIssues)(issues, []), kept = _a.issues, suppressed = _a.suppressed;
455
+ expect(kept).toHaveLength(3);
456
+ expect(suppressed).toHaveLength(0);
457
+ });
458
+ it('suppresses by message code, and leaves an uncoded issue alone', function () {
459
+ var _a = (0, collectLogs_1.partitionIssues)(issues, [
460
+ '22-322',
461
+ '49-169'
462
+ ]), kept = _a.issues, suppressed = _a.suppressed;
463
+ expect(kept).toHaveLength(1);
464
+ expect(kept[0].severity).toEqual('warning');
465
+ expect(suppressed).toHaveLength(2);
466
+ });
467
+ });
468
+ describe('countIssues', function () {
469
+ it('counts by severity', function () {
470
+ expect((0, collectLogs_1.countIssues)([
471
+ { severity: 'error' },
472
+ { severity: 'error' },
473
+ { severity: 'warning' },
474
+ { severity: 'note' }
475
+ ])).toEqual({ errors: 2, warnings: 1, notes: 1 });
476
+ });
477
+ });