@sasjs/cli 6.20.0 → 6.21.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.
@@ -323,7 +323,8 @@ function printHelpText() {
323
323
  name: 'lint',
324
324
  title: 'lint',
325
325
  description: [
326
- "Provides the capability to identify, for SAS file, whether there are any ERRORs or WARNINGs present and if so, which line number they are on."
326
+ "Provides the capability to identify, for SAS file, whether there are any ERRORs or WARNINGs present and if so, which line number they are on.",
327
+ "[2spaces]command example: sasjs lint --fail-on warning"
327
328
  ]
328
329
  },
329
330
  {
@@ -50,6 +50,31 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
50
50
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
51
  }
52
52
  };
53
+ var __read = (this && this.__read) || function (o, n) {
54
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
55
+ if (!m) return o;
56
+ var i = m.call(o), r, ar = [], e;
57
+ try {
58
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
59
+ }
60
+ catch (error) { e = { error: error }; }
61
+ finally {
62
+ try {
63
+ if (r && !r.done && (m = i["return"])) m.call(i);
64
+ }
65
+ finally { if (e) throw e.error; }
66
+ }
67
+ return ar;
68
+ };
69
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
70
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
71
+ if (ar || !(i in from)) {
72
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
73
+ ar[i] = from[i];
74
+ }
75
+ }
76
+ return to.concat(ar || Array.prototype.slice.call(from));
77
+ };
53
78
  Object.defineProperty(exports, "__esModule", { value: true });
54
79
  exports.LintCommand = void 0;
55
80
  var initLint_1 = require("./initLint");
@@ -57,15 +82,35 @@ var processLint_1 = require("./processLint");
57
82
  var command_1 = require("../../types/command");
58
83
  var types_1 = require("../../types");
59
84
  var utils_1 = require("../../utils");
85
+ var subCommands = ['init', 'fix', 'find'];
86
+ var failOnValues = ['error', 'warning'];
60
87
  var syntax = 'lint <subCommand> [filterStrings..]';
61
- var usage = 'sasjs lint [ find | fix | init ]';
88
+ var usage = 'sasjs lint [ find | fix | init ] [--fail-on error|warning]';
62
89
  var description = "Provides the capability to identify, for SAS file, whether there are any ERRORs or WARNINGs present and if so, which line number they are on.";
