@sasjs/lint 4.6.1 → 4.8.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.
Files changed (52) hide show
  1. package/README.md +30 -0
  2. package/package.json +1 -1
  3. package/rules/file/hasDoxygenHeader.js +1 -1
  4. package/rules/file/hasMacroNameInMend.js +22 -10
  5. package/rules/file/hasMacroNameInMend.js.map +1 -1
  6. package/rules/file/hasMacroParentheses.js +6 -3
  7. package/rules/file/hasMacroParentheses.js.map +1 -1
  8. package/rules/file/index.d.ts +1 -0
  9. package/rules/file/index.js +3 -1
  10. package/rules/file/index.js.map +1 -1
  11. package/rules/file/lineEndings.js +7 -5
  12. package/rules/file/lineEndings.js.map +1 -1
  13. package/rules/file/minMacroNameLength.js +2 -4
  14. package/rules/file/minMacroNameLength.js.map +1 -1
  15. package/rules/file/noMacroIfInOpenCode.d.ts +11 -0
  16. package/rules/file/noMacroIfInOpenCode.js +84 -0
  17. package/rules/file/noMacroIfInOpenCode.js.map +1 -0
  18. package/rules/file/noNestedCommentsInHeader.js +1 -1
  19. package/rules/file/noNestedMacros.js +2 -2
  20. package/rules/file/noNestedMacros.js.map +1 -1
  21. package/rules/file/noSingleAsteriskComments.js +1 -1
  22. package/rules/file/noSingleAsteriskComments.js.map +1 -1
  23. package/rules/file/strictMacroDefinition.js +121 -46
  24. package/rules/file/strictMacroDefinition.js.map +1 -1
  25. package/rules/line/noBannedStrings.js +1 -1
  26. package/rules/line/noBannedStrings.js.map +1 -1
  27. package/rules/line/noEncodedPasswords.js +1 -1
  28. package/rules/line/noEncodedPasswords.js.map +1 -1
  29. package/rules/line/noGremlins.js +1 -1
  30. package/rules/line/noGremlins.js.map +1 -1
  31. package/rules/line/noTabs.js +1 -1
  32. package/sasjslint-schema.json +17 -0
  33. package/types/Diagnostic.d.ts +5 -0
  34. package/types/LintConfig.js +6 -0
  35. package/types/LintConfig.js.map +1 -1
  36. package/utils/escapeRegExp.d.ts +2 -0
  37. package/utils/escapeRegExp.js +7 -0
  38. package/utils/escapeRegExp.js.map +1 -0
  39. package/utils/getColumnNumber.d.ts +14 -1
  40. package/utils/getColumnNumber.js +20 -3
  41. package/utils/getColumnNumber.js.map +1 -1
  42. package/utils/getLintConfig.d.ts +1 -0
  43. package/utils/getLintConfig.js +1 -0
  44. package/utils/getLintConfig.js.map +1 -1
  45. package/utils/index.d.ts +1 -0
  46. package/utils/index.js +1 -0
  47. package/utils/index.js.map +1 -1
  48. package/utils/parseMacros.js +45 -20
  49. package/utils/parseMacros.js.map +1 -1
  50. package/utils/trimComments.d.ts +21 -1
  51. package/utils/trimComments.js +52 -30
  52. package/utils/trimComments.js.map +1 -1
@@ -3,10 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMacros = void 0;
4
4
  const trimComments_1 = require("./trimComments");
5
5
  const splitLines_1 = require("./splitLines");
