Skip to content

Commit 3ae833a

Browse files
committed
two-fer: detect and block stub throw implementations
1 parent 225bec8 commit 3ae833a

3 files changed

Lines changed: 52 additions & 2 deletions

File tree

src/analyzers/practice/two-fer/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import {
3636
import { extractNamedFunction } from '~src/extracts/extract_named_function'
3737
import { makeNoSourceOutput } from '~src/output/makeNoSourceOutput'
3838
import { makeParseErrorOutput } from '~src/output/makeParseErrorOutput'
39+
import { hasStubThrow } from '~src/analyzers/utils/extract_main_method'
40+
import { REMOVE_STUB_THROW } from '~src/comments/remove_stub_throw'
3941

4042
type ConditionalExpression = TSESTree.ConditionalExpression
4143
type IfStatement = TSESTree.IfStatement
@@ -82,19 +84,24 @@ export class TwoFerAnalyzer extends AnalyzerImpl {
8284
private program!: Program
8385
private source!: string
8486

85-
private mainMethod!: ExtractedFunction
87+
private mainMethod?: ExtractedFunction
8688

8789
protected async execute(input: Input): Promise<void> {
8890
const [parsed] = await this.parse(input)
8991

9092
this.program = parsed.program
9193
this.source = parsed.source
9294

93-
this.mainMethod = extractNamedFunction('twoFer', this.program)!
95+
this.mainMethod = extractNamedFunction('twoFer', this.program)
9496

9597
// Firstly we want to check that the structure of this solution is correct
9698
// and that there is nothing structural stopping it from passing the tests
9799
this.checkStructure()
100+
if (!this.mainMethod) return
101+
102+
if (hasStubThrow(this.mainMethod)) {
103+
this.disapprove(REMOVE_STUB_THROW())
104+
}
98105

99106
// Now we want to ensure that the method signature is sane and that it has
100107
// valid arguments

src/analyzers/utils/extract_main_method.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,41 @@ export function extractMainMethod<T extends string = string>(
7979

8080
return undefined
8181
}
82+
83+
84+
function isNewExpression(node: unknown): node is TSESTree.NewExpression {
85+
return (
86+
typeof node === 'object' &&
87+
node !== null &&
88+
(node as TSESTree.Node).type === 'NewExpression'
89+
)
90+
}
91+
92+
export function hasStubThrow(fn: { body?: TSESTree.Node }): boolean {
93+
if (!fn.body) return false
94+
if (fn.body.type !== 'BlockStatement') return false
95+
96+
const block = fn.body
97+
if (block.body.length !== 1) return false
98+
99+
const statement = block.body[0]
100+
if (statement.type !== 'ThrowStatement') return false
101+
102+
const argument: unknown = statement.argument
103+
if (!isNewExpression(argument)) return false
104+
105+
const callee = argument.callee
106+
if (callee.type !== 'Identifier') return false
107+
if (callee.name !== 'Error') return false
108+
109+
const [firstArg] = argument.arguments
110+
if (!firstArg || firstArg.type !== 'Literal') return false
111+
if (typeof firstArg.value !== 'string') return false
112+
113+
return (
114+
firstArg.value.includes('Please implement') ||
115+
firstArg.value.includes('Remove this line and implement') ||
116+
firstArg.value.includes('Implement the') ||
117+
firstArg.value.includes('Remove this statement and implement')
118+
)
119+
}

src/comments/remove_stub_throw.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { factory, CommentType } from '~src/comments/comment'
2+
3+
export const REMOVE_STUB_THROW = factory`
4+
Remove this placeholder throw statement. It is dead code.
5+
`('javascript.general.remove_stub_throw', CommentType.Actionable)

0 commit comments

Comments
 (0)