Skip to content

Instantly share code, notes, and snippets.

@nyteshade
Created December 16, 2023 09:04
Show Gist options
  • Save nyteshade/d540ea79443028466292ac9b32669f9c to your computer and use it in GitHub Desktop.
Save nyteshade/d540ea79443028466292ac9b32669f9c to your computer and use it in GitHub Desktop.
globalThis.Descriptor = class Descriptor {
static base(enumerable = true, configurable = true) {
return { enumerable, configurable }
}
static data(value, writable = true, { configurable, writable } = this.base()) {
return { value, enumerable, configurable, writable }
}
static accessor( getter, setter, store, { configurable, writable } = this.base()) {
if (Object.isObject(store)) {
// controversial
const injectStore = (fn) => {
let source = String(fn)
source = source.replace(/(?:get|set)(\s*)(\w+)?\((.*?)\)/, 'function$1$2($3)')
source = source.replace(/^(.*?)\{/, )
}
}
}
}
Object.defineProperties(Function, {
isClass: {
value(value) {
return String(value).includes('class')
},
configurable: true,
enumerable: true,
writable: true,
}
})
Object.defineProperties(Object, {
isObject: {
value(value, falseIfIsArray = false) {
if ((Array.isArray(value) && falseIfIsArray) || value instanceof Function) {
return false
}
return ((value !== null && typeof(value) === 'object') || value instanceof Object)
},
configurable: true,
enumerable: true,
writable: true,
},
copy: {
value(...sources) {
const prototype = Object.getPrototypeOf(sources?.[0] ?? {})
const target = Object.create(prototype)
return Object.copyTo(target, ...sources)
},
configurable: true,
enumerable: true,
writable: true,
},
copyTo: {
value(target, ...sources) {
if (!Object.isObject(target)) {
return null
}
sources.forEach(source => {
if (!source) {
return
}
const isArray = a => Array.isArray(a?.value)
const isObject = o => Object.isObject(o?.value)
const isRegExp = r =>
const arrayClone = a => (a?.map(element => {
if (Object.isObject(element)) return Object.copy(element)
if (Array.isArray(element)) return arrayClone(element)
}) ?? null)
const descriptors = (Object.descriptors(source)
.reduce((accumulator, [key, descriptor]) => {
if (isArray(descriptor)) {
accumulator[key] = { ...descriptor, value: arrayClone(descriptor.value) }
}
else if (isObject(descriptor)) {
accumulator[key] = { ...descriptor, value: Object.copy(descriptor.value) }
}
else {
accumulator[key] = descriptor
}
return accumulator
}, {})
)
Object.defineProperties(target, descriptors)
})
return target
}
},
descriptors: {
value(object, asObject = false, includeThis = false) {
const isClass = (value) => String(value?.constructor).includes('class')
function transform(value, isProto = false) {
const keys = Reflect.ownKeys(value)
return keys.reduce((accumulator, key) => {
const descriptor = Object.getOwnPropertyDescriptor(value, key)
if (asObject) {
accumulator[key] = descriptor
if (includeThis) {
accumulator[`${String(key)}:this`] = value
accumulator[`${String(key)}:isPrototype`] = isProto
}
}
else {
const entry = [key, descriptor]
if (includeThis) {
entry.push(value)
entry.push(isProto)
}
accumulator.push(entry)
}
return accumulator
}, asObject ? {} : [])
}
let descriptors = asObject ? {} : []
if (isClass(object) && object?.constructor?.prototype) {
const prototype = object.constructor.prototype
if (asObject)
descriptors = { ...descriptors, ...transform(prototype, true) }
else
descriptors = descriptors.concat(transform(prototype, true))
}
if (asObject)
descriptors = { ...descriptors, ...transform(object) }
else
descriptors = descriptors.concat(transform(object))
return descriptors
},
enumerable: true,
configurable: true,
writable: true,
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment