diff --git a/src/analyzers/practice/two-fer/index.ts b/src/analyzers/practice/two-fer/index.ts index 6203d186..6466746d 100644 --- a/src/analyzers/practice/two-fer/index.ts +++ b/src/analyzers/practice/two-fer/index.ts @@ -36,6 +36,8 @@ import { import { extractNamedFunction } from '~src/extracts/extract_named_function' import { makeNoSourceOutput } from '~src/output/makeNoSourceOutput' import { makeParseErrorOutput } from '~src/output/makeParseErrorOutput' +import { hasStubThrow } from '~src/analyzers/utils/extract_main_method' +import { REMOVE_STUB_THROW } from '~src/comments/remove_stub_throw' type ConditionalExpression = TSESTree.ConditionalExpression type IfStatement = TSESTree.IfStatement @@ -82,7 +84,7 @@ export class TwoFerAnalyzer extends AnalyzerImpl { private program!: Program private source!: string - private mainMethod!: ExtractedFunction + private mainMethod?: ExtractedFunction protected async execute(input: Input): Promise { const [parsed] = await this.parse(input) @@ -90,11 +92,16 @@ export class TwoFerAnalyzer extends AnalyzerImpl { this.program = parsed.program this.source = parsed.source - this.mainMethod = extractNamedFunction('twoFer', this.program)! + this.mainMethod = extractNamedFunction('twoFer', this.program) // Firstly we want to check that the structure of this solution is correct // and that there is nothing structural stopping it from passing the tests this.checkStructure() + if (!this.mainMethod) return + + if (hasStubThrow(this.mainMethod)) { + this.disapprove(REMOVE_STUB_THROW()) + } // Now we want to ensure that the method signature is sane and that it has // valid arguments diff --git a/src/analyzers/utils/extract_main_method.ts b/src/analyzers/utils/extract_main_method.ts index 6232d55b..50907136 100644 --- a/src/analyzers/utils/extract_main_method.ts +++ b/src/analyzers/utils/extract_main_method.ts @@ -79,3 +79,41 @@ export function extractMainMethod( return undefined } + + +function isNewExpression(node: unknown): node is TSESTree.NewExpression { + return ( + typeof node === 'object' && + node !== null && + (node as TSESTree.Node).type === 'NewExpression' + ) +} + +export function hasStubThrow(fn: { body?: TSESTree.Node }): boolean { + if (!fn.body) return false + if (fn.body.type !== 'BlockStatement') return false + + const block = fn.body + if (block.body.length !== 1) return false + + const statement = block.body[0] + if (statement.type !== 'ThrowStatement') return false + + const argument: unknown = statement.argument + if (!isNewExpression(argument)) return false + + const callee = argument.callee + if (callee.type !== 'Identifier') return false + if (callee.name !== 'Error') return false + + const [firstArg] = argument.arguments + if (!firstArg || firstArg.type !== 'Literal') return false + if (typeof firstArg.value !== 'string') return false + + return ( + firstArg.value.includes('Please implement') || + firstArg.value.includes('Remove this line and implement') || + firstArg.value.includes('Implement the') || + firstArg.value.includes('Remove this statement and implement') + ) +} diff --git a/src/comments/remove_stub_throw.ts b/src/comments/remove_stub_throw.ts new file mode 100644 index 00000000..616eeb63 --- /dev/null +++ b/src/comments/remove_stub_throw.ts @@ -0,0 +1,5 @@ +import { factory, CommentType } from '~src/comments/comment' + +export const REMOVE_STUB_THROW = factory` +Remove this placeholder throw statement. It is dead code. +`('javascript.general.remove_stub_throw', CommentType.Actionable)