@sasjs/lint 5.1.0 → 5.1.1
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 +3 -3
- package/package.json +1 -1
- package/rules/file/hasDoxygenHeader.js +111 -31
- package/rules/file/hasDoxygenHeader.js.map +1 -1
- package/rules/file/noUndeclaredMacros.js +18 -9
- package/rules/file/noUndeclaredMacros.js.map +1 -1
- package/sasjslint-schema.json +2 -2
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/index.js.map +1 -1
- package/utils/isDoxygenHeader.d.ts +17 -0
- package/utils/isDoxygenHeader.js +58 -0
- package/utils/isDoxygenHeader.js.map +1 -0
package/README.md
CHANGED
|
@@ -161,9 +161,9 @@ If creating a new value, use `{lineEnding}` instead of `\n`, eg as follows:
|
|
|
161
161
|
|
|
162
162
|
### hasDoxygenHeader
|
|
163
163
|
|
|
164
|
-
The SASjs framework recommends the use of Doxygen headers for describing all types of SAS program. This check identifies files where a Doxygen header does not begin on the first line, where it opens with a single asterisk,
|
|
164
|
+
The SASjs framework recommends the use of Doxygen headers for describing all types of SAS program. This check identifies files where a Doxygen header does not begin on the first line, where it opens with a single asterisk, where it closes with one, where the close shares its line with the header's content, and where the block is never closed. A header is located by its close: the line that holds nothing but `**/`, which is the form `sasjs compile` and this rule set read. A block opened with `/**` whose close sits at the end of a content line, or which has no close at all, is therefore not yet a header.
|
|
165
165
|
|
|
166
|
-
The closing half matters beyond style. This rule set and `sasjs compile` both locate the header's end by its `**/` terminator, so a header closed with a plain `*/` has no end they can find - a comment inside such a header can truncate it without being reported by [`noNestedCommentsInHeader`](#nonestedcommentsinheader). The fix widens the close marker to `**/`, which puts the header back where that check can see it. A header whose body already holds a comment opener is left alone: the first close marker may belong to that comment, and that decision belongs to the author.
|
|
166
|
+
The closing half matters beyond style. This rule set and `sasjs compile` both locate the header's end by its `**/` terminator, so a header closed with a plain `*/` has no end they can find - a comment inside such a header can truncate it without being reported by [`noNestedCommentsInHeader`](#nonestedcommentsinheader). The fix widens the close marker to `**/`, and moves a close that shares its line onto a line of its own, which puts the header back where that check can see it. The repairs are applied in sequence inside the rule's single fix call, so a header carrying more than one defect - `/* c */` needs its opener widened, its close widened and then moved - reaches the Doxygen form in one `sasjs lint fix` run. An unclosed block is reported but not rewritten: closing it at the end of the file would swallow whatever the author meant to keep outside it. A header whose body already holds a comment opener is left alone: the first close marker may belong to that comment, and that decision belongs to the author.
|
|
167
167
|
|
|
168
168
|
- Default: true
|
|
169
169
|
- Severity: WARNING
|
|
@@ -487,7 +487,7 @@ This will highlight lines with trailing spaces. Trailing spaces serve no useful
|
|
|
487
487
|
|
|
488
488
|
SASjs programs declare the macros they use in the `<h4> SAS Macros </h4>` section of the header, so that the compiler can assemble the job before it runs. This rule reports a warning for each macro that a file invokes without declaring it - either by defining it in the file, or by listing it in the `<h4> SAS Macros </h4>` section. That is the only header list `sasjs compile` reads, so it is the only one that makes a macro available to the job; entries anywhere else in the header do not count.
|
|
489
489
|
|
|
490
|
-
The rule only looks at a file that has a header
|
|
490
|
+
The rule only looks at a file that has a Doxygen header: a block comment that opens with `/**` and closes with a line holding nothing but `**/`. A file with no header has no `<h4> SAS Macros </h4>` section to declare a macro in, and the formatter cannot create one, so its calls are not reported - `hasDoxygenHeader` reports the missing header, and that is the change the file needs first. A leading comment that is not a header is skipped rather than reported against a fix that cannot write: that covers a comment which fits on one line, one opened with a single asterisk (`/* some comment */`), and a `/**` block whose close shares its line or never arrives. `hasDoxygenHeader` reports each of those shapes, and its fixes put the header into the form this rule can write into earlier in the same `sasjs lint fix` pass; an unclosed block has no safe automatic repair, so it is left for the author and the declarations are checked once it closes.
|
|
491
491
|
|
|
492
492
|
The macros that ship with SAS (`%scan`, `%index`, `%sysfunc` and the other macro functions, along with the macro language keywords such as `%if`, `%then` and `%do`) are always considered declared, so they are never reported. That list is generated from the `macroStatements` and `macroFunctions` groups of `@sasjs/sas-language` (`npm run generate:macros`), so it tracks the SAS language data rather than being maintained here. Macros made available through the `SASAUTOS` system option are not visible to the linter and will be reported - list them in [`ignoredMacros`](#ignoredmacros), which carries `webout` by default.
|
|
493
493
|
|
package/package.json
CHANGED
|
@@ -13,29 +13,37 @@ const description = 'Enforce a Doxygen header at the start of each file, in the
|
|
|
13
13
|
const message = 'File missing Doxygen header';
|
|
14
14
|
const messageForSingleAsterisk = 'File not following Doxygen header style, use double asterisks';
|
|
15
15
|
const messageForSingleAsteriskClose = 'File not following Doxygen header style, close with double asterisks';
|
|
16
|
+
const messageForCloseNotOnOwnLine = 'File not following Doxygen header style, close with the marker on a line of its own';
|
|
17
|
+
const messageForUnclosedHeader = 'File not following Doxygen header style, header is never closed';
|
|
16
18
|
const CLOSE = '*/';
|
|
17
19
|
/**
|
|
18
|
-
*
|
|
19
|
-
* asterisk, which is the closer half of the same style the opening check
|
|
20
|
-
* enforces.
|
|
20
|
+
* Locates the close of a header that opens at `start`.
|
|
21
21
|
*
|
|
22
22
|
* A header that holds a comment opener of its own is left alone: the first
|
|
23
23
|
* close marker may belong to that comment rather than to the header, and that
|
|
24
|
-
* ambiguity belongs to the author, not to a formatter.
|
|
25
|
-
*
|
|
26
|
-
* @returns the index of the close marker to widen, or `null`.
|
|
24
|
+
* ambiguity belongs to the author, not to a formatter. That is the only case
|
|
25
|
+
* that answers `null`.
|
|
27
26
|
*/
|
|
28
|
-
const
|
|
27
|
+
const findHeaderClose = (value, start) => {
|
|
29
28
|
const close = value.indexOf(CLOSE, start + 2);
|
|
30
29
|
if (close === -1)
|
|
31
|
-
return
|
|
32
|
-
// Already closed in the Doxygen form.
|
|
33
|
-
if (value[close - 1] === '*')
|
|
34
|
-
return null;
|
|
30
|
+
return { kind: 'none' };
|
|
35
31
|
// A comment opener before the close makes the extent ambiguous.
|
|
36
32
|
if (value.slice(start + 2, close).includes('/*'))
|
|
37
33
|
return null;
|
|
38
|
-
|
|
34
|
+
// A close written with one asterisk, which the fix widens.
|
|
35
|
+
if (value[close - 1] !== '*')
|
|
36
|
+
return { kind: 'single', index: close };
|
|
37
|
+
// `close` points at the second asterisk of the marker. The line holds nothing
|
|
38
|
+
// but the marker when the text before its first asterisk and after its slash
|
|
39
|
+
// is whitespace only.
|
|
40
|
+
const lineStart = value.lastIndexOf('\n', close - 1) + 1;
|
|
41
|
+
const lineEnd = value.indexOf('\n', close);
|
|
42
|
+
const before = value.slice(lineStart, close - 1);
|
|
43
|
+
const after = value.slice(close + 2, lineEnd === -1 ? value.length : lineEnd);
|
|
44
|
+
return before.trim() === '' && after.trim() === ''
|
|
45
|
+
? { kind: 'own-line', index: close }
|
|
46
|
+
: { kind: 'inline', index: close };
|
|
39
47
|
};
|
|
40
48
|
const diagnose = (value, config) => {
|
|
41
49
|
var _a;
|
|
@@ -43,17 +51,32 @@ const diagnose = (value, config) => {
|
|
|
43
51
|
try {
|
|
44
52
|
const start = value.search(/\S/);
|
|
45
53
|
if (value.trimStart().startsWith('/**')) {
|
|
46
|
-
const close =
|
|
47
|
-
|
|
54
|
+
const close = findHeaderClose(value, start);
|
|
55
|
+
// The block's extent is ambiguous - leave it to the author.
|
|
56
|
+
if (close === null || close.kind === 'own-line')
|
|
48
57
|
return null;
|
|
49
|
-
|
|
58
|
+
if (close.kind === 'none') {
|
|
59
|
+
const { lineNumber, columnNumber } = (0, getPosition_1.getPosition)(value, start);
|
|
60
|
+
return {
|
|
61
|
+
message: messageForUnclosedHeader,
|
|
62
|
+
lineNumber,
|
|
63
|
+
startColumnNumber: columnNumber,
|
|
64
|
+
endColumnNumber: columnNumber + 3,
|
|
65
|
+
severity,
|
|
66
|
+
close: null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const { lineNumber, columnNumber } = (0, getPosition_1.getPosition)(value, close.index);
|
|
70
|
+
const inline = close.kind === 'inline';
|
|
50
71
|
return {
|
|
51
|
-
message:
|
|
72
|
+
message: inline
|
|
73
|
+
? messageForCloseNotOnOwnLine
|
|
74
|
+
: messageForSingleAsteriskClose,
|
|
52
75
|
lineNumber,
|
|
53
76
|
startColumnNumber: columnNumber,
|
|
54
|
-
endColumnNumber: columnNumber + 1,
|
|
77
|
+
endColumnNumber: columnNumber + (inline ? 2 : 1),
|
|
55
78
|
severity,
|
|
56
|
-
close
|
|
79
|
+
close: close.index
|
|
57
80
|
};
|
|
58
81
|
}
|
|
59
82
|
const hasFileHeaderWithSingleAsterisk = value.trimStart().startsWith('/*');
|
|
@@ -64,7 +87,7 @@ const diagnose = (value, config) => {
|
|
|
64
87
|
startColumnNumber: 1,
|
|
65
88
|
endColumnNumber: 1,
|
|
66
89
|
severity,
|
|
67
|
-
close:
|
|
90
|
+
close: null
|
|
68
91
|
};
|
|
69
92
|
return {
|
|
70
93
|
message,
|
|
@@ -72,7 +95,7 @@ const diagnose = (value, config) => {
|
|
|
72
95
|
startColumnNumber: 1,
|
|
73
96
|
endColumnNumber: 1,
|
|
74
97
|
severity,
|
|
75
|
-
close:
|
|
98
|
+
close: null
|
|
76
99
|
};
|
|
77
100
|
}
|
|
78
101
|
catch (e) {
|
|
@@ -82,7 +105,7 @@ const diagnose = (value, config) => {
|
|
|
82
105
|
startColumnNumber: 1,
|
|
83
106
|
endColumnNumber: 1,
|
|
84
107
|
severity,
|
|
85
|
-
close:
|
|
108
|
+
close: null
|
|
86
109
|
};
|
|
87
110
|
}
|
|
88
111
|
};
|
|
@@ -100,23 +123,80 @@ const test = (value, config) => {
|
|
|
100
123
|
}
|
|
101
124
|
];
|
|
102
125
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Puts a close marker on a line of its own, moving any text that followed the
|
|
128
|
+
* marker onto the next line. A close that overlaps the opener - an empty
|
|
129
|
+
* comment - has no body to keep, so the whole block is rewritten.
|
|
130
|
+
*
|
|
131
|
+
* `close` is the index of the second asterisk of the marker, as `indexOf` finds
|
|
132
|
+
* it, so the marker itself starts one character earlier.
|
|
133
|
+
*/
|
|
134
|
+
const expandClose = (value, close, start) => {
|
|
135
|
+
const lineEnding = value.includes('\r\n') ? '\r\n' : '\n';
|
|
136
|
+
if (close <= start + 2) {
|
|
137
|
+
return `${value.slice(0, start)}/**${lineEnding}**/${value.slice(close + 2)}`;
|
|
138
|
+
}
|
|
139
|
+
const markerStart = close - 1;
|
|
140
|
+
const head = value.slice(0, markerStart).replace(/[ \t]+$/, '');
|
|
141
|
+
const lineEnd = value.indexOf('\n', close);
|
|
142
|
+
const after = value.slice(close + 2, lineEnd === -1 ? value.length : lineEnd);
|
|
143
|
+
if (after.trim() === '')
|
|
144
|
+
return `${head}${lineEnding}${value.slice(markerStart)}`;
|
|
145
|
+
const rest = value.slice(lineEnd === -1 ? value.length : lineEnd);
|
|
146
|
+
return `${head}${lineEnding}${value.slice(markerStart, close + 2)}${lineEnding}${after.trimStart()}${rest}`;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Applies the repair a diagnosis calls for, or returns the text unchanged when
|
|
150
|
+
* it has none. `hasDoxygenHeader` repairs one defect per call so that the
|
|
151
|
+
* diagnosis and the repair cannot drift apart; `fix` below keeps calling it
|
|
152
|
+
* until the header is clean.
|
|
153
|
+
*/
|
|
154
|
+
const repair = (value, diagnosis, config) => {
|
|
107
155
|
if (diagnosis.message == messageForSingleAsterisk)
|
|
108
156
|
return value.replace('/*', '/**');
|
|
109
157
|
if (diagnosis.message == messageForSingleAsteriskClose)
|
|
110
158
|
return `${value.slice(0, diagnosis.close)}*${value.slice(diagnosis.close)}`;
|
|
111
|
-
|
|
112
|
-
|
|
159
|
+
if (diagnosis.message == messageForCloseNotOnOwnLine)
|
|
160
|
+
return expandClose(value, diagnosis.close, value.search(/\S/));
|
|
161
|
+
// An unclosed header has no safe repair: closing it at the end of the file
|
|
162
|
+
// would swallow whatever the author meant to keep outside it. The warning
|
|
163
|
+
// stays for the author to resolve.
|
|
164
|
+
if (diagnosis.message == messageForUnclosedHeader)
|
|
165
|
+
return value;
|
|
166
|
+
const cfg = config || new types_1.LintConfig(getLintConfig_1.DefaultLintConfiguration);
|
|
167
|
+
const lineEndingConfig = (cfg === null || cfg === void 0 ? void 0 : cfg.lineEndings) || LineEndings_1.LineEndings.LF;
|
|
113
168
|
const lineEnding = lineEndingConfig === LineEndings_1.LineEndings.LF ? '\n' : '\r\n';
|
|
114
|
-
return `${
|
|
169
|
+
return `${cfg === null || cfg === void 0 ? void 0 : cfg.defaultHeader.replace(/{lineEnding}/g, lineEnding)}${lineEnding}${value}`;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Repairs a header until it is clean, or until a repair stops changing the
|
|
173
|
+
* text.
|
|
174
|
+
*
|
|
175
|
+
* One header can hold more than one defect, and the formatter calls a rule's
|
|
176
|
+
* `fix` once per pass - a single-line comment in the single-asterisk form needs
|
|
177
|
+
* the opener widened, the close widened, and then the close moved onto a line
|
|
178
|
+
* of its own. Repairing a single defect leaves the file warning again after the
|
|
179
|
+
* pass, and leaves `noUndeclaredMacros` switched off for it, so the remaining
|
|
180
|
+
* repairs are taken here. Each repair moves the header strictly closer to the
|
|
181
|
+
* target shape, and the bound stops a repair that somehow does not.
|
|
182
|
+
*/
|
|
183
|
+
const fix = (value, config) => {
|
|
184
|
+
let repaired = value;
|
|
185
|
+
for (let step = 0; step < 3; step++) {
|
|
186
|
+
const diagnosis = diagnose(repaired, config);
|
|
187
|
+
if (!diagnosis)
|
|
188
|
+
return repaired;
|
|
189
|
+
const next = repair(repaired, diagnosis, config);
|
|
190
|
+
if (next === repaired)
|
|
191
|
+
return repaired;
|
|
192
|
+
repaired = next;
|
|
193
|
+
}
|
|
194
|
+
return repaired;
|
|
115
195
|
};
|
|
116
196
|
// Lint rule that checks for a Doxygen header in the double-asterisk form at the
|
|
117
|
-
// start of a given file: the opening check, the closing
|
|
118
|
-
//
|
|
119
|
-
//
|
|
197
|
+
// start of a given file: the opening check, the closing checks (one asterisk,
|
|
198
|
+
// a close that shares its line, and a block that never closes), and the fixes
|
|
199
|
+
// that widen a single-asterisk close or move a close onto a line of its own.
|
|
120
200
|
exports.hasDoxygenHeader = {
|
|
121
201
|
type: LintRuleType_1.LintRuleType.File,
|
|
122
202
|
name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasDoxygenHeader.js","sourceRoot":"","sources":["../../../src/rules/file/hasDoxygenHeader.ts"],"names":[],"mappings":";;;AAAA,uCAAoD;AACpD,yDAAqD;AAErD,2DAAuD;AACvD,mDAA+C;AAC/C,6DAAoE;AACpE,yDAAqD;AACrD,yDAAqD;AAErD,MAAM,IAAI,GAAG,kBAAkB,CAAA;AAC/B,MAAM,WAAW,GACf,8EAA8E,CAAA;AAChF,MAAM,OAAO,GAAG,6BAA6B,CAAA;AAC7C,MAAM,wBAAwB,GAC5B,+DAA+D,CAAA;AACjE,MAAM,6BAA6B,GACjC,sEAAsE,CAAA;
|
|
1
|
+
{"version":3,"file":"hasDoxygenHeader.js","sourceRoot":"","sources":["../../../src/rules/file/hasDoxygenHeader.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ exports.noUndeclaredMacros = void 0;
|
|
|
4
4
|
const types_1 = require("../../types");
|
|
5
5
|
const LintRuleType_1 = require("../../types/LintRuleType");
|
|
6
6
|
const Severity_1 = require("../../types/Severity");
|
|
7
|
-
const getHeaderLinesCount_1 = require("../../utils/getHeaderLinesCount");
|
|
8
7
|
const headerMacros_1 = require("../../utils/headerMacros");
|
|
8
|
+
const isDoxygenHeader_1 = require("../../utils/isDoxygenHeader");
|
|
9
9
|
const parseMacroCalls_1 = require("../../utils/parseMacroCalls");
|
|
10
10
|
const parseMacros_1 = require("../../utils/parseMacros");
|
|
11
11
|
const sasMacros_1 = require("../../utils/sasMacros");
|
|
@@ -22,8 +22,10 @@ const message = `Macro '{macro}' is not declared - add it to the <h4> SAS Macros
|
|
|
22
22
|
* names the configuration lists in `ignoredMacros` - a macro such as `%webout`
|
|
23
23
|
* has no file to point at.
|
|
24
24
|
*
|
|
25
|
-
* A file with no header is not scanned at all: the declaration the rule
|
|
26
|
-
* for goes in the header, so a file without one has no place to put it
|
|
25
|
+
* A file with no Doxygen header is not scanned at all: the declaration the rule
|
|
26
|
+
* asks for goes in the header, so a file without one has no place to put it,
|
|
27
|
+
* and a leading comment written with a single asterisk is a plain comment
|
|
28
|
+
* rather than a header.
|
|
27
29
|
*
|
|
28
30
|
* The scan leaves out the argument of `%str` / `%nrstr`: a file that masks a
|
|
29
31
|
* trigger usually does so to print it, and reporting it would be a new warning
|
|
@@ -34,12 +36,19 @@ const message = `Macro '{macro}' is not declared - add it to the <h4> SAS Macros
|
|
|
34
36
|
const getUndeclaredCalls = (value, config) => {
|
|
35
37
|
if (!value)
|
|
36
38
|
return [];
|
|
37
|
-
// A file with no header has no `<h4> SAS Macros </h4>` section to
|
|
38
|
-
// macro in, and `addMacrosToHeader` cannot write into one - so a
|
|
39
|
-
// would be a warning no pass could resolve. It is also the only
|
|
40
|
-
// lets `test` and `fix` agree on such a file. `hasDoxygenHeader`
|
|
41
|
-
// missing header itself, which is the change the file needs.
|
|
42
|
-
|
|
39
|
+
// A file with no Doxygen header has no `<h4> SAS Macros </h4>` section to
|
|
40
|
+
// declare a macro in, and `addMacrosToHeader` cannot write into one - so a
|
|
41
|
+
// report here would be a warning no pass could resolve. It is also the only
|
|
42
|
+
// reading that lets `test` and `fix` agree on such a file. `hasDoxygenHeader`
|
|
43
|
+
// reports the missing header itself, which is the change the file needs.
|
|
44
|
+
//
|
|
45
|
+
// A comment that is not a Doxygen header - one that fits on one line, one
|
|
46
|
+
// opened with a single asterisk, or a `/**` block whose close is not a line
|
|
47
|
+
// of its own or never arrives - leaves nothing the fix can write into, and
|
|
48
|
+
// reading any of them as a header made this rule report invocations against a
|
|
49
|
+
// header it then left untouched. `hasDoxygenHeader` reports each shape, and
|
|
50
|
+
// its fixes put the header into the form this rule reads.
|
|
51
|
+
if (!(0, isDoxygenHeader_1.isDoxygenHeader)(value))
|
|
43
52
|
return [];
|
|
44
53
|
const declared = new Set();
|
|
45
54
|
(0, parseMacros_1.parseMacros)(value, config).forEach((macro) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noUndeclaredMacros.js","sourceRoot":"","sources":["../../../src/rules/file/noUndeclaredMacros.ts"],"names":[],"mappings":";;;AAAA,uCAAoD;AAEpD,2DAAuD;AACvD,mDAA+C;AAC/C,
|
|
1
|
+
{"version":3,"file":"noUndeclaredMacros.js","sourceRoot":"","sources":["../../../src/rules/file/noUndeclaredMacros.ts"],"names":[],"mappings":";;;AAAA,uCAAoD;AAEpD,2DAAuD;AACvD,mDAA+C;AAC/C,2DAA6E;AAC7E,iEAA6D;AAC7D,iEAAwE;AACxE,yDAAqD;AACrD,qDAAkD;AAClD,yDAAqD;AAErD,MAAM,IAAI,GAAG,oBAAoB,CAAA;AACjC,MAAM,WAAW,GAAG,sDAAsD,CAAA;AAC1E,MAAM,OAAO,GAAG,mIAAmI,CAAA;AAEnJ;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAE,MAAkB,EAAe,EAAE;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IAErB,0EAA0E;IAC1E,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,yEAAyE;IACzE,EAAE;IACF,0EAA0E;IAC1E,4EAA4E;IAC5E,2EAA2E;IAC3E,8EAA8E;IAC9E,4EAA4E;IAC5E,0DAA0D;IAC1D,IAAI,CAAC,IAAA,iCAAe,EAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAEtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAElC,IAAA,yBAAW,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,IAAI,KAAK,CAAC,IAAI;YAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,8EAA8E;IAC9E,+EAA+E;IAC/E,4EAA4E;IAC5E,YAAY;IACZ,sBAAsB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9C,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,IAAA,8BAAe,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAChE,CAAA;IAED,MAAM,UAAU,GAAgB,EAAE,CAAA;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAE9B,IAAA,iCAAe,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAA;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAM;QACzB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAEb,wEAAwE;QACxE,0EAA0E;QAC1E,kEAAkE;QAClE,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,MAAA,MAAM,CAAC,kBAAkB,mCAAI,CAAC,CAAC;YAAE,OAAM;QAE/D,yEAAyE;QACzE,0EAA0E;QAC1E,2EAA2E;QAC3E,wEAAwE;QACxE,iDAAiD;QACjD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAEzC,IAAI,IAAA,sBAAU,EAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAM;QACjC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAM;QAC5B,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAM;QAE7B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,sBAAsB,GAAG,CAAC,KAAa,EAAY,EAAE,CACzD;IACE,GAAG,KAAK,CAAC,QAAQ,CACf,0DAA0D,CAC3D;CACF,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAE5B,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAgB,EAAE;IAChE,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,kBAAU,EAAE,CAAA;IACtC,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,GAAG,EAAE,IAAI,EAAE,mBAAQ,CAAC,OAAO,CAAC,CAAA;IAEzD,OAAO,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC;QAC9C,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,QAAQ;KACT,CAAC,CAAC,CAAA;AACL,CAAC,CAAA;AAED,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAU,EAAE;IACzD,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,kBAAU,EAAE,CAAA;IACtC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEtE,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEhC,OAAO,IAAA,gCAAiB,EAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;AAC9C,CAAC,CAAA;AAED;;;;GAIG;AACU,QAAA,kBAAkB,GAAiB;IAC9C,IAAI,EAAE,2BAAY,CAAC,IAAI;IACvB,IAAI;IACJ,WAAW;IACX,OAAO;IACP,IAAI;IACJ,GAAG;CACJ,CAAA"}
|
package/sasjslint-schema.json
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"$id": "#/properties/hasDoxygenHeader",
|
|
95
95
|
"type": "boolean",
|
|
96
96
|
"title": "hasDoxygenHeader",
|
|
97
|
-
"description": "Enforces
|
|
97
|
+
"description": "Enforces a Doxygen header at the start of each SAS file: a comment block that opens with `/**` and closes with a line holding nothing but `**/`. Shows a warning when the header is absent, when it opens or closes with a single asterisk, when the close shares its line with the header content, and when the block is never closed. The fix widens a single-asterisk marker and moves a close onto a line of its own; an unclosed block is left for the author.",
|
|
98
98
|
"default": true,
|
|
99
99
|
"examples": [true, false]
|
|
100
100
|
},
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
"$id": "#/properties/noUndeclaredMacros",
|
|
275
275
|
"type": "boolean",
|
|
276
276
|
"title": "noUndeclaredMacros",
|
|
277
|
-
"description": "Reports a warning for each macro a file invokes without declaring it in the `<h4> SAS Macros </h4>` section of the header - the only header list `sasjs compile` reads. Macros that ship with SAS are always considered declared, and so are the macros listed in `ignoredMacros` (`webout` by default). The formatter resolves the warning by adding the macro names to the header, sorted alphabetically. A file with no header is not reported: it has no `<h4> SAS Macros </h4>` section, and the fix cannot write into one, so `hasDoxygenHeader` reports the missing header instead.",
|
|
277
|
+
"description": "Reports a warning for each macro a file invokes without declaring it in the `<h4> SAS Macros </h4>` section of the header - the only header list `sasjs compile` reads. Macros that ship with SAS are always considered declared, and so are the macros listed in `ignoredMacros` (`webout` by default). The formatter resolves the warning by adding the macro names to the header, sorted alphabetically. A file with no Doxygen header is not reported: it has no `<h4> SAS Macros </h4>` section, and the fix cannot write into one, so `hasDoxygenHeader` reports the missing header instead. The same skip covers a leading comment that is not a header - one that fits on one line, one opened with a single asterisk, or a `/**` block whose close is not a line of its own - because `hasDoxygenHeader` reports each of those shapes and its fixes put the header into the form this rule can write into.",
|
|
278
278
|
"default": true,
|
|
279
279
|
"examples": [true, false]
|
|
280
280
|
},
|
package/utils/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './getPosition';
|
|
|
9
9
|
export * from './splitLines';
|
|
10
10
|
export * from './getIndicesOf';
|
|
11
11
|
export * from './getHeaderLinesCount';
|
|
12
|
+
export * from './isDoxygenHeader';
|
|
12
13
|
export * from './getDataSectionsDetail';
|
|
13
14
|
export * from './defaultBannedStrings';
|
|
14
15
|
export * from './defaultIgnoredMacros';
|
package/utils/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __exportStar(require("./getPosition"), exports);
|
|
|
25
25
|
__exportStar(require("./splitLines"), exports);
|
|
26
26
|
__exportStar(require("./getIndicesOf"), exports);
|
|
27
27
|
__exportStar(require("./getHeaderLinesCount"), exports);
|
|
28
|
+
__exportStar(require("./isDoxygenHeader"), exports);
|
|
28
29
|
__exportStar(require("./getDataSectionsDetail"), exports);
|
|
29
30
|
__exportStar(require("./defaultBannedStrings"), exports);
|
|
30
31
|
__exportStar(require("./defaultIgnoredMacros"), exports);
|
package/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA8B;AAC9B,kDAA+B;AAC/B,mDAAgC;AAChC,sDAAmC;AACnC,8CAA2B;AAC3B,iDAA8B;AAC9B,8CAA2B;AAC3B,gDAA6B;AAC7B,+CAA4B;AAC5B,iDAA8B;AAC9B,wDAAqC;AACrC,0DAAuC;AACvC,yDAAsC;AACtC,yDAAsC;AACtC,iDAA8B;AAC9B,gDAA6B;AAC7B,iDAA8B;AAC9B,oDAAiC;AACjC,kDAA+B;AAC/B,sDAAmC;AACnC,oDAAiC;AACjC,8CAA2B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA8B;AAC9B,kDAA+B;AAC/B,mDAAgC;AAChC,sDAAmC;AACnC,8CAA2B;AAC3B,iDAA8B;AAC9B,8CAA2B;AAC3B,gDAA6B;AAC7B,+CAA4B;AAC5B,iDAA8B;AAC9B,wDAAqC;AACrC,oDAAiC;AACjC,0DAAuC;AACvC,yDAAsC;AACtC,yDAAsC;AACtC,iDAA8B;AAC9B,gDAA6B;AAC7B,iDAA8B;AAC9B,oDAAiC;AACjC,kDAA+B;AAC/B,sDAAmC;AACnC,oDAAiC;AACjC,8CAA2B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a file opens with a Doxygen header - a block comment that opens with
|
|
3
|
+
* two asterisks as the first non-whitespace text in the file, and closes with a
|
|
4
|
+
* line that holds nothing but the close marker.
|
|
5
|
+
*
|
|
6
|
+
* The close is what tells a header from a plain comment. A comment that fits on
|
|
7
|
+
* one line, a block opened with a single asterisk, and a block opened with two
|
|
8
|
+
* that is never closed all fail here; `hasDoxygenHeader` reports each of those
|
|
9
|
+
* shapes, and its fix puts the close on a line of its own.
|
|
10
|
+
*
|
|
11
|
+
* The opener is the first non-whitespace text, so a header that follows a
|
|
12
|
+
* statement is not one, and the first close marker ends the block - a close
|
|
13
|
+
* line below a block that already closed belongs to something else.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} text - the text content of the file.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isDoxygenHeader: (text: string) => boolean;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isDoxygenHeader = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The close of a Doxygen header: a line that holds nothing but the marker (two
|
|
6
|
+
* asterisks and a slash), so both the rules and `sasjs compile` can locate the
|
|
7
|
+
* header's end. Leading whitespace is allowed; anything else on the line is
|
|
8
|
+
* not.
|
|
9
|
+
*/
|
|
10
|
+
const doxygenHeaderClose = '**/';
|
|
11
|
+
/**
|
|
12
|
+
* Whether a file opens with a Doxygen header - a block comment that opens with
|
|
13
|
+
* two asterisks as the first non-whitespace text in the file, and closes with a
|
|
14
|
+
* line that holds nothing but the close marker.
|
|
15
|
+
*
|
|
16
|
+
* The close is what tells a header from a plain comment. A comment that fits on
|
|
17
|
+
* one line, a block opened with a single asterisk, and a block opened with two
|
|
18
|
+
* that is never closed all fail here; `hasDoxygenHeader` reports each of those
|
|
19
|
+
* shapes, and its fix puts the close on a line of its own.
|
|
20
|
+
*
|
|
21
|
+
* The opener is the first non-whitespace text, so a header that follows a
|
|
22
|
+
* statement is not one, and the first close marker ends the block - a close
|
|
23
|
+
* line below a block that already closed belongs to something else.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} text - the text content of the file.
|
|
26
|
+
*/
|
|
27
|
+
const isDoxygenHeader = (text) => {
|
|
28
|
+
if (!text)
|
|
29
|
+
return false;
|
|
30
|
+
const lines = text.split(/\r\n|\n/);
|
|
31
|
+
let first = -1;
|
|
32
|
+
for (let index = 0; index < lines.length; index++) {
|
|
33
|
+
if (lines[index].trim() !== '') {
|
|
34
|
+
first = index;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (first === -1)
|
|
39
|
+
return false;
|
|
40
|
+
const opener = lines[first].trimStart();
|
|
41
|
+
if (!opener.startsWith('/**'))
|
|
42
|
+
return false;
|
|
43
|
+
// A close on the opener's own line is not a close of its own: the block ends
|
|
44
|
+
// there, so no later line can close it.
|
|
45
|
+
if (opener.includes('*/'))
|
|
46
|
+
return false;
|
|
47
|
+
for (let index = first + 1; index < lines.length; index++) {
|
|
48
|
+
const line = lines[index];
|
|
49
|
+
if (line.trim() === doxygenHeaderClose)
|
|
50
|
+
return true;
|
|
51
|
+
// The block closed earlier, on a line that is not a close of its own.
|
|
52
|
+
if (line.includes('*/'))
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
};
|
|
57
|
+
exports.isDoxygenHeader = isDoxygenHeader;
|
|
58
|
+
//# sourceMappingURL=isDoxygenHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isDoxygenHeader.js","sourceRoot":"","sources":["../../src/utils/isDoxygenHeader.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,KAAK,CAAA;AAEhC;;;;;;;;;;;;;;;GAeG;AACI,MAAM,eAAe,GAAG,CAAC,IAAY,EAAW,EAAE;IACvD,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACnC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAA;IAEd,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/B,KAAK,GAAG,KAAK,CAAA;YACb,MAAK;QACP,CAAC;IACH,CAAC;IAED,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IAE9B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,CAAA;IACvC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAE3C,6EAA6E;IAC7E,wCAAwC;IACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAEvC,KAAK,IAAI,KAAK,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QAEzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,kBAAkB;YAAE,OAAO,IAAI,CAAA;QAEnD,sEAAsE;QACtE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAA;IACvC,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAhCY,QAAA,eAAe,mBAgC3B"}
|