@sasjs/lint 2.6.0 → 3.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/.git-hooks/pre-commit +18 -0
- package/.github/CONTRIBUTING.md +27 -0
- package/.github/workflows/build.yml +13 -7
- package/.github/workflows/publish.yml +12 -1
- package/.pre-commit-config.yaml +16 -0
- package/README.md +49 -1
- package/package.json +12 -12
- package/rules/file/index.d.ts +3 -0
- package/rules/file/index.js +7 -1
- package/rules/file/index.js.map +1 -1
- package/rules/file/noSingleAsteriskComments.d.ts +7 -0
- package/rules/file/noSingleAsteriskComments.js +219 -0
- package/rules/file/noSingleAsteriskComments.js.map +1 -0
- package/rules/file/noUndeclaredMacros.d.ts +7 -0
- package/rules/file/noUndeclaredMacros.js +77 -0
- package/rules/file/noUndeclaredMacros.js.map +1 -0
- package/rules/file/noUnusedMacros.d.ts +7 -0
- package/rules/file/noUnusedMacros.js +67 -0
- package/rules/file/noUnusedMacros.js.map +1 -0
- package/sasjslint-schema.json +53 -2
- package/scripts/generate-macro-names.mjs +101 -0
- package/types/LintConfig.js +9 -0
- package/types/LintConfig.js.map +1 -1
- package/utils/getLintConfig.js +1 -1
- package/utils/getLintConfig.js.map +1 -1
- package/utils/headerMacros.d.ts +51 -0
- package/utils/headerMacros.js +309 -0
- package/utils/headerMacros.js.map +1 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +3 -0
- package/utils/index.js.map +1 -1
- package/utils/parseMacroCalls.d.ts +28 -0
- package/utils/parseMacroCalls.js +230 -0
- package/utils/parseMacroCalls.js.map +1 -0
- package/utils/sasMacros.d.ts +16 -0
- package/utils/sasMacros.generated.d.ts +6 -0
- package/utils/sasMacros.generated.js +136 -0
- package/utils/sasMacros.generated.js.map +1 -0
- package/utils/sasMacros.js +22 -0
- package/utils/sasMacros.js.map +1 -0
- package/scripts/audit.mjs +0 -131
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.removeMacrosFromHeader = exports.addMacrosToHeader = exports.getHeaderMacros = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const LineEndings_1 = require("../types/LineEndings");
|
|
6
|
+
const getHeaderLinesCount_1 = require("./getHeaderLinesCount");
|
|
7
|
+
const splitText_1 = require("./splitText");
|
|
8
|
+
const sasMacrosHeader = /<h4>\s*SAS Macros\s*<\/h4>/i;
|
|
9
|
+
const otherMacrosHeader = /<h4>\s*Other Macros\s*<\/h4>/i;
|
|
10
|
+
const anyHeader = /<h4>/i;
|
|
11
|
+
const headerTag = '</h4>';
|
|
12
|
+
const listItem = /^(\s*@li\s+)(.+?)(\s*)$/;
|
|
13
|
+
/**
|
|
14
|
+
* Reads an `@li` entry, returning the macro name and the column at which it
|
|
15
|
+
* starts. The column is derived from the entry text rather than from a search
|
|
16
|
+
* for the name, so an entry such as `@li li.sas` reports the `li` after the
|
|
17
|
+
* tag, not the `li` inside it.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} text - the line, or the tail of a line, to read.
|
|
20
|
+
* @param {number} offset - the 0-based column at which `text` starts in the
|
|
21
|
+
* line, so a trailing entry on a `<h4>` line still reports its real position.
|
|
22
|
+
*/
|
|
23
|
+
const parseListItem = (text, offset = 0) => {
|
|
24
|
+
const match = listItem.exec(text);
|
|
25
|
+
if (!match)
|
|
26
|
+
return null;
|
|
27
|
+
const entry = match[2];
|
|
28
|
+
const firstToken = entry.trim().split(/\s+/)[0] || '';
|
|
29
|
+
const normalised = firstToken.replace(/\\/g, '/');
|
|
30
|
+
const fileName = normalised.split('/').pop() || '';
|
|
31
|
+
const name = fileName.replace(/\.sas$/i, '');
|
|
32
|
+
if (!name)
|
|
33
|
+
return null;
|
|
34
|
+
const tokenOffset = entry.indexOf(firstToken);
|
|
35
|
+
const fileOffset = normalised.lastIndexOf('/') + 1;
|
|
36
|
+
const column = offset + match[1].length + tokenOffset + fileOffset + 1;
|
|
37
|
+
return { name, column };
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Reads the `@li` entries of a section that starts at `sectionIndex`.
|
|
41
|
+
*
|
|
42
|
+
* A blank line ends the list unless the next non-blank line is another entry,
|
|
43
|
+
* so a list broken up by a stray blank line is still read in full - the
|
|
44
|
+
* formatter rewrites exactly the lines it read, and an entry it did not read
|
|
45
|
+
* would be left behind and duplicated.
|
|
46
|
+
*
|
|
47
|
+
* @returns the entries, and the index of the first line after the last one.
|
|
48
|
+
*/
|
|
49
|
+
const readSectionList = (lines, sectionIndex, limit) => {
|
|
50
|
+
const entries = [];
|
|
51
|
+
let end = sectionIndex + 1;
|
|
52
|
+
let index = sectionIndex + 1;
|
|
53
|
+
while (index < limit && index < lines.length) {
|
|
54
|
+
const line = lines[index];
|
|
55
|
+
if (line.trim() === '') {
|
|
56
|
+
let next = index;
|
|
57
|
+
while (next < limit && next < lines.length && lines[next].trim() === '') {
|
|
58
|
+
next++;
|
|
59
|
+
}
|
|
60
|
+
if (next < limit && next < lines.length && listItem.test(lines[next])) {
|
|
61
|
+
index = next;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
const parsed = parseListItem(line);
|
|
67
|
+
if (!parsed)
|
|
68
|
+
break;
|
|
69
|
+
entries.push({
|
|
70
|
+
name: parsed.name,
|
|
71
|
+
line,
|
|
72
|
+
lineNumber: index + 1,
|
|
73
|
+
column: parsed.column
|
|
74
|
+
});
|
|
75
|
+
index++;
|
|
76
|
+
end = index;
|
|
77
|
+
}
|
|
78
|
+
return { entries, end };
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Reads the macros declared in the header of a file - both the
|
|
82
|
+
* `<h4> SAS Macros </h4>` and the `<h4> Other Macros </h4>` sections.
|
|
83
|
+
* @param {string} text - the text content of the file.
|
|
84
|
+
* @param {LintConfig} config - the lint configuration, used for line endings.
|
|
85
|
+
* @returns {HeaderMacro[]} the declared macros, in the order they appear.
|
|
86
|
+
*/
|
|
87
|
+
const getHeaderMacros = (text, config) => {
|
|
88
|
+
if (!text)
|
|
89
|
+
return [];
|
|
90
|
+
const cfg = config || new types_1.LintConfig();
|
|
91
|
+
const headerLinesCount = (0, getHeaderLinesCount_1.getHeaderLinesCount)(text, cfg);
|
|
92
|
+
if (!headerLinesCount)
|
|
93
|
+
return [];
|
|
94
|
+
const lines = (0, splitText_1.splitText)(text, cfg);
|
|
95
|
+
const macros = [];
|
|
96
|
+
for (let index = 0; index < headerLinesCount && index < lines.length; index++) {
|
|
97
|
+
const line = lines[index];
|
|
98
|
+
const section = sasMacrosHeader.test(line)
|
|
99
|
+
? 'sasMacros'
|
|
100
|
+
: otherMacrosHeader.test(line)
|
|
101
|
+
? 'otherMacros'
|
|
102
|
+
: null;
|
|
103
|
+
if (!section)
|
|
104
|
+
continue;
|
|
105
|
+
// An entry can share the line with the section tag.
|
|
106
|
+
const tagEnd = line.indexOf(headerTag) + headerTag.length;
|
|
107
|
+
const trailing = parseListItem(line.slice(tagEnd), tagEnd);
|
|
108
|
+
if (trailing) {
|
|
109
|
+
macros.push({
|
|
110
|
+
name: trailing.name,
|
|
111
|
+
lineNumber: index + 1,
|
|
112
|
+
startColumnNumber: trailing.column,
|
|
113
|
+
endColumnNumber: trailing.column + trailing.name.length,
|
|
114
|
+
section
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
readSectionList(lines, index, headerLinesCount).entries.forEach((entry) => {
|
|
118
|
+
macros.push({
|
|
119
|
+
name: entry.name,
|
|
120
|
+
lineNumber: entry.lineNumber,
|
|
121
|
+
startColumnNumber: entry.column,
|
|
122
|
+
endColumnNumber: entry.column + entry.name.length,
|
|
123
|
+
section
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return macros;
|
|
128
|
+
};
|
|
129
|
+
exports.getHeaderMacros = getHeaderMacros;
|
|
130
|
+
/**
|
|
131
|
+
* Derives the indentation used by the content lines of a header. Falls back to
|
|
132
|
+
* two spaces, which is the indentation of the default header.
|
|
133
|
+
*/
|
|
134
|
+
const getHeaderIndent = (lines, headerLinesCount) => {
|
|
135
|
+
for (let index = 1; index < headerLinesCount && index < lines.length; index++) {
|
|
136
|
+
const match = /^(\s+)\S/.exec(lines[index]);
|
|
137
|
+
if (match)
|
|
138
|
+
return match[1];
|
|
139
|
+
}
|
|
140
|
+
return ' ';
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Ensures a blank line separates a header section from its neighbours. The
|
|
144
|
+
* section header sits at `sectionIndex` and `listEnd` is the index of the first
|
|
145
|
+
* line after the section's `@li` entries.
|
|
146
|
+
*/
|
|
147
|
+
const withSectionSpacing = (lines, sectionIndex, listEnd) => {
|
|
148
|
+
const result = [...lines];
|
|
149
|
+
if (listEnd < result.length && result[listEnd].trim() !== '') {
|
|
150
|
+
result.splice(listEnd, 0, '');
|
|
151
|
+
}
|
|
152
|
+
if (sectionIndex > 0 && result[sectionIndex - 1].trim() !== '') {
|
|
153
|
+
result.splice(sectionIndex, 0, '');
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Locates the `<h4> SAS Macros </h4>` section of a header.
|
|
159
|
+
*
|
|
160
|
+
* Returns `null` when the section is absent, and `null` when it cannot be
|
|
161
|
+
* rewritten without disturbing the surrounding text: when the section shares a
|
|
162
|
+
* line with the header's closing `**`, or when an `@li` entry shares the line
|
|
163
|
+
* with the section tag. In those cases the caller leaves the file alone, so a
|
|
164
|
+
* warning that cannot be resolved is preferable to a corrupted header.
|
|
165
|
+
*/
|
|
166
|
+
const findSasMacrosSection = (lines, headerLinesCount) => {
|
|
167
|
+
let sectionIndex = -1;
|
|
168
|
+
for (let index = 0; index < headerLinesCount && index < lines.length; index++) {
|
|
169
|
+
if (sasMacrosHeader.test(lines[index])) {
|
|
170
|
+
sectionIndex = index;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (sectionIndex === -1)
|
|
175
|
+
return null;
|
|
176
|
+
if (sectionIndex === headerLinesCount - 1)
|
|
177
|
+
return null;
|
|
178
|
+
const tagEnd = lines[sectionIndex].indexOf(headerTag) + headerTag.length;
|
|
179
|
+
if (parseListItem(lines[sectionIndex].slice(tagEnd)))
|
|
180
|
+
return null;
|
|
181
|
+
const { entries, end } = readSectionList(lines, sectionIndex, headerLinesCount);
|
|
182
|
+
return { sectionIndex, entries, end };
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Adds macro names to the `<h4> SAS Macros </h4>` section of a file header,
|
|
186
|
+
* merging them with the entries that are already listed, de-duplicating by
|
|
187
|
+
* name, and sorting the result alphabetically. A new section is added when the
|
|
188
|
+
* header has none.
|
|
189
|
+
*
|
|
190
|
+
* A blank line separates the section from the header content before it and from
|
|
191
|
+
* whatever follows the list, so the section reads as its own block.
|
|
192
|
+
*
|
|
193
|
+
* @param {string} text - the text content of the file.
|
|
194
|
+
* @param {LintConfig} config - the lint configuration, used for line endings.
|
|
195
|
+
* @param {string[]} macros - the macro names to add.
|
|
196
|
+
* @returns {string} the updated text content.
|
|
197
|
+
*/
|
|
198
|
+
const addMacrosToHeader = (text, config, macros) => {
|
|
199
|
+
if (!text || !macros.length)
|
|
200
|
+
return text;
|
|
201
|
+
const headerLinesCount = (0, getHeaderLinesCount_1.getHeaderLinesCount)(text, config);
|
|
202
|
+
if (!headerLinesCount)
|
|
203
|
+
return text;
|
|
204
|
+
const lines = (0, splitText_1.splitText)(text, config);
|
|
205
|
+
const lineEnding = config.lineEndings === LineEndings_1.LineEndings.CRLF ? '\r\n' : '\n';
|
|
206
|
+
const headerEndIndex = headerLinesCount - 1;
|
|
207
|
+
const section = findSasMacrosSection(lines, headerLinesCount);
|
|
208
|
+
if (!section) {
|
|
209
|
+
// No section, or one that cannot be rewritten. Only a genuinely absent
|
|
210
|
+
// section is safe to create, so check for the tag first.
|
|
211
|
+
const hasSection = lines
|
|
212
|
+
.slice(0, headerLinesCount)
|
|
213
|
+
.some((line) => sasMacrosHeader.test(line));
|
|
214
|
+
if (hasSection || headerEndIndex === 0)
|
|
215
|
+
return text;
|
|
216
|
+
const indent = getHeaderIndent(lines, headerLinesCount);
|
|
217
|
+
const sectionLines = [
|
|
218
|
+
`${indent}<h4> SAS Macros </h4>`,
|
|
219
|
+
...macros.map((macro) => `${indent}@li ${macro}.sas`)
|
|
220
|
+
];
|
|
221
|
+
const result = [
|
|
222
|
+
...lines.slice(0, headerEndIndex),
|
|
223
|
+
...sectionLines,
|
|
224
|
+
...lines.slice(headerEndIndex)
|
|
225
|
+
];
|
|
226
|
+
return withSectionSpacing(result, headerEndIndex, headerEndIndex + sectionLines.length).join(lineEnding);
|
|
227
|
+
}
|
|
228
|
+
const { sectionIndex, entries, end } = section;
|
|
229
|
+
const indent = lines[sectionIndex].match(/^\s*/)[0];
|
|
230
|
+
const byName = new Map();
|
|
231
|
+
entries.forEach((entry) => {
|
|
232
|
+
const key = entry.name.toLowerCase();
|
|
233
|
+
if (!byName.has(key))
|
|
234
|
+
byName.set(key, { name: entry.name, line: entry.line });
|
|
235
|
+
});
|
|
236
|
+
macros.forEach((macro) => {
|
|
237
|
+
const key = macro.toLowerCase();
|
|
238
|
+
if (byName.has(key))
|
|
239
|
+
return;
|
|
240
|
+
byName.set(key, { name: macro, line: `${indent}@li ${macro}.sas` });
|
|
241
|
+
});
|
|
242
|
+
const sortedLines = [...byName.values()]
|
|
243
|
+
.sort((a, b) => compareMacroNames(a.name, b.name))
|
|
244
|
+
.map((entry) => entry.line);
|
|
245
|
+
const result = [
|
|
246
|
+
...lines.slice(0, sectionIndex + 1),
|
|
247
|
+
...sortedLines,
|
|
248
|
+
...lines.slice(end)
|
|
249
|
+
];
|
|
250
|
+
return withSectionSpacing(result, sectionIndex, sectionIndex + 1 + sortedLines.length).join(lineEnding);
|
|
251
|
+
};
|
|
252
|
+
exports.addMacrosToHeader = addMacrosToHeader;
|
|
253
|
+
/**
|
|
254
|
+
* Removes macro names from the `<h4> SAS Macros </h4>` section of a file
|
|
255
|
+
* header. The section header itself is kept, so an empty list remains a valid
|
|
256
|
+
* place for the formatter to add entries. The blank line before the section and
|
|
257
|
+
* after the list is preserved.
|
|
258
|
+
*
|
|
259
|
+
* The file is returned unchanged when it has no Doxygen header, when the header
|
|
260
|
+
* has no `SAS Macros` section, when the section cannot be rewritten safely, or
|
|
261
|
+
* when none of the named macros are listed.
|
|
262
|
+
*
|
|
263
|
+
* @param {string} text - the text content of the file.
|
|
264
|
+
* @param {LintConfig} config - the lint configuration, used for line endings.
|
|
265
|
+
* @param {string[]} macros - the macro names to remove.
|
|
266
|
+
* @returns {string} the updated text content.
|
|
267
|
+
*/
|
|
268
|
+
const removeMacrosFromHeader = (text, config, macros) => {
|
|
269
|
+
if (!text || !macros.length)
|
|
270
|
+
return text;
|
|
271
|
+
const headerLinesCount = (0, getHeaderLinesCount_1.getHeaderLinesCount)(text, config);
|
|
272
|
+
if (!headerLinesCount)
|
|
273
|
+
return text;
|
|
274
|
+
const lines = (0, splitText_1.splitText)(text, config);
|
|
275
|
+
const lineEnding = config.lineEndings === LineEndings_1.LineEndings.CRLF ? '\r\n' : '\n';
|
|
276
|
+
const section = findSasMacrosSection(lines, headerLinesCount);
|
|
277
|
+
if (!section)
|
|
278
|
+
return text;
|
|
279
|
+
const { sectionIndex, entries, end } = section;
|
|
280
|
+
const remove = new Set(macros.map((macro) => macro.toLowerCase()));
|
|
281
|
+
const kept = [];
|
|
282
|
+
const seen = new Set();
|
|
283
|
+
let changed = false;
|
|
284
|
+
entries.forEach((entry) => {
|
|
285
|
+
const key = entry.name.toLowerCase();
|
|
286
|
+
if (remove.has(key)) {
|
|
287
|
+
changed = true;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (seen.has(key)) {
|
|
291
|
+
// A duplicate entry for a macro that is kept.
|
|
292
|
+
changed = true;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
seen.add(key);
|
|
296
|
+
kept.push(entry.line);
|
|
297
|
+
});
|
|
298
|
+
if (!changed)
|
|
299
|
+
return text;
|
|
300
|
+
const result = [
|
|
301
|
+
...lines.slice(0, sectionIndex + 1),
|
|
302
|
+
...kept,
|
|
303
|
+
...lines.slice(end)
|
|
304
|
+
];
|
|
305
|
+
return withSectionSpacing(result, sectionIndex, sectionIndex + 1 + kept.length).join(lineEnding);
|
|
306
|
+
};
|
|
307
|
+
exports.removeMacrosFromHeader = removeMacrosFromHeader;
|
|
308
|
+
const compareMacroNames = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase());
|
|
309
|
+
//# sourceMappingURL=headerMacros.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headerMacros.js","sourceRoot":"","sources":["../../src/utils/headerMacros.ts"],"names":[],"mappings":"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"}
|
package/utils/index.d.ts
CHANGED
package/utils/index.js
CHANGED
|
@@ -24,4 +24,7 @@ __exportStar(require("./splitText"), exports);
|
|
|
24
24
|
__exportStar(require("./getIndicesOf"), exports);
|
|
25
25
|
__exportStar(require("./getHeaderLinesCount"), exports);
|
|
26
26
|
__exportStar(require("./getDataSectionsDetail"), exports);
|
|
27
|
+
__exportStar(require("./headerMacros"), exports);
|
|
28
|
+
__exportStar(require("./parseMacroCalls"), exports);
|
|
29
|
+
__exportStar(require("./sasMacros"), exports);
|
|
27
30
|
//# sourceMappingURL=index.js.map
|
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,iDAA8B;AAC9B,wDAAqC;AACrC,0DAAuC"}
|
|
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,iDAA8B;AAC9B,wDAAqC;AACrC,0DAAuC;AACvC,iDAA8B;AAC9B,oDAAiC;AACjC,8CAA2B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LintConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* A macro invocation found in a file, with the position of its `%` character.
|
|
4
|
+
*/
|
|
5
|
+
export interface MacroCall {
|
|
6
|
+
name: string;
|
|
7
|
+
lineNumber: number;
|
|
8
|
+
startColumnNumber: number;
|
|
9
|
+
endColumnNumber: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Finds the macro invocations in a file.
|
|
13
|
+
*
|
|
14
|
+
* SAS resolves macro triggers inside double-quoted strings but not inside
|
|
15
|
+
* single-quoted strings, so a double-quoted string is scanned as code while a
|
|
16
|
+
* single-quoted string is opaque. Invocations inside block comments, macro
|
|
17
|
+
* comments, comment statements, masking functions (`%str` / `%nrstr`), data
|
|
18
|
+
* sections and embedded-language `submit` blocks are excluded.
|
|
19
|
+
*
|
|
20
|
+
* Every `%name` token is reported, including the macro language keywords and
|
|
21
|
+
* the macros that ship with SAS. Callers decide which names are interesting.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} text - the text content to scan.
|
|
24
|
+
* @param {LintConfig} config - the lint configuration. It is accepted for
|
|
25
|
+
* symmetry with the other utilities and is not used by the scan.
|
|
26
|
+
* @returns {MacroCall[]} the invocations, in the order they appear.
|
|
27
|
+
*/
|
|
28
|
+
export declare const parseMacroCalls: (text: string, config?: LintConfig) => MacroCall[];
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMacroCalls = void 0;
|
|
4
|
+
/** Matches a macro invocation at the start of the supplied text. */
|
|
5
|
+
const macroNameStart = /^%([a-z_][a-z0-9_]*)/i;
|
|
6
|
+
/** Matches the statements that open a data section. */
|
|
7
|
+
const dataSectionStart = /^(datalines4?|cards4?|parmcards4?)\s*;/i;
|
|
8
|
+
/** Matches the functions whose argument is data rather than code. */
|
|
9
|
+
const maskingFunctionStart = /^%(nrstr|str)\s*\(/i;
|
|
10
|
+
/** Matches the procedures whose `submit` block holds another language. */
|
|
11
|
+
const embeddedLanguageProc = /^proc\s+(lua|groovy)\b/i;
|
|
12
|
+
/** Matches the statement that closes an embedded-language block. */
|
|
13
|
+
const embeddedLanguageEnd = /^endsubmit\s*;/i;
|
|
14
|
+
const embeddedLanguageEndSearch = /endsubmit/i;
|
|
15
|
+
/**
|
|
16
|
+
* Finds the macro invocations in a file.
|
|
17
|
+
*
|
|
18
|
+
* SAS resolves macro triggers inside double-quoted strings but not inside
|
|
19
|
+
* single-quoted strings, so a double-quoted string is scanned as code while a
|
|
20
|
+
* single-quoted string is opaque. Invocations inside block comments, macro
|
|
21
|
+
* comments, comment statements, masking functions (`%str` / `%nrstr`), data
|
|
22
|
+
* sections and embedded-language `submit` blocks are excluded.
|
|
23
|
+
*
|
|
24
|
+
* Every `%name` token is reported, including the macro language keywords and
|
|
25
|
+
* the macros that ship with SAS. Callers decide which names are interesting.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} text - the text content to scan.
|
|
28
|
+
* @param {LintConfig} config - the lint configuration. It is accepted for
|
|
29
|
+
* symmetry with the other utilities and is not used by the scan.
|
|
30
|
+
* @returns {MacroCall[]} the invocations, in the order they appear.
|
|
31
|
+
*/
|
|
32
|
+
const parseMacroCalls = (text, config) => {
|
|
33
|
+
const calls = [];
|
|
34
|
+
if (!text)
|
|
35
|
+
return calls;
|
|
36
|
+
const length = text.length;
|
|
37
|
+
let index = 0;
|
|
38
|
+
let lineNumber = 1;
|
|
39
|
+
let columnNumber = 1;
|
|
40
|
+
let atStatementStart = true;
|
|
41
|
+
let inDoubleQuote = false;
|
|
42
|
+
/**
|
|
43
|
+
* Advances the cursor to `target`, keeping the line and column counters in
|
|
44
|
+
* step. Every branch that consumes a non-code region moves through here.
|
|
45
|
+
*/
|
|
46
|
+
const advanceTo = (target) => {
|
|
47
|
+
const limit = Math.min(target, length);
|
|
48
|
+
while (index < limit) {
|
|
49
|
+
if (text[index] === '\n') {
|
|
50
|
+
lineNumber++;
|
|
51
|
+
columnNumber = 1;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
columnNumber++;
|
|
55
|
+
}
|
|
56
|
+
index++;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
while (index < length) {
|
|
60
|
+
const char = text[index];
|
|
61
|
+
if (char === '\n') {
|
|
62
|
+
lineNumber++;
|
|
63
|
+
columnNumber = 1;
|
|
64
|
+
inDoubleQuote = false;
|
|
65
|
+
index++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (char === '\r' || char === ' ' || char === '\t') {
|
|
69
|
+
columnNumber++;
|
|
70
|
+
index++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Single-quoted string - opaque. `''` is an escaped quote character. An
|
|
74
|
+
// apostrophe inside a double-quoted string is ordinary text.
|
|
75
|
+
if (char === "'") {
|
|
76
|
+
if (inDoubleQuote) {
|
|
77
|
+
columnNumber++;
|
|
78
|
+
index++;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
let end = index + 1;
|
|
82
|
+
while (end < length) {
|
|
83
|
+
if (text[end] === "'") {
|
|
84
|
+
if (text[end + 1] === "'") {
|
|
85
|
+
end += 2;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
end++;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
if (text[end] === '\n')
|
|
92
|
+
break;
|
|
93
|
+
end++;
|
|
94
|
+
}
|
|
95
|
+
advanceTo(end);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Double-quoted string - SAS resolves macro triggers inside it, so the
|
|
99
|
+
// scan continues until the closing quote.
|
|
100
|
+
if (char === '"') {
|
|
101
|
+
inDoubleQuote = !inDoubleQuote;
|
|
102
|
+
columnNumber++;
|
|
103
|
+
index++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (!inDoubleQuote) {
|
|
107
|
+
if (char === ';') {
|
|
108
|
+
atStatementStart = true;
|
|
109
|
+
columnNumber++;
|
|
110
|
+
index++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Block comment - /* ... */
|
|
114
|
+
if (char === '/' && text[index + 1] === '*') {
|
|
115
|
+
let end = index + 2;
|
|
116
|
+
while (end < length && !(text[end] === '*' && text[end + 1] === '/')) {
|
|
117
|
+
end++;
|
|
118
|
+
}
|
|
119
|
+
advanceTo(Math.min(end + 2, length));
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (char === '%') {
|
|
124
|
+
// Macro comment - %* ... ;
|
|
125
|
+
if (text[index + 1] === '*') {
|
|
126
|
+
let end = index + 2;
|
|
127
|
+
while (end < length && text[end] !== ';')
|
|
128
|
+
end++;
|
|
129
|
+
advanceTo(Math.min(end + 1, length));
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// Masking functions - the argument is data, not code. `%(` and `%)` are
|
|
133
|
+
// the escapes for literal parentheses inside the argument, so they do
|
|
134
|
+
// not affect the nesting depth.
|
|
135
|
+
const maskingFunction = maskingFunctionStart.exec(text.slice(index));
|
|
136
|
+
if (maskingFunction) {
|
|
137
|
+
let depth = 0;
|
|
138
|
+
let end = index + maskingFunction[0].length - 1;
|
|
139
|
+
while (end < length) {
|
|
140
|
+
if (text[end] === '%' &&
|
|
141
|
+
(text[end + 1] === '(' || text[end + 1] === ')')) {
|
|
142
|
+
end += 2;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (text[end] === '(')
|
|
146
|
+
depth++;
|
|
147
|
+
else if (text[end] === ')') {
|
|
148
|
+
depth--;
|
|
149
|
+
if (depth === 0) {
|
|
150
|
+
end++;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
end++;
|
|
155
|
+
}
|
|
156
|
+
advanceTo(end);
|
|
157
|
+
atStatementStart = false;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const macroName = macroNameStart.exec(text.slice(index));
|
|
161
|
+
if (macroName) {
|
|
162
|
+
// A macro statement label - `%label:` - is not an invocation.
|
|
163
|
+
if (text[index + macroName[0].length] !== ':') {
|
|
164
|
+
calls.push({
|
|
165
|
+
name: macroName[1],
|
|
166
|
+
lineNumber,
|
|
167
|
+
startColumnNumber: columnNumber,
|
|
168
|
+
endColumnNumber: columnNumber + 1 + macroName[1].length
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
advanceTo(index + macroName[0].length);
|
|
172
|
+
atStatementStart = false;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (atStatementStart && !inDoubleQuote) {
|
|
177
|
+
// A proc lua / proc groovy submit block holds another language, so its
|
|
178
|
+
// body is skipped. The block is only entered when an `endsubmit`
|
|
179
|
+
// statement closes it, so a stray `proc lua;` cannot swallow the rest
|
|
180
|
+
// of the file.
|
|
181
|
+
const embeddedProcStart = embeddedLanguageProc.exec(text.slice(index));
|
|
182
|
+
if (embeddedProcStart &&
|
|
183
|
+
embeddedLanguageEndSearch.test(text.slice(index))) {
|
|
184
|
+
const afterProc = index + embeddedProcStart[0].length;
|
|
185
|
+
const offset = text.slice(afterProc).search(embeddedLanguageEndSearch);
|
|
186
|
+
const endSubmit = embeddedLanguageEnd.exec(text.slice(afterProc + offset));
|
|
187
|
+
advanceTo(endSubmit ? afterProc + offset + endSubmit[0].length : length);
|
|
188
|
+
atStatementStart = true;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
// A data section - everything up to its terminating line is data, not
|
|
192
|
+
// code. The terminator is a line containing only the `;` or `;;;;`.
|
|
193
|
+
const dataSection = dataSectionStart.exec(text.slice(index));
|
|
194
|
+
if (dataSection) {
|
|
195
|
+
const terminator = /4/.test(dataSection[1]) ? ';;;;' : ';';
|
|
196
|
+
let lineStart = index + dataSection[0].length;
|
|
197
|
+
let end = length;
|
|
198
|
+
while (lineStart <= length) {
|
|
199
|
+
const lineEnd = text.indexOf('\n', lineStart);
|
|
200
|
+
const actualEnd = lineEnd === -1 ? length : lineEnd;
|
|
201
|
+
if (text.slice(lineStart, actualEnd).trim() === terminator) {
|
|
202
|
+
end = actualEnd;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
if (lineEnd === -1)
|
|
206
|
+
break;
|
|
207
|
+
lineStart = lineEnd + 1;
|
|
208
|
+
}
|
|
209
|
+
advanceTo(end);
|
|
210
|
+
atStatementStart = true;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
// A comment statement - its body is opaque up to the terminating `;`.
|
|
214
|
+
if (char === '*') {
|
|
215
|
+
let end = index + 1;
|
|
216
|
+
while (end < length && text[end] !== ';')
|
|
217
|
+
end++;
|
|
218
|
+
advanceTo(end + 1);
|
|
219
|
+
atStatementStart = true;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
atStatementStart = false;
|
|
224
|
+
columnNumber++;
|
|
225
|
+
index++;
|
|
226
|
+
}
|
|
227
|
+
return calls;
|
|
228
|
+
};
|
|
229
|
+
exports.parseMacroCalls = parseMacroCalls;
|
|
230
|
+
//# sourceMappingURL=parseMacroCalls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseMacroCalls.js","sourceRoot":"","sources":["../../src/utils/parseMacroCalls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The set of macro names that ship with SAS, lower-cased for comparison.
|
|
3
|
+
*
|
|
4
|
+
* The names are generated from the macroStatements and macroFunctions groups of
|
|
5
|
+
* `@sasjs/sas-language`, which owns the SAS language data - see
|
|
6
|
+
* `scripts/generate-macro-names.mjs`. A macro matching one of these names is
|
|
7
|
+
* treated as declared, so it is never reported by `noUndeclaredMacros` and
|
|
8
|
+
* never written to a file header by the formatter.
|
|
9
|
+
*/
|
|
10
|
+
export declare const sasMacros: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Reports whether a macro name is one of the macros that ship with SAS.
|
|
13
|
+
* @param {string} name - the macro name to test.
|
|
14
|
+
* @returns {boolean} true when the name belongs to a SAS-provided macro.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isSasMacro: (name: string) => boolean;
|