refactor: move arrow function handler logic to a dedicated utility function
Some checks failed
Publish to npm / quality (push) Failing after 20s
Publish to npm / publish (push) Has been skipped

This commit is contained in:
Astrian Zheng 2025-05-21 16:07:42 +10:00
parent 8f6b4a6cd9
commit fe046f4500
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
4 changed files with 102 additions and 66 deletions

View File

@ -137,7 +137,6 @@ export default (options: ComponentOptions) => {
utils.processTemplateMacros(rootElement, this, {
updateTextNode: this._updateTextNode.bind(this),
setupAttributeBinding: this._setupAttributeBinding.bind(this),
setupArrowFunctionHandler: this._setupArrowFunctionHandler.bind(this),
setupExpressionHandler: this._setupExpressionHandler.bind(this),
setupFunctionCallHandler: this._setupFunctionCallHandler.bind(this),
stateToElementsMap: this._stateToElementsMap,
@ -156,6 +155,7 @@ export default (options: ComponentOptions) => {
this._extractStatePathsFromExpression.bind(this),
states: this._states,
triggerFunc: this.triggerFunc.bind(this),
setupArrowFunctionHandler: utils.setupArrowFunctionHandler.bind(this),
})
}
@ -243,71 +243,6 @@ export default (options: ComponentOptions) => {
)
}
// Handle arrow function
private _setupArrowFunctionHandler(
element: Element,
eventName: string,
handlerValue: string,
) {
element.addEventListener(eventName, (event: Event) => {
try {
// Arrow function parsing
const splitted = handlerValue.split('=>')
if (splitted.length !== 2) {
throw new Error(`Invalid arrow function syntax: ${handlerValue}`)
}
const paramsStr = (() => {
if (splitted[0].includes('(')) return splitted[0].trim()
return `(${splitted[0].trim()})`
})()
const bodyStr = splitted[1].trim()
// Check if the function body is wrapped in {}
const isMultiline = bodyStr.startsWith('{') && bodyStr.endsWith('}')
// If it is a multiline function body, remove the outer braces
if (isMultiline) {
// Remove the outer braces
let bodyStr = handlerValue.split('=>')[1].trim()
bodyStr = bodyStr.substring(1, bodyStr.length - 1)
// Build code for multiline arrow function
const functionCode = `
return function${paramsStr} {
${bodyStr}
}
`
// Create context object
const context = this._createHandlerContext(event, element)
// Create and call function
const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event])
} else {
// Single line arrow function, directly return expression result
const functionCode = `
return function${paramsStr} {
return ${bodyStr}
}
`
// Create context object
const context = this._createHandlerContext(event, element)
// Create and call function
const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event])
}
} catch (err) {
console.error(
`Error executing arrow function handler: ${handlerValue}`,
err,
)
}
})
}
// Create handler context
private _createHandlerContext(event: Event, element: Element) {
// Basic context, including state

View File

@ -1,9 +1,11 @@
import parseTemplate from './parseTemplate'
import processTemplateMacros from './processTemplateMarco'
import triggerDomUpdates from './triggerDomUpdates'
import setupArrowFunctionHandler from './setupArrowFunctionHandler'
export default {
parseTemplate,
processTemplateMacros,
triggerDomUpdates,
setupArrowFunctionHandler,
}

View File

@ -13,6 +13,19 @@ export default function processTemplateMacros(
element: Element,
eventName: string,
handlerValue: string,
ops: {
createHandlerContext: (
event: Event,
element: Element,
) => {
states: Record<string, unknown>
stateToElementsMap: Record<string, Set<HTMLElement>>
statesListeners: Record<string, (value: unknown) => void>
setState: (keyPath: string, value: unknown) => void
getState: (keyPath: string) => unknown
triggerFunc: (eventName: string, ...args: unknown[]) => void
}
},
) => void
setupFunctionCallHandler: (
element: Element,
@ -153,6 +166,16 @@ export default function processTemplateMacros(
currentElementNode,
eventName,
handlerValue,
{
createHandlerContext: (_event: Event, _element: Element) => ({
states: options.states,
stateToElementsMap: options.stateToElementsMap,
statesListeners: options.stateListeners,
setState: context.setState.bind(context),
getState: context.getState.bind(context),
triggerFunc: options.triggerFunc.bind(context),
}),
},
)
} else if (handlerValue.includes('(') && handlerValue.includes(')')) {
// Handle function call: @click="increment(5)"

View File

@ -0,0 +1,76 @@
export default function setupArrowFunctionHandler(
element: Element,
eventName: string,
handlerValue: string,
ops: {
createHandlerContext: (
event: Event,
element: Element,
) => {
states: Record<string, unknown>
stateToElementsMap: Record<string, Set<HTMLElement>>
statesListeners: Record<string, (value: unknown) => void>
setState: (keyPath: string, value: unknown) => void
getState: (keyPath: string) => unknown
triggerFunc: (eventName: string, ...args: unknown[]) => void
}
},
) {
element.addEventListener(eventName, (event: Event) => {
try {
// Arrow function parsing
const splitted = handlerValue.split('=>')
if (splitted.length !== 2) {
throw new Error(`Invalid arrow function syntax: ${handlerValue}`)
}
const paramsStr = (() => {
if (splitted[0].includes('(')) return splitted[0].trim()
return `(${splitted[0].trim()})`
})()
const bodyStr = splitted[1].trim()
// Check if the function body is wrapped in {}
const isMultiline = bodyStr.startsWith('{') && bodyStr.endsWith('}')
// If it is a multiline function body, remove the outer braces
if (isMultiline) {
// Remove the outer braces
let bodyStr = handlerValue.split('=>')[1].trim()
bodyStr = bodyStr.substring(1, bodyStr.length - 1)
// Build code for multiline arrow function
const functionCode = `
return function${paramsStr} {
${bodyStr}
}
`
// Create context object
const context = ops.createHandlerContext(event, element)
// Create and call function
const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event])
} else {
// Single line arrow function, directly return expression result
const functionCode = `
return function${paramsStr} {
return ${bodyStr}
}
`
// Create context object
const context = ops.createHandlerContext(event, element)
// Create and call function
const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event])
}
} catch (err) {
console.error(
`Error executing arrow function handler: ${handlerValue}`,
err,
)
}
})
}