Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

formating rules port #461

Merged
merged 2 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading