Skip to content

Commit

Permalink
formating rules port (#461)
Browse files Browse the repository at this point in the history
* feat(initial): setup rules

* chore(final-touches): nothing
  • Loading branch information
veritem committed May 25, 2024
1 parent 6aa0aca commit a1ad196
Show file tree
Hide file tree
Showing 21 changed files with 1,665 additions and 4 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
],
"author": "Verite Mugabo <https://veritemugabo.com/>",
"type": "module",
"main": "./dist/index.mjs",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
Expand Down
28 changes: 26 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ import preferSpyOn, { RULE_NAME as preferSpyOnName } from './rules/prefer-spy-on
import preferComparisonMatcher, { RULE_NAME as preferComparisonMatcherName } from './rules/prefer-comparison-matcher'
import preferToContain, { RULE_NAME as preferToContainName } from './rules/prefer-to-contain'
import preferExpectAssertions, { RULE_NAME as preferExpectAssertionsName } from './rules/prefer-expect-assertions'
import paddingAroundAfterAllBlocks, { RULE_NAME as paddingAroundAfterAllBlocksName } from "./rules/padding-around-after-all-blocks"
import paddingAroundAfterEachBlocks, { RULE_NAME as paddingAroundAfterEachBlocksName } from "./rules/padding-around-after-each-blocks"
import paddingAroundAll, { RULE_NAME as paddingAroundAllName } from "./rules/padding-around-all"
import paddingAroundBeforeAllBlocks, { RULE_NAME as paddingAroundBeforeAllBlocksName } from "./rules/padding-around-before-all-blocks"
import paddingAroundBeforeEachBlocks, { RULE_NAME as paddingAroundBeforeEachBlocksName } from "./rules/padding-around-before-each-blocks"
import paddingAroundDescribeBlocks, { RULE_NAME as paddingAroundDescribeBlocksName } from "./rules/padding-around-describe-blocks"
import paddingAroundExpectGroups, { RULE_NAME as paddingAroundExpectGroupsName } from "./rules/padding-around-expect-groups"
import paddingAroundTestBlocks, { RULE_NAME as paddingAroundTestBlocksName } from "./rules/padding-around-test-blocks"

const createConfig = <R extends Linter.RulesRecord>(rules: R) => (
Object.keys(rules).reduce((acc, ruleName) => {
Expand Down Expand Up @@ -117,7 +125,15 @@ const allRules = {
[preferComparisonMatcherName]: 'warn',
[preferToContainName]: 'warn',
[preferExpectAssertionsName]: 'warn',
[usePreferTobe]: 'warn'
[usePreferTobe]: 'warn',
[paddingAroundAfterAllBlocksName]: 'warn',
[paddingAroundAfterEachBlocksName]: 'warn',
[paddingAroundAllName]: 'warn',
[paddingAroundBeforeAllBlocksName]: 'warn',
[paddingAroundBeforeEachBlocksName]: 'warn',
[paddingAroundDescribeBlocksName]: 'warn',
[paddingAroundExpectGroupsName]: 'warn',
[paddingAroundTestBlocksName]: 'warn'
} as const

const recommended = {
Expand Down Expand Up @@ -188,7 +204,15 @@ const plugin = {
[preferSpyOnName]: preferSpyOn,
[preferComparisonMatcherName]: preferComparisonMatcher,
[preferToContainName]: preferToContain,
[preferExpectAssertionsName]: preferExpectAssertions
[preferExpectAssertionsName]: preferExpectAssertions,
[paddingAroundAfterAllBlocksName]: paddingAroundAfterAllBlocks,
[paddingAroundAfterEachBlocksName]: paddingAroundAfterEachBlocks,
[paddingAroundAllName]: paddingAroundAll,
[paddingAroundBeforeAllBlocksName]: paddingAroundBeforeAllBlocks,
[paddingAroundBeforeEachBlocksName]: paddingAroundBeforeEachBlocks,
[paddingAroundDescribeBlocksName]: paddingAroundDescribeBlocks,
[paddingAroundExpectGroupsName]: paddingAroundExpectGroups,
[paddingAroundTestBlocksName]: paddingAroundTestBlocks
},
configs: {
'legacy-recommended': createConfigLegacy(recommended),
Expand Down
18 changes: 18 additions & 0 deletions src/rules/padding-around-after-all-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Config, PaddingType, StatementType, createPaddingRule } from "../utils/padding"
import { URL } from "node:url"

export const RULE_NAME = new URL('', import.meta.url).pathname

export const config: Config[] = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: StatementType.AfterAllToken
},
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.AfterAllToken,
nextStatementType: StatementType.Any
}
]
export default createPaddingRule(RULE_NAME, 'Enforce padding around `afterAll` blocks', config)
19 changes: 19 additions & 0 deletions src/rules/padding-around-after-each-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Config, PaddingType, StatementType, createPaddingRule } from "../utils/padding";
import { get_filename } from "../utils/msc";

