From fc939aa82fb33ac158954adec309d26db2752fed Mon Sep 17 00:00:00 2001 From: MeesterDev Date: Wed, 2 Jul 2025 11:24:42 +0200 Subject: [PATCH] Make static properties/methods accessible through the runtime object built from the class --- src/component.ts | 7 ++++--- src/utils.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/component.ts b/src/component.ts index f49e0c9..456466e 100644 --- a/src/component.ts +++ b/src/component.ts @@ -1,6 +1,6 @@ import { defineComponent, type ComponentCustomOptions, type MethodOptions } from 'vue'; import { obtainSlot } from './slot' -import { getSuperSlot, getProviderFunction, optionNullableClassDecorator } from './utils' +import { getSuperSlot, getProviderFunction, optionNullableClassDecorator, assignStaticClassProperties } from './utils' import { build as optionSetup } from './option/setup' import { build as optionComputed } from './option/computed' import { build as optionData } from './option/data' @@ -31,7 +31,7 @@ function componentOptionFactory(cons: VueCons, extend?: any) { optionRef(cons, optionBuilder)//after Computed optionAccessor(cons, optionBuilder) optionMethodsAndHooks(cons, optionBuilder)//the last one - const raw = { + const raw: any = { name: cons.name, setup: optionBuilder.setup, data() { @@ -51,7 +51,8 @@ function componentOptionFactory(cons: VueCons, extend?: any) { ...optionBuilder.hooks, extends: extend } - return raw as any + assignStaticClassProperties(cons, raw); + return raw } type ComponentOption = { diff --git a/src/utils.ts b/src/utils.ts index 51281a8..cd3c4c0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -128,3 +128,32 @@ export function optionNullableClassDecorator(handler: { (cons: VueCons, optio return decorator } +export function assignStaticClassProperties(source: T, target: any) { + // keep track of things we've assigned (e.g. overridden variables in child class) + const previouslyAssigned: Record = {}; + + while (source !== Base) { + const classObject = source; + for (const property of Object.getOwnPropertyNames(classObject)) { + if (property === 'prototype' || property === 'name' || property === 'length') { + continue; + } + if ((property in target) && !(property in previouslyAssigned)) { + console.warn(`Property/method ${property} of ${classObject.name} is not supported for static access, as it conflicts with property names in the underlying Vue object.`); + continue; + } + previouslyAssigned[property] = true; + if (typeof (classObject as any)[property] === 'function') { + target[property] = (...args: unknown[]): unknown => { + return (classObject as any)[property].apply(classObject, args); + } + } else { + target[property] = new Proxy(classObject, { + get(target: any, prop) { return target[prop] }, + set(target: any, prop, value) { target[prop] = value; return true; }, + }); + } + } + source = Object.getPrototypeOf(classObject); + } +}