Skip to content

Instantly share code, notes, and snippets.

@Mefistophell
Created July 24, 2024 11:32
Show Gist options
  • Save Mefistophell/07d63b44d69d38af9406bc59a35c3ec7 to your computer and use it in GitHub Desktop.
Save Mefistophell/07d63b44d69d38af9406bc59a35c3ec7 to your computer and use it in GitHub Desktop.

Revisions

  1. Mefistophell created this gist Jul 24, 2024.
    68 changes: 68 additions & 0 deletions decorator-metadata.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    // Another way is to use const serializables = Symbol();
    const serializables = new WeakMap<object, string[]>();

    type Context =
    | ClassAccessorDecoratorContext
    | ClassGetterDecoratorContext
    | ClassFieldDecoratorContext
    ;

    function serialize(_target: any, context: Context): void {
    if (context.static || context.private) {
    throw new Error("Can only serialize public instance members.")
    }
    if (typeof context.name !== "string") {
    throw new Error("Can only serialize string properties.");
    }

    // if Symbol used: const propNames = (context.metadata[serializables] as string[] | undefined) ??= [];

    let propNames = serializables.get(context.metadata || {});
    if (propNames === undefined) {
    serializables.set(context.metadata || {}, propNames = []);
    }
    propNames.push(context.name);
    }
    function jsonify(instance: object): string {

    // @ts-ignore
    const metadata = instance.constructor[Symbol.metadata];

    // if Symbol used: const propNames = metadata?.[serializables] as string[] | undefined;
    const propNames = metadata && serializables.get(metadata);
    if (!propNames) {
    throw new Error("No members marked with @serialize.");
    }
    const pairStrings = propNames.map((key: string) => {
    const strKey = JSON.stringify(key);
    const strValue = JSON.stringify((instance as any)[key]);
    return `${strKey}: ${strValue}`;
    });
    return `{ ${pairStrings.join(", ")} }`;
    }


    class Person {
    firstName: string;
    lastName: string;

    @serialize
    age: number

    @serialize
    get fullName() {
    return `${this.firstName} ${this.lastName}`;
    }
    toJSON() {
    return jsonify(this)
    }
    constructor(firstName: string, lastName: string, age: number) {
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    }
    }

    const person = new Person('Alice', 'Sofia', 4)

    console.log(person.toJSON())