export const RULE_NAME = get_filename(import.meta.url)

export const config: Config[] = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: StatementType.AfterEachToken
},
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.AfterEachToken,
nextStatementType: StatementType.Any
}
]

export default createPaddingRule(RULE_NAME, 'Enforce padding around `afterEach` blocks', config)
26 changes: 26 additions & 0 deletions src/rules/padding-around-all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

import { config as paddingAroundAfterAllBlocksConfig } from './padding-around-after-all-blocks';
import { config as paddingAroundAfterEachBlocksConfig } from './padding-around-after-each-blocks';
import { config as paddingAroundBeforeAllBlocksConfig } from './padding-around-before-all-blocks';
import { config as paddingAroundBeforeEachBlocksConfig } from './padding-around-before-each-blocks';
import { config as paddingAroundDescribeBlocksConfig } from './padding-around-describe-blocks';
import { config as paddingAroundExpectGroupsConfig } from './padding-around-expect-groups';
import { config as paddingAroundTestBlocksConfig } from './padding-around-test-blocks';
import { createPaddingRule } from '../utils/padding';
import { get_filename } from '../utils/msc';

export const RULE_NAME = get_filename(import.meta.url)

export default createPaddingRule(
RULE_NAME,
'Enforce padding around vitest functions',
[
...paddingAroundAfterAllBlocksConfig,
...paddingAroundAfterEachBlocksConfig,
...paddingAroundBeforeAllBlocksConfig,
...paddingAroundBeforeEachBlocksConfig,
...paddingAroundDescribeBlocksConfig,
...paddingAroundExpectGroupsConfig,
...paddingAroundTestBlocksConfig,
],
);
19 changes: 19 additions & 0 deletions src/rules/padding-around-before-all-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { get_filename } from "../utils/msc";
import { Config, PaddingType, StatementType, createPaddingRule } from "../utils/padding";

export const RULE_NAME = get_filename(import.meta.url)

export const config: Config[] = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: StatementType.BeforeAllToken
},
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.BeforeAllToken,
nextStatementType: StatementType.Any
}
]

export default createPaddingRule(RULE_NAME, 'Enforce padding around `beforeAll` blocks', config)
24 changes: 24 additions & 0 deletions src/rules/padding-around-before-each-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

import { get_filename } from '../utils/msc';
import { PaddingType, StatementType, createPaddingRule } from '../utils/padding';

export const RULE_NAME = get_filename(import.meta.url)

export const config = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: StatementType.BeforeEachToken,
},
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.BeforeEachToken,
nextStatementType: StatementType.Any,
},
];

export default createPaddingRule(
RULE_NAME,
'Enforce padding around `beforeEach` blocks',
config,
);
32 changes: 32 additions & 0 deletions src/rules/padding-around-describe-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

import { get_filename } from '../utils/msc';
import { Config, PaddingType, StatementType, createPaddingRule } from '../utils/padding';

export const RULE_NAME = get_filename(import.meta.url)

export const config: Config[] = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: [
StatementType.DescribeToken,
StatementType.FdescribeToken,
StatementType.XdescribeToken,
],
},
{
paddingType: PaddingType.Always,
prevStatementType: [
StatementType.DescribeToken,
StatementType.FdescribeToken,
StatementType.XdescribeToken,
],
nextStatementType: StatementType.Any,
},
];

export default createPaddingRule(
RULE_NAME,
'Enforce padding around `describe` blocks',
config,
);
28 changes: 28 additions & 0 deletions src/rules/padding-around-expect-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { get_filename } from "../utils/msc";
import { Config, PaddingType, StatementType, createPaddingRule } from "../utils/padding";

export const RULE_NAME = get_filename(import.meta.url)

export const config: Config[] = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: StatementType.ExpectToken,
},
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.ExpectToken,
nextStatementType: StatementType.Any,
},
{
paddingType: PaddingType.Any,
prevStatementType: StatementType.ExpectToken,
nextStatementType: StatementType.ExpectToken,
},
];

export default createPaddingRule(
RULE_NAME,
'Enforce padding around `expect` groups',
config,
);
36 changes: 36 additions & 0 deletions src/rules/padding-around-test-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

import { get_filename } from '../utils/msc';
import { PaddingType, StatementType, createPaddingRule } from '../utils/padding';

export const RULE_NAME = get_filename(import.meta.url)

