@sasjs/lint 3.0.0 → 4.1.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.
- package/README.md +107 -6
- package/format/formatFile.js +2 -1
- package/format/formatFile.js.map +1 -1
- package/format/formatText.js +1 -1
- package/format/formatText.js.map +1 -1
- package/lint/lintFile.js +3 -2
- package/lint/lintFile.js.map +1 -1
- package/lint/lintText.js +1 -1
- package/lint/lintText.js.map +1 -1
- package/package.json +1 -1
- package/rules/file/index.d.ts +1 -0
- package/rules/file/index.js +3 -1
- package/rules/file/index.js.map +1 -1
- package/rules/file/noUnusedLibnames.d.ts +15 -0
- package/rules/file/noUnusedLibnames.js +56 -0
- package/rules/file/noUnusedLibnames.js.map +1 -0
- package/sasjslint-schema.json +41 -14
- package/types/LintConfig.d.ts +14 -0
- package/types/LintConfig.js +49 -15
- package/types/LintConfig.js.map +1 -1
- package/utils/getLintConfig.d.ts +28 -13
- package/utils/getLintConfig.js +29 -14
- package/utils/getLintConfig.js.map +1 -1
- package/utils/index.d.ts +3 -0
- package/utils/index.js +3 -0
- package/utils/index.js.map +1 -1
- package/utils/mergeLintConfig.d.ts +10 -0
- package/utils/mergeLintConfig.js +67 -0
- package/utils/mergeLintConfig.js.map +1 -0
- package/utils/parseLibnames.d.ts +33 -0
- package/utils/parseLibnames.js +237 -0
- package/utils/parseLibnames.js.map +1 -0
- package/utils/parseLintOverride.d.ts +36 -0
- package/utils/parseLintOverride.js +109 -0
- package/utils/parseLintOverride.js.map +1 -0
package/README.md
CHANGED
|
@@ -17,16 +17,18 @@ Our goal is to help SAS developers everywhere spend less time on code reviews, b
|
|
|
17
17
|
- [@sasjs/vscode-extension](https://github.com/sasjs/vscode-extension) - just download SASjs in the VSCode marketplace, and select view/problems in the menu bar.
|
|
18
18
|
- [@sasjs/cli](https://cli.sasjs.io/lint) - run `sasjs lint` to get a list of all files with their problems, along with line and column indexes.
|
|
19
19
|
|
|
20
|
-
Configuration is via a `.sasjslint` file with the following structure (these are also the defaults
|
|
20
|
+
Configuration is via a `.sasjslint` file with the following structure (these are also the defaults - a setting that is absent, and a project with no `.sasjslint` file at all, uses the value below):
|
|
21
21
|
|
|
22
22
|
```json
|
|
23
23
|
{
|
|
24
|
+
"allowedGremlins": [],
|
|
25
|
+
"defaultHeader": "/**{lineEnding} @file{lineEnding} @brief <Your brief here>{lineEnding}{lineEnding} <h4> SAS Macros </h4>{lineEnding}{lineEnding}**/",
|
|
24
26
|
"hasDoxygenHeader": true,
|
|
25
27
|
"hasMacroNameInMend": true,
|
|
26
28
|
"hasMacroParentheses": true,
|
|
27
29
|
"hasRequiredMacroOptions": false,
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
+
"ignoreList": [],
|
|
31
|
+
"ignoredLibnames": [],
|
|
30
32
|
"indentationMultiple": 2,
|
|
31
33
|
"lineEndings": "off",
|
|
32
34
|
"lowerCaseFileNames": true,
|
|
@@ -34,18 +36,23 @@ Configuration is via a `.sasjslint` file with the following structure (these are
|
|
|
34
36
|
"maxHeaderLineLength": 80,
|
|
35
37
|
"maxLineLength": 80,
|
|
36
38
|
"noEncodedPasswords": true,
|
|
39
|
+
"noGremlins": true,
|
|
37
40
|
"noNestedMacros": true,
|
|
38
41
|
"noSingleAsteriskComments": false,
|
|
39
|
-
"noGremlins": true,
|
|
40
42
|
"noSpacesInFileNames": true,
|
|
41
43
|
"noTabs": true,
|
|
42
44
|
"noTrailingSpaces": true,
|
|
43
45
|
"noUndeclaredMacros": true,
|
|
46
|
+
"noUnusedLibnames": false,
|
|
44
47
|
"noUnusedMacros": true,
|
|
45
|
-
"
|
|
48
|
+
"requiredMacroOptions": [],
|
|
49
|
+
"severityLevel": {},
|
|
50
|
+
"strictMacroDefinition": true
|
|
46
51
|
}
|
|
47
52
|
```
|
|
48
53
|
|
|
54
|
+
Two keys do not have a section of their own. `requiredMacroOptions` is documented with [`hasRequiredMacroOptions`](#hasrequiredmacrooptions), the rule it configures. The deprecated alias `noTabIndentation` is accepted in place of `noTabs`, and is therefore not listed above - it is an alternative spelling rather than a setting of its own.
|
|
55
|
+
|
|
49
56
|
## SAS Lint Settings
|
|
50
57
|
|
|
51
58
|
Each setting can have three states:
|
|
@@ -54,10 +61,33 @@ Each setting can have three states:
|
|
|
54
61
|
- WARN - a warning is written to the log, but the return code will be 0
|
|
55
62
|
- ERROR - an error is written to the log, and the return code is 1
|
|
56
63
|
|
|
57
|
-
For more details, and the default state, see the description of each rule below. It is also possible to change whether a rule returns ERROR or WARN using the `
|
|
64
|
+
For more details, and the default state, see the description of each rule below. It is also possible to change whether a rule returns ERROR or WARN using the `severityLevel` object.
|
|
58
65
|
|
|
59
66
|
Configuring a non-zero return code (ERROR) is helpful when running `sasjs lint` as part of a git pre-commit hook. An example is available [here](https://github.com/sasjs/template_jobs/blob/main/.git-hooks/pre-commit).
|
|
60
67
|
|
|
68
|
+
## Per-file overrides
|
|
69
|
+
|
|
70
|
+
A file can adjust the configuration for itself, with a `@sasjslint` block in its Doxygen header:
|
|
71
|
+
|
|
72
|
+
```sas
|
|
73
|
+
/**
|
|
74
|
+
@file
|
|
75
|
+
@brief Calls the settlement API
|
|
76
|
+
|
|
77
|
+
@sasjslint {"maxHeaderLineLength": 200, "noUndeclaredMacros": false}
|
|
78
|
+
**/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The block holds a JSON object that is merged over the resolved `.sasjslint`:
|
|
82
|
+
|
|
83
|
+
- scalars replace, so a file can switch a rule off, switch one on, or raise a limit for itself;
|
|
84
|
+
- arrays are additive, so `allowedGremlins` and `requiredMacroOptions` gain entries rather than replacing the project's;
|
|
85
|
+
- objects merge key by key, so a file can set one `severityLevel` without dropping the others.
|
|
86
|
+
|
|
87
|
+
The override applies to the whole file, and to the formatter, so `sasjs lint fix` and format-on-save honour it - a file that switches `noUnusedMacros` off keeps the entries it would otherwise lose. Only the header is read, so an override cannot be hidden in the body of a file, and a block that is malformed is ignored rather than raised. Place it outside the `<h4> SAS Macros </h4>` section, which the formatter rewrites.
|
|
88
|
+
|
|
89
|
+
One exception: `ignoreList` is evaluated before a file is read, so an entry a header adds cannot exclude the file it sits in.
|
|
90
|
+
|
|
61
91
|
### allowedGremlins
|
|
62
92
|
|
|
63
93
|
An array of hex codes that represents allowed gremlins (invisible / undesirable characters). To allow all gremlins, you can also set the `noGremlins` rule to `false`. The full gremlin list is [here](https://github.com/sasjs/lint/blob/main/src/utils/gremlinCharacters.ts).
|
|
@@ -137,6 +167,21 @@ Example
|
|
|
137
167
|
|
|
138
168
|
There may be specific files (or folders) that are not good candidates for linting. Simply list them in this array and they will be ignored. In addition, any files in the project `.gitignore` file will also be ignored.
|
|
139
169
|
|
|
170
|
+
### ignoredLibnames
|
|
171
|
+
|
|
172
|
+
The librefs that `noUnusedLibnames` leaves alone. List the librefs that a file assigns but does not use itself - because the connection is used by an autoexec, by `%include`d code, or by another file in the same flow:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"ignoredLibnames": ["outData", "TESTWORK"]
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
A single file can add to this list with the `ignoredLibnames` key of its [`@sasjslint`](#per-file-overrides) header block, which is the per-file escape hatch for the rule.
|
|
181
|
+
|
|
182
|
+
- Default: []
|
|
183
|
+
- Used by: `noUnusedLibnames`
|
|
184
|
+
|
|
140
185
|
### indentationMultiple
|
|
141
186
|
|
|
142
187
|
This will check each line to ensure that the count of leading spaces can be divided cleanly by this multiple.
|
|
@@ -306,6 +351,50 @@ The warning is resolved by adding the macro name to the header. Running `sasjs l
|
|
|
306
351
|
- Default: true
|
|
307
352
|
- Severity: WARNING
|
|
308
353
|
|
|
354
|
+
### noUnusedLibnames
|
|
355
|
+
|
|
356
|
+
Assigning a libref opens a connection, and on a remote engine that costs time, so a `LIBNAME` statement that a file never uses is worth knowing about.
|
|
357
|
+
|
|
358
|
+
This rule reports a warning for each libref a file assigns and never mentions again. A mention is any occurrence of the libref outside the `LIBNAME` statement, which covers the indirect forms SAS accepts as well as two-level names:
|
|
359
|
+
|
|
360
|
+
```sas
|
|
361
|
+
libname outData "&dirOut.";
|
|
362
|
+
libname TESTWORK "&work";
|
|
363
|
+
libname path2 "&sasjswork/path2";
|
|
364
|
+
|
|
365
|
+
libText = pathname("outData", "L"); /* the libref as a string */
|
|
366
|
+
%let dir = %sysfunc(pathname(TESTWORK)); /* the libref unquoted */
|
|
367
|
+
proc format library=path2; /* the libref as an option value */
|
|
368
|
+
options insert=(fmtsearch=(path1 path2));
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
The test is deliberately generous, because a use that is missed becomes a false positive. A `LIBNAME` statement that deassigns (`libname foo;`), clears (`libname foo clear;`) or reports (`libname foo list;`) assigns nothing, so it is never reported - and it counts as a use, since it refers to a libref assigned elsewhere. The reporting form `libname _all_ list;` names no libref. A libref built at runtime (`libname &lib;`) is not a literal, so there is nothing to check.
|
|
372
|
+
|
|
373
|
+
The rule is **off by default**. A `.sas` file is not a complete job, so a libref it assigns can be used by:
|
|
374
|
+
|
|
375
|
+
- an `autoexec.sas` that pre-assigns librefs
|
|
376
|
+
- macros, functions or `%include`d programs that the linter never sees
|
|
377
|
+
- another file in the same flow - in the SASjs framework, a secondary artefact
|
|
378
|
+
|
|
379
|
+
Enable it per project with `"noUnusedLibnames": true`, and list the librefs it should leave alone in [`ignoredLibnames`](#ignoredlibnames). An individual file can exempt its own librefs, or enable the rule for itself, in its `@sasjslint` header block:
|
|
380
|
+
|
|
381
|
+
```sas
|
|
382
|
+
/**
|
|
383
|
+
@file
|
|
384
|
+
@brief Loads the settlement feed
|
|
385
|
+
|
|
386
|
+
<h4> SAS Macros </h4>
|
|
387
|
+
@li mf_trim.sas
|
|
388
|
+
|
|
389
|
+
@sasjslint {"noUnusedLibnames": true, "ignoredLibnames": ["outData"]}
|
|
390
|
+
**/
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
There is no fix. `sasjs lint fix` leaves the file alone, because the formatter cannot see the rest of the job - removing the statement could break it, and silencing every warning into the ignore list would make the rule pointless.
|
|
394
|
+
|
|
395
|
+
- Default: false
|
|
396
|
+
- Severity: WARNING
|
|
397
|
+
|
|
309
398
|
### noUnusedMacros
|
|
310
399
|
|
|
311
400
|
The counterpart of `noUndeclaredMacros`. This rule reports a warning for each macro listed under `<h4> SAS Macros </h4>` that the file itself never invokes, which usually means the header is out of date.
|
|
@@ -317,6 +406,18 @@ Running `sasjs lint fix` (or saving in the SASjs VS Code extension with `formatO
|
|
|
317
406
|
- Default: true
|
|
318
407
|
- Severity: WARNING
|
|
319
408
|
|
|
409
|
+
### strictMacroDefinition
|
|
410
|
+
|
|
411
|
+
This will check the syntax of a macro definition, and warn about two things:
|
|
412
|
+
|
|
413
|
+
- a parameter name that contains a space, as in `%macro myMacro(my var);`
|
|
414
|
+
- an option that SAS does not recognise, as in `%macro myMacro()/nonsense;`
|
|
415
|
+
|
|
416
|
+
The options SAS accepts are `CMD`, `DES`, `MINDELIMITER`, `MINOPERATOR`, `NOMINOPERATOR`, `PARMBUFF`, `SECURE`, `NOSECURE`, `STMT`, `SOURCE`, `SRC` and `STORE`.
|
|
417
|
+
|
|
418
|
+
- Default: true
|
|
419
|
+
- Severity: WARNING
|
|
420
|
+
|
|
320
421
|
## severityLevel
|
|
321
422
|
|
|
322
423
|
This setting allows the default severity to be adjusted. This is helpful when running the lint in a pipeline or git hook. Simply list the rules you would like to adjust along with the desired setting ("warn" or "error"), eg as follows:
|
package/format/formatFile.js
CHANGED
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.formatFile = void 0;
|
|
13
13
|
const file_1 = require("@sasjs/utils/file");
|
|
14
14
|
const lint_1 = require("../lint");
|
|
15
|
+
const parseLintOverride_1 = require("../utils/parseLintOverride");
|
|
15
16
|
const getLintConfig_1 = require("../utils/getLintConfig");
|
|
16
17
|
const shared_1 = require("./shared");
|
|
17
18
|
/**
|
|
@@ -25,7 +26,7 @@ const formatFile = (filePath, configuration) => __awaiter(void 0, void 0, void 0
|
|
|
25
26
|
const diagnosticsBeforeFormat = yield (0, lint_1.lintFile)(filePath, config);
|
|
26
27
|
const diagnosticsCountBeforeFormat = diagnosticsBeforeFormat.length;
|
|
27
28
|
const text = yield (0, file_1.readFile)(filePath);
|
|
28
|
-
const formattedText = (0, shared_1.processText)(text, config);
|
|
29
|
+
const formattedText = (0, shared_1.processText)(text, (0, parseLintOverride_1.applyLintOverride)(text, config));
|
|
29
30
|
yield (0, file_1.createFile)(filePath, formattedText);
|
|
30
31
|
const diagnosticsAfterFormat = yield (0, lint_1.lintFile)(filePath, config);
|
|
31
32
|
const diagnosticsCountAfterFormat = diagnosticsAfterFormat.length;
|
package/format/formatFile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatFile.js","sourceRoot":"","sources":["../../src/format/formatFile.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,4CAAwD;AACxD,kCAAkC;AAGlC,0DAAsD;AACtD,qCAAsC;AAEtC;;;;;GAKG;AACI,MAAM,UAAU,GAAG,CACxB,QAAgB,EAChB,aAA0B,EACH,EAAE;IACzB,MAAM,MAAM,GAAG,aAAa,IAAI,CAAC,MAAM,IAAA,6BAAa,GAAE,CAAC,CAAA;IACvD,MAAM,uBAAuB,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAChE,MAAM,4BAA4B,GAAG,uBAAuB,CAAC,MAAM,CAAA;IAEnE,MAAM,IAAI,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAA;IAErC,MAAM,aAAa,GAAG,IAAA,oBAAW,EAAC,IAAI,EAAE,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"formatFile.js","sourceRoot":"","sources":["../../src/format/formatFile.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,4CAAwD;AACxD,kCAAkC;AAGlC,kEAA8D;AAC9D,0DAAsD;AACtD,qCAAsC;AAEtC;;;;;GAKG;AACI,MAAM,UAAU,GAAG,CACxB,QAAgB,EAChB,aAA0B,EACH,EAAE;IACzB,MAAM,MAAM,GAAG,aAAa,IAAI,CAAC,MAAM,IAAA,6BAAa,GAAE,CAAC,CAAA;IACvD,MAAM,uBAAuB,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAChE,MAAM,4BAA4B,GAAG,uBAAuB,CAAC,MAAM,CAAA;IAEnE,MAAM,IAAI,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAA;IAErC,MAAM,aAAa,GAAG,IAAA,oBAAW,EAAC,IAAI,EAAE,IAAA,qCAAiB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAExE,MAAM,IAAA,iBAAU,EAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IAEzC,MAAM,sBAAsB,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC/D,MAAM,2BAA2B,GAAG,sBAAsB,CAAC,MAAM,CAAA;IAEjE,MAAM,qBAAqB,GACzB,4BAA4B,GAAG,2BAA2B,CAAA;IAE5D,MAAM,gBAAgB,GAAa,EAAE,CAAA;IAErC,IAAI,qBAAqB,EAAE,CAAC;QAC1B,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,OAAO;QACL,gBAAgB;QAChB,qBAAqB;QACrB,kBAAkB,EAAE,sBAAsB;KAC3C,CAAA;AACH,CAAC,CAAA,CAAA;AA/BY,QAAA,UAAU,cA+BtB"}
|
package/format/formatText.js
CHANGED
|
@@ -14,7 +14,7 @@ const utils_1 = require("../utils");
|
|
|
14
14
|
const shared_1 = require("./shared");
|
|
15
15
|
const formatText = (text, configuration) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
16
|
const config = configuration || (yield (0, utils_1.getLintConfig)());
|
|
17
|
-
return (0, shared_1.processText)(text, config);
|
|
17
|
+
return (0, shared_1.processText)(text, (0, utils_1.applyLintOverride)(text, config));
|
|
18
18
|
});
|
|
19
19
|
exports.formatText = formatText;
|
|
20
20
|
//# sourceMappingURL=formatText.js.map
|
package/format/formatText.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatText.js","sourceRoot":"","sources":["../../src/format/formatText.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,
|
|
1
|
+
{"version":3,"file":"formatText.js","sourceRoot":"","sources":["../../src/format/formatText.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oCAA2D;AAC3D,qCAAsC;AAE/B,MAAM,UAAU,GAAG,CAAO,IAAY,EAAE,aAA0B,EAAE,EAAE;IAC3E,MAAM,MAAM,GAAG,aAAa,IAAI,CAAC,MAAM,IAAA,qBAAa,GAAE,CAAC,CAAA;IACvD,OAAO,IAAA,oBAAW,EAAC,IAAI,EAAE,IAAA,yBAAiB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;AAC3D,CAAC,CAAA,CAAA;AAHY,QAAA,UAAU,cAGtB"}
|
package/lint/lintFile.js
CHANGED
|
@@ -24,8 +24,9 @@ const lintFile = (filePath, configuration) => __awaiter(void 0, void 0, void 0,
|
|
|
24
24
|
return [];
|
|
25
25
|
const config = configuration || (yield (0, utils_1.getLintConfig)());
|
|
26
26
|
const text = yield (0, file_1.readFile)(filePath);
|
|
27
|
-
const
|
|
28
|
-
const
|
|
27
|
+
const effectiveConfig = (0, utils_1.applyLintOverride)(text, config);
|
|
28
|
+
const fileDiagnostics = (0, shared_1.processFile)(filePath, effectiveConfig);
|
|
29
|
+
const textDiagnostics = (0, shared_1.processText)(text, effectiveConfig);
|
|
29
30
|
return [...fileDiagnostics, ...textDiagnostics];
|
|
30
31
|
});
|
|
31
32
|
exports.lintFile = lintFile;
|
package/lint/lintFile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lintFile.js","sourceRoot":"","sources":["../../src/lint/lintFile.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,4CAA4C;AAE5C,
|
|
1
|
+
{"version":3,"file":"lintFile.js","sourceRoot":"","sources":["../../src/lint/lintFile.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,4CAA4C;AAE5C,oCAAsE;AACtE,qCAAmD;AAEnD;;;;;GAKG;AACI,MAAM,QAAQ,GAAG,CACtB,QAAgB,EAChB,aAA0B,EACH,EAAE;IACzB,IAAI,MAAM,IAAA,iBAAS,EAAC,QAAQ,EAAE,aAAa,CAAC;QAAE,OAAO,EAAE,CAAA;IAEvD,MAAM,MAAM,GAAG,aAAa,IAAI,CAAC,MAAM,IAAA,qBAAa,GAAE,CAAC,CAAA;IACvD,MAAM,IAAI,GAAG,MAAM,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAA;IACrC,MAAM,eAAe,GAAG,IAAA,yBAAiB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAEvD,MAAM,eAAe,GAAG,IAAA,oBAAW,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAC9D,MAAM,eAAe,GAAG,IAAA,oBAAW,EAAC,IAAI,EAAE,eAAe,CAAC,CAAA;IAE1D,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,eAAe,CAAC,CAAA;AACjD,CAAC,CAAA,CAAA;AAdY,QAAA,QAAQ,YAcpB"}
|
package/lint/lintText.js
CHANGED
|
@@ -22,7 +22,7 @@ const shared_1 = require("./shared");
|
|
|
22
22
|
*/
|
|
23
23
|
const lintText = (text, configuration) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
24
|
const config = configuration || (yield (0, utils_1.getLintConfig)());
|
|
25
|
-
return (0, shared_1.processText)(text, config);
|
|
25
|
+
return (0, shared_1.processText)(text, (0, utils_1.applyLintOverride)(text, config));
|
|
26
26
|
});
|
|
27
27
|
exports.lintText = lintText;
|
|
28
28
|
//# sourceMappingURL=lintText.js.map
|
package/lint/lintText.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lintText.js","sourceRoot":"","sources":["../../src/lint/lintText.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,
|
|
1
|
+
{"version":3,"file":"lintText.js","sourceRoot":"","sources":["../../src/lint/lintText.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,oCAA2D;AAC3D,qCAAsC;AAEtC;;;;;;;GAOG;AACI,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,aAA0B,EACH,EAAE;IACzB,MAAM,MAAM,GAAG,aAAa,IAAI,CAAC,MAAM,IAAA,qBAAa,GAAE,CAAC,CAAA;IACvD,OAAO,IAAA,oBAAW,EAAC,IAAI,EAAE,IAAA,yBAAiB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;AAC3D,CAAC,CAAA,CAAA;AANY,QAAA,QAAQ,YAMpB"}
|
package/package.json
CHANGED
package/rules/file/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { lineEndings } from './lineEndings';
|
|
|
5
5
|
export { noNestedMacros } from './noNestedMacros';
|
|
6
6
|
export { noUndeclaredMacros } from './noUndeclaredMacros';
|
|
7
7
|
export { noUnusedMacros } from './noUnusedMacros';
|
|
8
|
+
export { noUnusedLibnames } from './noUnusedLibnames';
|
|
8
9
|
export { strictMacroDefinition } from './strictMacroDefinition';
|
|
9
10
|
export { hasRequiredMacroOptions } from './hasRequiredMacroOptions';
|
|
10
11
|
export { noSingleAsteriskComments } from './noSingleAsteriskComments';
|
package/rules/file/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noSingleAsteriskComments = exports.hasRequiredMacroOptions = exports.strictMacroDefinition = exports.noUnusedMacros = exports.noUndeclaredMacros = exports.noNestedMacros = exports.lineEndings = exports.hasMacroParentheses = exports.hasMacroNameInMend = exports.hasDoxygenHeader = void 0;
|
|
3
|
+
exports.noSingleAsteriskComments = exports.hasRequiredMacroOptions = exports.strictMacroDefinition = exports.noUnusedLibnames = exports.noUnusedMacros = exports.noUndeclaredMacros = exports.noNestedMacros = exports.lineEndings = exports.hasMacroParentheses = exports.hasMacroNameInMend = exports.hasDoxygenHeader = void 0;
|
|
4
4
|
var hasDoxygenHeader_1 = require("./hasDoxygenHeader");
|
|
5
5
|
Object.defineProperty(exports, "hasDoxygenHeader", { enumerable: true, get: function () { return hasDoxygenHeader_1.hasDoxygenHeader; } });
|
|
6
6
|
var hasMacroNameInMend_1 = require("./hasMacroNameInMend");
|
|
@@ -15,6 +15,8 @@ var noUndeclaredMacros_1 = require("./noUndeclaredMacros");
|
|
|
15
15
|
Object.defineProperty(exports, "noUndeclaredMacros", { enumerable: true, get: function () { return noUndeclaredMacros_1.noUndeclaredMacros; } });
|
|
16
16
|
var noUnusedMacros_1 = require("./noUnusedMacros");
|
|
17
17
|
Object.defineProperty(exports, "noUnusedMacros", { enumerable: true, get: function () { return noUnusedMacros_1.noUnusedMacros; } });
|
|
18
|
+
var noUnusedLibnames_1 = require("./noUnusedLibnames");
|
|
19
|
+
Object.defineProperty(exports, "noUnusedLibnames", { enumerable: true, get: function () { return noUnusedLibnames_1.noUnusedLibnames; } });
|
|
18
20
|
var strictMacroDefinition_1 = require("./strictMacroDefinition");
|
|
19
21
|
Object.defineProperty(exports, "strictMacroDefinition", { enumerable: true, get: function () { return strictMacroDefinition_1.strictMacroDefinition; } });
|
|
20
22
|
var hasRequiredMacroOptions_1 = require("./hasRequiredMacroOptions");
|
package/rules/file/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/file/index.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA2D;AAAlD,0HAAA,mBAAmB,OAAA;AAC5B,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,iEAA+D;AAAtD,8HAAA,qBAAqB,OAAA;AAC9B,qEAAmE;AAA1D,kIAAA,uBAAuB,OAAA;AAChC,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/file/index.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA2D;AAAlD,0HAAA,mBAAmB,OAAA;AAC5B,6CAA2C;AAAlC,0GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,uDAAqD;AAA5C,oHAAA,gBAAgB,OAAA;AACzB,iEAA+D;AAAtD,8HAAA,qBAAqB,OAAA;AAC9B,qEAAmE;AAA1D,kIAAA,uBAAuB,OAAA;AAChC,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FileLintRule } from '../../types/LintRule';
|
|
2
|
+
/**
|
|
3
|
+
* Lint rule that reports each libref a file assigns and never uses.
|
|
4
|
+
*
|
|
5
|
+
* The rule is off by default. A file is not a complete job, so a libref it
|
|
6
|
+
* assigns can be used by an autoexec, by `%include`d code, or by another file
|
|
7
|
+
* in the same SASjs flow - in the framework, by a secondary artefact. Enable it
|
|
8
|
+
* per project with `noUnusedLibnames`, and list the librefs it should leave
|
|
9
|
+
* alone in `ignoredLibnames`, or in the `@sasjslint` block of one file.
|
|
10
|
+
*
|
|
11
|
+
* There is no fix. The formatter cannot see the rest of the job, so the safe
|
|
12
|
+
* correction is not knowable, and silencing every warning into the ignore list
|
|
13
|
+
* would make the rule pointless.
|
|
14
|
+
*/
|
|
15
|
+
export declare const noUnusedLibnames: FileLintRule;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUnusedLibnames = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const LintRuleType_1 = require("../../types/LintRuleType");
|
|
6
|
+
const Severity_1 = require("../../types/Severity");
|
|
7
|
+
const parseLibnames_1 = require("../../utils/parseLibnames");
|
|
8
|
+
const name = 'noUnusedLibnames';
|
|
9
|
+
const description = 'Report librefs that a file assigns and never uses in that file.';
|
|
10
|
+
const message = `Libref '{libref}' is assigned but never used in this file - remove the LIBNAME statement, or list the libref in 'ignoredLibnames'`;
|
|
11
|
+
/**
|
|
12
|
+
* Collects the librefs the file assigns and never mentions, leaving out the
|
|
13
|
+
* ones the configuration lists in `ignoredLibnames`.
|
|
14
|
+
*
|
|
15
|
+
* A libref can be used by a file the linter never sees - an autoexec, an
|
|
16
|
+
* `%include`d program, or another file in the same job - which is why the rule
|
|
17
|
+
* is off by default and why the ignore list exists.
|
|
18
|
+
*/
|
|
19
|
+
const getUnused = (value, config) => {
|
|
20
|
+
if (!value)
|
|
21
|
+
return [];
|
|
22
|
+
const ignored = new Set(config.ignoredLibnames.map((libref) => libref.toLowerCase()));
|
|
23
|
+
return (0, parseLibnames_1.getUnusedLibnames)(value, config).filter(({ libref }) => !ignored.has(libref.toLowerCase()));
|
|
24
|
+
};
|
|
25
|
+
const test = (value, config) => {
|
|
26
|
+
const cfg = config || new types_1.LintConfig();
|
|
27
|
+
const severity = cfg.severityLevel[name] || Severity_1.Severity.Warning;
|
|
28
|
+
return getUnused(value, cfg).map((assignment) => ({
|
|
29
|
+
message: message.replace('{libref}', assignment.libref),
|
|
30
|
+
lineNumber: assignment.lineNumber,
|
|
31
|
+
startColumnNumber: assignment.startColumnNumber,
|
|
32
|
+
endColumnNumber: assignment.endColumnNumber,
|
|
33
|
+
severity
|
|
34
|
+
}));
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Lint rule that reports each libref a file assigns and never uses.
|
|
38
|
+
*
|
|
39
|
+
* The rule is off by default. A file is not a complete job, so a libref it
|
|
40
|
+
* assigns can be used by an autoexec, by `%include`d code, or by another file
|
|
41
|
+
* in the same SASjs flow - in the framework, by a secondary artefact. Enable it
|
|
42
|
+
* per project with `noUnusedLibnames`, and list the librefs it should leave
|
|
43
|
+
* alone in `ignoredLibnames`, or in the `@sasjslint` block of one file.
|
|
44
|
+
*
|
|
45
|
+
* There is no fix. The formatter cannot see the rest of the job, so the safe
|
|
46
|
+
* correction is not knowable, and silencing every warning into the ignore list
|
|
47
|
+
* would make the rule pointless.
|
|
48
|
+
*/
|
|
49
|
+
exports.noUnusedLibnames = {
|
|
50
|
+
type: LintRuleType_1.LintRuleType.File,
|
|
51
|
+
name,
|
|
52
|
+
description,
|
|
53
|
+
message,
|
|
54
|
+
test
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=noUnusedLibnames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noUnusedLibnames.js","sourceRoot":"","sources":["../../../src/rules/file/noUnusedLibnames.ts"],"names":[],"mappings":";;;AAAA,uCAAoD;AAEpD,2DAAuD;AACvD,mDAA+C;AAC/C,6DAAgF;AAEhF,MAAM,IAAI,GAAG,kBAAkB,CAAA;AAC/B,MAAM,WAAW,GACf,iEAAiE,CAAA;AACnE,MAAM,OAAO,GAAG,mIAAmI,CAAA;AAEnJ;;;;;;;GAOG;AACH,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,MAAkB,EAAuB,EAAE;IAC3E,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IAErB,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAC7D,CAAA;IAED,OAAO,IAAA,iCAAiB,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAC5C,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CACnD,CAAA;AACH,CAAC,CAAA;AAED,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAgB,EAAE;IAChE,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,kBAAU,EAAE,CAAA;IACtC,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,mBAAQ,CAAC,OAAO,CAAA;IAE5D,OAAO,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC;QACvD,UAAU,EAAE,UAAU,CAAC,UAAU;QACjC,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,eAAe,EAAE,UAAU,CAAC,eAAe;QAC3C,QAAQ;KACT,CAAC,CAAC,CAAA;AACL,CAAC,CAAA;AAED;;;;;;;;;;;;GAYG;AACU,QAAA,gBAAgB,GAAiB;IAC5C,IAAI,EAAE,2BAAY,CAAC,IAAI;IACvB,IAAI;IACJ,WAAW;IACX,OAAO;IACP,IAAI;CACL,CAAA"}
|
package/sasjslint-schema.json
CHANGED
|
@@ -3,18 +3,23 @@
|
|
|
3
3
|
"$id": "https://github.com/sasjs/lint/blob/main/sasjslint-schema.json",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"title": "SASjs Lint Config File",
|
|
6
|
-
"description": "The SASjs Lint Config file provides the settings for customising SAS code style in your project.",
|
|
6
|
+
"description": "The SASjs Lint Config file provides the settings for customising SAS code style in your project. A SAS file can override these settings for itself with a `@sasjslint` block in its Doxygen header.",
|
|
7
7
|
"default": {
|
|
8
|
-
"
|
|
9
|
-
"hasDoxygenHeader": true,
|
|
8
|
+
"allowedGremlins": [],
|
|
10
9
|
"defaultHeader": "/**{lineEnding} @file{lineEnding} @brief <Your brief here>{lineEnding}{lineEnding} <h4> SAS Macros </h4>{lineEnding}{lineEnding}**/",
|
|
11
|
-
"
|
|
10
|
+
"hasDoxygenHeader": true,
|
|
11
|
+
"hasMacroNameInMend": true,
|
|
12
12
|
"hasMacroParentheses": true,
|
|
13
|
+
"hasRequiredMacroOptions": false,
|
|
14
|
+
"ignoreList": [],
|
|
15
|
+
"ignoredLibnames": [],
|
|
13
16
|
"indentationMultiple": 2,
|
|
17
|
+
"lineEndings": "off",
|
|
14
18
|
"lowerCaseFileNames": true,
|
|
15
|
-
"maxLineLength": 80,
|
|
16
|
-
"maxHeaderLineLength": 80,
|
|
17
19
|
"maxDataLineLength": 80,
|
|
20
|
+
"maxHeaderLineLength": 80,
|
|
21
|
+
"maxLineLength": 80,
|
|
22
|
+
"noEncodedPasswords": true,
|
|
18
23
|
"noGremlins": true,
|
|
19
24
|
"noNestedMacros": true,
|
|
20
25
|
"noSingleAsteriskComments": false,
|
|
@@ -22,12 +27,11 @@
|
|
|
22
27
|
"noTabs": true,
|
|
23
28
|
"noTrailingSpaces": true,
|
|
24
29
|
"noUndeclaredMacros": true,
|
|
30
|
+
"noUnusedLibnames": false,
|
|
25
31
|
"noUnusedMacros": true,
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"hasRequiredMacroOptions": false,
|
|
30
|
-
"requiredMacroOptions": []
|
|
32
|
+
"requiredMacroOptions": [],
|
|
33
|
+
"severityLevel": {},
|
|
34
|
+
"strictMacroDefinition": true
|
|
31
35
|
},
|
|
32
36
|
"examples": [
|
|
33
37
|
{
|
|
@@ -106,7 +110,7 @@
|
|
|
106
110
|
"type": "boolean",
|
|
107
111
|
"title": "hasMacroNameInMend",
|
|
108
112
|
"description": "Enforces the presence of macro names in %mend statements. Shows a warning for %mend statements with missing or mismatched macro names.",
|
|
109
|
-
"default":
|
|
113
|
+
"default": true,
|
|
110
114
|
"examples": [true, false]
|
|
111
115
|
},
|
|
112
116
|
"hasMacroParentheses": {
|
|
@@ -213,6 +217,14 @@
|
|
|
213
217
|
"default": true,
|
|
214
218
|
"examples": [true, false]
|
|
215
219
|
},
|
|
220
|
+
"noUnusedLibnames": {
|
|
221
|
+
"$id": "#/properties/noUnusedLibnames",
|
|
222
|
+
"type": "boolean",
|
|
223
|
+
"title": "noUnusedLibnames",
|
|
224
|
+
"description": "Reports a warning for each libref a file assigns with a LIBNAME statement and never uses in that file. A mention of the libref anywhere else counts as a use, including the indirect forms SAS accepts, such as `pathname(TESTWORK)`, `library=path2` and `fmtsearch=(path1 path2)`. Off by default, because a file is not a complete job - the libref can be used by an autoexec, by `%include`d code, or by another file in the same flow. There is no fix; list the librefs to leave alone in `ignoredLibnames`.",
|
|
225
|
+
"default": false,
|
|
226
|
+
"examples": [true, false]
|
|
227
|
+
},
|
|
216
228
|
"lineEndings": {
|
|
217
229
|
"$id": "#/properties/lineEndings",
|
|
218
230
|
"type": "string",
|
|
@@ -235,8 +247,16 @@
|
|
|
235
247
|
"type": "array",
|
|
236
248
|
"title": "ignoreList",
|
|
237
249
|
"description": "An array of paths or path patterns to ignore when linting. Any files or matching patterns in the .gitignore file will also be ignored.",
|
|
238
|
-
"default": [
|
|
239
|
-
"examples": ["sasjs/tests", "tmp/scratch.sas"]
|
|
250
|
+
"default": [],
|
|
251
|
+
"examples": [["sasjsbuild/", "sasjsresults/"], ["sasjs/tests", "tmp/scratch.sas"]]
|
|
252
|
+
},
|
|
253
|
+
"ignoredLibnames": {
|
|
254
|
+
"$id": "#/properties/ignoredLibnames",
|
|
255
|
+
"type": "array",
|
|
256
|
+
"title": "ignoredLibnames",
|
|
257
|
+
"description": "An array of librefs that `noUnusedLibnames` leaves alone. A single file can add to this list with the `ignoredLibnames` key of its `@sasjslint` header block.",
|
|
258
|
+
"default": [],
|
|
259
|
+
"examples": [["outData", "TESTWORK"]]
|
|
240
260
|
},
|
|
241
261
|
"hasRequiredMacroOptions": {
|
|
242
262
|
"$id": "#/properties/hasRequiredMacroOptions",
|
|
@@ -378,6 +398,13 @@
|
|
|
378
398
|
"enum": ["error", "warn"],
|
|
379
399
|
"default": "warn"
|
|
380
400
|
},
|
|
401
|
+
"noUnusedLibnames": {
|
|
402
|
+
"$id": "#/properties/severityLevel/noUnusedLibnames",
|
|
403
|
+
"title": "noUnusedLibnames",
|
|
404
|
+
"type": "string",
|
|
405
|
+
"enum": ["error", "warn"],
|
|
406
|
+
"default": "warn"
|
|
407
|
+
},
|
|
381
408
|
"lineEndings": {
|
|
382
409
|
"$id": "#/properties/severityLevel/lineEndings",
|
|
383
410
|
"title": "lineEndings",
|
package/types/LintConfig.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ import { Severity } from './Severity';
|
|
|
9
9
|
* More types of rules, when available, will be added here.
|
|
10
10
|
*/
|
|
11
11
|
export declare class LintConfig {
|
|
12
|
+
/** The JSON this configuration was built from, so it can be overridden. */
|
|
13
|
+
readonly source: any;
|
|
12
14
|
readonly ignoreList: string[];
|
|
13
15
|
readonly allowedGremlins: string[];
|
|
14
16
|
readonly lineLintRules: LineLintRule[];
|
|
@@ -24,5 +26,17 @@ export declare class LintConfig {
|
|
|
24
26
|
[key: string]: Severity;
|
|
25
27
|
};
|
|
26
28
|
readonly requiredMacroOptions: string[];
|
|
29
|
+
readonly ignoredLibnames: string[];
|
|
27
30
|
constructor(json?: any);
|
|
31
|
+
/**
|
|
32
|
+
* Returns a new configuration with an override merged over this one, so a
|
|
33
|
+
* file can adjust the rules that apply to it.
|
|
34
|
+
*
|
|
35
|
+
* Scalars replace, arrays are additive and objects merge key by key - see
|
|
36
|
+
* `mergeLintConfig`.
|
|
37
|
+
*
|
|
38
|
+
* @param {object} json - the override, as read from a `@sasjslint` block.
|
|
39
|
+
* @returns {LintConfig} a new configuration; this one is unchanged.
|
|
40
|
+
*/
|
|
41
|
+
override(json: any): LintConfig;
|
|
28
42
|
}
|
package/types/LintConfig.js
CHANGED
|
@@ -6,6 +6,7 @@ const line_1 = require("../rules/line");
|
|
|
6
6
|
const path_1 = require("../rules/path");
|
|
7
7
|
const LineEndings_1 = require("./LineEndings");
|
|
8
8
|
const utils_1 = require("../utils");
|
|
9
|
+
const mergeLintConfig_1 = require("../utils/mergeLintConfig");
|
|
9
10
|
const Severity_1 = require("./Severity");
|
|
10
11
|
/**
|
|
11
12
|
* LintConfig is the logical representation of the .sasjslint file.
|
|
@@ -29,6 +30,8 @@ class LintConfig {
|
|
|
29
30
|
this.defaultHeader = (0, utils_1.getDefaultHeader)();
|
|
30
31
|
this.severityLevel = {};
|
|
31
32
|
this.requiredMacroOptions = [];
|
|
33
|
+
this.ignoredLibnames = [];
|
|
34
|
+
this.source = json !== null && json !== void 0 ? json : {};
|
|
32
35
|
if (json === null || json === void 0 ? void 0 : json.ignoreList) {
|
|
33
36
|
if (Array.isArray(json.ignoreList)) {
|
|
34
37
|
json.ignoreList.forEach((item) => {
|
|
@@ -52,9 +55,13 @@ class LintConfig {
|
|
|
52
55
|
if ((json === null || json === void 0 ? void 0 : json.noTabs) === false || (json === null || json === void 0 ? void 0 : json.noTabIndentation) === false) {
|
|
53
56
|
this.lineLintRules.pop();
|
|
54
57
|
}
|
|
55
|
-
|
|
58
|
+
// An absent setting falls back to the default, so the rule is on unless the
|
|
59
|
+
// value switches it off (0 or a negative number).
|
|
60
|
+
if ((json === null || json === void 0 ? void 0 : json.maxLineLength) === undefined || (json === null || json === void 0 ? void 0 : json.maxLineLength) > 0) {
|
|
56
61
|
this.lineLintRules.push(line_1.maxLineLength);
|
|
57
|
-
|
|
62
|
+
if (!isNaN(json === null || json === void 0 ? void 0 : json.maxLineLength)) {
|
|
63
|
+
this.maxLineLength = json.maxLineLength;
|
|
64
|
+
}
|
|
58
65
|
if (!isNaN(json === null || json === void 0 ? void 0 : json.maxHeaderLineLength)) {
|
|
59
66
|
this.maxHeaderLineLength = json.maxHeaderLineLength;
|
|
60
67
|
}
|
|
@@ -86,7 +93,7 @@ class LintConfig {
|
|
|
86
93
|
if ((json === null || json === void 0 ? void 0 : json.lowerCaseFileNames) !== false) {
|
|
87
94
|
this.pathLintRules.push(path_1.lowerCaseFileNames);
|
|
88
95
|
}
|
|
89
|
-
if (json === null || json === void 0 ? void 0 : json.hasMacroNameInMend) {
|
|
96
|
+
if ((json === null || json === void 0 ? void 0 : json.hasMacroNameInMend) !== false) {
|
|
90
97
|
this.fileLintRules.push(file_1.hasMacroNameInMend);
|
|
91
98
|
}
|
|
92
99
|
if ((json === null || json === void 0 ? void 0 : json.noNestedMacros) !== false) {
|
|
@@ -101,20 +108,17 @@ class LintConfig {
|
|
|
101
108
|
if (json === null || json === void 0 ? void 0 : json.hasRequiredMacroOptions) {
|
|
102
109
|
this.fileLintRules.push(file_1.hasRequiredMacroOptions);
|
|
103
110
|
if (json === null || json === void 0 ? void 0 : json.requiredMacroOptions) {
|
|
104
|
-
if (Array.isArray(json.requiredMacroOptions)
|
|
105
|
-
json.requiredMacroOptions.length > 0) {
|
|
106
|
-
json.requiredMacroOptions.forEach((item) => {
|
|
107
|
-
if (typeof item === 'string') {
|
|
108
|
-
this.requiredMacroOptions.push(item);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
throw new Error(`Property "requiredMacroOptions" has invalid type of values. It can only contain strings.`);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
111
|
+
if (!Array.isArray(json.requiredMacroOptions)) {
|
|
116
112
|
throw new Error(`Property "requiredMacroOptions" can only be an array of strings.`);
|
|
117
113
|
}
|
|
114
|
+
json.requiredMacroOptions.forEach((item) => {
|
|
115
|
+
if (typeof item === 'string') {
|
|
116
|
+
this.requiredMacroOptions.push(item);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
throw new Error(`Property "requiredMacroOptions" has invalid type of values. It can only contain strings.`);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
if (json === null || json === void 0 ? void 0 : json.noSingleAsteriskComments) {
|
|
@@ -126,6 +130,23 @@ class LintConfig {
|
|
|
126
130
|
if ((json === null || json === void 0 ? void 0 : json.noUnusedMacros) !== false) {
|
|
127
131
|
this.fileLintRules.push(file_1.noUnusedMacros);
|
|
128
132
|
}
|
|
133
|
+
// Off by default: a libref a file assigns can be used by another file.
|
|
134
|
+
if (json === null || json === void 0 ? void 0 : json.noUnusedLibnames) {
|
|
135
|
+
this.fileLintRules.push(file_1.noUnusedLibnames);
|
|
136
|
+
if (json === null || json === void 0 ? void 0 : json.ignoredLibnames) {
|
|
137
|
+
if (!Array.isArray(json.ignoredLibnames)) {
|
|
138
|
+
throw new Error(`Property "ignoredLibnames" can only be an array of strings.`);
|
|
139
|
+
}
|
|
140
|
+
json.ignoredLibnames.forEach((item) => {
|
|
141
|
+
if (typeof item === 'string') {
|
|
142
|
+
this.ignoredLibnames.push(item);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
throw new Error(`Property "ignoredLibnames" has invalid type of values. It can only contain strings.`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
129
150
|
if ((json === null || json === void 0 ? void 0 : json.noGremlins) !== false) {
|
|
130
151
|
this.lineLintRules.push(line_1.noGremlins);
|
|
131
152
|
if (json === null || json === void 0 ? void 0 : json.allowedGremlins) {
|
|
@@ -151,6 +172,19 @@ class LintConfig {
|
|
|
151
172
|
}
|
|
152
173
|
}
|
|
153
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Returns a new configuration with an override merged over this one, so a
|
|
177
|
+
* file can adjust the rules that apply to it.
|
|
178
|
+
*
|
|
179
|
+
* Scalars replace, arrays are additive and objects merge key by key - see
|
|
180
|
+
* `mergeLintConfig`.
|
|
181
|
+
*
|
|
182
|
+
* @param {object} json - the override, as read from a `@sasjslint` block.
|
|
183
|
+
* @returns {LintConfig} a new configuration; this one is unchanged.
|
|
184
|
+
*/
|
|
185
|
+
override(json) {
|
|
186
|
+
return new LintConfig((0, mergeLintConfig_1.mergeLintConfig)(this.source, json));
|
|
187
|
+
}
|
|
154
188
|
}
|
|
155
189
|
exports.LintConfig = LintConfig;
|
|
156
190
|
//# sourceMappingURL=LintConfig.js.map
|