isml-linter 5.38.2 → 5.39.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 (34) hide show
  1. package/CHANGELOG.md +63 -33
  2. package/README.md +2 -1
  3. package/package.json +2 -2
  4. package/src/Constants.js +2 -2
  5. package/src/IsmlLinter.js +14 -0
  6. package/src/enums/{SfccTags.js → SfccTagContainer.js} +0 -0
  7. package/src/isml_tree/ContainerNode.js +1 -1
  8. package/src/isml_tree/IsmlNode.js +88 -83
  9. package/src/isml_tree/MaskUtils.js +2 -2
  10. package/src/isml_tree/ParseUtils.js +15 -13
  11. package/src/isml_tree/TreeBuilder.js +47 -18
  12. package/src/rules/prototypes/TreeRulePrototype.js +4 -8
  13. package/src/rules/tree/align-isset.js +2 -2
  14. package/src/rules/tree/contextual-attrs.js +4 -4
  15. package/src/rules/tree/custom-tags.js +6 -6
  16. package/src/rules/tree/disallow-tags.js +2 -2
  17. package/src/rules/tree/empty-eof.js +11 -11
  18. package/src/rules/tree/enforce-security.js +2 -2
  19. package/src/rules/tree/eslint-to-isscript.js +13 -12
  20. package/src/rules/tree/indent.js +73 -73
  21. package/src/rules/tree/leading-iscache.js +1 -1
  22. package/src/rules/tree/leading-iscontent.js +1 -1
  23. package/src/rules/tree/no-deprecated-attrs.js +4 -4
  24. package/src/rules/tree/no-embedded-isml.js +2 -2
  25. package/src/rules/tree/no-hardcode.js +6 -6
  26. package/src/rules/tree/no-iselse-slash.js +3 -3
  27. package/src/rules/tree/no-redundant-context.js +8 -8
  28. package/src/rules/tree/no-require-in-loop.js +8 -8
  29. package/src/rules/tree/one-element-per-line.js +3 -3
  30. package/src/util/ConsoleUtils.js +44 -2
  31. package/src/util/{CustomTagUtils.js → CustomTagContainer.js} +0 -0
  32. package/src/util/ExceptionUtils.js +27 -0
  33. package/src/util/RuleUtils.js +16 -6
  34. package/src/util/TempRuleUtils.js +4 -4
@@ -1,5 +1,5 @@
1
1
  const TreeRulePrototype = require('../prototypes/TreeRulePrototype');
2
- const SfccTags = require('../../enums/SfccTags');
2
+ const SfccTagContainer = require('../../enums/SfccTagContainer');
3
3
 
4
4
  const ruleId = require('path').basename(__filename).slice(0, -3);
5
5
  const description = 'Attribute label or value is deprecated';
