123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- 'use strict';
- const path = require('node:path');
- const fs = require('node:fs');
- const getDocumentationUrl = require('./get-documentation-url.js');
- const isIterable = object => typeof object?.[Symbol.iterator] === 'function';
- class FixAbortError extends Error {}
- const fixOptions = {
- abort() {
- throw new FixAbortError('Fix aborted.');
- },
- };
- function wrapFixFunction(fix) {
- return fixer => {
- const result = fix(fixer, fixOptions);
- if (isIterable(result)) {
- try {
- return [...result];
- } catch (error) {
- if (error instanceof FixAbortError) {
- return;
- }
- /* c8 ignore next */
- throw error;
- }
- }
- return result;
- };
- }
- function reportListenerProblems(listener, context) {
- // Listener arguments can be `codePath, node` or `node`
- return function (...listenerArguments) {
- let problems = listener(...listenerArguments);
- if (!problems) {
- return;
- }
- if (!isIterable(problems)) {
- problems = [problems];
- }
- for (const problem of problems) {
- if (problem.fix) {
- problem.fix = wrapFixFunction(problem.fix);
- }
- if (Array.isArray(problem.suggest)) {
- for (const suggest of problem.suggest) {
- if (suggest.fix) {
- suggest.fix = wrapFixFunction(suggest.fix);
- }
- suggest.data = {
- ...problem.data,
- ...suggest.data,
- };
- }
- }
- context.report(problem);
- }
- };
- }
- // `checkVueTemplate` function will wrap `create` function, there is no need to wrap twice
- const wrappedFunctions = new Set();
- function reportProblems(create) {
- if (wrappedFunctions.has(create)) {
- return create;
- }
- const wrapped = context => {
- const listeners = create(context);
- if (!listeners) {
- return {};
- }
- return Object.fromEntries(
- Object.entries(listeners)
- .map(([selector, listener]) => [selector, reportListenerProblems(listener, context)]),
- );
- };
- wrappedFunctions.add(wrapped);
- return wrapped;
- }
- function checkVueTemplate(create, options) {
- const {
- visitScriptBlock,
- } = {
- visitScriptBlock: true,
- ...options,
- };
- create = reportProblems(create);
- const wrapped = context => {
- const listeners = create(context);
- // `vue-eslint-parser`
- if (context.parserServices?.defineTemplateBodyVisitor) {
- return visitScriptBlock
- ? context.parserServices.defineTemplateBodyVisitor(listeners, listeners)
- : context.parserServices.defineTemplateBodyVisitor(listeners);
- }
- return listeners;
- };
- wrappedFunctions.add(wrapped);
- return wrapped;
- }
- /** @returns {import('eslint').Rule.RuleModule} */
- function loadRule(ruleId) {
- const rule = require(`../${ruleId}`);
- return {
- meta: {
- // If there is are, options add `[]` so ESLint can validate that no data is passed to the rule.
- // https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-schema.md
- schema: [],
- ...rule.meta,
- docs: {
- ...rule.meta.docs,
- url: getDocumentationUrl(ruleId),
- },
- },
- create: reportProblems(rule.create),
- };
- }
- function loadRules() {
- return Object.fromEntries(
- fs.readdirSync(path.join(__dirname, '..'), {withFileTypes: true})
- .filter(file => file.isFile())
- .map(file => {
- const ruleId = path.basename(file.name, '.js');
- return [ruleId, loadRule(ruleId)];
- }),
- );
- }
- module.exports = {
- loadRule,
- loadRules,
- checkVueTemplate,
- };
|