Skip to content

Commit

Permalink
refactor: separate cb hell to fns
Browse files Browse the repository at this point in the history
  • Loading branch information
yarastqt committed Dec 20, 2020
1 parent e1095d3 commit 5d423df
Showing 1 changed file with 59 additions and 58 deletions.
117 changes: 59 additions & 58 deletions packages/feature-flags-webpack-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,73 @@
import { Plugin, Compiler } from 'webpack'
import { Expression, CallExpression, Identifier, SpreadElement } from 'estree'
import { Compilation, Compiler, javascript } from 'webpack'

const featureFlagsFunctionName = 'isFeatureEnabled'
type PluginOptions = {
/**
* Function name for match
*
* @default 'isFeatureEnabled'
*/
isFeatureEnabledFnName: string
/**
* Object with flags
*/
flags: Record<string, any>
}

function isFeatureFlagFunction(expression: any) {
if (expression.callee.property) {
return expression.callee.property.name === featureFlagsFunctionName
class FeatureFlagsWebpackPlugin {
constructor(public options: PluginOptions) {
Object.assign(this.options, { isFeatureEnabledFnName: 'isFeatureEnabled' })
}
return expression.callee.name === featureFlagsFunctionName
}

function getFeatureProperties(expression: any) {
if (!expression || !expression.arguments.length) return []
return expression.arguments[0].properties
}
apply(compiler: Compiler) {
const { isFeatureEnabledFnName, flags } = this.options

function getFeatureFlag(properties: any) {
return properties.reduce((result: any, property: any) => {
const key = property.key.name
const value = property.value.value
result[key] = value
return result
}, {})
}
function onCallExpression(expression: Expression, parser: javascript.JavascriptParser) {
if (isFeatureFlagFunction(expression, isFeatureEnabledFnName)) {
const argument = expression.arguments[0]
if (isIdentifier(argument)) {
const isEnabled = flags[argument.name] !== undefined
const result = isEnabled ? parser.evaluate(true) : parser.evaluate(false)
if (result !== undefined) {
result.setRange(expression.range)
}
return result
}
}
return undefined
}

function isEnabledFlag(flag: any, options: any) {
return options.some(
(option: any) => option.value === flag.value && option.component === flag.component,
)
}
function onParseJavascript(parser: javascript.JavascriptParser) {
parser.hooks.evaluate
.for('CallExpression')
.tap('FeatureFlagsWebpackPlugin', (expression) => onCallExpression(expression, parser))
}

class FeatureFlagsWebpackPlugin extends Plugin {
options: any[]
function onThisCompilation(_compilation: Compilation, compilationParams: any) {
compilationParams.normalModuleFactory.hooks.parser
.for('javascript/auto')
.tap('FeatureFlagsWebpackPlugin', onParseJavascript)
}

constructor(options: any[]) {
super()
this.options = options || []
compiler.hooks.thisCompilation.tap('FeatureFlagsWebpackPlugin', onThisCompilation)
}
}

apply(compiler: Compiler) {
const options = this.options

compiler.hooks.thisCompilation.tap(
'FeatureFlagsWebpackPlugin',
(_, { normalModuleFactory }) => {
normalModuleFactory.hooks.parser
.for('javascript/auto')
.tap('FeatureFlagsWebpackPlugin', (parser) => {
// @ts-expect-error
const getTrue = () => parser.evaluate(true)
// @ts-expect-error
const getFalse = () => parser.evaluate(false)

parser.hooks.evaluate
.for('CallExpression')
.tap('FeatureFlagsWebpackPlugin', (expression) => {
if (!isFeatureFlagFunction(expression)) return
function isFeatureFlagFunction(
expression: Expression,
isFeatureEnabledFnName: string,
): expression is CallExpression {
// prettier-ignore
return (
expression.type === 'CallExpression'
&& expression.arguments.length > 0
&& expression.callee.type === 'Identifier'
&& expression.callee.name === isFeatureEnabledFnName
)
}

const properties = getFeatureProperties(expression)
const flag = getFeatureFlag(properties)
const isEnabled = isEnabledFlag(flag, options)
const result = isEnabled ? getTrue() : getFalse()
result.setRange(expression.range)
return result
})
})
},
)
}
function isIdentifier(expression: Expression | SpreadElement): expression is Identifier {
return expression.type === 'Identifier'
}

module.exports = FeatureFlagsWebpackPlugin

0 comments on commit 5d423df

Please sign in to comment.