export const config = [
{
paddingType: PaddingType.Always,
prevStatementType: StatementType.Any,
nextStatementType: [
StatementType.TestToken,
StatementType.ItToken,
StatementType.FitToken,
StatementType.XitToken,
StatementType.XtestToken,
],
},
{
paddingType: PaddingType.Always,
prevStatementType: [
StatementType.TestToken,
StatementType.ItToken,
StatementType.FitToken,
StatementType.XitToken,
StatementType.XtestToken,
],
nextStatementType: StatementType.Any,
},
];

export default createPaddingRule(
RULE_NAME,
'Enforce padding around afterAll blocks',
config,
);
78 changes: 78 additions & 0 deletions src/utils/ast-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESLint, TSESTree } from "@typescript-eslint/utils";
import { createRequire } from "node:module"

const eslintRequire = createRequire(require.resolve("eslint"))

export const espreeParser = eslintRequire.resolve('espree');


// We'll only verify nodes with these parent types
const STATEMENT_LIST_PARENTS = new Set([
AST_NODE_TYPES.Program,
AST_NODE_TYPES.BlockStatement,
AST_NODE_TYPES.SwitchCase,
AST_NODE_TYPES.SwitchStatement,
]);

export const isValidParent = (parentType: AST_NODE_TYPES): boolean => {
return STATEMENT_LIST_PARENTS.has(parentType)
}

export const isTokenASemicolon = (token: TSESTree.Token): boolean =>
token.value === ';' && token.type === AST_TOKEN_TYPES.Punctuator


/**
* Gets the actual last token.
*
* If a semicolon is semicolon-less style's semicolon, this ignores it.
* For example:
*
* foo()
* ;[1, 2, 3].forEach(bar)
*/
export const getActualLastToken = (sourceCode: TSESLint.SourceCode, node: TSESTree.Node): TSESTree.Token => {

const semiToken = sourceCode.getLastToken(node)!;
const prevToken = sourceCode.getTokenBefore(semiToken)!;
const nextToken = sourceCode.getTokenAfter(semiToken)

const isSemicolonLessStyle = Boolean(
prevToken &&
nextToken &&
prevToken.range[0] >= node.range[0] &&
isTokenASemicolon(semiToken) &&
semiToken.loc.start.line !== prevToken.loc.end.line &&
semiToken.loc.end.line === nextToken.loc.start.line,
);

return isSemicolonLessStyle ? prevToken : semiToken;

}

export const getPaddingLineSequences = (prevNode: TSESTree.Node, nextNode: TSESTree.Node, sourceCode: TSESLint.SourceCode) => {
const pairs: TSESTree.Token[][] = []
const includeComments = true

let prevToken = getActualLastToken(sourceCode, prevNode)

if ((nextNode.loc.start.line - prevNode.loc.end.line) >= 2) {
do {
const token = sourceCode.getTokenAfter(prevToken, { includeComments }) as TSESTree.Token

if ((token.loc.start.line - prevToken.loc.end.line) >= 2) {
pairs.push([prevToken, token])
}

prevToken = token
} while (prevToken.range[0] < nextNode.range[0])
}

return pairs
}


export const areTokensOnSameLine = (
left: TSESTree.Node | TSESTree.Token,
right: TSESTree.Node | TSESTree.Token,
): boolean => left.loc.end.line === right.loc.start.line;
9 changes: 8 additions & 1 deletion src/utils/msc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'
import { getFirstMatcherArg, ParsedExpectVitestFnCall } from './parse-vitest-fn-call'
import { EqualityMatcher } from './types'
import { getAccessorValue, isSupportedAccessor } from '.'
import { basename, parse } from "node:path";
import { fileURLToPath } from 'node:url';

export const isBooleanLiteral = (node: TSESTree.Node): node is TSESTree.BooleanLiteral =>
node.type === AST_NODE_TYPES.Literal && typeof node.value === 'boolean'
Expand Down Expand Up @@ -35,11 +37,16 @@ export const isInstanceOfBinaryExpression = (
&& isSupportedAccessor(node.right, className)

export interface CallExpressionWithSingleArgument<
Argument extends TSESTree.CallExpression['arguments'][number] = TSESTree.CallExpression['arguments'][number]
Argument extends TSESTree.CallExpression['arguments'][number] = TSESTree.CallExpression['arguments'][number]
> extends TSESTree.CallExpression {
arguments: [Argument]
}

export const hasOnlyOneArgument = (
call: TSESTree.CallExpression
): call is CallExpressionWithSingleArgument => call.arguments.length === 1


export function get_filename(url: string) {
return parse(basename(fileURLToPath(url))).name
}

0 comments on commit a1ad196

Please sign in to comment.