You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9 lines
140 KiB
JavaScript
9 lines
140 KiB
JavaScript
|
3 months ago
|
"use strict";const utils=require("@typescript-eslint/utils"),n$4=require("typescript"),node_path=require("node:path"),node_module=require("node:module"),scopeManager=require("@typescript-eslint/scope-manager");var _documentCurrentScript=typeof document<"u"?document.currentScript:null;function _interopDefaultCompat(e){return e&&typeof e=="object"&&"default"in e?e.default:e}const n__default=_interopDefaultCompat(n$4),version="1.3.20",createEslintRule=utils.ESLintUtils.RuleCreator(e=>`https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/docs/rules/${e}.md`),joinNames=(e,b)=>e&&b?`${e}.${b}`:null,isFunction=e=>e.type===utils.AST_NODE_TYPES.FunctionExpression||e.type===utils.AST_NODE_TYPES.ArrowFunctionExpression;function getNodeName(e){if(isSupportedAccessor(e))return getAccessorValue(e);switch(e.type){case utils.AST_NODE_TYPES.TaggedTemplateExpression:return getNodeName(e.tag);case utils.AST_NODE_TYPES.MemberExpression:return joinNames(getNodeName(e.object),getNodeName(e.property));case utils.AST_NODE_TYPES.NewExpression:case utils.AST_NODE_TYPES.CallExpression:return getNodeName(e.callee)}return null}const isSupportedAccessor=(e,b)=>isIdentifier(e,b)||isStringNode(e,b),isIdentifier=(e,b)=>e.type===utils.AST_NODE_TYPES.Identifier&&(b===void 0||e.name===b),S$6=(e,b)=>e.type===utils.AST_NODE_TYPES.TemplateLiteral&&e.quasis.length===1&&(b===void 0||e.quasis[0].value.raw===b),g$4=(e,b)=>e.type===utils.AST_NODE_TYPES.Literal&&typeof e.value=="string"&&(b===void 0||e.value===b),isStringNode=(e,b)=>g$4(e,b)||S$6(e,b),getAccessorValue=e=>e.type===utils.AST_NODE_TYPES.Identifier?e.name:getStringValue(e),getStringValue=e=>e?.type===utils.AST_NODE_TYPES.TemplateLiteral?e.quasis[0].value.raw:e?.value,replaceAccessorFixer=(e,b,d)=>e.replaceText(b,b.type===utils.AST_NODE_TYPES.Identifier?d:`'${d}'`),removeExtraArgumentsFixer=(e,b,d,Y)=>{const q=d.arguments[Y],$=d.arguments[d.arguments.length-1],{sourceCode:F}=b;let V=F.getTokenAfter($);return V.value===","&&(V=F.getTokenAfter(V)),e.removeRange([q.range[0],V.range[0]])},isParsedInstanceOfMatcherCall=(e,b)=>getAccessorValue(e.matcher)==="toBeInstanceOf"&&e.args.length===1&&isSupportedAccessor(e.args[0],b);var UtilName=(e=>(e.vi="vi",e.vitest="vitest",e))(UtilName||{}),DescribeAlias=(e=>(e.describe="describe",e.fdescribe="fdescribe",e.xdescribe="xdescribe",e))(DescribeAlias||{}),TestCaseName=(e=>(e.fit="fit",e.it="it",e.test="test",e.xit="xit",e.xtest="xtest",e.bench="bench",e))(TestCaseName||{}),HookName=(e=>(e.beforeAll="beforeAll",e.beforeEach="beforeEach",e.afterAll="afterAll",e.afterEach="afterEach",e))(HookName||{}),ModifierName=(e=>(e.to="to",e.have="have",e.not="not",e.rejects="rejects",e.resolves="resolves",e.returns="returns",e.branded="branded",e.asserts="asserts",e.constructorParameters="constructorParameters",e.parameters="parameters",e.thisParameter="thisParameter",e.guards="guards",e.instance="instance",e.items="items",e))(ModifierName||{}),EqualityMatcher=(e=>(e.toBe="toBe",e.toEqual="toEqual",e.toStrictEqual="toStrictEqual",e))(EqualityMatcher||{});function isClassOrFunctionType(e){return e.getCallSignatures().length>0?!0:e.getSymbol()?.getDeclarations()?.some(b=>n__default.isArrowFunction(b)||n__default.isClassDeclaration(b)||n__default.isClassExpression(b)||n__default.isFunctionDeclaration(b)||n__default.isFunctionExpression(b)||n__default.isMethodDeclaration(b)||n__default.isFunctionTypeNode(b))??!1}const ValidVitestFnCallChains=new Set(["beforeEach","beforeAll","afterEach","afterAll","it","it.skip","it.only","it.concurrent","it.sequential","it.todo","it.fails","it.extend","it.skipIf","it.runIf","it.each","it.skip.only","it.skip.concurrent","it.skip.sequential","it.skip.todo","it.skip.fails","it.only.skip","it.only.concurrent","it.only.sequential","it.only.todo","it.only.fails","it.concurrent.skip","it.concurrent.only","it.concurrent.sequential","it.concurrent.todo","it.concurrent.fails","it.sequential.skip","it.sequential.only","it.sequential.concurrent","it.sequential.todo","it.sequential.fails","it.todo.skip","it.todo.only","it.todo.concurrent","it.todo.seque
|
||
|
|
`+e.sourceCode.getText(Y)+";"):yield F.insertTextAfterRange([0,0],e.sourceCode.getText(Y)+`;
|
||
|
|
`)}});const $=Y.callee.property;$.name==="mock"&&q.push({messageId:"suggestReplaceMockWithDoMock",fix(F){return F.replaceText($,"doMock")}}),e.report({node:Y,messageId:"hoistedApisOnTop",suggest:q})}}}}}),RULE_NAME$13="consistent-test-it",h$3=(e,b,d)=>Y=>[Y.replaceText(e.type===utils.AST_NODE_TYPES.MemberExpression?e.object:e,S$5(b,d))];function S$5(e,b){return e===TestCaseName.fit?"test.only":e.startsWith("f")||e.startsWith("x")?e.charAt(0)+b:b}function T$3(e){return e===TestCaseName.test?TestCaseName.it:TestCaseName.test}const Se=createEslintRule({name:RULE_NAME$13,meta:{type:"suggestion",fixable:"code",docs:{description:"enforce using test or it but not both",recommended:!1},messages:{consistentMethod:"Prefer using {{ testFnKeyWork }} instead of {{ oppositeTestKeyword }}",consistentMethodWithinDescribe:"Prefer using {{ testKeywordWithinDescribe }} instead of {{ oppositeTestKeyword }} within describe"},schema:[{type:"object",properties:{fn:{type:"string",enum:[TestCaseName.test,TestCaseName.it]},withinDescribe:{type:"string",enum:[TestCaseName.test,TestCaseName.it]}},additionalProperties:!1}]},defaultOptions:[{}],create(e,b){const{fn:d,withinDescribe:Y}=b[0],q=d||TestCaseName.test,$=Y||d||TestCaseName.it,F=q===$?q:void 0;let V=0;return{ImportDeclaration(G){if(F==null||G.source.type!=="Literal"||G.source.value!=="vitest")return;const X=T$3(F);for(const z of G.specifiers)z.type==="ImportSpecifier"&&z.imported.type==="Identifier"&&z.local.name===z.imported.name&&z.local.name===X&&e.report({node:z,data:{testFnKeyWork:q,oppositeTestKeyword:X},messageId:"consistentMethod",fix:J=>{const te=G.specifiers.filter(Q=>Q.local.name!==X);if(te.length>0){const Q=te.map(Z=>Z.local.name).join(", "),se=G.specifiers.at(-1)?.range;return se?J.replaceTextRange([G.specifiers[0].range[0],se[1]],Q):null}return J.replaceText(z.local,F)}})},CallExpression(G){if(G.callee.type===utils.AST_NODE_TYPES.Identifier&&G.callee.name==="bench")return;const X=parseVitestFnCall(G,e);if(!X)return;if(X.type==="describe"){V++;return}const z=G.callee.type===utils.AST_NODE_TYPES.TaggedTemplateExpression?G.callee.tag:G.callee.type===utils.AST_NODE_TYPES.CallExpression?G.callee.callee:G.callee;if(X.type==="test"&&V===0&&!X.name.endsWith(q)){const J=T$3(q);e.report({node:G.callee,data:{testFnKeyWork:q,oppositeTestKeyword:J},messageId:"consistentMethod",fix:h$3(z,X.name,q)})}else if(X.type==="test"&&V>0&&!X.name.endsWith($)){const J=T$3($);e.report({messageId:"consistentMethodWithinDescribe",node:G.callee,data:{testKeywordWithinDescribe:$,oppositeTestKeyword:J},fix:h$3(z,X.name,$)})}},"CallExpression:exit"(G){isTypeOfVitestFnCall(G,e,["describe"])&&V--}}}}),RULE_NAME$12="consistent-vitest-vi",g$3=e=>e===UtilName.vi?UtilName.vitest:UtilName.vi,De=createEslintRule({name:RULE_NAME$12,meta:{type:"suggestion",fixable:"code",docs:{description:"enforce using vitest or vi but not both",recommended:!1},messages:{consistentUtil:"Prefer using {{ utilKeyword }} instead of {{ oppositeUtilKeyword }}"},schema:[{type:"object",properties:{fn:{type:"string",enum:[UtilName.vi,UtilName.vitest],default:UtilName.vi}},additionalProperties:!1}]},defaultOptions:[{fn:UtilName.vi}],create(e,b){const d=b[0].fn,Y=g$3(d);return{ImportDeclaration(q){if(!(q.source.type!==utils.AST_NODE_TYPES.Literal||q.source.value!=="vitest"))for(const $ of q.specifiers)$.type===utils.AST_NODE_TYPES.ImportSpecifier&&$.imported.type===utils.AST_NODE_TYPES.Identifier&&$.local.name===$.imported.name&&$.imported.name===Y&&e.report({node:$,messageId:"consistentUtil",data:{utilKeyword:d,oppositeUtilKeyword:Y},fix:F=>{const V=q.specifiers.filter(G=>G.local.name!==Y);if(V.length>0){const G=V.map(z=>z.local.name).join(", "),X=q.specifiers.at(-1)?.range;return X?F.replaceTextRange([q.specifiers[0].range[0],X[1]],G):null}return F.replaceText($.local,d)}})},CallExpression(q){if(parseVitestFnCall(q,e)?.type!==Y)return;const $=q.callee.type===utils.AST_NODE_TYPES.MemberExpression?q.callee.object:q.callee;e.report({node:$,data:{utilKeyword:d,oppositeUtilKeyword:Y},messageId:"consistentUtil",fix:F=>F.replaceText($,d)})}}}}),RULE
|
||
|
|
`);if(d.find(J=>J.type==="ImportNamespaceSpecifier"))return V.insertTextBefore(G.body[0],`import { ${$} } from 'vitest';
|
||
|
|
`);const X=d.find(J=>J.type==="ImportDefaultSpecifier");if(X)return V.insertTextAfter(X,`, { ${$} }`);const z=d[d.length-1];return V.insertTextAfter(z,`, ${$}`)}})}}}}),RULE_NAME$S="no-conditional-in-test",Je=createEslintRule({name:RULE_NAME$S,meta:{docs:{description:"disallow conditional tests",requiresTypeChecking:!1,recommended:!1},messages:{noConditionalInTest:"Remove conditional tests"},schema:[],type:"problem"},defaultOptions:[],create(e){return{IfStatement(b){b.parent?.parent?.parent?.type==="CallExpression"&&isTypeOfVitestFnCall(b.parent?.parent?.parent,e,["test","it"])&&e.report({messageId:"noConditionalInTest",node:b})}}}}),RULE_NAME$R="no-disabled-tests",Qe=createEslintRule({name:RULE_NAME$R,meta:{type:"suggestion",docs:{description:"disallow disabled tests",recommended:!1},messages:{missingFunction:"Test is missing function argument",pending:"Call to pending()",pendingSuite:"Call to pending() within test suite",pendingTest:"Call to pending() within test",disabledSuite:"Disabled test suite - if you want to skip a test suite temporarily, use .todo() instead",disabledTest:"Disabled test - if you want to skip a test temporarily, use .todo() instead"},schema:[]},defaultOptions:[],create(e){let b=0,d=0;return{CallExpression(Y){const q=parseVitestFnCall(Y,e);if(!q)return;q.type==="describe"&&b++,q.type==="test"&&(d++,Y.arguments.length<2&&q.members.every(F=>getAccessorValue(F)==="skip")&&e.report({messageId:"missingFunction",node:Y}));const $=q.members.find(F=>getAccessorValue(F)==="skip");(q.name.startsWith("x")||$!==void 0)&&e.report({messageId:q.type==="describe"?"disabledSuite":"disabledTest",node:$??q.head.node})},"CallExpression:exit"(Y){const q=parseVitestFnCall(Y,e);q&&(q.type==="describe"&&b--,q.type==="test"&&d--)},'CallExpression[callee.name="pending"]'(Y){const q=getScope(e,Y);resolveScope(q,"pending")||(d>0?e.report({messageId:"pendingTest",node:Y}):b>0?e.report({messageId:"pendingSuite",node:Y}):e.report({messageId:"pending",node:Y}))}}}}),RULE_NAME$Q="no-done-callback",P$1=(e,b,d)=>{if(b)return e.arguments[1];const Y=parseVitestFnCall(e,d);return Y?.type==="hook"&&e.arguments.length>=1?e.arguments[0]:Y?.type==="test"&&e.arguments.length>=2?e.arguments[1]:null},Xe=createEslintRule({name:RULE_NAME$Q,meta:{type:"suggestion",docs:{description:"disallow using a callback in asynchronous tests and hooks",recommended:!1},deprecated:!0,schema:[],messages:{noDoneCallback:"Return a promise instead of relying on callback parameter",suggestWrappingInPromise:"Wrap in `new Promise({{ callback }} => ...`",useAwaitInsteadOfCallback:"Use `await` instead of callback in async function"},hasSuggestions:!0},defaultOptions:[],create(e){return{CallExpression(b){const d=/\.each$|\.concurrent$/.test(getNodeName(b.callee)??"");if(d&&b.callee.type!==utils.AST_NODE_TYPES.TaggedTemplateExpression||e.sourceCode.getAncestors(b).some(F=>F.type!==utils.AST_NODE_TYPES.CallExpression||!isTypeOfVitestFnCall(F,e,["describe","test"])?!1:F.callee.type===utils.AST_NODE_TYPES.MemberExpression&&isSupportedAccessor(F.callee.property,"concurrent")))return;const Y=P$1(b,d,e),q=Number(d);if(!Y||!isFunction(Y)||Y.params.length!==1+q)return;const $=Y.params[q];if($.type!==utils.AST_NODE_TYPES.Identifier){e.report({node:$,messageId:"noDoneCallback"});return}if(Y.async){e.report({node:$,messageId:"useAwaitInsteadOfCallback"});return}e.report({node:b,messageId:"noDoneCallback",suggest:[{messageId:"suggestWrappingInPromise",data:{callback:$.name},fix(F){const{body:V,params:G}=Y,{sourceCode:X}=e,z=X.getFirstToken(V),J=X.getLastToken(V),[te]=G,Q=G[G.length-1],se=X.getTokenBefore(te);let Z=X.getTokenAfter(Q);if(Z?.value===","&&(Z=X.getTokenAfter(Z)),!z||!J||!se||!Z)throw new Error(`Unexpected null when attempting to fix ${e.filename} - please file an issue at https://github/veritem/eslint-plugin-vitest`);let ee=F.replaceText(te,"()");se.value==="("&&Z.value===")"&&(ee=F.removeRange([se.range[1],Z.range[0]]));let re=`new Promise(${$.name} => `,oe=")",ne=!0;return V.type===utils.AST_NODE_TYPES.BlockStatement&&(re=`return ${re}{`,oe+="}",ne=!1),[ee,ne?F.inse
|
||
|
|
|
||
|
|
`:`
|
||
|
|
`;return $.insertTextAfter(F,G)}})},m$2={0:()=>!0,1:x$1},y$1=()=>{let e=null;return{get prevNode(){return e.prevNode},set prevNode(b){e.prevNode=b},enter(){e={upper:e,prevNode:null}},exit(){e=e.upper}}},i=e=>(b,d)=>{let Y=b;if(Y.type===utils.AST_NODE_TYPES.ExpressionStatement){Y.expression.type===utils.AST_NODE_TYPES.AwaitExpression&&(Y=Y.expression.argument);const q=d.getFirstToken(Y);return q?.type===utils.AST_TOKEN_TYPES.Identifier&&q.value===e}return!1},A$1={0:()=>!0,1:i("afterAll"),2:i("afterEach"),3:i("beforeAll"),4:i("beforeEach"),5:i("describe"),6:i("expect"),7:i("expectTypeOf"),8:i("fdescribe"),9:i("fit"),10:i("it"),11:i("test"),12:i("xdescribe"),13:i("xit"),14:i("xtest")},l$1=(e,b,d)=>{let Y=e;const{sourceCode:q}=d;for(;Y.type===utils.AST_NODE_TYPES.LabeledStatement;)Y=Y.body;return Array.isArray(b)?b.some($=>l$1(Y,$,d)):A$1[b](Y,q)},N$2=(e,b,d)=>{const{configs:Y}=d,q=$=>m$2[$](e,b,d);for(let $=Y.length-1;$>=0;--$){const{prevStatementType:F,nextStatementType:V,paddingType:G}=Y[$];if(l$1(e,F,d)&&l$1(b,V,d))return q(G)}return q(0)},u=(e,b)=>{const{scopeInfo:d}=b;isValidParent(e?.parent.type)&&(d.prevNode&&N$2(d.prevNode,e,b),d.prevNode=e)},createPaddingRule=(e,b,d,Y=!1)=>createEslintRule({name:e,meta:{docs:{description:b},fixable:"whitespace",deprecated:Y,messages:{missingPadding:"expect blank line before this statement"},schema:[],type:"suggestion"},defaultOptions:[],create(q){const $={ruleContext:q,sourceCode:q.sourceCode??q.getSourceCode(),scopeInfo:y$1(),configs:d},{scopeInfo:F}=$;return{Program:F.enter,"Program:exit":F.exit,BlockStatement:F.enter,"BlockStatement:exit":F.exit,SwitchStatement:F.enter,"SwitchStatement:exit":F.exit,":statement":V=>u(V,$),SwitchCase(V){u(V,$),F.enter()},"SwitchCase:exit":F.exit}}}),RULE_NAME$g="padding-around-after-all-blocks",config$6=[{paddingType:PaddingType.Always,prevStatementType:StatementType.Any,nextStatementType:StatementType.AfterAllToken},{paddingType:PaddingType.Always,prevStatementType:StatementType.AfterAllToken,nextStatementType:StatementType.Any}],Ir=createPaddingRule(RULE_NAME$g,"Enforce padding around `afterAll` blocks",config$6),RULE_NAME$f="padding-around-after-each-blocks",config$5=[{paddingType:PaddingType.Always,prevStatementType:StatementType.Any,nextStatementType:StatementType.AfterEachToken},{paddingType:PaddingType.Always,prevStatementType:StatementType.AfterEachToken,nextStatementType:StatementType.Any}],yr=createPaddingRule(RULE_NAME$f,"Enforce padding around `afterEach` blocks",config$5),RULE_NAME$e="padding-around-before-all-blocks",config$4=[{paddingType:PaddingType.Always,prevStatementType:StatementType.Any,nextStatementType:StatementType.BeforeAllToken},{paddingType:PaddingType.Always,prevStatementType:StatementType.BeforeAllToken,nextStatementType:StatementType.Any}],Sr=createPaddingRule(RULE_NAME$e,"Enforce padding around `beforeAll` blocks",config$4),RULE_NAME$d="padding-around-before-each-blocks",config$3=[{paddingType:PaddingType.Always,prevStatementType:StatementType.Any,nextStatementType:StatementType.BeforeEachToken},{paddingType:PaddingType.Always,prevStatementType:StatementType.BeforeEachToken,nextStatementType:StatementType.Any}],Dr=createPaddingRule(RULE_NAME$d,"Enforce padding around `beforeEach` blocks",config$3),RULE_NAME$c="padding-around-describe-blocks",config$2=[{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}],Hr=createPaddingRule(RULE_NAME$c,"Enforce padding around `describe` blocks",config$2),RULE_NAME$b="padding-around-expect-groups",config$1=[{paddingType:PaddingType.Always,prevStatementType:StatementType.Any,nextStatementType:StatementType.ExpectToken},{paddingType:PaddingType.Always,prevStatementType:StatementType.ExpectToken,nextStatementType:StatementType.Any},{paddingType:PaddingType.Any,prevStatementType:StatementType.Ex
|