checkExamples.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _lodash = _interopRequireDefault(require("lodash"));
  7. var _eslint = require("eslint");
  8. var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc"));
  9. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  10. function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
  11. function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
  12. function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
  13. function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
  14. function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
  15. function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
  16. function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
  17. function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
  18. var zeroBasedLineIndexAdjust = -1;
  19. var likelyNestedJSDocIndentSpace = 1;
  20. var preTagSpaceLength = 1;
  21. var hasCaptionRegex = /^\s*<caption>.*?<\/caption>/;
  22. var escapeStringRegexp = function escapeStringRegexp(str) {
  23. return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  24. };
  25. var countChars = function countChars(str, ch) {
  26. return (str.match(new RegExp(escapeStringRegexp(ch), 'g')) || []).length;
  27. };
  28. var _default = (0, _iterateJsdoc.default)(function (_ref) {
  29. var jsdoc = _ref.jsdoc,
  30. report = _ref.report,
  31. utils = _ref.utils;
  32. var exampleCodeRegex = utils.getExampleCodeRegex();
  33. var rejectExampleCodeRegex = utils.getRejectExampleCodeRegex();
  34. var noDefaultExampleRules = utils.hasNoDefaultExampleRules();
  35. var eslintrcForExamples = utils.useEslintrcForExamples();
  36. var filename = utils.getMatchingFileName();
  37. var baseConfig = utils.getBaseConfig();
  38. var configFile = utils.getConfigFile();
  39. var allowInlineConfig = utils.allowInlineConfig();
  40. var reportUnusedDisableDirectives = utils.reportUnusedDisableDirectives(); // Make this configurable?
  41. var rulePaths = [];
  42. var rules = noDefaultExampleRules ? undefined : {
  43. // "always" newline rule at end unlikely in sample code
  44. 'eol-last': 0,
  45. // Wouldn't generally expect example paths to resolve relative to JS file
  46. 'import/no-unresolved': 0,
  47. // Snippets likely too short to always include import/export info
  48. 'import/unambiguous': 0,
  49. // Unlikely to have inadvertent debugging within examples
  50. 'no-console': 0,
  51. // Many variables in examples will be `undefined`
  52. 'no-undef': 0,
  53. // Common to define variables for clarity without always using them
  54. 'no-unused-vars': 0,
  55. // See import/no-unresolved
  56. 'node/no-missing-import': 0,
  57. 'node/no-missing-require': 0,
  58. // Can generally look nicer to pad a little even if code imposes more stringency
  59. 'padded-blocks': 0
  60. };
  61. exampleCodeRegex = exampleCodeRegex && new RegExp(exampleCodeRegex, '');
  62. rejectExampleCodeRegex = rejectExampleCodeRegex && new RegExp(rejectExampleCodeRegex, '');
  63. _lodash.default.forEach(jsdoc.tags, function (tag) {
  64. if (tag.tag !== 'example') {
  65. return;
  66. } // If a space is present, we should ignore it
  67. var initialTag = tag.source.match(/^@example ?/);
  68. var initialTagLength = initialTag[0].length;
  69. var firstLinePrefixLength = preTagSpaceLength + initialTagLength;
  70. var source = tag.source.slice(initialTagLength);
  71. var match = source.match(hasCaptionRegex);
  72. if (utils.isCaptionRequired() && !match) {
  73. report('Caption is expected for examples.', null, tag);
  74. } // If we allow newlines in hasCaptionRegex, we should add to line count
  75. source = source.replace(hasCaptionRegex, '');
  76. if (exampleCodeRegex && !exampleCodeRegex.test(source) || rejectExampleCodeRegex && rejectExampleCodeRegex.test(source)) {
  77. return;
  78. }
  79. var nonJSPrefacingLines = 0;
  80. var nonJSPrefacingCols = 0;
  81. if (exampleCodeRegex) {
  82. var idx = source.search(exampleCodeRegex); // Strip out anything preceding user regex match (can affect line numbering)
  83. var preMatchLines = 0;
  84. var preMatch = source.slice(0, idx);
  85. preMatchLines = countChars(preMatch, '\n');
  86. nonJSPrefacingLines = preMatchLines;
  87. var colDelta = preMatchLines ? preMatch.slice(preMatch.lastIndexOf('\n') + 1).length - initialTagLength : preMatch.length; // Get rid of text preceding user regex match (even if it leaves valid JS, it
  88. // could cause us to count newlines twice)
  89. source = source.slice(idx);
  90. source = source.replace(exampleCodeRegex, function (n0, n1) {
  91. if (!n1) {
  92. return n0;
  93. }
  94. var index = n0.indexOf(n1);
  95. var nonJSPreface = n0.slice(0, index);
  96. var nonJSPrefaceLineCount = countChars(nonJSPreface, '\n');
  97. nonJSPrefacingLines += nonJSPrefaceLineCount; // Ignore `preMatch` delta if newlines here
  98. if (nonJSPrefaceLineCount) {
  99. var charsInLastLine = nonJSPreface.slice(nonJSPreface.lastIndexOf('\n') + 1).length;
  100. nonJSPrefacingCols += charsInLastLine - initialTagLength;
  101. } else {
  102. nonJSPrefacingCols += colDelta + nonJSPreface.length;
  103. }
  104. return n1;
  105. });
  106. } // Programmatic ESLint API: https://eslint.org/docs/developer-guide/nodejs-api
  107. var cli = new _eslint.CLIEngine({
  108. allowInlineConfig,
  109. baseConfig,
  110. configFile,
  111. reportUnusedDisableDirectives,
  112. rulePaths,
  113. rules,
  114. useEslintrc: eslintrcForExamples
  115. });
  116. var messages;
  117. if (filename) {
  118. var config = cli.getConfigForFile(filename);
  119. var linter = new _eslint.Linter();
  120. var linterRules = _toConsumableArray(cli.getRules().entries()).reduce(function (obj, _ref2) {
  121. var _ref3 = _slicedToArray(_ref2, 2),
  122. key = _ref3[0],
  123. val = _ref3[1];
  124. obj[key] = val;
  125. return obj;
  126. }, {});
  127. linter.defineRules(linterRules);
  128. messages = linter.verify(source, config, {
  129. filename,
  130. reportUnusedDisableDirectives
  131. });
  132. } else {
  133. var _cli$executeOnText = cli.executeOnText(source);
  134. var _cli$executeOnText$re = _slicedToArray(_cli$executeOnText.results, 1);
  135. messages = _cli$executeOnText$re[0].messages;
  136. } // NOTE: `tag.line` can be 0 if of form `/** @tag ... */`
  137. var codeStartLine = tag.line + nonJSPrefacingLines;
  138. var codeStartCol = likelyNestedJSDocIndentSpace;
  139. messages.forEach(function (_ref4) {
  140. var message = _ref4.message,
  141. line = _ref4.line,
  142. column = _ref4.column,
  143. severity = _ref4.severity,
  144. ruleId = _ref4.ruleId;
  145. var startLine = codeStartLine + line + zeroBasedLineIndexAdjust;
  146. var startCol = codeStartCol + ( // This might not work for line 0, but line 0 is unlikely for examples
  147. line <= 1 ? nonJSPrefacingCols + firstLinePrefixLength : preTagSpaceLength) + column; // Could perhaps make fixable
  148. report('@example ' + (severity === 2 ? 'error' : 'warning') + (ruleId ? ' (' + ruleId + ')' : '') + ': ' + message, null, {
  149. column: startCol,
  150. line: startLine
  151. });
  152. });
  153. });
  154. });
  155. exports.default = _default;
  156. module.exports = exports.default;
  157. //# sourceMappingURL=checkExamples.js.map