rule.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. 'use strict';
  2. const path = require('path');
  3. const fs = require('fs');
  4. const getDocumentationUrl = require('./get-documentation-url.js');
  5. const isIterable = object => typeof object[Symbol.iterator] === 'function';
  6. function reportListenerProblems(listener, context) {
  7. // Listener arguments can be `codePath, node` or `node`
  8. return function (...listenerArguments) {
  9. let problems = listener(...listenerArguments);
  10. if (!problems) {
  11. return;
  12. }
  13. if (!isIterable(problems)) {
  14. problems = [problems];
  15. }
  16. // TODO: Allow `fix` function to abort
  17. for (const problem of problems) {
  18. if (problem) {
  19. context.report(problem);
  20. }
  21. }
  22. };
  23. }
  24. // `checkVueTemplate` function will wrap `create` function, there is no need to wrap twice
  25. const wrappedFunctions = new Set();
  26. function reportProblems(create) {
  27. if (wrappedFunctions.has(create)) {
  28. return create;
  29. }
  30. const wrapped = context => Object.fromEntries(
  31. Object.entries(create(context))
  32. .map(([selector, listener]) => [selector, reportListenerProblems(listener, context)]),
  33. );
  34. wrappedFunctions.add(wrapped);
  35. return wrapped;
  36. }
  37. function checkVueTemplate(create, options) {
  38. const {
  39. visitScriptBlock,
  40. } = {
  41. visitScriptBlock: true,
  42. ...options,
  43. };
  44. create = reportProblems(create);
  45. const wrapped = context => {
  46. const listeners = create(context);
  47. // `vue-eslint-parser`
  48. if (
  49. context.parserServices
  50. && context.parserServices.defineTemplateBodyVisitor
  51. ) {
  52. return visitScriptBlock
  53. ? context.parserServices.defineTemplateBodyVisitor(listeners, listeners)
  54. : context.parserServices.defineTemplateBodyVisitor(listeners);
  55. }
  56. return listeners;
  57. };
  58. wrappedFunctions.add(wrapped);
  59. return wrapped;
  60. }
  61. /** @returns {import('eslint').Rule.RuleModule} */
  62. function loadRule(ruleId) {
  63. const rule = require(`../${ruleId}`);
  64. return {
  65. meta: {
  66. // If there is are, options add `[]` so ESLint can validate that no data is passed to the rule.
  67. // https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-schema.md
  68. schema: [],
  69. ...rule.meta,
  70. docs: {
  71. ...rule.meta.docs,
  72. url: getDocumentationUrl(ruleId),
  73. },
  74. },
  75. create: reportProblems(rule.create),
  76. };
  77. }
  78. function loadRules() {
  79. return Object.fromEntries(
  80. fs.readdirSync(path.join(__dirname, '..'), {withFileTypes: true})
  81. .filter(file => file.isFile())
  82. .map(file => {
  83. const ruleId = path.basename(file.name, '.js');
  84. return [ruleId, loadRule(ruleId)];
  85. }),
  86. );
  87. }
  88. module.exports = {
  89. loadRule,
  90. loadRules,
  91. checkVueTemplate,
  92. };