routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+118
@@ -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']);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
const functionTypes = [
|
||||
'FunctionDeclaration',
|
||||
'FunctionExpression',
|
||||
'ArrowFunctionExpression',
|
||||
];
|
||||
|
||||
export default functionTypes;
|
||||
+31
@@ -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';
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export default function isArrowFunctionBody(node) {
|
||||
return node.parent.type === 'ArrowFunctionExpression' && node.parent.body === node;
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
const isDirective = node => node.type === 'ExpressionStatement'
|
||||
&& typeof node.directive === 'string';
|
||||
|
||||
export default isDirective;
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
const isEmptyArrayExpression = node =>
|
||||
node.type === 'ArrayExpression'
|
||||
&& node.elements.length === 0;
|
||||
|
||||
export default isEmptyArrayExpression;
|
||||
+17
@@ -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;
|
||||
}
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
const isEmptyArrayExpression = node =>
|
||||
node.type === 'ObjectExpression'
|
||||
&& node.properties.length === 0;
|
||||
|
||||
export default isEmptyArrayExpression;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export default function isExpressionStatement(node) {
|
||||
return node.type === 'ExpressionStatement'
|
||||
|| (
|
||||
node.type === 'ChainExpression'
|
||||
&& node.parent.type === 'ExpressionStatement'
|
||||
);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import functionTypes from './function-types.js';
|
||||
|
||||
export default function isFunction(node) {
|
||||
return functionTypes.includes(node.type);
|
||||
}
|
||||
+98
@@ -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;
|
||||
}
|
||||
+62
@@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
+8
@@ -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;
|
||||
}
|
||||
+159
@@ -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);
|
||||
}
|
||||
+10
@@ -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;
|
||||
Generated
Vendored
+24
@@ -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;
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export default function isUndefined(node) {
|
||||
return node?.type === 'Identifier' && node.name === 'undefined';
|
||||
}
|
||||
+19
@@ -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, '');
|
||||
Reference in New Issue
Block a user