6
+ /** The `%macro` statement, in any capitalisation. */
7
+ const macroStatement = /^%macro\b/i;
8
+ /** The `%mend` statement, in any capitalisation. */
9
+ const mendStatement = /^%mend\b/i;
10
+ /**
11
+ * The name in a `%macro` declaration, as written.
12
+ *
13
+ * The name runs to the first character that cannot belong to it: whitespace, an
14
+ * opening parenthesis, the `/` that introduces the options, or an end of
15
+ * statement. Reading it by pattern rather than from a fixed offset is what makes
16
+ * `%MACRO`, `%macro s` and `%macro\ts` yield the same name - the keyword and the
17
+ * whitespace before the name can each be a different length.
18
+ */
19
+ const declarationName = /^%macro\b\s*([^\s(;/]*)/i;
20
+ /** The name in a `%mend` statement, as written. */
21
+ const mendName = /^%mend\b\s*([^\s;]*)/i;
22
+ /** The name a macro statement carries, or an empty string when it has none. */
23
+ const getName = (statement, pattern) => {
24
+ const match = pattern.exec(statement);
25
+ return match ? match[1].trim() : '';
26
+ };
6
27
  const parseMacros = (text, config) => {
7
28
  const lines = (0, splitLines_1.splitLines)(text);
8
29
  const macros = [];
9
30
  let isCommentStarted = false;
31
+ let isQuoteStarted = '';
10
32
  let macroStack = [];
11
33
  let isReadingMacroDefinition = false;
12
34
  let isStatementContinues = true;
@@ -14,8 +36,14 @@ const parseMacros = (text, config) => {
14
36
  let tempMacroDeclarationLines = [];
15
37
  let tempStartLineNumbers = [];
16
38
  lines.forEach((line, lineIndex) => {
17
- const { statement: trimmedLine, commentStarted } = (0, trimComments_1.trimComments)(line, isCommentStarted);
18
- isCommentStarted = commentStarted;
39
+ // The state a line STARTS in belongs to the line's statements, and the state
40
+ // it ENDS in belongs to the next line. Reading the second into the statement
41
+ // loop swallowed the code that precedes a comment opening mid-line
42
+ // (sasjs/lint#274).
43
+ const stateBeforeLine = isCommentStarted;
44
+ const { statement: trimmedLine, commentStarted: stateAfterLine, quoteStarted: quoteAfterLine } = (0, trimComments_1.trimComments)(line, stateBeforeLine, false, isQuoteStarted);
45
+ isCommentStarted = stateAfterLine;
46
+ isQuoteStarted = quoteAfterLine;
19
47
  isStatementContinues = !trimmedLine.endsWith(';');
20
48
  const statements = trimmedLine.split(';');
21
49
  if (isReadingMacroDefinition) {
@@ -31,8 +59,11 @@ const parseMacros = (text, config) => {
31
59
  });
32
60
  }
33
61
  statements.forEach((statement, statementIndex) => {
34
- const { statement: trimmedStatement, commentStarted } = (0, trimComments_1.trimComments)(statement, isCommentStarted);
35
- isCommentStarted = commentStarted;
62
+ // The statements were split from the line's ALREADY trimmed text, so they
63
+ // carry no comment and no quoted value: trimming them again either swallowed
64
+ // the code after a comment that closes at the start of the line (`... */
65
+ // %macro foo;`) or re-read a `/*` inside a multi-line string as a comment.
66
+ const trimmedStatement = statement.trim();
36
67
  if (isReadingMacroDefinition) {
37
68
  tempMacroDeclaration =
38
69
  tempMacroDeclaration +
@@ -41,12 +72,7 @@ const parseMacros = (text, config) => {
41
72
  tempStartLineNumbers.push(lineIndex + 1);
42
73
  if (!Object.is(statements.length - 1, statementIndex)) {
43
74
  isReadingMacroDefinition = false;
44
- const name = tempMacroDeclaration
45
- .slice(7, tempMacroDeclaration.length)
46
- .trim()
47
- .split('/')[0]
48
- .split('(')[0]
49
- .trim();
75
+ const name = getName(tempMacroDeclaration, declarationName);
50
76
  macroStack.push({
51
77
  name,
52
78
  startLineNumbers: tempStartLineNumbers,
@@ -63,7 +89,7 @@ const parseMacros = (text, config) => {
63
89
  });
64
90
  }
65
91
  }
66
- if (trimmedStatement.startsWith('%macro')) {
92
+ if (macroStatement.test(trimmedStatement)) {
67
93
  const startLineNumber = lineIndex + 1;
68
94
  if (isStatementContinues &&
69
95
  Object.is(statements.length - 1, statementIndex)) {
@@ -73,12 +99,7 @@ const parseMacros = (text, config) => {
73
99
  isReadingMacroDefinition = true;
74
100
  return;
75
101
  }
76
- const name = trimmedStatement
77
- .slice(7, trimmedStatement.length)
78
- .trim()
79
- .split('/')[0]
80
- .split('(')[0]
81
- .trim();
102
+ const name = getName(trimmedStatement, declarationName);
82
103
  macroStack.push({
83
104
  name,
84
105
  startLineNumbers: [startLineNumber],
@@ -94,12 +115,16 @@ const parseMacros = (text, config) => {
94
115
  termination: ''
95
116
  });
96
117
  }
97
- else if (trimmedStatement.startsWith('%mend')) {
118
+ else if (mendStatement.test(trimmedStatement)) {
98
119
  if (macroStack.length) {
99
120
  const macro = macroStack.pop();
100
- const mendMacroName = trimmedStatement.split(' ').filter((s) => !!s)[1] || '';
121
+ const mendMacroName = getName(trimmedStatement, mendName);
101
122
  macro.endLineNumber = lineIndex + 1;
102
- macro.hasMacroNameInMend = mendMacroName === macro.name;
123
+ // SAS matches a macro name without regard to case, so `%mend s` closes
124
+ // `%macro S()`. The name is kept as written for the rules that point at
125
+ // it, and only the comparison folds the case.
126
+ macro.hasMacroNameInMend =
127
+ mendMacroName.toLowerCase() === macro.name.toLowerCase();
103
128
  macro.mismatchedMendMacroName = macro.hasMacroNameInMend
104
129
  ? ''
105
130
  : mendMacroName;
@@ -1 +1 @@
1
- {"version":3,"file":"parseMacros.js","sourceRoot":"","sources":["../../src/utils/parseMacros.ts"],"names":[],"mappings":";;;AACA,iDAA6C;AAC7C,6CAAyC;AAElC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,MAAmB,EAAW,EAAE;IACxE,MAAM,KAAK,GAAG,IAAA,uBAAU,EAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAA;IAE1B,IAAI,gBAAgB,GAAG,KAAK,CAAA;IAC5B,IAAI,UAAU,GAAY,EAAE,CAAA;IAC5B,IAAI,wBAAwB,GAAG,KAAK,CAAA;IACpC,IAAI,oBAAoB,GAAG,IAAI,CAAA;IAC/B,IAAI,oBAAoB,GAAG,EAAE,CAAA;IAC7B,IAAI,yBAAyB,GAAa,EAAE,CAAA;IAC5C,IAAI,oBAAoB,GAAa,EAAE,CAAA;IACvC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QAChC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,IAAA,2BAAY,EAC7D,IAAI,EACJ,gBAAgB,CACjB,CAAA;QACD,gBAAgB,GAAG,cAAc,CAAA;QAEjC,oBAAoB,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEjD,MAAM,UAAU,GAAa,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEnD,IAAI,wBAAwB,EAAE,CAAC;YAC7B,6FAA6F;YAC7F,iDAAiD;YACjD,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE;gBAC/C,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;oBACnC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,CAAC,CAAA;oBACvC,MAAM,gBAAgB,GAAG,GAAG,SAAS,IACnC,UAAU,CAAC,cAAc,GAAG,CAAC,CAC/B,EAAE,CAAA;oBACF,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAA;oBACtD,UAAU,CAAC,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;gBAC1C,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE;YAC/C,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,GAAG,IAAA,2BAAY,EAClE,SAAS,EACT,gBAAgB,CACjB,CAAA;YACD,gBAAgB,GAAG,cAAc,CAAA;YAEjC,IAAI,wBAAwB,EAAE,CAAC;gBAC7B,oBAAoB;oBAClB,oBAAoB;wBACpB,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;gBAClD,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACpC,oBAAoB,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;gBAExC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC;oBACtD,wBAAwB,GAAG,KAAK,CAAA;oBAEhC,MAAM,IAAI,GAAG,oBAAoB;yBAC9B,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC;yBACrC,IAAI,EAAE;yBACN,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;yBACb,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;yBACb,IAAI,EAAE,CAAA;oBACT,UAAU,CAAC,IAAI,CAAC;wBACd,IAAI;wBACJ,gBAAgB,EAAE,oBAAoB;wBACtC,aAAa,EAAE,IAAI;wBACnB,WAAW,EAAE,UAAU,CAAC,MAAM;4BAC5B,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI;4BACxC,CAAC,CAAC,EAAE;wBACN,kBAAkB,EAAE,KAAK;wBACzB,uBAAuB,EAAE,EAAE;wBAC3B,gBAAgB,EAAE,yBAAyB;wBAC3C,eAAe,EAAE,EAAE;wBACnB,WAAW,EAAE,oBAAoB;wBACjC,WAAW,EAAE,EAAE;qBAChB,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,gBAAgB,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1C,MAAM,eAAe,GAAG,SAAS,GAAG,CAAC,CAAA;gBAErC,IACE,oBAAoB;oBACpB,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,cAAc,CAAC,EAChD,CAAC;oBACD,oBAAoB,GAAG,gBAAgB,CAAA;oBACvC,yBAAyB,GAAG,CAAC,IAAI,CAAC,CAAA;oBAClC,oBAAoB,GAAG,CAAC,eAAe,CAAC,CAAA;oBACxC,wBAAwB,GAAG,IAAI,CAAA;oBAC/B,OAAM;gBACR,CAAC;gBAED,MAAM,IAAI,GAAG,gBAAgB;qBAC1B,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC;qBACjC,IAAI,EAAE;qBACN,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;qBACb,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;qBACb,IAAI,EAAE,CAAA;gBACT,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI;oBACJ,gBAAgB,EAAE,CAAC,eAAe,CAAC;oBACnC,aAAa,EAAE,IAAI;oBACnB,WAAW,EAAE,UAAU,CAAC,MAAM;wBAC5B,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI;wBACxC,CAAC,CAAC,EAAE;oBACN,kBAAkB,EAAE,KAAK;oBACzB,uBAAuB,EAAE,EAAE;oBAC3B,gBAAgB,EAAE,CAAC,IAAI,CAAC;oBACxB,eAAe,EAAE,EAAE;oBACnB,WAAW,EAAE,gBAAgB;oBAC7B,WAAW,EAAE,EAAE;iBAChB,CAAC,CAAA;YACJ,CAAC;iBAAM,IAAI,gBAAgB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;oBACtB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAW,CAAA;oBACvC,MAAM,aAAa,GACjB,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;oBACjE,KAAK,CAAC,aAAa,GAAG,SAAS,GAAG,CAAC,CAAA;oBACnC,KAAK,CAAC,kBAAkB,GAAG,aAAa,KAAK,KAAK,CAAC,IAAI,CAAA;oBACvD,KAAK,CAAC,uBAAuB,GAAG,KAAK,CAAC,kBAAkB;wBACtD,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,aAAa,CAAA;oBACjB,KAAK,CAAC,eAAe,GAAG,IAAI,CAAA;oBAC5B,KAAK,CAAC,WAAW,GAAG,gBAAgB,CAAA;oBACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACpB,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,EAAE;wBACR,gBAAgB,EAAE,EAAE;wBACpB,aAAa,EAAE,SAAS,GAAG,CAAC;wBAC5B,WAAW,EAAE,EAAE;wBACf,kBAAkB,EAAE,KAAK;wBACzB,uBAAuB,EAAE,EAAE;wBAC3B,gBAAgB,EAAE,EAAE;wBACpB,eAAe,EAAE,IAAI;wBACrB,WAAW,EAAE,EAAE;wBACf,WAAW,EAAE,gBAAgB;qBAC9B,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAA;IAE1B,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAjJY,QAAA,WAAW,eAiJvB"}
1
+ {"version":3,"file":"parseMacros.js","sourceRoot":"","sources":["../../src/utils/parseMacros.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,24 @@
1
- export declare const trimComments: (statement: string, commentStarted?: boolean, trimEnd?: boolean) => {
1
+ /**
2
+ * Removes the block comments from a statement, or from one line of a statement.
3
+ *
4
+ * The scan tracks two states the previous implementation did not:
5
+ *
6
+ * - a quoted value, because SAS accepts both quote characters, so an opening
7
+ * comment marker inside a string is data rather than the start of a comment;
8
+ * - a comment that is still open at the end of the text, which is reported back
9
+ * as `commentStarted` so the caller carries it into the next line. The old
10
+ * implementation lost that state when the opening marker had no closing
11
+ * delimiter on the same line, and returned the comment's content as code
12
+ * (sasjs/lint#274).
13
+ *
14
+ * A quoted value is carried across lines too (`quoteStarted`), because a SAS
15
+ * literal really does continue onto the next physical line: measured on a live
16
+ * engine, `x = "ab` / `cd";` is one string and `length(x)` is 4. An UNTERMINATED
17
+ * quote is carried as far as the text goes, which is also what the engine does -
18
+ * it consumes the rest of the file as string content.
19
+ */
20
+ export declare const trimComments: (statement: string, commentStarted?: boolean, trimEnd?: boolean, quoteStarted?: string) => {
2
21
  statement: string;
3
22
  commentStarted: boolean;
23
+ quoteStarted: string;
4
24
  };
@@ -1,40 +1,62 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.trimComments = void 0;
4
- const trimComments = (statement, commentStarted = false, trimEnd = false) => {
5
- let trimmed = trimEnd ? (statement || '').trimEnd() : (statement || '').trim();
6
- if (commentStarted || trimmed.startsWith('/*')) {
7
- const parts = trimmed.startsWith('/*')
8
- ? trimmed.slice(2).split('*/')
9
- : trimmed.split('*/');
10
- if (parts.length === 2) {
11
- return {
12
- statement: parts.pop().trim(),
13
- commentStarted: false
14
- };
4
+ /**
5
+ * Removes the block comments from a statement, or from one line of a statement.
6
+ *
7
+ * The scan tracks two states the previous implementation did not:
8
+ *
9
+ * - a quoted value, because SAS accepts both quote characters, so an opening
10
+ * comment marker inside a string is data rather than the start of a comment;
11
+ * - a comment that is still open at the end of the text, which is reported back
12
+ * as `commentStarted` so the caller carries it into the next line. The old
13
+ * implementation lost that state when the opening marker had no closing
14
+ * delimiter on the same line, and returned the comment's content as code
15
+ * (sasjs/lint#274).
16
+ *
17
+ * A quoted value is carried across lines too (`quoteStarted`), because a SAS
18
+ * literal really does continue onto the next physical line: measured on a live
19
+ * engine, `x = "ab` / `cd";` is one string and `length(x)` is 4. An UNTERMINATED
20
+ * quote is carried as far as the text goes, which is also what the engine does -
21
+ * it consumes the rest of the file as string content.
22
+ */
23
+ const trimComments = (statement, commentStarted = false, trimEnd = false, quoteStarted = '') => {
24
+ const text = statement || '';
25
+ let result = '';
26
+ let quote = quoteStarted;
27
+ let inComment = commentStarted;
28
+ for (let index = 0; index < text.length; index++) {
29
+ const character = text[index];
30
+ if (inComment) {
31
+ if (character === '*' && text[index + 1] === '/') {
32
+ inComment = false;
33
+ index++;
34
+ }
35
+ continue;
15
36
  }
16
- else if (parts.length > 2) {
17
- parts.shift();
18
- return (0, exports.trimComments)(parts.join('*/'), false);
37
+ if (quote) {
38
+ result += character;
39
+ if (character === quote)
40
+ quote = '';
41
+ continue;
19
42
  }
20
- else {
21
- return { statement: '', commentStarted: true };
43
+ if (character === "'" || character === '"') {
44
+ quote = character;
45
+ result += character;
46
+ continue;
22
47
  }
48
+ if (character === '/' && text[index + 1] === '*') {
49
+ inComment = true;
50
+ index++;
51
+ continue;
52
+ }
53
+ result += character;
23
54
  }
24
- else if (trimmed.includes('/*')) {
25
- const statementBeforeCommentStarts = trimmed.slice(0, trimmed.indexOf('/*'));
26
- trimmed = trimmed.slice(trimmed.indexOf('/*') + 2);
27
- const remainingStatement = trimmed.slice(trimmed.indexOf('*/') + 2);
28
- const result = (0, exports.trimComments)(remainingStatement, false, true);
29
- const completeStatement = statementBeforeCommentStarts + result.statement;
30
- return {
31
- statement: trimEnd
32
- ? completeStatement.trimEnd()
33
- : completeStatement.trim(),
34
- commentStarted: result.commentStarted
35
- };
36
- }
37
- return { statement: trimmed, commentStarted: false };
55
+ return {
56
+ statement: trimEnd ? result.trimEnd() : result.trim(),
57
+ commentStarted: inComment,
58
+ quoteStarted: quote
59
+ };
38
60
  };
39
61
  exports.trimComments = trimComments;
40
62
  //# sourceMappingURL=trimComments.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trimComments.js","sourceRoot":"","sources":["../../src/utils/trimComments.ts"],"names":[],"mappings":";;;AAAO,MAAM,YAAY,GAAG,CAC1B,SAAiB,EACjB,iBAA0B,KAAK,EAC/B,UAAmB,KAAK,EACwB,EAAE;IAClD,IAAI,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IAE9E,IAAI,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YACpC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YAC9B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;gBACL,SAAS,EAAG,KAAK,CAAC,GAAG,EAAa,CAAC,IAAI,EAAE;gBACzC,cAAc,EAAE,KAAK;aACtB,CAAA;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,OAAO,IAAA,oBAAY,EAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAA;QAC9C,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;QAChD,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,4BAA4B,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5E,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAClD,MAAM,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAEnE,MAAM,MAAM,GAAG,IAAA,oBAAY,EAAC,kBAAkB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QAC5D,MAAM,iBAAiB,GAAG,4BAA4B,GAAG,MAAM,CAAC,SAAS,CAAA;QACzE,OAAO;YACL,SAAS,EAAE,OAAO;gBAChB,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE;gBAC7B,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE;YAC5B,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAA;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,CAAA;AACtD,CAAC,CAAA;AArCY,QAAA,YAAY,gBAqCxB"}
1
+ {"version":3,"file":"trimComments.js","sourceRoot":"","sources":["../../src/utils/trimComments.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACI,MAAM,YAAY,GAAG,CAC1B,SAAiB,EACjB,iBAA0B,KAAK,EAC/B,UAAmB,KAAK,EACxB,eAAuB,EAAE,EAC6C,EAAE;IACxE,MAAM,IAAI,GAAG,SAAS,IAAI,EAAE,CAAA;IAC5B,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,KAAK,GAAG,YAAY,CAAA;IACxB,IAAI,SAAS,GAAG,cAAc,CAAA;IAE9B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAE7B,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,SAAS,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACjD,SAAS,GAAG,KAAK,CAAA;gBACjB,KAAK,EAAE,CAAA;YACT,CAAC;YAED,SAAQ;QACV,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,SAAS,CAAA;YACnB,IAAI,SAAS,KAAK,KAAK;gBAAE,KAAK,GAAG,EAAE,CAAA;YACnC,SAAQ;QACV,CAAC;QAED,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YAC3C,KAAK,GAAG,SAAS,CAAA;YACjB,MAAM,IAAI,SAAS,CAAA;YACnB,SAAQ;QACV,CAAC;QAED,IAAI,SAAS,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjD,SAAS,GAAG,IAAI,CAAA;YAChB,KAAK,EAAE,CAAA;YACP,SAAQ;QACV,CAAC;QAED,MAAM,IAAI,SAAS,CAAA;IACrB,CAAC;IAED,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;QACrD,cAAc,EAAE,SAAS;QACzB,YAAY,EAAE,KAAK;KACpB,CAAA;AACH,CAAC,CAAA;AAjDY,QAAA,YAAY,gBAiDxB"}