use symbol.metadata

This commit is contained in:
Rowan 2025-05-18 21:42:39 -05:00
parent 6dc5d9ebed
commit cf3bdfba48
5 changed files with 30 additions and 40 deletions

9
package-lock.json generated
View file

@ -8,6 +8,9 @@
"name": "serde",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@tsmetadata/polyfill": "^1.1.3"
},
"devDependencies": {
"esbuild": "^0.25.4",
"typescript": "^5.8.3"
@ -438,6 +441,12 @@
"node": ">=18"
}
},
"node_modules/@tsmetadata/polyfill": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@tsmetadata/polyfill/-/polyfill-1.1.3.tgz",
"integrity": "sha512-uSRn4aPO4F3wlSG/cPCAvclF9Sxf01OizWfWbSoSYsSHAK8LnYdua9iJAm7v2ePUrGWMP4ZCn9QjniZEKZHyFg==",
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",

View file

@ -32,5 +32,8 @@
"devDependencies": {
"esbuild": "^0.25.4",
"typescript": "^5.8.3"
},
"dependencies": {
"@tsmetadata/polyfill": "^1.1.3"
}
}

View file

@ -1,56 +1,33 @@
import { ContainerOptions, PropertyOptions, SerdeOptions } from './options'
import { GlobalRegistry, Registry } from './registry'
export const Serde = Symbol('Serde')
function decorateContainer(options: ContainerOptions, constructor: any) {
if (constructor[Serde] == null) {
constructor[Serde] = new SerdeOptions(constructor, options)
} else {
constructor[Serde].options = options
}
return constructor
function decorateContainer(target: any, context: any, options: ContainerOptions) {
const meta = context.metadata
const serde = (meta.serde || new SerdeOptions(target))
serde.options = options
meta.serde = serde
}
function decorateProperty(options: PropertyOptions, target: any, property: PropertyKey) {
let constructor: any
if (typeof target === 'function') {
constructor = target
} else {
constructor = target.constructor
}
if (constructor[Serde] == null) {
constructor[Serde] = SerdeOptions.from(target)
}
constructor[Serde].properties.set(property, options)
return target
function decorateProperty(target: any, context: any, options: PropertyOptions) {
const meta = context.metadata
const serde = (meta.serde || new SerdeOptions(target))
serde.properties.set(context, options)
meta.serde = serde
}
export function serde(options: ContainerOptions | PropertyOptions) {
return function(target: any, property?: PropertyKey) {
if (property != null) {
return decorateProperty(options as PropertyOptions, target, property)
return function(target: any, context: any) {
if (context != null) {
decorateProperty(target, context, options as PropertyOptions)
} else {
return decorateContainer(options, target)
decorateContainer(target, context, options as ContainerOptions)
}
}
}
export function getMetadata(value: any) {
return value[Serde]
}
export function register(registry: Registry = GlobalRegistry) {
return function(target: any) {
if (target[Serde] == null) {
target[Serde] = SerdeOptions.from(target)
}
return function(target: any, _context: any) {
registry.add(target)
return target
}
}

View file

@ -1,5 +1,4 @@
import { IterableSerializer, ObjectSerializer, Serializable, Serializer } from './interface'
import { Serde } from '../decorator'
import { SerdeOptions, Stage } from '../options'
import { ifNull, isFunction, isIterable, isPlainObject, Nullable, orElse } from '../utils'
@ -41,7 +40,7 @@ function serializeIter<T, V extends Iterable<any>>(serializer: IterableSerialize
}
function defaultOptions(value: any) {
return value.constructor[Serde]
return value.constructor[Symbol.metadata]
}
// dispatches in the order of serializeType -> serializeAny -> throw TypeError

View file

@ -1,3 +1,5 @@
import '@tsmetadata/polyfill'
export * from './interface'
export * from './mixin'
export * from './impl'