Add Biome for lint and code quality check #2

Merged
Astrian merged 15 commits from dev into main 2025-05-16 10:18:55 +00:00
2 changed files with 41 additions and 47 deletions
Showing only changes of commit fcbee7c0b2 - Show all commits

View File

@ -19,10 +19,7 @@
"linter": { "linter": {
"enabled": true, "enabled": true,
"rules": { "rules": {
"recommended": true, "recommended": true
"suspicious": {
"noExplicitAny": "off"
}
} }
}, },
"javascript": { "javascript": {

View File

@ -1,6 +1,6 @@
interface CustomElement extends HTMLElement { interface CustomElement extends HTMLElement {
setState(key_path: string, value: any): void setState(key_path: string, value: unknown): void
getState(key_path: string): any getState(key_path: string): unknown
} }
interface ComponentOptions { interface ComponentOptions {
@ -14,9 +14,9 @@ interface ComponentOptions {
oldValue: string, oldValue: string,
newValue: string, newValue: string,
) => void ) => void
states?: Record<string, any> states?: Record<string, unknown>
statesListeners?: { [key: string]: (value: any) => void } statesListeners?: { [key: string]: (value: unknown) => void }
funcs?: { [key: string]: (...args: any[]) => void } funcs?: { [key: string]: (...args: unknown[]) => void }
} }
export default (options: ComponentOptions) => { export default (options: ComponentOptions) => {
@ -35,10 +35,10 @@ export default (options: ComponentOptions) => {
componentRegistry.set(tag, options) componentRegistry.set(tag, options)
class CustomElementImpl extends HTMLElement { class CustomElementImpl extends HTMLElement {
private _states: Record<string, any> = {} private _states: Record<string, unknown> = {}
private _stateToElementsMap: Record<string, Set<HTMLElement>> = {} private _stateToElementsMap: Record<string, Set<HTMLElement>> = {}
private _currentRenderingElement: HTMLElement | null = null private _currentRenderingElement: HTMLElement | null = null
private _statesListeners: Record<string, (...args: any[]) => void> = {} private _statesListeners: Record<string, (...args: unknown[]) => void> = {}
private _textBindings: Array<{ private _textBindings: Array<{
node: Text node: Text
expr: string expr: string
@ -66,7 +66,7 @@ export default (options: ComponentOptions) => {
this._states = new Proxy( this._states = new Proxy(
{ ...(states || {}) }, { ...(states || {}) },
{ {
set: (target: Record<string, any>, keyPath: string, value: any) => { set: (target: Record<string, unknown>, keyPath: string, value: unknown) => {
const valueRoute = keyPath.split('.') const valueRoute = keyPath.split('.')
let currentTarget = target let currentTarget = target
for (const i in valueRoute) { for (const i in valueRoute) {
@ -74,10 +74,9 @@ export default (options: ComponentOptions) => {
if (Number.parseInt(i) === valueRoute.length - 1) { if (Number.parseInt(i) === valueRoute.length - 1) {
currentTarget[key] = value currentTarget[key] = value
} else { } else {
if (!currentTarget[key]) { if (!currentTarget[key])
currentTarget[key] = {} currentTarget[key] = {}
} currentTarget = currentTarget[key] as Record<string, unknown>
currentTarget = currentTarget[key]
} }
} }
// trigger dom updates // trigger dom updates
@ -97,7 +96,7 @@ export default (options: ComponentOptions) => {
return true return true
}, },
get: (target: Record<string, any>, keyPath: string) => { get: (target: Record<string, unknown>, keyPath: string) => {
// collect state dependencies // collect state dependencies
if (this._currentRenderingElement) { if (this._currentRenderingElement) {
if (!this._stateToElementsMap[keyPath]) if (!this._stateToElementsMap[keyPath])
@ -116,7 +115,7 @@ export default (options: ComponentOptions) => {
if (!currentTarget[key]) if (!currentTarget[key])
currentTarget[key] = {} currentTarget[key] = {}
currentTarget = currentTarget[key] currentTarget = currentTarget[key] as Record<string, unknown>
} }
return undefined return undefined
}, },
@ -205,7 +204,7 @@ export default (options: ComponentOptions) => {
} }
private _updateElement(element: HTMLElement) { private _updateElement(element: HTMLElement) {
const renderFunction = (element as any)._renderFunction const renderFunction = (element as { _renderFunction?: () => string | Node })._renderFunction
if (renderFunction) { if (renderFunction) {
// Set rendering context // Set rendering context
this._currentRenderingElement = element this._currentRenderingElement = element
@ -350,11 +349,11 @@ export default (options: ComponentOptions) => {
eventName, eventName,
handlerValue, handlerValue,
) )
} else if (typeof (this as any)[handlerValue] === 'function') { } else if (typeof (this as Record<string, unknown>)[handlerValue] === 'function') {
// Handle method reference: @click="handleClick" // Handle method reference: @click="handleClick"
currentElementNode.addEventListener( currentElementNode.addEventListener(
eventName, eventName,
(this as any)[handlerValue].bind(this), ((this as unknown as Record<string, (...args: unknown[]) => void>)[handlerValue]).bind(this),
) )
} else { } else {
// Handle simple expression: @click="count++" or @input="name = $event.target.value" // Handle simple expression: @click="count++" or @input="name = $event.target.value"
@ -425,14 +424,13 @@ export default (options: ComponentOptions) => {
}) })
// Add event listener for state changes // Add event listener for state changes
this._statesListeners[expr] = (newValue: any) => { this._statesListeners[expr] = (newValue: unknown) => {
if (element instanceof HTMLInputElement) { if (element instanceof HTMLInputElement)
element.value = newValue element.value = newValue as string
} else { else
element.setAttribute('data-laterano-connect', String(newValue)) element.setAttribute('data-laterano-connect', String(newValue))
} }
} }
}
// Handle condition rendering (%if macro) // Handle condition rendering (%if macro)
private _setupConditionRendering(element: Element, expr: string) { private _setupConditionRendering(element: Element, expr: string) {
@ -482,8 +480,8 @@ export default (options: ComponentOptions) => {
// Store current rendered items // Store current rendered items
const renderedItems: Array<{ const renderedItems: Array<{
element: Element element: Element
key: any key: unknown
data: any data: unknown
index: number index: number
}> = [] }> = []
@ -620,10 +618,10 @@ export default (options: ComponentOptions) => {
// Recursively process the element and its children, applying the item context // Recursively process the element and its children, applying the item context
private _processElementWithItemContext( private _processElementWithItemContext(
element: Element, element: Element,
itemContext: Record<string, any>, itemContext: Record<string, unknown>,
) { ) {
// 1. Store the item context of the element so that subsequent updates can find it // 1. Store the item context of the element so that subsequent updates can find it
; (element as any)._itemContext = itemContext ; (element as { _itemContext?: Record<string, unknown> })._itemContext = itemContext
// 2. Process bindings in text nodes // 2. Process bindings in text nodes
const processTextNodes = (node: Node) => { const processTextNodes = (node: Node) => {
@ -768,7 +766,7 @@ export default (options: ComponentOptions) => {
private _setupNestedListRendering( private _setupNestedListRendering(
element: Element, element: Element,
expr: string, expr: string,
parentItemContext: Record<string, any>, parentItemContext: Record<string, unknown>,
) { ) {
// Similar to _setupListRendering, but applies to nested situations // Similar to _setupListRendering, but applies to nested situations
// Parse the expression (e.g., "subItem in item.subItems") // Parse the expression (e.g., "subItem in item.subItems")
@ -837,11 +835,11 @@ export default (options: ComponentOptions) => {
// Evaluate expressions using the item context // Evaluate expressions using the item context
private _evaluateExpressionWithItemContext( private _evaluateExpressionWithItemContext(
expression: string, expression: string,
itemContext: Record<string, any>, itemContext: Record<string, unknown>,
index?: number, index?: number,
itemVar?: string, itemVar?: string,
indexVar?: string, indexVar?: string,
): any { ): unknown {
try { try {
// Check if the expression directly references the item variable // Check if the expression directly references the item variable
if (itemVar && expression === itemVar) { if (itemVar && expression === itemVar) {
@ -857,7 +855,7 @@ export default (options: ComponentOptions) => {
for (const part of parts) { for (const part of parts) {
if (value === undefined || value === null) if (value === undefined || value === null)
return undefined return undefined
value = value[part] value = (value as { [key: string]: unknown})[part]
} }
return value return value
@ -911,7 +909,7 @@ export default (options: ComponentOptions) => {
} }
} }
private _evaluateExpression(expression: string): any { private _evaluateExpression(expression: string): unknown {
try { try {
// get the state keys and values // get the state keys and values
if (this._states[expression] !== undefined) if (this._states[expression] !== undefined)
@ -1012,12 +1010,12 @@ export default (options: ComponentOptions) => {
private _createHandlerContext(event: Event, element: Element) { private _createHandlerContext(event: Event, element: Element) {
// Basic context, including state // Basic context, including state
const context: { const context: {
[key: string]: any [key: string]: unknown
$event: Event $event: Event
$el: Element $el: Element
this: CustomElementImpl // Provide reference to the component instance this: CustomElementImpl // Provide reference to the component instance
setState: (keyPath: string, value: any) => void setState: (keyPath: string, value: unknown) => void
getState: (keyPath: string) => any getState: (keyPath: string) => unknown
} = { } = {
...this._states, ...this._states,
$event: event, $event: event,
@ -1032,10 +1030,10 @@ export default (options: ComponentOptions) => {
// (name) => { // (name) => {
for (const name of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) for (const name of Object.getOwnPropertyNames(Object.getPrototypeOf(this)))
if ( if (
typeof (this as any)[name] === 'function' && typeof (this as Record<string, unknown>)[name] === 'function' &&
name !== 'constructor' name !== 'constructor'
) )
context[name] = (this as any)[name].bind(this) context[name] = (this as unknown as Record<string, (...args: unknown[]) => void>)[name].bind(this)
return context return context
} }
@ -1147,16 +1145,15 @@ export default (options: ComponentOptions) => {
} }
// Get nested state value // Get nested state value
private _getNestedState(path: string): any { private _getNestedState(path: string): unknown {
// Handle nested paths, such as "profile.name" // Handle nested paths, such as "profile.name"
const parts = path.split('.') const parts = path.split('.')
let result = this._states let result = this._states
for (const part of parts) { for (const part of parts) {
if (result === undefined || result === null) { if (result === undefined || result === null)
return undefined return undefined
} result = (result as { [key: string]: Record<string, unknown> })[part]
result = result[part]
} }
return result return result
@ -1183,23 +1180,23 @@ export default (options: ComponentOptions) => {
} }
// state manager // state manager
setState(keyPath: string, value: any) { setState(keyPath: string, value: unknown) {
this._states[keyPath] = value this._states[keyPath] = value
} }
getState(keyPath: string): any { getState(keyPath: string): unknown {
const parts = keyPath.split('.') const parts = keyPath.split('.')
let result = this._states let result = this._states
for (const part of parts) { for (const part of parts) {
if (result === undefined || result === null) if (result === undefined || result === null)
return undefined return undefined
result = result[part] result = (result as { [key: string]: Record<string, unknown> })[part]
} }
return result return result
} }
// function trigger // function trigger
triggerFunc(eventName: string, ...args: any[]) { triggerFunc(eventName: string, ...args: unknown[]) {
funcs?.[eventName]?.call(this, ...args) funcs?.[eventName]?.call(this, ...args)
} }
} }