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,118 @@
/**
@typedef {
{
name?: string,
names?: string[],
argumentsLength?: number,
minimumArguments?: number,
maximumArguments?: number,
allowSpreadElement?: boolean,
optional?: boolean,
} | string | string[]
} CallOrNewExpressionCheckOptions
*/
// eslint-disable-next-line complexity
function create(node, options, types) {
if (!types.includes(node?.type)) {
return false;
}
if (typeof options === 'string') {
options = {names: [options]};
}
if (Array.isArray(options)) {
options = {names: options};
}
let {
name,
names,
argumentsLength,
minimumArguments,
maximumArguments,
allowSpreadElement,
optional,
} = {
minimumArguments: 0,
maximumArguments: Number.POSITIVE_INFINITY,
allowSpreadElement: false,
...options,
};
if (name) {
names = [name];
}
if (
(optional === true && (node.optional !== optional))
|| (
optional === false
// `node.optional` can be `undefined` in some parsers
&& node.optional
)
) {
return false;
}
if (typeof argumentsLength === 'number' && node.arguments.length !== argumentsLength) {
return false;
}
if (minimumArguments !== 0 && node.arguments.length < minimumArguments) {
return false;
}
if (Number.isFinite(maximumArguments) && node.arguments.length > maximumArguments) {
return false;
}
if (!allowSpreadElement) {
const maximumArgumentsLength = Number.isFinite(maximumArguments) ? maximumArguments : argumentsLength;
if (
typeof maximumArgumentsLength === 'number'
&& node.arguments.some((node, index) =>
node.type === 'SpreadElement'
&& index < maximumArgumentsLength)
) {
return false;
}
}
if (
Array.isArray(names)
&& names.length > 0
&& (
node.callee.type !== 'Identifier'
|| !names.includes(node.callee.name)
)
) {
return false;
}
return true;
}
/**
@param {CallOrNewExpressionCheckOptions} [options]
@returns {boolean}
*/
export const isCallExpression = (node, options) => create(node, options, ['CallExpression']);
/**
@param {CallOrNewExpressionCheckOptions} [options]
@returns {boolean}
*/
export const isNewExpression = (node, options) => {
if (typeof options?.optional === 'boolean') {
throw new TypeError('Cannot check node.optional in `isNewExpression`.');
}
return create(node, options, ['NewExpression']);
};
/**
@param {CallOrNewExpressionCheckOptions} [options]
@returns {boolean}
*/
export const isCallOrNewExpression = (node, options) => create(node, options, ['CallExpression', 'NewExpression']);
@@ -0,0 +1,7 @@
const functionTypes = [
'FunctionDeclaration',
'FunctionExpression',
'ArrowFunctionExpression',
];
export default functionTypes;
+31
View File
@@ -0,0 +1,31 @@
export {
isLiteral,
isStringLiteral,
isNumericLiteral,
isBigIntLiteral,
isNullLiteral,
isRegexLiteral,
isEmptyStringLiteral,
} from './literal.js';
export {
isNewExpression,
isCallExpression,
isCallOrNewExpression,
} from './call-or-new-expression.js';
export {default as isArrowFunctionBody} from './is-arrow-function-body.js';
export {default as isDirective} from './is-directive.js';
export {default as isEmptyNode} from './is-empty-node.js';
export {default as isEmptyArrayExpression} from './is-empty-array-expression.js';
export {default as isEmptyObjectExpression} from './is-empty-object-expression.js';
export {default as isExpressionStatement} from './is-expression-statement.js';
export {default as isFunction} from './is-function.js';
export {default as isMemberExpression} from './is-member-expression.js';
export {default as isMethodCall} from './is-method-call.js';
export {default as isNegativeOne} from './is-negative-one.js';
export {default as isReferenceIdentifier} from './is-reference-identifier.js';
export {default as isStaticRequire} from './is-static-require.js';
export {default as isTaggedTemplateLiteral} from './is-tagged-template-literal.js';
export {default as isUndefined} from './is-undefined.js';
export {default as functionTypes} from './function-types.js';
@@ -0,0 +1,3 @@
export default function isArrowFunctionBody(node) {
return node.parent.type === 'ArrowFunctionExpression' && node.parent.body === node;
}
@@ -0,0 +1,4 @@
const isDirective = node => node.type === 'ExpressionStatement'
&& typeof node.directive === 'string';
export default isDirective;
@@ -0,0 +1,5 @@
const isEmptyArrayExpression = node =>
node.type === 'ArrayExpression'
&& node.elements.length === 0;
export default isEmptyArrayExpression;
+17
View File
@@ -0,0 +1,17 @@
export default function isEmptyNode(node, additionalEmpty) {
const {type} = node;
if (type === 'BlockStatement') {
return node.body.every(currentNode => isEmptyNode(currentNode, additionalEmpty));
}
if (type === 'EmptyStatement') {
return true;
}
if (additionalEmpty?.(node)) {
return true;
}
return false;
}
@@ -0,0 +1,5 @@
const isEmptyArrayExpression = node =>
node.type === 'ObjectExpression'
&& node.properties.length === 0;
export default isEmptyArrayExpression;
@@ -0,0 +1,7 @@
export default function isExpressionStatement(node) {
return node.type === 'ExpressionStatement'
|| (
node.type === 'ChainExpression'
&& node.parent.type === 'ExpressionStatement'
);
}
+5
View File
@@ -0,0 +1,5 @@
import functionTypes from './function-types.js';
export default function isFunction(node) {
return functionTypes.includes(node.type);
}
@@ -0,0 +1,98 @@
/* eslint-disable complexity */
/**
@param {
{
property?: string,
properties?: string[],
object?: string,
objects?: string[],
optional?: boolean,
computed?: boolean
} | string | string[]
} [options]
@returns {string}
*/
export default function isMemberExpression(node, options) {
if (node?.type !== 'MemberExpression') {
return false;
}
if (typeof options === 'string') {
options = {properties: [options]};
}
if (Array.isArray(options)) {
options = {properties: options};
}
let {
property,
properties,
object,
objects,
optional,
computed,
} = {
property: '',
properties: [],
object: '',
...options,
};
if (property) {
properties = [property];
}
if (object) {
objects = [object];
}
if (
(optional === true && (node.optional !== optional))
|| (
optional === false
// `node.optional` can be `undefined` in some parsers
&& node.optional
)
) {
return false;
}
if (
Array.isArray(properties)
&& properties.length > 0
) {
if (
node.property.type !== 'Identifier'
|| !properties.includes(node.property.name)
) {
return false;
}
computed ??= false;
}
if (
(computed === true && (node.computed !== computed))
|| (
computed === false
// `node.computed` can be `undefined` in some parsers
&& node.computed
)
) {
return false;
}
if (
Array.isArray(objects)
&& objects.length > 0
&& (
node.object.type !== 'Identifier'
|| !objects.includes(node.object.name)
)
) {
return false;
}
return true;
}
@@ -0,0 +1,62 @@
import isMemberExpression from './is-member-expression.js';
import {isCallExpression} from './call-or-new-expression.js';
/**
@param {
{
// `isCallExpression` options
argumentsLength?: number,
minimumArguments?: number,
maximumArguments?: number,
optionalCall?: boolean,
allowSpreadElement?: boolean,
// `isMemberExpression` options
method?: string,
methods?: string[],
object?: string,
objects?: string[],
optionalMember?: boolean,
computed?: boolean
} | string | string[]
} [options]
@returns {string}
*/
export default function isMethodCall(node, options) {
if (typeof options === 'string') {
options = {methods: [options]};
}
if (Array.isArray(options)) {
options = {methods: options};
}
const {
optionalCall,
optionalMember,
method,
methods,
} = {
method: '',
methods: [],
...options,
};
return (
isCallExpression(node, {
argumentsLength: options.argumentsLength,
minimumArguments: options.minimumArguments,
maximumArguments: options.maximumArguments,
allowSpreadElement: options.allowSpreadElement,
optional: optionalCall,
})
&& isMemberExpression(node.callee, {
object: options.object,
objects: options.objects,
computed: options.computed,
property: method,
properties: methods,
optional: optionalMember,
})
);
}
@@ -0,0 +1,8 @@
import {isNumericLiteral} from './literal.js';
export default function isNegativeOne(node) {
return node?.type === 'UnaryExpression'
&& node.operator === '-'
&& isNumericLiteral(node.argument)
&& node.argument.value === 1;
}
@@ -0,0 +1,159 @@
// eslint-disable-next-line complexity
function isNotReference(node) {
const {parent} = node;
switch (parent.type) {
// `foo.Identifier`
case 'MemberExpression': {
return !parent.computed && parent.property === node;
}
case 'FunctionDeclaration':
case 'FunctionExpression': {
return (
// `function foo(Identifier) {}`
// `const foo = function(Identifier) {}`
parent.params.includes(node)
// `function Identifier() {}`
// `const foo = function Identifier() {}`
|| parent.id === node
);
}
case 'ArrowFunctionExpression': {
// `const foo = (Identifier) => {}`
return parent.params.includes(node);
}
// `class Identifier() {}`
// `const foo = class Identifier() {}`
// `const Identifier = 1`
case 'ClassDeclaration':
case 'ClassExpression':
case 'VariableDeclarator': {
return parent.id === node;
}
// `class Foo {Identifier = 1}`
// `class Foo {Identifier() {}}`
case 'PropertyDefinition':
case 'MethodDefinition': {
return !parent.computed && parent.key === node;
}
// `const foo = {Identifier: 1}`
// `const {Identifier} = {}`
// `const {Identifier: foo} = {}`
// `const {Identifier} = {}`
// `const {foo: Identifier} = {}`
case 'Property': {
return (
(
!parent.computed
&& parent.key === node
&& (
(parent.parent.type === 'ObjectExpression' || parent.parent.type === 'ObjectPattern')
&& parent.parent.properties.includes(parent)
)
)
|| (
parent.value === node
&& parent.parent.type === 'ObjectPattern'
&& parent.parent.properties.includes(parent)
)
);
}
// `const [Identifier] = []`
case 'ArrayPattern': {
return parent.elements.includes(node);
}
/*
```
Identifier: for (const foo of bar) {
continue Identifier;
break Identifier;
}
```
*/
case 'LabeledStatement':
case 'ContinueStatement':
case 'BreakStatement': {
return parent.label === node;
}
// `import * as Identifier from 'foo'`
// `import Identifier from 'foo'`
case 'ImportDefaultSpecifier':
case 'ImportNamespaceSpecifier': {
return parent.local === node;
}
// `export * as Identifier from 'foo'`
case 'ExportAllDeclaration': {
return parent.exported === node;
}
// `import {foo as Identifier} from 'foo'`
// `import {Identifier as foo} from 'foo'`
case 'ImportSpecifier': {
return (parent.local === node || parent.imported === node);
}
// `export {foo as Identifier}`
// `export {Identifier as foo}`
case 'ExportSpecifier': {
return (parent.local === node || parent.exported === node);
}
// TypeScript
case 'TSDeclareFunction':
case 'TSEnumMember': {
return parent.id === node;
}
// `type Foo = { [Identifier: string]: string }`
case 'TSIndexSignature': {
return parent.parameters.includes(node);
}
// `@typescript-eslint/parse` v7
// `type Foo = { [Identifier in keyof string]: number; };`
case 'TSTypeParameter': {
return parent.name === node;
}
// `@typescript-eslint/parse` v8
// `type Foo = { [Identifier in keyof string]: number; };`
case 'TSMappedType': {
return parent.key === node;
}
// `type Identifier = Foo`
case 'TSTypeAliasDeclaration': {
return parent.id === node;
}
case 'TSPropertySignature': {
return parent.key === node;
}
// No default
}
return false;
}
export default function isReferenceIdentifier(node, nameOrNames = []) {
if (node.type !== 'Identifier') {
return false;
}
const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
if (names.length > 0 && !names.includes(node.name)) {
return false;
}
return !isNotReference(node);
}
@@ -0,0 +1,10 @@
import {isStringLiteral} from './literal.js';
import {isCallExpression} from './call-or-new-expression.js';
const isStaticRequire = node => isCallExpression(node, {
name: 'require',
argumentsLength: 1,
optional: false,
}) && isStringLiteral(node.arguments[0]);
export default isStaticRequire;
@@ -0,0 +1,24 @@
import {isNodeMatches} from '../utils/is-node-matches.js';
/**
Check if the given node is a tagged template literal.
@param {Node} node - The AST node to check.
@param {string[]} tags - The object name or key paths.
@returns {boolean}
*/
export default function isTaggedTemplateLiteral(node, tags) {
if (
node.type !== 'TemplateLiteral'
|| node.parent.type !== 'TaggedTemplateExpression'
|| node.parent.quasi !== node
) {
return false;
}
if (tags) {
return isNodeMatches(node.parent.tag, tags);
}
return true;
}
@@ -0,0 +1,3 @@
export default function isUndefined(node) {
return node?.type === 'Identifier' && node.name === 'undefined';
}
+19
View File
@@ -0,0 +1,19 @@
export function isLiteral(node, value) {
if (node?.type !== 'Literal') {
return false;
}
return node.value === value;
}
export const isStringLiteral = node => node?.type === 'Literal' && typeof node.value === 'string';
export const isNumericLiteral = node => node.type === 'Literal' && typeof node.value === 'number';
export const isRegexLiteral = node => node.type === 'Literal' && Boolean(node.regex);
export const isNullLiteral = node => node?.type === 'Literal' && node.raw === 'null';
export const isBigIntLiteral = node => node.type === 'Literal' && Boolean(node.bigint);
export const isEmptyStringLiteral = node => isLiteral(node, '');