Skip to content

Commit 73beb0f

Browse files
committed
Fix isOptimalHelper
Based on `resistor-color` # Fixes #50
1 parent e0be9bb commit 73beb0f

2 files changed

Lines changed: 95 additions & 23 deletions

File tree

src/analyzers/resistor-color-duo/ResistorColorDuoSolution.ts

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type MainExport = ReturnType<typeof extractExport>
2929

3030
const EXPECTED_METHOD = 'value'
3131
const EXPECTED_EXPORT = 'value'
32+
const PROBABLE_CONSTANT = 'COLORS'
3233

3334
export class MissingExpectedCall {
3435
constructor(public readonly methodName: string, public readonly reason: string) {}
@@ -54,9 +55,11 @@ type Issue = undefined
5455

5556
class Constant {
5657
public readonly name: string
58+
public readonly signature: string;
5759

58-
constructor(private readonly constant: Readonly<ProgramConstant>) {
60+
constructor(private readonly constant: Readonly<ProgramConstant>, source: Source) {
5961
this.name = (constant && isIdentifier(constant.id) && constant.id.name) || '<NO-CONSTANT-NAME>'
62+
this.signature = source.getOuter(constant.parent || constant)
6063
}
6164

6265
public get kind(): ProgramConstant['kind'] {
@@ -652,38 +655,96 @@ class Entry {
652655
return false
653656
}
654657

655-
public isOptimalHelper(func: ArrowFunctionExpression | FunctionExpression | MainMethod<string>, constant: Readonly<Constant>): boolean {
656-
if (func.body && func.body.type === AST_NODE_TYPES.BlockStatement && func.body.body && func.body.body[0].type === AST_NODE_TYPES.ReturnStatement) {
657-
func.body = func.body.body[0].argument
658+
public isOptimalHelper(func: Node, constant: Readonly<Constant>): boolean {
659+
const logger = getProcessLogger()
660+
661+
let body: Node | null
662+
let params: Parameter[] | null
663+
664+
switch(func.type) {
665+
case AST_NODE_TYPES.BlockStatement: {
666+
body = func.body[0]
667+
params = null
668+
break;
669+
}
670+
case AST_NODE_TYPES.ReturnStatement: {
671+
body = func.argument
672+
params = null
673+
break;
674+
}
675+
case AST_NODE_TYPES.CallExpression: {
676+
body = func
677+
params = null
678+
break;
679+
}
680+
case AST_NODE_TYPES.MemberExpression: {
681+
body = func
682+
params = null
683+
break;
684+
}
685+
case AST_NODE_TYPES.FunctionDeclaration: {
686+
body = func.body || null
687+
params = func.params
688+
break;
689+
}
690+
case AST_NODE_TYPES.ArrowFunctionExpression: {
691+
body = func.body || null
692+
params = func.params
693+
break;
694+
}
695+
case AST_NODE_TYPES.FunctionExpression: {
696+
body = func.body || null
697+
params = func.params
698+
break;
699+
}
700+
default: {
701+
logger.log(`~> the helper type ${func.type} is not processable`)
702+
return false
703+
}
704+
}
705+
706+
if (!params) {
707+
logger.log('~> could not get function parameters')
708+
return false
709+
}
710+
711+
if (body && body.type === AST_NODE_TYPES.BlockStatement && body.body && body.body[0].type === AST_NODE_TYPES.ReturnStatement) {
712+
body = body.body[0].argument
713+
}
714+
715+
if (!body) {
716+
return false
658717
}
659718

660719
if (constant.isOptimalArray) {
720+
logger.log('=> constant is optimal array')
721+
661722
// Only looking for:
662723
//
663724
// COLORS.indexOf(param)
664-
const { body } = func
665-
return body
666-
&& isCallExpression(body, constant.name, 'indexOf')
667-
&& func.params.length === 1
668-
&& isIdentifier(func.params[0])
725+
return isCallExpression(body, constant.name, 'indexOf')
726+
&& params.length === 1
727+
&& isIdentifier(params[0])
669728
&& body.arguments.length === 1
670-
&& isIdentifier(body.arguments[0], func.params[0].name)
729+
&& isIdentifier(body.arguments[0], params[0].name)
671730
|| false
672731
}
673732

674733
if (constant.isOptimalObject) {
734+
logger.log('=> constant is optimal object')
735+
675736
// Only looking for:
676737
//
677-
// COLORS[param]
678-
const { body } = func
679-
return body
680-
&& func.params.length === 1
681-
&& isIdentifier(func.params[0])
682-
&& isCallExpression(body, constant.name, func.params[0].name)
683-
&& body.callee.computed
738+
// REF_COLORS[param]
739+
return params.length === 1
740+
&& isIdentifier(params[0])
741+
&& constant.referencedSourceObjectName
742+
&& isMemberExpression(body, constant.referencedSourceObjectName, params[0].name)
743+
&& body.computed
684744
|| false
685745
}
686746

747+
logger.log(`~> constant is not optimal`)
687748
return false
688749
}
689750
}
@@ -694,6 +755,7 @@ export class ResistorColorDuoSolution {
694755
private mainMethod: Entry
695756
private mainExport: [NonNullable<MainExport[0]>, MainExport[1]]
696757
private fileConstants: ProgramConstants
758+
private mainConstant: Constant | undefined;
697759

698760
constructor(public readonly program: Program, source: string) {
699761
this.source = new Source(source)
@@ -704,6 +766,12 @@ export class ResistorColorDuoSolution {
704766
// All constants at the top level that are _not_ the main method
705767
this.fileConstants = findTopLevelConstants(program, ['let', 'const', 'var'])
706768
.filter((declaration): boolean => declaration && isIdentifier(declaration.id) && declaration.id.name !== EXPECTED_METHOD)
769+
770+
const expectedConstant = this.fileConstants.find((constant) => isIdentifier(constant.id, PROBABLE_CONSTANT)) ||
771+
// Or find the first array or object assignment
772+
this.fileConstants.find((constant) => constant.init && [AST_NODE_TYPES.ArrayExpression, AST_NODE_TYPES.ObjectExpression].indexOf(constant.init.type))
773+
774+
this.mainConstant = expectedConstant && new Constant(expectedConstant, this.source) || undefined
707775
}
708776

709777
public get entry(): Readonly<Entry> {
@@ -715,7 +783,7 @@ export class ResistorColorDuoSolution {
715783
}
716784

717785
public get hasOptimalEntry(): boolean {
718-
return this.entry.isOptimal(new Constant(this.fileConstants[0]), this.program)
786+
return this.entry.isOptimal(this.mainConstant, this.program)
719787
}
720788

721789
public get areFileConstantsConst(): boolean {

src/analyzers/resistor-color-duo/index.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,15 @@ export class ResistorColorDuoAnalyzer extends IsolatedAnalyzerImpl {
284284
// output.add(BETA_COMMENTARY_PREFIX())
285285
}
286286

287-
output.add(
288-
TIP_DESTRUCTURING_IN_PARAMETER({
289-
'parameter': solution.entry.parameterName
290-
})
291-
)
287+
if (solution.entry.hasOneMap || solution.entry.hasOneReduce) {
288+
// TODO: comment to guide them to the math-y way
289+
} else {
290+
output.add(
291+
TIP_DESTRUCTURING_IN_PARAMETER({
292+
'parameter': solution.entry.parameterName
293+
})
294+
)
295+
}
292296
}
293297

294298
// TODO optimize param

0 commit comments

Comments
 (0)