routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
@@ -0,0 +1,9 @@
import path from 'node:path';
import packageJson from '../../package.json' with {type: 'json'};
const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';
export default function getDocumentationUrl(filename) {
const ruleName = path.basename(filename, '.js');
return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`;
}
+9
View File
@@ -0,0 +1,9 @@
/**
@import * as ESLint from 'eslint';
@import {UnicornCreate} from './to-eslint-create.js';
@import {UnicornRule} from './to-eslint-rule.js';
@import {UnicornContext} from './unicorn-context.js';
@import {TSESTree as Estree} from '@typescript-eslint/types';
*/
export {default as toEslintRules} from './to-eslint-rules.js';
@@ -0,0 +1,49 @@
import assert from 'node:assert/strict';
import createUnicornContext from './unicorn-context.js';
import UnicornListeners from './unicorn-listeners.js';
/**
@import * as ESLint from 'eslint';
@import {UnicornContext} from './unicorn-context.js';
@import {EslintListers, ListenerType, EslintListener} from './to-eslint-listener.js'
*/
/**
@typedef {ESLint.Rule.RuleModule['create']} EslintCreate
@typedef {(context: UnicornContext) => void} UnicornCreate
*/
// `checkVueTemplate` function will wrap `create` function, there is no need to wrap twice
const wrappedFunctions = new Set();
const markFunctionWrapped = create => {
wrappedFunctions.add(create);
return create;
};
/**
Convert Unicorn style of `create` to ESLint style
@param {UnicornCreate} unicornCreate
@returns {EslintCreate}
*/
function toEslintCreate(unicornCreate) {
if (wrappedFunctions.has(unicornCreate)) {
return unicornCreate;
}
return eslintContext => {
const unicornListeners = new UnicornListeners(eslintContext);
const unicornContext = createUnicornContext(eslintContext, unicornListeners);
const result = unicornCreate(unicornContext);
assert.equal(result, undefined, `[${eslintContext.id}] Rule \`create\` function should return \`undefined\`, please use \`context.on()\` instead of return listeners.`);
const eslintListeners = unicornListeners.toEslintListeners();
return eslintListeners;
};
}
export default toEslintCreate;
export {markFunctionWrapped};
@@ -0,0 +1,40 @@
import {iterateFixOrProblems} from './utilities.js';
import toEslintProblem from './to-eslint-problem.js';
/**
@import * as ESLint from 'eslint';
@import {UnicornContext} from './unicorn-context.js'
@import {UnicornProblems} from './to-eslint-problem.js'
*/
/**
@typedef {ESLint.Rule.RuleListener} EslintListers
@typedef {keyof EslintListers} ListenerType
@typedef {EslintListers[ListenerType]} EslintListener
@typedef {(...listenerArguments: Parameters<EslintListener>) => UnicornProblems} UnicornRuleListen
*/
/**
@param {UnicornContext} context
@param {UnicornRuleListen} listener
@returns {Listener}
*/
function toEslintListener(context, listener) {
// Listener arguments can be `codePath, node` or `node`
/**
@type {UnicornRuleListen}
*/
return (...listenerArguments) => {
const unicornProblems = listener(...listenerArguments);
for (const unicornProblem of iterateFixOrProblems(unicornProblems)) {
if (unicornProblem) {
const eslintProblem = toEslintProblem(unicornProblem);
context.report(eslintProblem);
}
}
};
}
export default toEslintListener;
@@ -0,0 +1,38 @@
import toEslintFixer from './to-eslint-rule-fixer.js';
/**
@import * as ESLint from 'eslint';
*/
/**
@typedef {Parameters<ESLint.Rule.RuleContext['report']>[0]} EslintProblem
@typedef {EslintProblem} UnicornProblem
@typedef {EslintProblem | undefined | EslintProblem[] | IterableIterator<EslintProblem>} UnicornProblems
*/
/**
@param {UnicornProblem} unicornProblem
@returns {EslintProblem}
*/
function toEslintProblem(unicornProblem) {
const eslintProblem = {...unicornProblem};
if (unicornProblem.fix) {
eslintProblem.fix = toEslintFixer(unicornProblem.fix);
}
if (Array.isArray(unicornProblem.suggest)) {
eslintProblem.suggest = unicornProblem.suggest.map(unicornSuggest => ({
...unicornSuggest,
fix: toEslintFixer(unicornSuggest.fix),
data: {
...unicornProblem.data,
...unicornSuggest.data,
},
}));
}
return eslintProblem;
}
export default toEslintProblem;
@@ -0,0 +1,49 @@
import {iterateFixOrProblems} from './utilities.js';
/**
@import * as ESLint from 'eslint';
*/
class FixAbortError extends Error {
name = 'FixAbortError';
}
const fixOptions = {
abort() {
throw new FixAbortError('Fix aborted.');
},
};
/**
@typedef {ESLint.Rule.ReportFixer | undefined} EslintReportFixer
@typedef {EslintReportFixer | IterableIterator<EslintReportFixer>} UnicornReportFixer
@typedef {(fixer: ESLint.Rule.RuleFixer, options: typeof fixOptions) => UnicornReportFixer} UnicornRuleFixer
*/
/**
Convert Unicorn style fix function to ESLint style fix function
@param {UnicornRuleFixer} fix
@returns {ESLint.Rule.RuleFixer}
*/
function toEslintRuleFixer(fix) {
/** @param {UnicornReportFixer} fixer */
return fixer => {
const unicornReport = fix(fixer, fixOptions);
const eslintReport = iterateFixOrProblems(unicornReport);
try {
return [...eslintReport];
} catch (error) {
if (error instanceof FixAbortError) {
return;
}
/* c8 ignore next */
throw error;
}
};
}
export default toEslintRuleFixer;
@@ -0,0 +1,38 @@
import getDocumentationUrl from '../utils/get-documentation-url.js';
import toEslintCreate from './to-eslint-create.js';
/**
@import * as ESLint from 'eslint';
@import {UnicornCreate} from './to-eslint-create.js';
*/
/**
@typedef {ESLint.Rule.RuleModule & {
create: UnicornCreate
}} UnicornRule
*/
/**
Convert Unicorn rule to Eslint rule
@param {string} ruleId
@param {UnicornRule} unicornRule
@returns {ESLint.Rule.RuleModule}
*/
function toEslintRule(ruleId, unicornRule) {
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: [],
...unicornRule.meta,
docs: {
...unicornRule.meta.docs,
url: getDocumentationUrl(ruleId),
},
},
create: toEslintCreate(unicornRule.create),
};
}
export default toEslintRule;
@@ -0,0 +1,11 @@
import toEslintRule from './to-eslint-rule.js';
function toEslintRules(rules) {
return Object.fromEntries(Object.entries(rules).map(([ruleId, rule]) => [
ruleId,
toEslintRule(ruleId, rule),
]));
}
export default toEslintRules;
@@ -0,0 +1,36 @@
/**
@import * as ESLint from 'eslint';
@import {UnicornListeners, ListenerType, Listener} from './to-eslint-create.js'
*/
/**
@typedef {(type: ListenerType | ListenerType[], listener: Listener) => ReturnType<Listener>} UnicornRuleListen
@typedef {ESLint.Rule.RuleContext & {
on: UnicornRuleListen
onExit: UnicornRuleListen
}} UnicornContext
*/
/**
Create a better `Context` object with `on` and `onExit` method to add listeners
@param {ESLint.Rule.RuleContext} eslintContext
@param {UnicornListeners} listeners
@returns {UnicornContext}
*/
function createUnicornContext(eslintContext, listeners) {
/** @type {UnicornContext} */
const context = new Proxy(eslintContext, {
get(target, property, receiver) {
if (property === 'on' || property === 'onExit') {
return listeners[property].bind(listeners);
}
return Reflect.get(target, property, receiver);
},
});
return context;
}
export default createUnicornContext;
@@ -0,0 +1,65 @@
import toEslintListener from './to-eslint-listener.js';
/**
@import {EslintListers, ListenerType, Listener} from './to-eslint-create.js'
*/
class UnicornListeners {
#context;
#listeners = new Map();
constructor(context) {
this.#context = context;
}
#addEventListener(selectors, listener) {
const listeners = this.#listeners;
for (const selector of selectors) {
if (listeners.has(selector)) {
listeners.get(selector).push(listener);
} else {
listeners.set(selector, [listener]);
}
}
}
/**
@param {ListenerType | ListenerType[]} selectorOrSelectors
@param {Listener} listener
*/
on(selectorOrSelectors, listener) {
const selectors = Array.isArray(selectorOrSelectors) ? selectorOrSelectors : [selectorOrSelectors];
this.#addEventListener(selectors, listener);
}
/**
@param {ListenerType | ListenerType[]} selectorOrSelectors
@param {Listener} listener
*/
onExit(selectorOrSelectors, listener) {
const selectors = Array.isArray(selectorOrSelectors) ? selectorOrSelectors : [selectorOrSelectors];
this.#addEventListener(selectors.map(selector => `${selector}:exit`), listener);
}
/**
@returns {EslintListers}
*/
toEslintListeners() {
const eslintListeners = {};
for (const [selector, listeners] of this.#listeners) {
eslintListeners[selector] = toEslintListener(
this.#context,
function * (...listenerArguments) {
for (const listener of listeners) {
yield listener(...listenerArguments);
}
},
);
}
return eslintListeners;
}
}
export default UnicornListeners;
+27
View File
@@ -0,0 +1,27 @@
const isIterable = object => typeof object?.[Symbol.iterator] === 'function';
/**
@import * as ESLint from 'eslint';
@import {UnicornReportFixer} from './to-eslint-rule-fixer.js';
@import {UnicornProblems, UnicornProblem} from './to-eslint-problem.js';
*/
/**
Iterate ESLint fix or ESLint problem
@template {UnicornReportFixer | UnicornProblems} ValueType
@param {ValueType} value
@returns {IterableIterator<ValueType extends UnicornReportFixer ? ESLint.Rule.Fix : UnicornProblem>}
*/
export function * iterateFixOrProblems(value) {
if (!isIterable(value)) {
yield value;
return;
}
for (const element of value) {
yield * iterateFixOrProblems(element);
}
}