UNPKG

eslint-plugin-jest-formatting

Version:
170 lines (169 loc) 6.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createRule = exports.PaddingType = exports.StatementType = void 0; const astUtils = require("../ast-utils"); var StatementType; (function (StatementType) { StatementType[StatementType["Any"] = 0] = "Any"; StatementType[StatementType["AfterAllToken"] = 1] = "AfterAllToken"; StatementType[StatementType["AfterEachToken"] = 2] = "AfterEachToken"; StatementType[StatementType["BeforeAllToken"] = 3] = "BeforeAllToken"; StatementType[StatementType["BeforeEachToken"] = 4] = "BeforeEachToken"; StatementType[StatementType["DescribeToken"] = 5] = "DescribeToken"; StatementType[StatementType["ExpectToken"] = 6] = "ExpectToken"; StatementType[StatementType["FdescribeToken"] = 7] = "FdescribeToken"; StatementType[StatementType["FitToken"] = 8] = "FitToken"; StatementType[StatementType["ItToken"] = 9] = "ItToken"; StatementType[StatementType["TestToken"] = 10] = "TestToken"; StatementType[StatementType["XdescribeToken"] = 11] = "XdescribeToken"; StatementType[StatementType["XitToken"] = 12] = "XitToken"; StatementType[StatementType["XtestToken"] = 13] = "XtestToken"; })(StatementType = exports.StatementType || (exports.StatementType = {})); var PaddingType; (function (PaddingType) { PaddingType[PaddingType["Any"] = 0] = "Any"; PaddingType[PaddingType["Always"] = 1] = "Always"; })(PaddingType = exports.PaddingType || (exports.PaddingType = {})); const createTokenTester = (tokenName) => { return (node, sourceCode) => { let activeNode = node; if (activeNode.type === 'ExpressionStatement') { if (activeNode.expression.type === 'AwaitExpression') { activeNode = activeNode.expression.argument; } const token = sourceCode.getFirstToken(activeNode); return token.type === 'Identifier' && token.value === tokenName; } return false; }; }; const statementTesters = { [0]: () => true, [1]: createTokenTester('afterAll'), [2]: createTokenTester('afterEach'), [3]: createTokenTester('beforeAll'), [4]: createTokenTester('beforeEach'), [5]: createTokenTester('describe'), [6]: createTokenTester('expect'), [7]: createTokenTester('fdescribe'), [8]: createTokenTester('fit'), [9]: createTokenTester('it'), [10]: createTokenTester('test'), [11]: createTokenTester('xdescribe'), [12]: createTokenTester('xit'), [13]: createTokenTester('xtest'), }; const paddingAlwaysTester = (prevNode, nextNode, paddingContext) => { const { sourceCode, ruleContext } = paddingContext; const paddingLines = astUtils.getPaddingLineSequences(prevNode, nextNode, sourceCode); if (paddingLines.length > 0) { return; } ruleContext.report({ node: nextNode, message: 'Expected blank line before this statement.', fix(fixer) { let prevToken = astUtils.getActualLastToken(sourceCode, prevNode); const nextToken = (sourceCode.getFirstTokenBetween(prevToken, nextNode, { includeComments: true, filter(token) { if (astUtils.areTokensOnSameLine(prevToken, token)) { prevToken = token; return false; } return true; }, }) || nextNode); const insertText = astUtils.areTokensOnSameLine(prevToken, nextToken) ? '\n\n' : '\n'; return fixer.insertTextAfter(prevToken, insertText); }, }); }; const paddingTesters = { [0]: () => true, [1]: paddingAlwaysTester, }; const createScopeInfo = () => { return (() => { let scope = null; return { get prevNode() { return scope.prevNode; }, set prevNode(node) { scope.prevNode = node; }, enter() { scope = { upper: scope, prevNode: null }; }, exit() { scope = scope.upper; }, }; })(); }; const nodeMatchesType = (node, statementType, paddingContext) => { let innerStatementNode = node; const { sourceCode } = paddingContext; while (innerStatementNode.type === 'LabeledStatement') { innerStatementNode = innerStatementNode.body; } if (Array.isArray(statementType)) { return statementType.some((type) => nodeMatchesType(innerStatementNode, type, paddingContext)); } return statementTesters[statementType](innerStatementNode, sourceCode); }; const testPadding = (prevNode, nextNode, paddingContext) => { const { configs } = paddingContext; const testType = (type) => paddingTesters[type](prevNode, nextNode, paddingContext); for (let i = configs.length - 1; i >= 0; --i) { const { prevStatementType: prevType, nextStatementType: nextType, paddingType, } = configs[i]; if (nodeMatchesType(prevNode, prevType, paddingContext) && nodeMatchesType(nextNode, nextType, paddingContext)) { return testType(paddingType); } } return testType(0); }; const verifyNode = (node, paddingContext) => { const { scopeInfo } = paddingContext; if (!astUtils.isValidParent(node.parent.type)) { return; } if (scopeInfo.prevNode) { testPadding(scopeInfo.prevNode, node, paddingContext); } scopeInfo.prevNode = node; }; const createRule = (configs, deprecated = false) => ({ meta: { fixable: 'whitespace', deprecated, }, create(context) { const paddingContext = { ruleContext: context, sourceCode: context.getSourceCode(), scopeInfo: createScopeInfo(), configs, }; const { scopeInfo } = paddingContext; return { Program: scopeInfo.enter, 'Program:exit': scopeInfo.enter, BlockStatement: scopeInfo.enter, 'BlockStatement:exit': scopeInfo.exit, SwitchStatement: scopeInfo.enter, 'SwitchStatement:exit': scopeInfo.exit, ':statement': (node) => verifyNode(node, paddingContext), SwitchCase: (node) => { verifyNode(node, paddingContext); scopeInfo.enter(); }, 'SwitchCase:exit': scopeInfo.exit, }; }, }); exports.createRule = createRule;