@@ -15,7 +15,7 @@ Rule.isBroken = function(node) {
15
15
 
16
16
  const attrList = node.getAttributeList();
17
17
  const nodeType = node.getType();
18
- const obj = SfccTags[nodeType];
18
+ const obj = SfccTagContainer[nodeType];
19
19
  let result = null;
20
20
 
21
21
  if (node.isStandardIsmlTag()) {
@@ -48,9 +48,9 @@ Rule.check = function(node, data) {
48
48
  const occurrence = this.isBroken(node);
49
49
  if (occurrence) {
50
50
  const error = this.getError(
51
- node.value.trim(),
51
+ node.head.trim(),
52
52
  node.lineNumber,
53
- node.columnNumber + node.value.trim().indexOf(occurrence.fullContent),
53
+ node.columnNumber + node.head.trim().indexOf(occurrence.fullContent),
54
54
  occurrence.attrGlobalPos,
55
55
  occurrence.length,
56
56
  occurrence.message
@@ -10,8 +10,8 @@ Rule.init(ruleId, description);
10
10
  Rule.isBroken = function(node) {
11
11
  return node.isHtmlTag() &&
12
12
  !node.isOfType('is') &&
13
- node.value.indexOf('<isprint') === -1 &&
14
- node.value.indexOf('<is') >= 0;
13
+ node.head.indexOf('<isprint') === -1 &&
14
+ node.head.indexOf('<is') >= 0;
15
15
  };
16
16
 
17
17
  module.exports = Rule;
@@ -18,25 +18,25 @@ Rule.isBroken = function(node) {
18
18
  const ruleExceptionList = this.getConfigs().except;
19
19
  const allowHtmlEntities = this.getConfigs().allowHtmlEntities;
20
20
  const isTagContent = isTagChild(node);
21
- const shouldCheckValue = node.isOfType('text') && !node.isExpression() && !isTagContent;
22
- const isTextAnHtmlEntity = node.value.trim().startsWith('&') && node.value.trim().endsWith(';');
23
- let nodeValue = node.value;
21
+ const shouldCheckHead = node.isOfType('text') && !node.isExpression() && !isTagContent;
22
+ const isTextAnHtmlEntity = node.head.trim().startsWith('&') && node.head.trim().endsWith(';');
23
+ let nodeHead = node.head;
24
24
 
25
- if (!shouldCheckValue) {
25
+ if (!shouldCheckHead) {
26
26
  return false;
27
27
  }
28
28
 
29
29
  for (let i = 0; i < ruleExceptionList.length; i++) {
30
30
  const char = ruleExceptionList[i];
31
31
 
32
- nodeValue = nodeValue.split(char).join('');
32
+ nodeHead = nodeHead.split(char).join('');
33
33
  }
34
34
 
35
35
  if (allowHtmlEntities && isTextAnHtmlEntity) {
36
36
  return false;
37
37
  }
38
38
 
39
- return nodeValue.trim().length > 0;
39
+ return nodeHead.trim().length > 0;
40
40
  };
41
41
 
42
42
  const isTagChild = node => {
@@ -11,7 +11,7 @@ Rule.init(ruleId, description);
11
11
 
12
12
  Rule.isBroken = function(node) {
13
13
  return (node.isOfType('iselse') || node.isOfType('iselseif')) &&
14
- node.value.trim().endsWith('/>');
14
+ node.head.trim().endsWith('/>');
15
15
  };
16
16
 
17
17
  Rule.getFixedContent = function(node) {
@@ -19,10 +19,10 @@ Rule.getFixedContent = function(node) {
19
19
  const child = node.children[i];
20
20
 
21
21
  if (child.isOfType('iselse') || child.isOfType('iselseif')) {
22
- const slashPos = MaskUtils.maskInBetween(child.value, '${', '}').lastIndexOf('/');
22
+ const slashPos = MaskUtils.maskInBetween(child.head, '${', '}').lastIndexOf('/');
23
23
 
24
24
  if (slashPos >= 0) {
25
- child.value = child.value.slice(0, slashPos) + child.value.slice(slashPos + 1);
25
+ child.head = child.head.slice(0, slashPos) + child.head.slice(slashPos + 1);
26
26
  }
27
27
  }
28
28
 
@@ -67,7 +67,7 @@ Rule.isBroken = function (node) {
67
67
  for (let i = 0; i < disallowedOccurrenceContainer.length; i++) {
68
68
  const disallowedOccurrence = disallowedOccurrenceContainer[i];
69
69
 
70
- if (node.value.indexOf(disallowedOccurrence.key) >= 0) {
70
+ if (node.head.indexOf(disallowedOccurrence.key) >= 0) {
71
71
  return disallowedOccurrence;
72
72
  }
73
73
  }
@@ -82,9 +82,9 @@ Rule.check = function(node, data) {
82
82
  const disallowedOccurrence = this.isBroken(node);
83
83
 
84
84
  if (disallowedOccurrence) {
85
- const trimmedValue = node.value.trim();
86
- const startPos = trimmedValue.indexOf(disallowedOccurrence.key);
87
- const beforeStartPos = trimmedValue.substring(0, startPos);
85
+ const trimmedHead = node.head.trim();
86
+ const startPos = trimmedHead.indexOf(disallowedOccurrence.key);
87
+ const beforeStartPos = trimmedHead.substring(0, startPos);
88
88
  const lineOffset = ParseUtils.getLineBreakQty(beforeStartPos);
89
89
  let globalPos = node.globalPos + startPos;
90
90
  const message = getMessage(disallowedOccurrence);
@@ -94,9 +94,9 @@ Rule.check = function(node, data) {
94
94
  }
95
95
 
96
96
  const error = this.getError(
97
- node.value.trim(),
97
+ node.head.trim(),
98
98
  node.lineNumber,
99
- node.columnNumber + node.value.trim().indexOf(disallowedOccurrence.key) - 1,
99
+ node.columnNumber + node.head.trim().indexOf(disallowedOccurrence.key) - 1,
100
100
  globalPos,
101
101
  disallowedOccurrence.wrong.length,
102
102
  message
@@ -113,8 +113,8 @@ Rule.getFixedContent = function(node) {
113
113
  for (let i = 0; i < disallowedOccurrenceContainer.length; i++) {
114
114
  const disallowedOccurrence = disallowedOccurrenceContainer[i];
115
115
 
116
- if (node.value.indexOf(disallowedOccurrence.key) >= 0) {
117
- node.value = node.value
116
+ if (node.head.indexOf(disallowedOccurrence.key) >= 0) {
117
+ node.head = node.head
118
118
  .split(disallowedOccurrence.key)
119
119
  .join(disallowedOccurrence.correct);
120
120
  }
@@ -11,7 +11,7 @@ Rule.init(ruleId, description);
11
11
 
12
12
  Rule.isBroken = function(node) {
13
13
 
14
- if (node.value.indexOf('require(') === -1) {
14
+ if (node.head.indexOf('require(') === -1) {
15
15
  return false;
16
16
  }
17
17
 
@@ -34,11 +34,11 @@ Rule.check = function(node, data) {
34
34
  const occurrenceList = this.checkChildren(node, data);
35
35
 
36
36
  if (this.isBroken(node)) {
37
- const trimmedValue = node.value.trim();
38
- const startPos = trimmedValue.indexOf('require(');
39
- const beforeStartPos = trimmedValue.substring(0, startPos);
37
+ const trimmedHead = node.head.trim();
38
+ const startPos = trimmedHead.indexOf('require(');
39
+ const beforeStartPos = trimmedHead.substring(0, startPos);
40
40
  const lineOffset = ParseUtils.getLineBreakQty(beforeStartPos);
41
- const afterStartPos = trimmedValue.substring(startPos);
41
+ const afterStartPos = trimmedHead.substring(startPos);
42
42
  const length = afterStartPos.indexOf(')') + 1;
43
43
  let globalPos = node.globalPos + startPos;
44
44
 
@@ -47,9 +47,9 @@ Rule.check = function(node, data) {
47
47
  }
48
48
 
49
49
  const error = this.getError(
50
- node.value.trim(),
51
- node.lineNumber,
52
- node.columnNumber + node.value.trim().indexOf('require('),
50
+ node.head.trim(),
51
+ node.lineNumber + lineOffset,
52
+ node.columnNumber + node.head.trim().indexOf('require('),
53
53
  globalPos,
54
54
  length
55
55
  );
@@ -45,10 +45,10 @@ Rule.isBroken = function(node) {
45
45
  // const indentation = getCorrectIndentation(child);
46
46
  // const parentIndentation = getCorrectIndentation(node);
47
47
 
48
- // child.value = `${Constants.EOL}${indentation}${child.value}${Constants.EOL}${parentIndentation}`;
48
+ // child.head = `${Constants.EOL}${indentation}${child.head}${Constants.EOL}${parentIndentation}`;
49
49
 
50
- // if (child.suffixValue) {
51
- // child.setSuffix(`${Constants.EOL}${indentation}${child.suffixValue}${Constants.EOL}`);
50
+ // if (child.tail) {
51
+ // child.setTail(`${Constants.EOL}${indentation}${child.tail}${Constants.EOL}`);
52
52
  // }
53
53
  // }
54
54
 
@@ -68,6 +68,10 @@ const displayUnparseableErrors = lintResult => {
68
68
  console.log(chalk`{red.bold ${Constants.EOL}An Isml abstract syntax tree could not be built for the following templates:}`);
69
69
 
70
70
  for (let i = 0; i < lintResult[INVALID_TEMPLATE].length; i++) {
71
+ if (config.printPartialResults && i > MAX_LISTED_ERRORS) {
72
+ break;
73
+ }
74
+
71
75
  const error = lintResult[INVALID_TEMPLATE][i];
72
76
  console.log(chalk.gray(i) + ' ' + error.templatePath + ':' + error.lineNumber);
73
77
  console.log('\t' + chalk`{red.bold >> }` + `${error.message}${Constants.EOL}`);
@@ -79,6 +83,29 @@ const displayUnparseableErrors = lintResult => {
79
83
  return partialSum;
80
84
  };
81
85
 
86
+ const displayRuleErrors = lintResult => {
87
+
88
+ const RULE_ERROR = ExceptionUtils.types.RULE_ERROR;
89
+ const config = ConfigUtils.load();
90
+ let partialSum = 0;
91
+
92
+ if (lintResult[RULE_ERROR] && lintResult[RULE_ERROR].length > 0) {
93
+ console.log(chalk`{red.bold ${Constants.EOL}An unexpected error occurred while applying rules to the following templates:}`);
94
+
95
+ for (let i = 0; i < lintResult[RULE_ERROR].length; i++) {
96
+ if (config.printPartialResults && i > MAX_LISTED_ERRORS) {
97
+ break;
98
+ }
99
+
100
+ const error = lintResult[RULE_ERROR][i];
101
+ console.log(chalk.gray(i) + '\t' + error.ruleID + ' :\t' + error.templatePath);
102
+ partialSum++;
103
+ }
104
+ }
105
+
106
+ return partialSum;
107
+ };
108
+
82
109
  const displayUnknownErrors = lintResult => {
83
110
  const UNKNOWN_ERROR = ExceptionUtils.types.UNKNOWN_ERROR;
84
111
  let partialSum = 0;
@@ -103,6 +130,7 @@ const displayOccurrenceList = lintResult => {
103
130
 
104
131
  displayUnparseableErrors(lintResult);
105
132
  displayUnknownErrors(lintResult);
133
+ displayRuleErrors(lintResult);
106
134
 
107
135
  // TODO Add this 'config' as a global const;
108
136
  const config = ConfigUtils.load();
@@ -144,7 +172,7 @@ const displayOccurrenceList = lintResult => {
144
172
  }
145
173
 
146
174
  if (config.printPartialResults) {
147
- console.log(chalk`{bold Displaying the first ${MAX_LISTED_ERRORS} occurrenceList of each group.}` + Constants.EOL);
175
+ console.log(chalk`{bold Displaying the first ${MAX_LISTED_ERRORS} occurrences of each group.}` + Constants.EOL);
148
176
  }
149
177
  }
150
178
  };
@@ -275,11 +303,25 @@ const getInfoData = lintResult => {
275
303
  };
276
304
  };
277
305
 
306
+ const displayVerboseMessage = (message, depth = 0) => {
307
+ const config = ConfigUtils.load();
308
+ let indentation = '';
309
+
310
+ for (let i = 0; i < depth; i++) {
311
+ indentation += ' ';
312
+ }
313
+
314
+ if (config.verbose) {
315
+ console.log(indentation + message);
316
+ }
317
+ };
318
+
278
319
  module.exports = {
279
320
  displayOccurrenceList,
280
321
  displayConfigError,
281
322
  displayEslintConfigError,
282
323
  displayInvalidTemplatesPaths,
283
324
  displayInvalidCommandError,
284
- printExceptionMsg
325
+ printExceptionMsg,
326
+ displayVerboseMessage
285
327
  };
@@ -5,6 +5,7 @@ const types = {
5
5
  UNCLOSED_DEPRECATED_ISML_COMMENT : 'UNCLOSED_DEPRECATED_ISML_COMMENT',
6
6
  INVALID_TEMPLATE : 'INVALID_TEMPLATE',
7
7
  INVALID_CHARACTER : 'INVALID_CHARACTER',
8
+ RULE_ERROR : 'RULE_ERROR',
8
9
  NO_CONFIG : 'NO_CONFIG',
9
10
  };
10
11
 
@@ -20,6 +21,18 @@ const unbalancedElementError = (elementType, lineNumber, globalPos, length, temp
20
21
  };
21
22
  };
22
23
 
24
+ const ruleApplianceError = (rule, originalError, templatePath) => {
25
+ return {
26
+ message : `An error happened while applying rule "${rule.id}" to ${templatePath}`,
27
+ ruleID : rule.id,
28
+ originalError,
29
+ lineNumber : 0,
30
+ templatePath : templatePath,
31
+ isCustom : true,
32
+ type : types.RULE_ERROR
33
+ };
34
+ };
35
+
23
36
  const unexpectedClosingElementError = (elementType, lineNumber, globalPos, length, templatePath) => {
24
37
  return {
25
38
  message : `Unexpected </${elementType}> element`,
@@ -32,6 +45,18 @@ const unexpectedClosingElementError = (elementType, lineNumber, globalPos, lengt
32
45
  };
33
46
  };
34
47
 
48
+ const unbalancedQuotesError = (elementType, lineNumber, globalPos, length, templatePath) => {
49
+ return {
50
+ message : `Unbalanced quotes in <${elementType}> element`,
51
+ templatePath : templatePath,
52
+ globalPos,
53
+ length,
54
+ lineNumber : lineNumber,
55
+ isCustom : true,
56
+ type : types.INVALID_TEMPLATE
57
+ };
58
+ };
59
+
35
60
  const unclosedDeprecatedIsmlComment = (lineNumber, globalPos, length, templatePath) => {
36
61
  return {
37
62
  message : '"<!---" element not correctly closed: use "--->" instead of "-->"',
@@ -92,6 +117,8 @@ const isLinterException = e => e && e.isCustom;
92
117
 
93
118
  module.exports = {
94
119
  parseError,
120
+ unbalancedQuotesError,
121
+ ruleApplianceError,
95
122
  unclosedDeprecatedIsmlComment,
96
123
  unbalancedElementError,
97
124
  unexpectedClosingElementError,
@@ -4,9 +4,11 @@ const Constants = require('../Constants');
4
4
  const TreeBuilder = require('../isml_tree/TreeBuilder');
5
5
  const ConfigUtils = require('./ConfigUtils');
6
6
  const lowercaseFilenameRule = require('../rules/line_by_line/lowercase-filename');
7
- const customTagContainer = require('./CustomTagUtils');
7
+ const CustomTagContainer = require('./CustomTagContainer');
8
8
  const CustomModulesRule = require('../rules/tree/custom-tags');
9
9
  const GeneralUtils = require('./GeneralUtils');
10
+ const ConsoleUtils = require('./ConsoleUtils');
11
+ const ExceptionUtils = require('./ExceptionUtils');
10
12
 
11
13
  const lineByLineRules = [];
12
14
  const treeRules = [];
@@ -41,8 +43,8 @@ const getLevelGroup = level => {
41
43
  };
42
44
 
43
45
  const checkCustomTag = tag => {
44
- if (Object.prototype.hasOwnProperty.call(customTagContainer, tag)) {
45
- const attrList = customTagContainer[tag].attrList;
46
+ if (Object.prototype.hasOwnProperty.call(CustomTagContainer, tag)) {
47
+ const attrList = CustomTagContainer[tag].attrList;
46
48
 
47
49
  for (let i = 0; i < attrList.length; i++) {
48
50
  const attr = attrList[i];
@@ -88,8 +90,14 @@ const applyRuleOnTemplate = (ruleArray, templatePath, root, config, data) => {
88
90
  for (let i = 0; i < ruleArray.length; i++) {
89
91
  const rule = ruleArray[i];
90
92
  if (!rule.shouldIgnore(templatePath)) {
91
- const ruleResults = rule.check(root, templateResults.data);
92
- applyRuleResult(config, ruleResults, templatePath, templateResults, rule);
93
+ try {
94
+ ConsoleUtils.displayVerboseMessage(`Applying "${rule.id}" rule`, 1);
95
+ const ruleResults = rule.check(root, templateResults.data);
96
+ applyRuleResult(config, ruleResults, templatePath, templateResults, rule);
97
+
98
+ } catch (error) {
99
+ throw ExceptionUtils.ruleApplianceError(rule, error, templatePath);
100
+ }
93
101
  }
94
102
  }
95
103
 
@@ -163,6 +171,7 @@ const checkFileName = (filename, templateContent) => {
163
171
 
164
172
  const checkTreeRules = (templatePath, templateContent, config, data) => {
165
173
  if (!config.disableTreeParse) {
174
+ ConsoleUtils.displayVerboseMessage(`Building tree for "${templatePath}"`, 1);
166
175
  const tree = TreeBuilder.build(templatePath, templateContent);
167
176
 
168
177
  if (!tree.rootNode) {
@@ -200,7 +209,7 @@ const checkCustomModules = () => {
200
209
  };
201
210
 
202
211
  if (CustomModulesRule.isEnabled()) {
203
- for (const tag in customTagContainer) {
212
+ for (const tag in CustomTagContainer) {
204
213
  const occurrenceObj = checkCustomTag(tag);
205
214
 
206
215
  if (occurrenceObj) {
@@ -213,6 +222,7 @@ const checkCustomModules = () => {
213
222
  };
214
223
 
215
224
  const checkTemplate = (templatePath, data, content = '', templateName = '') => {
225
+ ConsoleUtils.displayVerboseMessage(`\nChecking "${templatePath}" template`);
216
226
  const config = ConfigUtils.load();
217
227
  const templateContent = GeneralUtils.toLF(content || fs.readFileSync(templatePath, 'utf-8'));
218
228
  const lineResults = checkLineByLineRules(templatePath, templateContent, config, data);
@@ -12,15 +12,15 @@ const Constants = require('../Constants');
12
12
  const TreeBuilder = require('../isml_tree/TreeBuilder');
13
13
  const ConfigUtils = require('./ConfigUtils');
14
14
  const lowercaseFilenameRule = require('../rules/line_by_line/lowercase-filename');
15
- const customTagContainer = require('./CustomTagUtils');
15
+ const CustomTagContainer = require('./CustomTagContainer');
16
16
  const CustomModulesRule = require('../rules/tree/custom-tags');
17
17
 
18
18
  const lineByLineRules = [];
19
19
  const treeRules = [];
20
20
 
21
21
  const checkCustomTag = tag => {
22
- if (Object.prototype.hasOwnProperty.call(customTagContainer, tag)) {
23
- const attrList = customTagContainer[tag].attrList;
22
+ if (Object.prototype.hasOwnProperty.call(CustomTagContainer, tag)) {
23
+ const attrList = CustomTagContainer[tag].attrList;
24
24
 
25
25
  for (let i = 0; i < attrList.length; i++) {
26
26
  const attr = attrList[i];
@@ -164,7 +164,7 @@ const checkCustomModules = () => {
164
164
  };
165
165
 
166
166
  if (CustomModulesRule.isEnabled()) {
167
- for (const tag in customTagContainer) {
167
+ for (const tag in CustomTagContainer) {
168
168
  const errorObj = checkCustomTag(tag);
169
169
 
170
170
  if (errorObj) {