@sasjs/lint 4.8.1 → 5.0.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 +43 -6
- package/package.json +9 -16
- package/rules/file/index.d.ts +2 -0
- package/rules/file/index.js +5 -1
- package/rules/file/index.js.map +1 -1
- package/rules/file/lowerCaseMacroNames.d.ts +7 -0
- package/rules/file/lowerCaseMacroNames.js +166 -0
- package/rules/file/lowerCaseMacroNames.js.map +1 -0
- package/rules/file/noXcmd.d.ts +7 -0
- package/rules/file/noXcmd.js +489 -0
- package/rules/file/noXcmd.js.map +1 -0
- package/sasjslint-schema.json +33 -0
- package/types/LintConfig.js +6 -0
- package/types/LintConfig.js.map +1 -1
- package/utils/getLintConfig.d.ts +2 -0
- package/utils/getLintConfig.js +2 -0
- package/utils/getLintConfig.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-

|
|
2
|
-
[](https://github.com/sasjs/lint/issues?q=is%3Aissue+is%3Aclosed)
|
|
3
|
-
[](https://github.com/sasjs/lint/issues)
|
|
4
|
-

|
|
5
|
-
[](https://gitpod.io/#https://github.com/sasjs/lint)
|
|
6
|
-
|
|
7
1
|
# SAS Code linting and formatting
|
|
8
2
|
|
|
3
|
+
 [](https://github.com/sasjs/lint/issues?q=is%3Aissue+is%3Aclosed) [](https://github.com/sasjs/lint/issues) [](https://scorecard.dev/viewer/?uri=github.com/sasjs/lint)  [](https://gitpod.io/#https://github.com/sasjs/lint)
|
|
4
|
+
|
|
9
5
|
Our goal is to help SAS developers everywhere spend less time on code reviews, bug fixing and arguing about standards - and more time delivering extraordinary business value.
|
|
10
6
|
|
|
11
7
|
_Note:_ The SASjs project and its repositories are not affiliated with SAS Institute.
|
|
@@ -35,6 +31,7 @@ Configuration is via a `.sasjslint` file with the following structure (these are
|
|
|
35
31
|
"indentationMultiple": 2,
|
|
36
32
|
"lineEndings": "off",
|
|
37
33
|
"lowerCaseFileNames": true,
|
|
34
|
+
"lowerCaseMacroNames": true,
|
|
38
35
|
"maxDataLineLength": 80,
|
|
39
36
|
"maxHeaderLineLength": 80,
|
|
40
37
|
"maxLineLength": 80,
|
|
@@ -52,6 +49,7 @@ Configuration is via a `.sasjslint` file with the following structure (these are
|
|
|
52
49
|
"noUndeclaredMacros": true,
|
|
53
50
|
"noUnusedLibnames": false,
|
|
54
51
|
"noUnusedMacros": true,
|
|
52
|
+
"noXcmd": true,
|
|
55
53
|
"requiredMacroOptions": [],
|
|
56
54
|
"severityLevel": {},
|
|
57
55
|
"strictMacroDefinition": true
|
|
@@ -267,6 +265,22 @@ On *nix systems, it is imperative that autocall macros are in lowercase. When sh
|
|
|
267
265
|
- Default: true
|
|
268
266
|
- Severity: WARNING
|
|
269
267
|
|
|
268
|
+
### lowerCaseMacroNames
|
|
269
|
+
|
|
270
|
+
The companion to `lowerCaseFileNames`: it checks the macro names a project writes down, in the places they appear.
|
|
271
|
+
|
|
272
|
+
- the `@li` entries of the `<h4> SAS Macros </h4>` header - the list `sasjs compile` reads to find each dependency
|
|
273
|
+
- the `%macro` statement, and the name carried by `%mend`
|
|
274
|
+
|
|
275
|
+
`lowerCaseFileNames` only sees the file, and a file named `mf_GetUser.sas` resolves on Windows whatever the header says - then fails on any case-sensitive filesystem. With both rules on, the file and its declarations are reported together, and the fix lower cases the declarations.
|
|
276
|
+
|
|
277
|
+
`sasjs lint fix` rewrites the name in place wherever it appears: the header entry, the `%macro` name and the `%mend` name. Indentation, the order of the entries, and the rest of each line are left as they are.
|
|
278
|
+
|
|
279
|
+
Note the pairing: rewriting a header entry changes which file `sasjs compile` looks for. If the file itself is still `mf_GetUser.sas`, compilation reports a missing dependency until the file is renamed to match - which is what `lowerCaseFileNames` is reporting on that file.
|
|
280
|
+
|
|
281
|
+
- Default: true
|
|
282
|
+
- Severity: WARNING
|
|
283
|
+
|
|
270
284
|
### maxDataLineLength
|
|
271
285
|
|
|
272
286
|
Datalines can be very wide, so to avoid the need to increase `maxLineLength` for the entire project, it is possible to raise the line length limit for the data records only. On a related note, as a developer, you should also be aware that code submitted in batch may have a default line length limit which is lower than you expect. See this [usage note](https://support.sas.com/kb/15/883.html) (and thanks to [sasutils for reminding us](https://github.com/sasjs/lint/issues/47#issuecomment-1064340104)).
|
|
@@ -543,6 +557,29 @@ Running `sasjs lint fix` (or saving in the SASjs VS Code extension with `formatO
|
|
|
543
557
|
- Default: true
|
|
544
558
|
- Severity: WARNING
|
|
545
559
|
|
|
560
|
+
### noXcmd
|
|
561
|
+
|
|
562
|
+
This rule reports the SAS statements and functions that run an operating system command. They need the XCMD option, so on a server where it is off - a LOCKDOWN server, or a SASjs Server deployment that keeps it off - they fail at run time, and the failure arrives long after the code was reviewed. It is on by default for the same reason [`noEncodedPasswords`](#noencodedpasswords) is: the hazard is invisible in review and only shows up on the server that matters.
|
|
563
|
+
|
|
564
|
+
It reports:
|
|
565
|
+
|
|
566
|
+
- the `x` statement, quoted (`x "cmd";`) or bare (`x dir;`), where a statement begins and a command follows - so `keep x`, a variable named `x`, and the assignment and sum statements (`x = 1;`, `x + 1;`) are not commands;
|
|
567
|
+
- `call system(...)`, with or without a space before the parenthesis;
|
|
568
|
+
- `%sysexec`, anchored on the macro name, so a user macro such as `%mf_sysexec(...)` is not a match. The macro is the only form SAS has: the XCMD option's own list of what it governs names the `%SYSEXEC` macro, `CALL SYSTEM`, the SYSTEM function, PIPE and the X statement, and there is no `SYSEXEC` function or `CALL SYSEXEC` routine;
|
|
569
|
+
- `system(...)` as a function, and `%sysfunc(system(...))` through which it is usually reached - `%sysfunc(sysrc())` is not a command and is not reported;
|
|
570
|
+
- `options xcmd;` in its positive form ONLY - `options noxcmd;` is the hardening, and reporting it would push a project away from the setting that makes it safe;
|
|
571
|
+
- `filename <ref> pipe "cmd";` and `infile "cmd" pipe;`, where `pipe` stands in the option position of a `filename` statement or follows the quoted path of an `infile` - a fileref named `pipe`, or a variable of that name, is not reported;
|
|
572
|
+
- `systask command`.
|
|
573
|
+
|
|
574
|
+
The text is read as code rather than as text, which is what separates this rule from [`noBannedStrings`](#nobannedstrings): comments are not searched, so a header or a note that documents `options xcmd;` is not reported, and a quoted value is not searched either, so `put "x ""ls"";"` stays clean. A `datalines` payload is data, so it is skipped whether or not the statement is indented. Macro definitions and open code are read the same way, because the risk is the same in both - and for the same reason a command is reported inside a macro body as it is anywhere else.
|
|
575
|
+
|
|
576
|
+
One limit is worth stating: an UNTERMINATED quote masks the rest of the file, because SAS itself reads an unterminated literal that way - the engine consumes the remaining text as string content. A stray apostrophe in open code therefore hides the constructs after it, rather than reporting the words inside a string as commands. A `datalines` payload cannot cause it, because the payload is blanked before the comment and quote scan runs, so a data value such as `O'Brien` is harmless.
|
|
577
|
+
|
|
578
|
+
There is no fix. Which command a project should run instead is a change to the job, not a formatting decision.
|
|
579
|
+
|
|
580
|
+
- Default: true
|
|
581
|
+
- Severity: WARNING
|
|
582
|
+
|
|
546
583
|
### strictMacroDefinition
|
|
547
584
|
|
|
548
585
|
This will check the syntax of a macro definition, and warn about two things:
|
package/package.json
CHANGED
|
@@ -34,15 +34,6 @@
|
|
|
34
34
|
"prepareCmd": "npm version ${nextRelease.version} --no-git-tag-version --allow-same-version"
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
|
-
[
|
|
38
|
-
"@semantic-release/git",
|
|
39
|
-
{
|
|
40
|
-
"assets": [
|
|
41
|
-
"package.json",
|
|
42
|
-
"package-lock.json"
|
|
43
|
-
]
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
37
|
"@semantic-release/github"
|
|
47
38
|
]
|
|
48
39
|
},
|
|
@@ -65,14 +56,14 @@
|
|
|
65
56
|
"homepage": "https://github.com/sasjs/lint#readme",
|
|
66
57
|
"devDependencies": {
|
|
67
58
|
"@nogoo9/gitleaks": "8.30.1-post.2",
|
|
68
|
-
"@sasjs/sas-language": "0.3.
|
|
59
|
+
"@sasjs/sas-language": "0.3.3",
|
|
69
60
|
"@stryker-mutator/core": "10.1.1",
|
|
70
61
|
"@stryker-mutator/jest-runner": "10.1.1",
|
|
71
62
|
"@types/jest": "30.0.0",
|
|
72
|
-
"@types/node": "26.6.
|
|
63
|
+
"@types/node": "26.6.6",
|
|
73
64
|
"jest": "30.5.2",
|
|
74
65
|
"rimraf": "6.1.3",
|
|
75
|
-
"ts-jest": "29.4.
|
|
66
|
+
"ts-jest": "29.4.15",
|
|
76
67
|
"typescript": "6.0.3"
|
|
77
68
|
},
|
|
78
69
|
"files": [
|
|
@@ -94,13 +85,15 @@
|
|
|
94
85
|
"sasjslint-schema.json"
|
|
95
86
|
],
|
|
96
87
|
"dependencies": {
|
|
97
|
-
"@sasjs/utils": "^4.
|
|
98
|
-
"ignore": "7.0.
|
|
88
|
+
"@sasjs/utils": "^4.1.2",
|
|
89
|
+
"ignore": "7.0.14"
|
|
99
90
|
},
|
|
100
91
|
"overrides": {
|
|
101
|
-
"qs": "6.17.0"
|
|
92
|
+
"qs": "6.17.0",
|
|
93
|
+
"glob": "^14.0.2",
|
|
94
|
+
"minimatch": "^11.0.1"
|
|
102
95
|
},
|
|
103
|
-
"version": "
|
|
96
|
+
"version": "5.0.0",
|
|
104
97
|
"devEngines": {
|
|
105
98
|
"runtime": {
|
|
106
99
|
"name": "node",
|
package/rules/file/index.d.ts
CHANGED
|
@@ -6,9 +6,11 @@ export { minMacroNameLength } from './minMacroNameLength';
|
|
|
6
6
|
export { noMacroIfInOpenCode } from './noMacroIfInOpenCode';
|
|
7
7
|
export { noNestedCommentsInHeader } from './noNestedCommentsInHeader';
|
|
8
8
|
export { noNestedMacros } from './noNestedMacros';
|
|
9
|
+
export { noXcmd } from './noXcmd';
|
|
9
10
|
export { noUndeclaredMacros } from './noUndeclaredMacros';
|
|
10
11
|
export { noUnusedMacros } from './noUnusedMacros';
|
|
11
12
|
export { noUnusedLibnames } from './noUnusedLibnames';
|
|
12
13
|
export { strictMacroDefinition } from './strictMacroDefinition';
|
|
13
14
|
export { hasRequiredMacroOptions } from './hasRequiredMacroOptions';
|
|
14
15
|
export { noSingleAsteriskComments } from './noSingleAsteriskComments';
|
|
16
|
+
export { lowerCaseMacroNames } from './lowerCaseMacroNames';
|
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.noUnusedLibnames = exports.noUnusedMacros = exports.noUndeclaredMacros = exports.noNestedMacros = exports.noNestedCommentsInHeader = exports.noMacroIfInOpenCode = exports.minMacroNameLength = exports.lineEndings = exports.hasMacroParentheses = exports.hasMacroNameInMend = exports.hasDoxygenHeader = void 0;
|
|
3
|
+
exports.lowerCaseMacroNames = exports.noSingleAsteriskComments = exports.hasRequiredMacroOptions = exports.strictMacroDefinition = exports.noUnusedLibnames = exports.noUnusedMacros = exports.noUndeclaredMacros = exports.noXcmd = exports.noNestedMacros = exports.noNestedCommentsInHeader = exports.noMacroIfInOpenCode = exports.minMacroNameLength = 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");
|
|
@@ -17,6 +17,8 @@ var noNestedCommentsInHeader_1 = require("./noNestedCommentsInHeader");
|
|
|
17
17
|
Object.defineProperty(exports, "noNestedCommentsInHeader", { enumerable: true, get: function () { return noNestedCommentsInHeader_1.noNestedCommentsInHeader; } });
|
|
18
18
|
var noNestedMacros_1 = require("./noNestedMacros");
|
|
19
19
|
Object.defineProperty(exports, "noNestedMacros", { enumerable: true, get: function () { return noNestedMacros_1.noNestedMacros; } });
|
|
20
|
+
var noXcmd_1 = require("./noXcmd");
|
|
21
|
+
Object.defineProperty(exports, "noXcmd", { enumerable: true, get: function () { return noXcmd_1.noXcmd; } });
|
|
20
22
|
var noUndeclaredMacros_1 = require("./noUndeclaredMacros");
|
|
21
23
|
Object.defineProperty(exports, "noUndeclaredMacros", { enumerable: true, get: function () { return noUndeclaredMacros_1.noUndeclaredMacros; } });
|
|
22
24
|
var noUnusedMacros_1 = require("./noUnusedMacros");
|
|
@@ -29,4 +31,6 @@ var hasRequiredMacroOptions_1 = require("./hasRequiredMacroOptions");
|
|
|
29
31
|
Object.defineProperty(exports, "hasRequiredMacroOptions", { enumerable: true, get: function () { return hasRequiredMacroOptions_1.hasRequiredMacroOptions; } });
|
|
30
32
|
var noSingleAsteriskComments_1 = require("./noSingleAsteriskComments");
|
|
31
33
|
Object.defineProperty(exports, "noSingleAsteriskComments", { enumerable: true, get: function () { return noSingleAsteriskComments_1.noSingleAsteriskComments; } });
|
|
34
|
+
var lowerCaseMacroNames_1 = require("./lowerCaseMacroNames");
|
|
35
|
+
Object.defineProperty(exports, "lowerCaseMacroNames", { enumerable: true, get: function () { return lowerCaseMacroNames_1.lowerCaseMacroNames; } });
|
|
32
36
|
//# sourceMappingURL=index.js.map
|
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,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA2D;AAAlD,0HAAA,mBAAmB,OAAA;AAC5B,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA;AACjC,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"}
|
|
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,2DAAyD;AAAhD,wHAAA,kBAAkB,OAAA;AAC3B,6DAA2D;AAAlD,0HAAA,mBAAmB,OAAA;AAC5B,uEAAqE;AAA5D,oIAAA,wBAAwB,OAAA;AACjC,mDAAiD;AAAxC,gHAAA,cAAc,OAAA;AACvB,mCAAiC;AAAxB,gGAAA,MAAM,OAAA;AACf,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;AACjC,6DAA2D;AAAlD,0HAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FileLintRule } from '../../types/LintRule';
|
|
2
|
+
/**
|
|
3
|
+
* Lint rule that checks macro names are lower case, in the header's
|
|
4
|
+
* `<h4> SAS Macros </h4>` list and in the `%macro` / `%mend` statements, and
|
|
5
|
+
* rewrites the name in both places.
|
|
6
|
+
*/
|
|
7
|
+
export declare const lowerCaseMacroNames: FileLintRule;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lowerCaseMacroNames = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const LintRuleType_1 = require("../../types/LintRuleType");
|
|
6
|
+
const Severity_1 = require("../../types/Severity");
|
|
7
|
+
const LineEndings_1 = require("../../types/LineEndings");
|
|
8
|
+
const headerMacros_1 = require("../../utils/headerMacros");
|
|
9
|
+
const parseMacros_1 = require("../../utils/parseMacros");
|
|
10
|
+
const splitText_1 = require("../../utils/splitText");
|
|
11
|
+
const name = 'lowerCaseMacroNames';
|
|
12
|
+
const description = 'Enforce lower case macro names, in the <h4> SAS Macros </h4> header and in the %macro definition.';
|
|
13
|
+
const message = `Macro name '{macro}' contains uppercase characters`;
|
|
14
|
+
const headerMessage = (macro) => `Macro '${macro}.sas' is declared with uppercase characters in the <h4> SAS Macros </h4> header - the declaration and the file name have to match, and only a lower case pair resolves on a case-sensitive filesystem`;
|
|
15
|
+
const definitionMessage = (macro) => `Macro '${macro}' is defined with uppercase characters - rename it in the %macro statement`;
|
|
16
|
+
const mendMessage = (macro) => `Macro '${macro}' is named with uppercase characters in the %mend statement`;
|
|
17
|
+
const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
18
|
+
/**
|
|
19
|
+
* Reports the macro names that carry uppercase characters, in the two places a
|
|
20
|
+
* project writes one down: the `@li` entries of the `<h4> SAS Macros </h4>`
|
|
21
|
+
* header, which `sasjs compile` reads to find the files, and the `%macro` /
|
|
22
|
+
* `%mend` statements in the code.
|
|
23
|
+
*
|
|
24
|
+
* Both are read with the parsers the rest of the linter uses, so the rule
|
|
25
|
+
* agrees with the compiler about which entries exist and with
|
|
26
|
+
* `hasMacroNameInMend` about which name a `%mend` carries - and each diagnostic
|
|
27
|
+
* lands on the exact entry or name, not on line 1.
|
|
28
|
+
*
|
|
29
|
+
* `lowerCaseFileNames` covers the file itself. The pair is what removes the
|
|
30
|
+
* cross-platform trap: a file named `mf_GetUser.sas` resolves on Windows
|
|
31
|
+
* whatever the header says, and fails on any case-sensitive filesystem.
|
|
32
|
+
*/
|
|
33
|
+
const test = (value, config) => {
|
|
34
|
+
if (!value)
|
|
35
|
+
return [];
|
|
36
|
+
const cfg = config || new types_1.LintConfig();
|
|
37
|
+
const severity = cfg.severityLevel[name] || Severity_1.Severity.Warning;
|
|
38
|
+
const diagnostics = [];
|
|
39
|
+
(0, headerMacros_1.getHeaderMacros)(value, cfg).forEach((macro) => {
|
|
40
|
+
if (macro.name === macro.name.toLowerCase())
|
|
41
|
+
return;
|
|
42
|
+
diagnostics.push({
|
|
43
|
+
message: headerMessage(macro.name),
|
|
44
|
+
lineNumber: macro.lineNumber,
|
|
45
|
+
startColumnNumber: macro.startColumnNumber,
|
|
46
|
+
endColumnNumber: macro.endColumnNumber,
|
|
47
|
+
severity
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
const lines = (0, splitText_1.splitText)(value, cfg);
|
|
51
|
+
(0, parseMacros_1.parseMacros)(value, cfg).forEach((macro) => {
|
|
52
|
+
const definition = findName(lines[macro.startLineNumbers[0] - 1], '%macro');
|
|
53
|
+
if (definition && definition.macro !== definition.macro.toLowerCase()) {
|
|
54
|
+
diagnostics.push({
|
|
55
|
+
message: definitionMessage(definition.macro),
|
|
56
|
+
lineNumber: macro.startLineNumbers[0],
|
|
57
|
+
startColumnNumber: definition.column,
|
|
58
|
+
endColumnNumber: definition.column + definition.macro.length,
|
|
59
|
+
severity
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (macro.endLineNumber === null)
|
|
63
|
+
return;
|
|
64
|
+
const mend = findName(lines[macro.endLineNumber - 1], '%mend');
|
|
65
|
+
if (mend && mend.macro !== mend.macro.toLowerCase()) {
|
|
66
|
+
diagnostics.push({
|
|
67
|
+
message: mendMessage(mend.macro),
|
|
68
|
+
lineNumber: macro.endLineNumber,
|
|
69
|
+
startColumnNumber: mend.column,
|
|
70
|
+
endColumnNumber: mend.column + mend.macro.length,
|
|
71
|
+
severity
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return diagnostics;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Lower cases the name in both places: every `@li` entry of the
|
|
79
|
+
* `<h4> SAS Macros </h4>` header, and the name in each `%macro` and `%mend`
|
|
80
|
+
* statement.
|
|
81
|
+
*
|
|
82
|
+
* Only the name is rewritten. Indentation, ordering, descriptions on an entry
|
|
83
|
+
* and the rest of each line come back unchanged, and no line is added or
|
|
84
|
+
* removed - which is what keeps the fix composable with the other formatting
|
|
85
|
+
* passes.
|
|
86
|
+
*
|
|
87
|
+
* The header edit changes which file `sasjs compile` looks for, so a project
|
|
88
|
+
* whose file is still `mf_GetUser.sas` reports a missing dependency after the
|
|
89
|
+
* fix until the file is renamed. That pairing is the point of the rule and of
|
|
90
|
+
* `lowerCaseFileNames`, and stating it here is cheaper than a fix that silently
|
|
91
|
+
* half-applies.
|
|
92
|
+
*/
|
|
93
|
+
const fix = (value, config) => {
|
|
94
|
+
if (!value)
|
|
95
|
+
return value;
|
|
96
|
+
const cfg = config || new types_1.LintConfig();
|
|
97
|
+
const lineEnding = cfg.lineEndings === LineEndings_1.LineEndings.CRLF ? '\r\n' : '\n';
|
|
98
|
+
return lowerCaseDefinitions(lowerCaseHeaderEntries(value, cfg), cfg).join(lineEnding);
|
|
99
|
+
};
|
|
100
|
+
/** The lines of the file, with the declared macro names lower cased. */
|
|
101
|
+
const lowerCaseHeaderEntries = (value, config) => {
|
|
102
|
+
const lines = (0, splitText_1.splitText)(value, config);
|
|
103
|
+
(0, headerMacros_1.getHeaderMacros)(value, config).forEach((macro) => {
|
|
104
|
+
if (macro.name === macro.name.toLowerCase())
|
|
105
|
+
return;
|
|
106
|
+
const index = macro.lineNumber - 1;
|
|
107
|
+
const line = lines[index];
|
|
108
|
+
// The span was measured on this line by getHeaderMacros, from the same
|
|
109
|
+
// splitText read, so it always lands on the name.
|
|
110
|
+
const start = macro.startColumnNumber - 1;
|
|
111
|
+
const end = start + macro.name.length;
|
|
112
|
+
lines[index] =
|
|
113
|
+
line.slice(0, start) +
|
|
114
|
+
line.slice(start, end).toLowerCase() +
|
|
115
|
+
line.slice(end);
|
|
116
|
+
});
|
|
117
|
+
return lines;
|
|
118
|
+
};
|
|
119
|
+
/** The lines of the file, with the %macro and %mend names lower cased. */
|
|
120
|
+
const lowerCaseDefinitions = (lines, config) => {
|
|
121
|
+
(0, parseMacros_1.parseMacros)(lines.join('\n'), config).forEach((macro) => {
|
|
122
|
+
const definitionLine = macro.startLineNumbers[0];
|
|
123
|
+
if (definitionLine)
|
|
124
|
+
lowerCaseNameInLine(lines, definitionLine, '%macro');
|
|
125
|
+
if (macro.endLineNumber)
|
|
126
|
+
lowerCaseNameInLine(lines, macro.endLineNumber, '%mend');
|
|
127
|
+
});
|
|
128
|
+
return lines;
|
|
129
|
+
};
|
|
130
|
+
const lowerCaseNameInLine = (lines, lineNumber, tag) => {
|
|
131
|
+
const index = lineNumber - 1;
|
|
132
|
+
const line = lines[index];
|
|
133
|
+
const found = findName(line, tag);
|
|
134
|
+
if (!found || found.macro === found.macro.toLowerCase())
|
|
135
|
+
return;
|
|
136
|
+
const start = found.column - 1;
|
|
137
|
+
lines[index] =
|
|
138
|
+
line.slice(0, start) +
|
|
139
|
+
line.slice(start, start + found.macro.length).toLowerCase() +
|
|
140
|
+
line.slice(start + found.macro.length);
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Locates the name a statement carries: the token after `%macro` or `%mend`,
|
|
144
|
+
* excluding the parenthesis that opens a macro's own argument list.
|
|
145
|
+
*/
|
|
146
|
+
const findName = (line, tag) => {
|
|
147
|
+
const match = new RegExp(`${escape(tag)}\\s+([\\w]+)`, 'i').exec(line);
|
|
148
|
+
if (!match)
|
|
149
|
+
return null;
|
|
150
|
+
const column = match.index + match[0].length - match[1].length + 1;
|
|
151
|
+
return { macro: match[1], column };
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Lint rule that checks macro names are lower case, in the header's
|
|
155
|
+
* `<h4> SAS Macros </h4>` list and in the `%macro` / `%mend` statements, and
|
|
156
|
+
* rewrites the name in both places.
|
|
157
|
+
*/
|
|
158
|
+
exports.lowerCaseMacroNames = {
|
|
159
|
+
type: LintRuleType_1.LintRuleType.File,
|
|
160
|
+
name,
|
|
161
|
+
description,
|
|
162
|
+
message,
|
|
163
|
+
test,
|
|
164
|
+
fix
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=lowerCaseMacroNames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowerCaseMacroNames.js","sourceRoot":"","sources":["../../../src/rules/file/lowerCaseMacroNames.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FileLintRule } from '../../types/LintRule';
|
|
2
|
+
/**
|
|
3
|
+
* Lint rule that reports the statements and functions that need XCMD, so a
|
|
4
|
+
* program that shells out is found when it is linted rather than when it runs on
|
|
5
|
+
* a server where XCMD is off.
|
|
6
|
+
*/
|
|
7
|
+
export declare const noXcmd: FileLintRule;
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noXcmd = void 0;
|
|
4
|
+
const LintRuleType_1 = require("../../types/LintRuleType");
|
|
5
|
+
const Severity_1 = require("../../types/Severity");
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
7
|
+
const name = 'noXcmd';
|
|
8
|
+
const description = 'Disallow OS commands, which need XCMD: the x statement, call system, %sysexec, %sysfunc(system(...)), options xcmd, a pipe fileref and systask command. `options noxcmd;` is the hardening and is not reported.';
|
|
9
|
+
const message = 'OS command requires XCMD';
|
|
10
|
+
/**
|
|
11
|
+
* Blanks everything SAS does not compile, keeping the text's length so that a
|
|
12
|
+
* column measured here is the file's column.
|
|
13
|
+
*
|
|
14
|
+
* Comments become spaces and the CONTENT of a quoted value becomes `_`, which
|
|
15
|
+
* leaves the quotes themselves visible - `x "cmd";` reads as `x "____";`, so a
|
|
16
|
+
* construct is still recognisable while the words inside a string are not.
|
|
17
|
+
*
|
|
18
|
+
* Both comment syntaxes are blanked, because the constructs this rule looks for
|
|
19
|
+
* are exactly what a header or a note tends to mention: the block comment,
|
|
20
|
+
* which SAS ends at the first close marker, and the comment statement
|
|
21
|
+
* (`* ...;` and `%* ...;`), which SAS ends at the first semicolon. A comment
|
|
22
|
+
* statement only starts in statement position, so `x = a * b;` keeps its
|
|
23
|
+
* asterisk while `run; * note;` is a comment.
|
|
24
|
+
*
|
|
25
|
+
* Quotes are carried across lines, as the engine does: `x = "ab` / `cd";` is
|
|
26
|
+
* one string, and only that reading stops the continuation from being linted as
|
|
27
|
+
* code. An unterminated quote therefore hides the rest of the file rather than
|
|
28
|
+
* reporting a construct that is really string content.
|
|
29
|
+
*/
|
|
30
|
+
const maskNonCode = (text) => {
|
|
31
|
+
const characters = text.split('');
|
|
32
|
+
const statementStarts = [];
|
|
33
|
+
let statementStarted = false;
|
|
34
|
+
let inBlockComment = false;
|
|
35
|
+
let inCommentStatement = false;
|
|
36
|
+
let quote = '';
|
|
37
|
+
let index = 0;
|
|
38
|
+
const blank = (position) => {
|
|
39
|
+
if (text[position] !== '\n')
|
|
40
|
+
characters[position] = ' ';
|
|
41
|
+
};
|
|
42
|
+
while (index < text.length) {
|
|
43
|
+
const character = text[index];
|
|
44
|
+
const next = text[index + 1];
|
|
45
|
+
if (inBlockComment) {
|
|
46
|
+
if (character === '*' && next === '/') {
|
|
47
|
+
blank(index);
|
|
48
|
+
blank(index + 1);
|
|
49
|
+
inBlockComment = false;
|
|
50
|
+
index += 2;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
blank(index);
|
|
54
|
+
index++;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (inCommentStatement) {
|
|
58
|
+
// The terminating `;` stays: it ends the comment AND the statement the
|
|
59
|
+
// next construct may start from, so blanking it would hide `* note; x
|
|
60
|
+
// "ls";`. Only the comment text goes.
|
|
61
|
+
if (character === ';') {
|
|
62
|
+
inCommentStatement = false;
|
|
63
|
+
statementStarted = false;
|
|
64
|
+
index++;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
blank(index);
|
|
68
|
+
index++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (quote) {
|
|
72
|
+
if (character === quote) {
|
|
73
|
+
// A doubled delimiter is an escaped quote inside the literal, so the
|
|
74
|
+
// literal continues.
|
|
75
|
+
if (next === quote) {
|
|
76
|
+
characters[index] = '_';
|
|
77
|
+
characters[index + 1] = '_';
|
|
78
|
+
index += 2;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
quote = '';
|
|
82
|
+
index++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (character !== '\n')
|
|
86
|
+
characters[index] = '_';
|
|
87
|
+
index++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (character === '/' && next === '*') {
|
|
91
|
+
blank(index);
|
|
92
|
+
blank(index + 1);
|
|
93
|
+
inBlockComment = true;
|
|
94
|
+
index += 2;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!statementStarted && character === '%' && next === '*') {
|
|
98
|
+
blank(index);
|
|
99
|
+
blank(index + 1);
|
|
100
|
+
inCommentStatement = true;
|
|
101
|
+
index += 2;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (!statementStarted && character === '*') {
|
|
105
|
+
blank(index);
|
|
106
|
+
inCommentStatement = true;
|
|
107
|
+
index++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// A quoted value never BEGINS a statement, so this does not record a start:
|
|
111
|
+
// the patterns that read starts look for a keyword or for `x`, and a quote
|
|
112
|
+
// matches neither.
|
|
113
|
+
if (character === "'" || character === '"') {
|
|
114
|
+
quote = character;
|
|
115
|
+
statementStarted = true;
|
|
116
|
+
index++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (character === ';') {
|
|
120
|
+
statementStarted = false;
|
|
121
|
+
index++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!/\s/.test(character)) {
|
|
125
|
+
if (!statementStarted)
|
|
126
|
+
statementStarts.push(index);
|
|
127
|
+
statementStarted = true;
|
|
128
|
+
}
|
|
129
|
+
index++;
|
|
130
|
+
}
|
|
131
|
+
return { code: characters.join(''), statementStarts };
|
|
132
|
+
};
|
|
133
|
+
/** The offset each line starts at, so a line index becomes a character index. */
|
|
134
|
+
const getLineStarts = (text) => {
|
|
135
|
+
const starts = [0];
|
|
136
|
+
for (let index = 0; index < text.length; index++) {
|
|
137
|
+
if (text[index] === '\n')
|
|
138
|
+
starts.push(index + 1);
|
|
139
|
+
}
|
|
140
|
+
return starts;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Blanks the `datalines` payloads: data is not code, and a value holding
|
|
144
|
+
* `call system` is not something a developer typed as a command.
|
|
145
|
+
*
|
|
146
|
+
* Two passes, and both are load-bearing:
|
|
147
|
+
*
|
|
148
|
+
* - the STATEMENT is found in the text after `maskNonCode`, so a `datalines;`
|
|
149
|
+
* written inside a comment or a quoted value does not open a payload. Finding
|
|
150
|
+
* it on the raw text let a header that documents the statement blank every
|
|
151
|
+
* construct between it and the next line starting with `;`.
|
|
152
|
+
* - the PAYLOAD is then blanked in the RAW text, before the mask reads it,
|
|
153
|
+
* because a payload is arbitrary text: one holding a lone apostrophe (a name
|
|
154
|
+
* like O'Brien) or a `/*` would otherwise open a string or a comment inside
|
|
155
|
+
* the mask and hide everything after it.
|
|
156
|
+
*
|
|
157
|
+
* The statement is matched here rather than through `getDataSectionsDetail`,
|
|
158
|
+
* which requires the keyword at column 1 - an indented `datalines;` inside a
|
|
159
|
+
* macro body is not seen there. SAS ends a plain payload at the first line that
|
|
160
|
+
* starts with `;`, and a `datalines4` payload at the first line that starts
|
|
161
|
+
* with `;;;;`; both are matched at the start of the line, because an indented
|
|
162
|
+
* `;` is data.
|
|
163
|
+
*/
|
|
164
|
+
const blankDatalines = (text) => {
|
|
165
|
+
var _a;
|
|
166
|
+
const { code: codeOnly } = maskNonCode(text);
|
|
167
|
+
const statement = /(?:^|;)[ \t]*(datalines|cards|parmcards)(4)?[ \t]*;/gim;
|
|
168
|
+
const characters = text.split('');
|
|
169
|
+
const lineStarts = getLineStarts(text);
|
|
170
|
+
let match;
|
|
171
|
+
while ((match = statement.exec(codeOnly))) {
|
|
172
|
+
const terminator = match[2] ? /^;;;;/ : /^;/;
|
|
173
|
+
const from = match.index + match[0].length;
|
|
174
|
+
const end = lineStarts.findIndex((start, index) => {
|
|
175
|
+
if (start < from)
|
|
176
|
+
return false;
|
|
177
|
+
return terminator.test(text.slice(start, lineStarts[index + 1]));
|
|
178
|
+
});
|
|
179
|
+
// A statement with no terminator line is not a payload this scan can
|
|
180
|
+
// delimit, so nothing is blanked. Blanking to the end of the file would
|
|
181
|
+
// hide every construct after it, which is worse than reading a phantom
|
|
182
|
+
// payload as code.
|
|
183
|
+
if (end === -1)
|
|
184
|
+
continue;
|
|
185
|
+
// Through the end of the terminator line, so the payload's own content and
|
|
186
|
+
// the terminator are both taken out of the scanned text.
|
|
187
|
+
const to = (_a = lineStarts[end + 1]) !== null && _a !== void 0 ? _a : text.length;
|
|
188
|
+
for (let index = from; index < to; index++) {
|
|
189
|
+
if (characters[index] !== '\n')
|
|
190
|
+
characters[index] = ' ';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return characters.join('');
|
|
194
|
+
};
|
|
195
|
+
/** The words between two offsets, with the character index each one starts at. */
|
|
196
|
+
const getTokens = (code, from, to) => {
|
|
197
|
+
const tokens = [];
|
|
198
|
+
let index = from;
|
|
199
|
+
while (index < to) {
|
|
200
|
+
if (/\s/.test(code[index])) {
|
|
201
|
+
index++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const start = index;
|
|
205
|
+
while (index < to && !/\s/.test(code[index]))
|
|
206
|
+
index++;
|
|
207
|
+
// A token that ends a statement carries the terminator; the token is the
|
|
208
|
+
// word before it.
|
|
209
|
+
tokens.push({
|
|
210
|
+
value: code.slice(start, index).replace(/;$/, ''),
|
|
211
|
+
index: start
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return tokens;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* The `x` statement: the shell-out SAS spells as a single letter.
|
|
218
|
+
*
|
|
219
|
+
* Reported only where a statement begins, so `keep x` and a `%let x="a";` are
|
|
220
|
+
* not commands, and only when a command follows. The command may be quoted
|
|
221
|
+
* (`x "ls";`, the documented form) or bare (`x dir;`), so a bare word counts
|
|
222
|
+
* too - but a word followed by `=` or `+` is the DATA step's assignment and sum
|
|
223
|
+
* statement, and a `,`, `;` or `)` closes a statement that was not a command.
|
|
224
|
+
*/
|
|
225
|
+
const xStatement = {
|
|
226
|
+
label: 'x statement',
|
|
227
|
+
find: (code, statementStarts) => {
|
|
228
|
+
const found = [];
|
|
229
|
+
statementStarts.forEach((start) => {
|
|
230
|
+
// `^` here is the statement start the mask recorded, not a line start: a
|
|
231
|
+
// continuation line beginning `x from t;` in a multi-line PROC SQL is not
|
|
232
|
+
// a command.
|
|
233
|
+
if (!/^x[ \t]+(?![-+=,;)])\S/i.test(code.slice(start)))
|
|
234
|
+
return;
|
|
235
|
+
found.push({ index: start, length: 1 });
|
|
236
|
+
});
|
|
237
|
+
return found;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
/** `call system(...)`, with or without a space before the parenthesis. */
|
|
241
|
+
const callSystem = {
|
|
242
|
+
label: 'call system',
|
|
243
|
+
find: (code) => {
|
|
244
|
+
// `\s+` rather than a space class: a statement can be wrapped after `call`.
|
|
245
|
+
const regex = /\bcall\s+system\s*\(/gi;
|
|
246
|
+
const found = [];
|
|
247
|
+
let match;
|
|
248
|
+
while ((match = regex.exec(code))) {
|
|
249
|
+
found.push({ index: match.index, length: match[0].length });
|
|
250
|
+
}
|
|
251
|
+
return found;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* `%sysexec`, anchored on the macro name: the `%` is what makes it a call, so
|
|
256
|
+
* `%mf_sysexec(...)` is a user macro and does not match.
|
|
257
|
+
*/
|
|
258
|
+
const sysExec = {
|
|
259
|
+
label: '%sysexec',
|
|
260
|
+
find: (code) => {
|
|
261
|
+
const regex = /%sysexec\b/gi;
|
|
262
|
+
const found = [];
|
|
263
|
+
let match;
|
|
264
|
+
while ((match = regex.exec(code))) {
|
|
265
|
+
found.push({ index: match.index, length: match[0].length });
|
|
266
|
+
}
|
|
267
|
+
return found;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
/** `%sysfunc(system(...))` - the same command reached as a function call. */
|
|
271
|
+
const sysFuncSystem = {
|
|
272
|
+
label: '%sysfunc(system(...))',
|
|
273
|
+
find: (code) => {
|
|
274
|
+
const regex = /%sysfunc\s*\(\s*system\s*\(/gi;
|
|
275
|
+
const found = [];
|
|
276
|
+
let match;
|
|
277
|
+
while ((match = regex.exec(code))) {
|
|
278
|
+
found.push({ index: match.index, length: match[0].length });
|
|
279
|
+
}
|
|
280
|
+
return found;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Whether `name(` at this position is a data set reference rather than a call.
|
|
285
|
+
*
|
|
286
|
+
* SAS writes data set options straight after the member name - `set
|
|
287
|
+
* work.system(keep=x);`, `proc sort data=system(where=(...));` - so `system(`
|
|
288
|
+
* is not always the function. A member reference is preceded by `.` or by the
|
|
289
|
+
* keyword that takes the list (`set`, `merge`, `data=`, `out=`, ...). An
|
|
290
|
+
* ASSIGNMENT is not: `rc = system('ls');` has `rc` before the `=`, which is the
|
|
291
|
+
* case this guard must keep reporting.
|
|
292
|
+
*/
|
|
293
|
+
const DATASET_KEYWORDS = [
|
|
294
|
+
'set',
|
|
295
|
+
'merge',
|
|
296
|
+
'update',
|
|
297
|
+
'modify',
|
|
298
|
+
'data',
|
|
299
|
+
'out',
|
|
300
|
+
'in',
|
|
301
|
+
'base'
|
|
302
|
+
];
|
|
303
|
+
const isDatasetReference = (code, index) => {
|
|
304
|
+
var _a, _b;
|
|
305
|
+
const before = code.slice(0, index).trimEnd();
|
|
306
|
+
const lastCharacter = before[before.length - 1];
|
|
307
|
+
if (lastCharacter === '.')
|
|
308
|
+
return true;
|
|
309
|
+
// For `data=system(` the keyword sits before the `=`; for `set system(` it
|
|
310
|
+
// sits before the name with a space between them.
|
|
311
|
+
const prefix = lastCharacter === '=' ? before.slice(0, -1).trimEnd() : before;
|
|
312
|
+
const keyword = (_b = (_a = /([A-Za-z_][A-Za-z0-9_]*)$/.exec(prefix)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : '';
|
|
313
|
+
return DATASET_KEYWORDS.includes(keyword.toLowerCase());
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* `system(...)` as a function, which is the same command without the wrapping
|
|
317
|
+
* `%sysfunc`. A macro call (`%system(...)`) is a user macro rather than the SAS
|
|
318
|
+
* function, so a `%` immediately before the name is not a match.
|
|
319
|
+
*/
|
|
320
|
+
const systemFunction = {
|
|
321
|
+
label: 'system(...)',
|
|
322
|
+
find: (code) => {
|
|
323
|
+
const regex = /\bsystem\s*\(/gi;
|
|
324
|
+
const found = [];
|
|
325
|
+
let match;
|
|
326
|
+
while ((match = regex.exec(code))) {
|
|
327
|
+
if (code[match.index - 1] === '%')
|
|
328
|
+
continue;
|
|
329
|
+
// `%macro system();` names a macro rather than calling the function.
|
|
330
|
+
const before = code.slice(Math.max(0, match.index - 20), match.index);
|
|
331
|
+
if (/%(macro|mend)\s+$/i.test(before))
|
|
332
|
+
continue;
|
|
333
|
+
if (isDatasetReference(code, match.index))
|
|
334
|
+
continue;
|
|
335
|
+
found.push({ index: match.index, length: match[0].length });
|
|
336
|
+
}
|
|
337
|
+
return found;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
/** `systask command`. */
|
|
341
|
+
const sysTaskCommand = {
|
|
342
|
+
label: 'systask command',
|
|
343
|
+
find: (code) => {
|
|
344
|
+
const regex = /\bsystask\s+command\b/gi;
|
|
345
|
+
const found = [];
|
|
346
|
+
let match;
|
|
347
|
+
while ((match = regex.exec(code))) {
|
|
348
|
+
found.push({ index: match.index, length: match[0].length });
|
|
349
|
+
}
|
|
350
|
+
return found;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
/**
|
|
354
|
+
* `options xcmd;` - the positive form only. `options noxcmd;` is the statement
|
|
355
|
+
* that turns the capability off, and reporting it would push a project away from
|
|
356
|
+
* the hardening it performs.
|
|
357
|
+
*/
|
|
358
|
+
const optionsXcmd = {
|
|
359
|
+
label: 'options xcmd',
|
|
360
|
+
find: (code) => {
|
|
361
|
+
const regex = /(?:^|;)[ \t]*options\b([^;]*)/gim;
|
|
362
|
+
const found = [];
|
|
363
|
+
let match;
|
|
364
|
+
while ((match = regex.exec(code))) {
|
|
365
|
+
const to = match.index + match[0].length;
|
|
366
|
+
const from = to - match[1].length;
|
|
367
|
+
getTokens(code, from, to)
|
|
368
|
+
.filter((token) => token.value.toLowerCase() === 'xcmd')
|
|
369
|
+
.forEach((token) => found.push({ index: token.index, length: token.value.length }));
|
|
370
|
+
}
|
|
371
|
+
return found;
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* A fileref or an infile that reads from a pipe, which is an OS command with a
|
|
376
|
+
* file's clothes on.
|
|
377
|
+
*
|
|
378
|
+
* `pipe` stands in the option position of a `filename` statement, or after the
|
|
379
|
+
* quoted path of an `infile`. Requiring one of those positions is what keeps a
|
|
380
|
+
* variable named `pipe`, and the fileref `pipe`, from being reported.
|
|
381
|
+
*/
|
|
382
|
+
const pipeFileref = {
|
|
383
|
+
label: 'pipe',
|
|
384
|
+
find: (code) => {
|
|
385
|
+
const regex = /(?:^|;)[ \t]*(filename|infile)\b([^;]*)/gim;
|
|
386
|
+
const found = [];
|
|
387
|
+
let match;
|
|
388
|
+
while ((match = regex.exec(code))) {
|
|
389
|
+
const keyword = match[1].toLowerCase();
|
|
390
|
+
const to = match.index + match[0].length;
|
|
391
|
+
const tokens = getTokens(code, to - match[2].length, to);
|
|
392
|
+
if (keyword === 'filename') {
|
|
393
|
+
// The first token is the fileref being assigned, so `filename pipe;`
|
|
394
|
+
// deassigns that fileref rather than opening a pipe.
|
|
395
|
+
const pipe = tokens
|
|
396
|
+
.slice(1)
|
|
397
|
+
.find((token) => token.value.toLowerCase() === 'pipe');
|
|
398
|
+
if (pipe)
|
|
399
|
+
found.push({ index: pipe.index, length: pipe.value.length });
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
// `infile "path" pipe;` - the pipe follows the path it reads, which a
|
|
403
|
+
// macro-driven job may hold in a variable (`infile &cmd pipe;`).
|
|
404
|
+
const path = tokens.findIndex((token) => /["']$/.test(token.value) || /^[&%]/.test(token.value));
|
|
405
|
+
if (path === -1)
|
|
406
|
+
continue;
|
|
407
|
+
const pipe = tokens
|
|
408
|
+
.slice(path + 1)
|
|
409
|
+
.find((token) => token.value.toLowerCase() === 'pipe');
|
|
410
|
+
if (pipe)
|
|
411
|
+
found.push({ index: pipe.index, length: pipe.value.length });
|
|
412
|
+
}
|
|
413
|
+
return found;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const constructs = [
|
|
417
|
+
xStatement,
|
|
418
|
+
callSystem,
|
|
419
|
+
sysExec,
|
|
420
|
+
sysFuncSystem,
|
|
421
|
+
systemFunction,
|
|
422
|
+
sysTaskCommand,
|
|
423
|
+
optionsXcmd,
|
|
424
|
+
pipeFileref
|
|
425
|
+
];
|
|
426
|
+
/**
|
|
427
|
+
* Drops a finding that sits inside another, so one construct yields one
|
|
428
|
+
* diagnostic: `call system(...)` and `%sysfunc(system(...))` both contain a
|
|
429
|
+
* `system(` call, and reporting the inner one as well would triple the noise.
|
|
430
|
+
*/
|
|
431
|
+
const removeNested = (findings) => {
|
|
432
|
+
const kept = [];
|
|
433
|
+
return findings
|
|
434
|
+
.sort((a, b) => a.index - b.index || b.length - a.length)
|
|
435
|
+
.filter((finding) => {
|
|
436
|
+
const end = finding.index + finding.length;
|
|
437
|
+
if (kept.some((span) => finding.index >= span.index && end <= span.index + span.length))
|
|
438
|
+
return false;
|
|
439
|
+
kept.push(finding);
|
|
440
|
+
return true;
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
const test = (value, config) => {
|
|
444
|
+
if (!value)
|
|
445
|
+
return [];
|
|
446
|
+
const severity = (config === null || config === void 0 ? void 0 : config.severityLevel[name]) || Severity_1.Severity.Warning;
|
|
447
|
+
// Data first, then code: see blankDatalines for why the order is this way.
|
|
448
|
+
const { code, statementStarts } = maskNonCode(blankDatalines(value));
|
|
449
|
+
const findings = [];
|
|
450
|
+
constructs.forEach((construct) => {
|
|
451
|
+
construct
|
|
452
|
+
.find(code, statementStarts)
|
|
453
|
+
.forEach((found) => findings.push(Object.assign(Object.assign({}, found), { label: construct.label })));
|
|
454
|
+
});
|
|
455
|
+
return removeNested(findings)
|
|
456
|
+
.sort((a, b) => a.index - b.index || a.length - b.length)
|
|
457
|
+
.map((finding) => {
|
|
458
|
+
const { lineNumber, columnNumber } = (0, utils_1.getPosition)(code, finding.index);
|
|
459
|
+
// A construct wrapped over two lines is reported on the line it starts
|
|
460
|
+
// on, so its span stops at that line's end rather than running past it.
|
|
461
|
+
const lineEnd = code.indexOf('\n', finding.index);
|
|
462
|
+
const spanEnd = lineEnd === -1 || lineEnd >= finding.index + finding.length
|
|
463
|
+
? finding.index + finding.length - 1
|
|
464
|
+
: lineEnd - 1;
|
|
465
|
+
// On a CRLF file the last character of the line is the `\r`, which is not
|
|
466
|
+
// part of the construct.
|
|
467
|
+
const trimmedEnd = code[spanEnd] === '\r' ? spanEnd - 1 : spanEnd;
|
|
468
|
+
return {
|
|
469
|
+
message: `${message}: ${finding.label}`,
|
|
470
|
+
lineNumber,
|
|
471
|
+
startColumnNumber: columnNumber,
|
|
472
|
+
endColumnNumber: (0, utils_1.getPosition)(code, trimmedEnd).columnNumber,
|
|
473
|
+
severity
|
|
474
|
+
};
|
|
475
|
+
});
|
|
476
|
+
};
|
|
477
|
+
/**
|
|
478
|
+
* Lint rule that reports the statements and functions that need XCMD, so a
|
|
479
|
+
* program that shells out is found when it is linted rather than when it runs on
|
|
480
|
+
* a server where XCMD is off.
|
|
481
|
+
*/
|
|
482
|
+
exports.noXcmd = {
|
|
483
|
+
type: LintRuleType_1.LintRuleType.File,
|
|
484
|
+
name,
|
|
485
|
+
description,
|
|
486
|
+
message,
|
|
487
|
+
test
|
|
488
|
+
};
|
|
489
|
+
//# sourceMappingURL=noXcmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noXcmd.js","sourceRoot":"","sources":["../../../src/rules/file/noXcmd.ts"],"names":[],"mappings":"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"}
|
package/sasjslint-schema.json
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"indentationMultiple": 2,
|
|
19
19
|
"lineEndings": "off",
|
|
20
20
|
"lowerCaseFileNames": true,
|
|
21
|
+
"lowerCaseMacroNames": true,
|
|
21
22
|
"maxDataLineLength": 80,
|
|
22
23
|
"maxHeaderLineLength": 80,
|
|
23
24
|
"maxLineLength": 80,
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"noUndeclaredMacros": true,
|
|
36
37
|
"noUnusedLibnames": false,
|
|
37
38
|
"noUnusedMacros": true,
|
|
39
|
+
"noXcmd": true,
|
|
38
40
|
"requiredMacroOptions": [],
|
|
39
41
|
"severityLevel": {},
|
|
40
42
|
"strictMacroDefinition": true
|
|
@@ -61,6 +63,7 @@
|
|
|
61
63
|
"noSingleAsteriskComments": false,
|
|
62
64
|
"noUndeclaredMacros": true,
|
|
63
65
|
"noUnusedMacros": true,
|
|
66
|
+
"noXcmd": true,
|
|
64
67
|
"hasMacroParentheses": true,
|
|
65
68
|
"lineEndings": "crlf",
|
|
66
69
|
"strictMacroDefinition": true,
|
|
@@ -178,6 +181,14 @@
|
|
|
178
181
|
"default": true,
|
|
179
182
|
"examples": [true, false]
|
|
180
183
|
},
|
|
184
|
+
"lowerCaseMacroNames": {
|
|
185
|
+
"$id": "#/properties/lowerCaseMacroNames",
|
|
186
|
+
"type": "boolean",
|
|
187
|
+
"title": "lowerCaseMacroNames",
|
|
188
|
+
"description": "Enforces no uppercase characters in macro names, in the <h4> SAS Macros </h4> header and in the %macro and %mend statements. Shows a warning when they are present, and fixes the name in both places when asked to.",
|
|
189
|
+
"default": true,
|
|
190
|
+
"examples": [true, false]
|
|
191
|
+
},
|
|
181
192
|
"maxLineLength": {
|
|
182
193
|
"$id": "#/properties/maxLineLength",
|
|
183
194
|
"type": "number",
|
|
@@ -275,6 +286,14 @@
|
|
|
275
286
|
"default": true,
|
|
276
287
|
"examples": [true, false]
|
|
277
288
|
},
|
|
289
|
+
"noXcmd": {
|
|
290
|
+
"$id": "#/properties/noXcmd",
|
|
291
|
+
"type": "boolean",
|
|
292
|
+
"title": "noXcmd",
|
|
293
|
+
"description": "Reports the statements and functions that run an operating system command, which need XCMD: the `x` statement, `call system`, `%sysexec`, `system(...)` and `%sysfunc(system(...))`, `options xcmd`, a `pipe` fileref and `systask command`. `options noxcmd` is not reported. Comments, quoted values and `datalines` payloads are not searched. There is no fix.",
|
|
294
|
+
"default": true,
|
|
295
|
+
"examples": [true, false]
|
|
296
|
+
},
|
|
278
297
|
"noUnusedLibnames": {
|
|
279
298
|
"$id": "#/properties/noUnusedLibnames",
|
|
280
299
|
"type": "boolean",
|
|
@@ -418,6 +437,13 @@
|
|
|
418
437
|
"enum": ["error", "warn"],
|
|
419
438
|
"default": "warn"
|
|
420
439
|
},
|
|
440
|
+
"lowerCaseMacroNames": {
|
|
441
|
+
"$id": "#/properties/severityLevel/lowerCaseMacroNames",
|
|
442
|
+
"title": "lowerCaseMacroNames",
|
|
443
|
+
"type": "string",
|
|
444
|
+
"enum": ["error", "warn"],
|
|
445
|
+
"default": "warn"
|
|
446
|
+
},
|
|
421
447
|
"maxLineLength": {
|
|
422
448
|
"$id": "#/properties/severityLevel/maxLineLength",
|
|
423
449
|
"title": "maxLineLength",
|
|
@@ -488,6 +514,13 @@
|
|
|
488
514
|
"enum": ["error", "warn"],
|
|
489
515
|
"default": "warn"
|
|
490
516
|
},
|
|
517
|
+
"noXcmd": {
|
|
518
|
+
"$id": "#/properties/severityLevel/noXcmd",
|
|
519
|
+
"title": "noXcmd",
|
|
520
|
+
"type": "string",
|
|
521
|
+
"enum": ["error", "warn"],
|
|
522
|
+
"default": "warn"
|
|
523
|
+
},
|
|
491
524
|
"noUnusedLibnames": {
|
|
492
525
|
"$id": "#/properties/severityLevel/noUnusedLibnames",
|
|
493
526
|
"title": "noUnusedLibnames",
|
package/types/LintConfig.js
CHANGED
|
@@ -136,6 +136,9 @@ class LintConfig {
|
|
|
136
136
|
if ((json === null || json === void 0 ? void 0 : json.lowerCaseFileNames) !== false) {
|
|
137
137
|
this.pathLintRules.push(path_1.lowerCaseFileNames);
|
|
138
138
|
}
|
|
139
|
+
if ((json === null || json === void 0 ? void 0 : json.lowerCaseMacroNames) !== false) {
|
|
140
|
+
this.fileLintRules.push(file_1.lowerCaseMacroNames);
|
|
141
|
+
}
|
|
139
142
|
if ((json === null || json === void 0 ? void 0 : json.hasMacroNameInMend) !== false) {
|
|
140
143
|
this.fileLintRules.push(file_1.hasMacroNameInMend);
|
|
141
144
|
}
|
|
@@ -145,6 +148,9 @@ class LintConfig {
|
|
|
145
148
|
if ((json === null || json === void 0 ? void 0 : json.noNestedMacros) !== false) {
|
|
146
149
|
this.fileLintRules.push(file_1.noNestedMacros);
|
|
147
150
|
}
|
|
151
|
+
if ((json === null || json === void 0 ? void 0 : json.noXcmd) !== false) {
|
|
152
|
+
this.fileLintRules.push(file_1.noXcmd);
|
|
153
|
+
}
|
|
148
154
|
// Off by default: the rule encodes a SAS release floor - open-code %if
|
|
149
155
|
// needs 9.4M5 - so it is enabled by the projects whose floor is earlier
|
|
150
156
|
// and is noise for everyone else.
|
package/types/LintConfig.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LintConfig.js","sourceRoot":"","sources":["../../src/types/LintConfig.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"LintConfig.js","sourceRoot":"","sources":["../../src/types/LintConfig.ts"],"names":[],"mappings":"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"}
|
package/utils/getLintConfig.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare const DefaultLintConfiguration: {
|
|
|
23
23
|
indentationMultiple: number;
|
|
24
24
|
lineEndings: LineEndings;
|
|
25
25
|
lowerCaseFileNames: boolean;
|
|
26
|
+
lowerCaseMacroNames: boolean;
|
|
26
27
|
maxDataLineLength: number;
|
|
27
28
|
maxHeaderLineLength: number;
|
|
28
29
|
maxLineLength: number;
|
|
@@ -40,6 +41,7 @@ export declare const DefaultLintConfiguration: {
|
|
|
40
41
|
noUndeclaredMacros: boolean;
|
|
41
42
|
noUnusedLibnames: boolean;
|
|
42
43
|
noUnusedMacros: boolean;
|
|
44
|
+
noXcmd: boolean;
|
|
43
45
|
requiredMacroOptions: never[];
|
|
44
46
|
severityLevel: {};
|
|
45
47
|
strictMacroDefinition: boolean;
|
package/utils/getLintConfig.js
CHANGED
|
@@ -46,6 +46,7 @@ exports.DefaultLintConfiguration = {
|
|
|
46
46
|
indentationMultiple: 2,
|
|
47
47
|
lineEndings: LineEndings_1.LineEndings.OFF,
|
|
48
48
|
lowerCaseFileNames: true,
|
|
49
|
+
lowerCaseMacroNames: true,
|
|
49
50
|
maxDataLineLength: 80,
|
|
50
51
|
maxHeaderLineLength: 80,
|
|
51
52
|
maxLineLength: 80,
|
|
@@ -63,6 +64,7 @@ exports.DefaultLintConfiguration = {
|
|
|
63
64
|
noUndeclaredMacros: true,
|
|
64
65
|
noUnusedLibnames: false,
|
|
65
66
|
noUnusedMacros: true,
|
|
67
|
+
noXcmd: true,
|
|
66
68
|
requiredMacroOptions: [],
|
|
67
69
|
severityLevel: {},
|
|
68
70
|
strictMacroDefinition: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLintConfig.js","sourceRoot":"","sources":["../../src/utils/getLintConfig.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"getLintConfig.js","sourceRoot":"","sources":["../../src/utils/getLintConfig.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AA+DA,sCASC;AAxED,gDAAuB;AACvB,4CAAmB;AACnB,oDAAgD;AAChD,4CAA4C;AAC5C,qDAAiD;AACjD,sDAAkD;AAClD,iEAA6D;AAC7D,iEAA6D;AAEtD,MAAM,gBAAgB,GAAG,GAAG,EAAE,CACnC,wIAAwI,CAAA;AAD7H,QAAA,gBAAgB,oBAC6G;AAE1I;;;;;;;GAOG;AACU,QAAA,wBAAwB,GAAG;IACtC,eAAe,EAAE,EAAE;IACnB,aAAa,EAAE,CAAC,GAAG,2CAAoB,CAAC;IACxC,aAAa,EAAE,IAAA,wBAAgB,GAAE;IACjC,gBAAgB,EAAE,IAAI;IACtB,kBAAkB,EAAE,IAAI;IACxB,mBAAmB,EAAE,IAAI;IACzB,uBAAuB,EAAE,KAAK;IAC9B,UAAU,EAAE,EAAE;IACd,eAAe,EAAE,EAAE;IACnB,aAAa,EAAE,CAAC,GAAG,2CAAoB,CAAC;IACxC,mBAAmB,EAAE,CAAC;IACtB,WAAW,EAAE,yBAAW,CAAC,GAAG;IAC5B,kBAAkB,EAAE,IAAI;IACxB,mBAAmB,EAAE,IAAI;IACzB,iBAAiB,EAAE,EAAE;IACrB,mBAAmB,EAAE,EAAE;IACvB,aAAa,EAAE,EAAE;IACjB,kBAAkB,EAAE,CAAC;IACrB,eAAe,EAAE,IAAI;IACrB,kBAAkB,EAAE,IAAI;IACxB,UAAU,EAAE,IAAI;IAChB,mBAAmB,EAAE,KAAK;IAC1B,wBAAwB,EAAE,IAAI;IAC9B,cAAc,EAAE,IAAI;IACpB,wBAAwB,EAAE,KAAK;IAC/B,mBAAmB,EAAE,IAAI;IACzB,MAAM,EAAE,IAAI;IACZ,gBAAgB,EAAE,IAAI;IACtB,kBAAkB,EAAE,IAAI;IACxB,gBAAgB,EAAE,KAAK;IACvB,cAAc,EAAE,IAAI;IACpB,MAAM,EAAE,IAAI;IACZ,oBAAoB,EAAE,EAAE;IACxB,aAAa,EAAE,EAAE;IACjB,qBAAqB,EAAE,IAAI;CAC5B,CAAA;AAED;;;;GAIG;AACH,SAAsB,aAAa;;QACjC,MAAM,WAAW,GAAG,MAAM,IAAA,+BAAc,GAAE,CAAA;QAC1C,MAAM,gBAAgB,GAAG,WAAW,IAAI,YAAE,CAAC,OAAO,EAAE,CAAA;QACpD,MAAM,aAAa,GAAG,MAAM,IAAA,eAAQ,EAClC,cAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAC1C,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACZ,OAAO,IAAI,CAAC,SAAS,CAAC,gCAAwB,CAAC,CAAA;QACjD,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,uBAAU,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAA;IAClD,CAAC;CAAA"}
|