90
+ /**
91
+ * Inserts the default `find` subcommand unless the first argument is already a
92
+ * subcommand, so `sasjs lint --fail-on warning` and `sasjs lint src/app.sas`
93
+ * both report rather than fail to parse. The check is made on the arguments
94
+ * rather than on their number, because an option and its value count as
95
+ * arguments and used to push the subcommand out of position.
96
+ */
97
+ var withDefaultSubCommand = function (args) {
98
+ var firstPositional = args.slice(3).find(function (arg) { return !arg.startsWith('-'); });
99
+ return firstPositional && subCommands.includes(firstPositional)
100
+ ? args
101
+ : __spreadArray(__spreadArray(__spreadArray([], __read(args.slice(0, 3)), false), ['find'], false), __read(args.slice(3)), false);
102
+ };
63
103
  var examples = [
64
104
  {
65
105
  command: 'sasjs lint',
66
106
  description: 'Lints all .sas files in the current project.\n' +
67
107
  'All the exceptions (along with line / column numbers) will be shown in the console.'
68
108
  },
109
+ {
110
+ command: 'sasjs lint --fail-on warning',
111
+ description: 'Lints all .sas files in the current project and fails on a warning as well as an error.\n' +
112
+ 'The same can be set for every run by adding `"default": "error"` to `severityLevel` in `.sasjslint`.'
113
+ },
69
114
  {
70
115
  command: 'sasjs lint find mf_a mf_b',
71
116
  description: 'Lints all .sas files starting from mf_a or mf_b in the current project.\n' +
@@ -109,23 +154,32 @@ var examples = [
109
154
  var LintCommand = /** @class */ (function (_super) {
110
155
  __extends(LintCommand, _super);
111
156
  function LintCommand(args) {
112
- if (args.length < 4) {
113
- args.splice(3, 0, 'find');
114
- }
115
- return _super.call(this, args, {
157
+ return _super.call(this, withDefaultSubCommand(args), {
116
158
  syntax: syntax,
117
159
  usage: usage,
118
160
  description: description,
119
- examples: examples
161
+ examples: examples,
162
+ parseOptions: {
163
+ 'fail-on': {
164
+ type: 'string',
165
+ description: "Lowest severity that fails the command: ".concat(failOnValues.join(', '), ". Defaults to error, so a warning is reported without failing. Applies to the report run, not to lint fix.")
166
+ }
167
+ }
120
168
  }) || this;
121
169
  }
122
170
  LintCommand.prototype.execute = function () {
123
171
  return __awaiter(this, void 0, void 0, function () {
124
- var _a, subCommand, filterStrings;
125
- return __generator(this, function (_b) {
126
- switch (_b.label) {
172
+ var _a, subCommand, filterStrings, failOn, failOnSeverity;
173
+ var _b;
174
+ return __generator(this, function (_c) {
175
+ switch (_c.label) {
127
176
  case 0:
128
- _a = this.parsed, subCommand = _a.subCommand, filterStrings = _a.filterStrings;
177
+ _a = this.parsed, subCommand = _a.subCommand, filterStrings = _a.filterStrings, failOn = _a.failOn;
178
+ if (failOn !== undefined && !failOnValues.includes(failOn)) {
179
+ (0, utils_1.displayError)(new Error("Invalid value for --fail-on: ".concat(failOn, ". Use one of ").concat(failOnValues.join(', '), ".")));
180
+ return [2 /*return*/, command_1.ReturnCode.InvalidCommand];
181
+ }
182
+ failOnSeverity = (_b = failOn) !== null && _b !== void 0 ? _b : 'error';
129
183
  if (!(subCommand === 'init')) return [3 /*break*/, 2];
130
184
  return [4 /*yield*/, (0, initLint_1.initLint)()
131
185
  .then(function (res) {
@@ -139,7 +193,7 @@ var LintCommand = /** @class */ (function (_super) {
139
193
  (0, utils_1.displayError)(err, 'An error has occurred whilst initialising SASjs Lint.');
140
194
  return command_1.ReturnCode.InternalError;
141
195
  })];
142
- case 1: return [2 /*return*/, _b.sent()];
196
+ case 1: return [2 /*return*/, _c.sent()];
143
197
  case 2:
144
198
  if (!(subCommand === 'fix')) return [3 /*break*/, 4];
145
199
  return [4 /*yield*/, (0, processLint_1.lintFix)(filterStrings)
@@ -148,13 +202,20 @@ var LintCommand = /** @class */ (function (_super) {
148
202
  (0, utils_1.displayError)(err, 'An error has occurred while running SASjs Lint Fix.');
149
203
  return command_1.ReturnCode.LintError;
150
204
  })];
151
- case 3: return [2 /*return*/, _b.sent()];
205
+ case 3: return [2 /*return*/, _c.sent()];
152
206
  case 4: return [4 /*yield*/, (0, processLint_1.processLint)(filterStrings)
153
207
  .then(function (result) {
154
208
  if (result.errors) {
155
209
  (0, utils_1.displayError)('Please fix the identified lint errors.');
156
210
  return command_1.ReturnCode.LintError;
157
211
  }
212
+ if (result.warnings && failOnSeverity === 'warning') {
213
+ var count = result.warningCount;
214
+ (0, utils_1.displayError)(count === 1
215
+ ? '1 lint warning treated as an error because of --fail-on warning. Please fix it.'
216
+ : "".concat(count, " lint warnings treated as errors because of --fail-on warning. Please fix them."));
217
+ return command_1.ReturnCode.LintError;
218
+ }
158
219
  if (result.warnings) {
159
220
  process.logger.warn('Please fix the identified lint warnings.');
160
221
  return command_1.ReturnCode.Success;
@@ -166,7 +227,7 @@ var LintCommand = /** @class */ (function (_super) {
166
227
  (0, utils_1.displayError)(err, 'An error has occurred when processing lint operation.');
167
228
  return command_1.ReturnCode.InternalError;
168
229
  })];
169
- case 5: return [2 /*return*/, _b.sent()];
230
+ case 5: return [2 /*return*/, _c.sent()];
170
231
  }
171
232
  });
172
233
  });
@@ -1,6 +1,10 @@
1
1
  interface LintResult {
2
2
  warnings: boolean;
3
3
  errors: boolean;
4
+ /** Number of WARNING diagnostics found, across every linted file. */
5
+ warningCount: number;
6
+ /** Number of ERROR diagnostics found, across every linted file. */
7
+ errorCount: number;
4
8
  }
5
9
  /**
6
10
  * Fixes lint violations in all .sas files in the current project if no filterArray is provided
@@ -70,6 +70,12 @@ var path_1 = __importDefault(require("path"));
70
70
  var chalk_1 = __importDefault(require("chalk"));
71
71
  var lint_1 = require("@sasjs/lint");
72
72
  var utils_1 = require("@sasjs/utils");
73
+ /**
74
+ * `sasjs lint` is documented to work without a `sasjsconfig.json`, and loading
75
+ * that file is the only thing that sets `process.projectDir` - so a filter
76
+ * string is resolved against the current directory when no project was loaded.
77
+ */
78
+ var getProjectDir = function () { return process.projectDir || process.cwd(); };
73
79
  /**
74
80
  * Fixes lint violations in all .sas files in the current project if no filterArray is provided
75
81
  * Otherwise fixes lint violations of only those .sas files which matches filter array
@@ -125,7 +131,7 @@ function lintFix() {
125
131
  .map(function (pattern) { return "(".concat(pattern, ")"); })
126
132
  .join('|');
127
133
  regex_1 = new RegExp(regexPattern);
128
- return [4 /*yield*/, (0, utils_1.listSasFilesInFolder)(process.projectDir, true, [
134
+ return [4 /*yield*/, (0, utils_1.listSasFilesInFolder)(getProjectDir(), true, [
129
135
  'node_modules'
130
136
  ])];
131
137
  case 2:
@@ -194,7 +200,12 @@ function processLint() {
194
200
  return __generator(this, function (_a) {
195
201
  switch (_a.label) {
196
202
  case 0:
197
- found = { warnings: false, errors: false };
203
+ found = {
204
+ warnings: false,
205
+ errors: false,
206
+ warningCount: 0,
207
+ errorCount: 0
208
+ };
198
209
  sasjsDiagnosticsMap = new Map();
199
210
  if (!filterArray.length) return [3 /*break*/, 5];
200
211
  absoluteFilePaths = filterArray.filter(function (pattern) {
@@ -226,7 +237,7 @@ function processLint() {
226
237
  .map(function (pattern) { return "(".concat(pattern, ")"); })
227
238
  .join('|');
228
239
  regex_2 = new RegExp(regexPattern);
229
- return [4 /*yield*/, (0, utils_1.listSasFilesInFolder)(process.projectDir, true, [
240
+ return [4 /*yield*/, (0, utils_1.listSasFilesInFolder)(getProjectDir(), true, [
230
241
  'node_modules'
231
242
  ])];
232
243
  case 2:
@@ -237,7 +248,7 @@ function processLint() {
237
248
  return __generator(this, function (_d) {
238
249
  switch (_d.label) {
239
250
  case 0:
240
- filePath = path_1.default.join(process.projectDir, file);
251
+ filePath = path_1.default.join(getProjectDir(), file);
241
252
  _b = (_a = sasjsDiagnosticsMap).set;
242
253
  _c = [filePath];
243
254
  return [4 /*yield*/, (0, lint_1.lintFile)(filePath)];
@@ -258,12 +269,10 @@ function processLint() {
258
269
  _a.label = 7;
259
270
  case 7:
260
271
  sasjsDiagnosticsMap.forEach(function (sasjsDiagnostics, filePath) {
261
- found.warnings =
262
- found.warnings ||
263
- !!sasjsDiagnostics.find(function (d) { return d.severity === lint_1.Severity.Warning; });
264
- found.errors =
265
- found.errors ||
266
- !!sasjsDiagnostics.find(function (d) { return d.severity === lint_1.Severity.Error; });
272
+ found.warningCount += sasjsDiagnostics.filter(function (d) { return d.severity === lint_1.Severity.Warning; }).length;
273
+ found.errorCount += sasjsDiagnostics.filter(function (d) { return d.severity === lint_1.Severity.Error; }).length;
274
+ found.warnings = found.warnings || found.warningCount > 0;
275
+ found.errors = found.errors || found.errorCount > 0;
267
276
  if (sasjsDiagnostics.length) {
268
277
  displayDiagnostics(filePath, sasjsDiagnostics);
269
278
  }
@@ -138,10 +138,13 @@ describe('LintCommand', function () {
138
138
  switch (_a.label) {
139
139
  case 0:
140
140
  args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint'], false);
141
- jest
142
- .spyOn(processModule, 'processLint')
143
- .mockImplementation(function () {
144
- return Promise.resolve({ warnings: true, errors: false });
141
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
142
+ return Promise.resolve({
143
+ warnings: true,
144
+ errors: false,
145
+ warningCount: 3,
146
+ errorCount: 0
147
+ });
145
148
  });
146
149
  command = new lintCommand_1.LintCommand(args);
147
150
  return [4 /*yield*/, command.execute()];
@@ -178,10 +181,13 @@ describe('LintCommand', function () {
178
181
  switch (_a.label) {
179
182
  case 0:
180
183
  args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint'], false);
181
- jest
182
- .spyOn(processModule, 'processLint')
183
- .mockImplementation(function () {
184
- return Promise.resolve({ warnings: false, errors: true });
184
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
185
+ return Promise.resolve({
186
+ warnings: false,
187
+ errors: true,
188
+ warningCount: 0,
189
+ errorCount: 1
190
+ });
185
191
  });
186
192
  command = new lintCommand_1.LintCommand(args);
187
193
  return [4 /*yield*/, command.execute()];
@@ -193,6 +199,111 @@ describe('LintCommand', function () {
193
199
  }
194
200
  });
195
201
  }); });
202
+ it('should default the subcommand when --fail-on comes before the filter', function () {
203
+ var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on', 'warning', 'appinit'], false);
204
+ var command = new lintCommand_1.LintCommand(args);
205
+ expect(command.name).toEqual('lint');
206
+ expect(command.subCommand).toEqual('find');
207
+ });
208
+ it('should default the subcommand when only --fail-on is given', function () {
209
+ var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on=warning'], false);
210
+ var command = new lintCommand_1.LintCommand(args);
211
+ expect(command.name).toEqual('lint');
212
+ expect(command.subCommand).toEqual('find');
213
+ });
214
+ it('should keep an explicit subcommand ahead of --fail-on', function () {
215
+ var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', 'find', '--fail-on', 'warning'], false);
216
+ var command = new lintCommand_1.LintCommand(args);
217
+ expect(command.subCommand).toEqual('find');
218
+ });
219
+ it('should fail on warnings when --fail-on warning is passed', function () { return __awaiter(void 0, void 0, void 0, function () {
220
+ var args, command, returnCode;
221
+ return __generator(this, function (_a) {
222
+ switch (_a.label) {
223
+ case 0:
224
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on', 'warning'], false);
225
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
226
+ return Promise.resolve({
227
+ warnings: true,
228
+ errors: false,
229
+ warningCount: 2,
230
+ errorCount: 0
231
+ });
232
+ });
233
+ command = new lintCommand_1.LintCommand(args);
234
+ return [4 /*yield*/, command.execute()];
235
+ case 1:
236
+ returnCode = _a.sent();
237
+ expect(returnCode).toEqual(command_1.ReturnCode.LintError);
238
+ expect(process.logger.error).toHaveBeenCalledWith('', '2 lint warnings treated as errors because of --fail-on warning. Please fix them.');
239
+ return [2 /*return*/];
240
+ }
241
+ });
242
+ }); });
243
+ it('should word a single warning as one error', function () { return __awaiter(void 0, void 0, void 0, function () {
244
+ var args, command, returnCode;
245
+ return __generator(this, function (_a) {
246
+ switch (_a.label) {
247
+ case 0:
248
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on', 'warning'], false);
249
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
250
+ return Promise.resolve({
251
+ warnings: true,
252
+ errors: false,
253
+ warningCount: 1,
254
+ errorCount: 0
255
+ });
256
+ });
257
+ command = new lintCommand_1.LintCommand(args);
258
+ return [4 /*yield*/, command.execute()];
259
+ case 1:
260
+ returnCode = _a.sent();
261
+ expect(returnCode).toEqual(command_1.ReturnCode.LintError);
262
+ expect(process.logger.error).toHaveBeenCalledWith('', '1 lint warning treated as an error because of --fail-on warning. Please fix it.');
263
+ return [2 /*return*/];
264
+ }
265
+ });
266
+ }); });
267
+ it('should not fail on warnings when --fail-on error is passed', function () { return __awaiter(void 0, void 0, void 0, function () {
268
+ var args, command, returnCode;
269
+ return __generator(this, function (_a) {
270
+ switch (_a.label) {
271
+ case 0:
272
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on', 'error'], false);
273
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
274
+ return Promise.resolve({
275
+ warnings: true,
276
+ errors: false,
277
+ warningCount: 2,
278
+ errorCount: 0
279
+ });
280
+ });
281
+ command = new lintCommand_1.LintCommand(args);
282
+ return [4 /*yield*/, command.execute()];
283
+ case 1:
284
+ returnCode = _a.sent();
285
+ expect(returnCode).toEqual(command_1.ReturnCode.Success);
286
+ expect(process.logger.warn).toHaveBeenCalled();
287
+ return [2 /*return*/];
288
+ }
289
+ });
290
+ }); });
291
+ it('should reject an unknown --fail-on value', function () { return __awaiter(void 0, void 0, void 0, function () {
292
+ var args, command, returnCode;
293
+ return __generator(this, function (_a) {
294
+ switch (_a.label) {
295
+ case 0:
296
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['lint', '--fail-on', 'note'], false);
297
+ command = new lintCommand_1.LintCommand(args);
298
+ return [4 /*yield*/, command.execute()];
299
+ case 1:
300
+ returnCode = _a.sent();
301
+ expect(returnCode).toEqual(command_1.ReturnCode.InvalidCommand);
302
+ expect(processModule.processLint).not.toHaveBeenCalled();
303
+ return [2 /*return*/];
304
+ }
305
+ });
306
+ }); });
196
307
  });
197
308
  describe('LintCommand - fix', function () {
198
309
  beforeEach(function () {
@@ -295,10 +406,13 @@ var setupMocks = function () {
295
406
  jest.resetAllMocks();
296
407
  jest.mock('../processLint');
297
408
  jest.mock('../initLint');
298
- jest
299
- .spyOn(processModule, 'processLint')
300
- .mockImplementation(function () {
301
- return Promise.resolve({ warnings: false, errors: false });
409
+ jest.spyOn(processModule, 'processLint').mockImplementation(function () {
410
+ return Promise.resolve({
411
+ warnings: false,
412
+ errors: false,
413
+ warningCount: 0,
414
+ errorCount: 0
415
+ });
302
416
  });
303
417
  jest
304
418
  .spyOn(processModule, 'lintFix')
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,127 @@
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 = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["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 (g && (g = 0, op[0] && (_ = 0)), _) 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
+ var fs_1 = __importDefault(require("fs"));
43
+ var os_1 = __importDefault(require("os"));
44
+ var path_1 = __importDefault(require("path"));
45
+ var processLint_1 = require("../processLint");
46
+ /**
47
+ * `sasjs lint` is documented to run without a `sasjsconfig.json`, and loading
48
+ * that file is the only thing that sets `process.projectDir` - so these cases
49
+ * run with it empty, the way a project directory without a config does.
50
+ */
51
+ describe('processLint', function () {
52
+ var originalCwd = process.cwd();
53
+ var tmpDir;
54
+ beforeEach(function () {
55
+ tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'sasjs-lint-'));
56
+ fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'trailing.sas'), "%put 'hello'; \n");
57
+ process.chdir(tmpDir);
58
+ process.projectDir = '';
59
+ });
60
+ afterEach(function () {
61
+ process.chdir(originalCwd);
62
+ process.projectDir = '';
63
+ fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
64
+ });
65
+ it('should resolve a filter string against the current directory when no project is loaded', function () { return __awaiter(void 0, void 0, void 0, function () {
66
+ var result;
67
+ return __generator(this, function (_a) {
68
+ switch (_a.label) {
69
+ case 0: return [4 /*yield*/, (0, processLint_1.processLint)(['trailing'])];
70
+ case 1:
71
+ result = _a.sent();
72
+ expect(result.warnings).toEqual(true);
73
+ expect(result.warningCount).toBeGreaterThan(0);
74
+ expect(result.errors).toEqual(false);
75
+ expect(result.errorCount).toEqual(0);
76
+ return [2 /*return*/];
77
+ }
78
+ });
79
+ }); });
80
+ it('should still accept an absolute path when no project is loaded', function () { return __awaiter(void 0, void 0, void 0, function () {
81
+ var result;
82
+ return __generator(this, function (_a) {
83
+ switch (_a.label) {
84
+ case 0: return [4 /*yield*/, (0, processLint_1.processLint)([path_1.default.join(tmpDir, 'trailing.sas')])];
85
+ case 1:
86
+ result = _a.sent();
87
+ expect(result.warningCount).toBeGreaterThan(0);
88
+ return [2 /*return*/];
89
+ }
90
+ });
91
+ }); });
92
+ it('should report no findings when the filter matches nothing', function () { return __awaiter(void 0, void 0, void 0, function () {
93
+ var result;
94
+ return __generator(this, function (_a) {
95
+ switch (_a.label) {
96
+ case 0: return [4 /*yield*/, (0, processLint_1.processLint)(['no-such-file'])];
97
+ case 1:
98
+ result = _a.sent();
99
+ expect(result).toEqual({
100
+ warnings: false,
101
+ errors: false,
102
+ warningCount: 0,
103
+ errorCount: 0
104
+ });
105
+ return [2 /*return*/];
106
+ }
107
+ });
108
+ }); });
109
+ it('should count errors separately from warnings', function () { return __awaiter(void 0, void 0, void 0, function () {
110
+ var result;
111
+ return __generator(this, function (_a) {
112
+ switch (_a.label) {
113
+ case 0:
114
+ fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'password.sas'), "%put '{SASENC}'; \n");
115
+ return [4 /*yield*/, (0, processLint_1.processLint)(['password'])];
116
+ case 1:
117
+ result = _a.sent();
118
+ expect(result.errorCount).toBe(1);
119
+ expect(result.errors).toEqual(true);
120
+ // The trailing spaces and the missing header are both warnings, so the
121
+ // counts stay independent of the error.
122
+ expect(result.warningCount).toBeGreaterThanOrEqual(1);
123
+ return [2 /*return*/];
124
+ }
125
+ });
126
+ }); });
127
+ });
package/package.json CHANGED
@@ -73,7 +73,7 @@
73
73
  "@sasjs/adapter": "5.1.3",
74
74
  "@sasjs/api": "0.23.0",
75
75
  "@sasjs/core": "6.1.1",
76
- "@sasjs/lint": "5.0.1",
76
+ "@sasjs/lint": "^5.1.0",
77
77
  "@sasjs/utils": "4.9.0",
78
78
  "axios": "1.20.0",
79
79
  "chalk": "4.1.2",
@@ -125,5 +125,5 @@
125
125
  "ws": "8.21.0",
126
126
  "nanoid": "3.3.18"
127
127
  },
128
- "version": "6.20.0"
128
+ "version": "6.21.0"
129
129
  }