@sasjs/lint 2.7.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.
@@ -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
@@ -8,3 +8,6 @@ export * from './splitText';
8
8
  export * from './getIndicesOf';
9
9
  export * from './getHeaderLinesCount';
10
10
  export * from './getDataSectionsDetail';
11
+ export * from './headerMacros';
12
+ export * from './parseMacroCalls';
13
+ export * from './sasMacros';
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
@@ -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;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The macro names that ship with SAS, lower-cased and without the leading
3
+ * `%`, as published in the macroStatements and macroFunctions groups of
4
+ * `@sasjs/sas-language`.
5
+ */
6
+ export declare const sasMacros: readonly string[];