Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide access to custom EnumOptions, EnumValueOptions, and OneofOptions by utiliting WeakMap #537

Open
jcready opened this issue May 17, 2023 · 0 comments

Comments

@jcready
Copy link
Contributor

jcready commented May 17, 2023

Similar to #306 (comment) it seems like it should be possible to store and retrieve custom EnumOptions and EnumValueOptions by having the generated code hold onto a reference to the custom options in a WeakMap.

// generated code
import { registerEnumOptions } from "@protobuf-ts/runtime";

export enum ExampleEnum {
    /**
     * @generated from protobuf enum value: EXAMPLE = 0;
     */
    EXAMPLE = 0,
};

registerEnumOptions(
    ExampleEnum,
    {
        options: {
            "foo.bar": {
                "baz_qux": 123,
            }
        },
        valueOptions: {
            "EXAMPLE": { // Use enum "label" instead of "value" to avoid collisions with `allow_alias`
                "my.example" {
                    "enum_value_option": true,
                },
            },
        },
    }
);
// usage
import { readEnumOption, readEnumValueOption } from "@protobuf-ts/runtime";
import { ExampleEnum } from "../generated/code";

let enumOption = readEnumOption(ExampleEnum, "foo.bar", OptionalMessageType);
//  { bazQux: 123 }
let enumValueOption = readEnumValueOption(ExampleEnum, ExampleEnum[ExampleEnum.EXAMPLE], "my.example", OptionalMessageType);
//  { enumValueOption: true }
// @protobuf-ts/runtime implementation
interface EnumOptions {
    options?: JsonObject;
    valueOptions?: Record<string, JsonObject | undefined>;
}

const enumOptionsMap = new WeakMap<object, EnumOptions>();

export function registerEnumOptions(enum: object, options: EnumOptions): void {
    enumOptionsMap.set(enum, options);
}

export function readEnumOption<T extends object>(enum: object, extensionName: string): JsonValue | undefined;
export function readEnumOption<T extends object>(enum: object, extensionName: string, extensionType: IMessageType<T>): T | undefined;
export function readEnumOption<T extends object>(enum: object, extensionName: string, extensionType?: IMessageType<T>): T | JsonValue | undefined {
    const optionVal = enumOptionsMap.get(enum)?.options?.[extensionName];
    if (optionVal === undefined) {
        return optionVal;
    }
    return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}

export function readEnumValueOption<T extends object>(enum: object, enumValueName: string, extensionName: string): JsonValue | undefined;
export function readEnumValueOption<T extends object>(enum: object, enumValueName: string, extensionName: string, extensionType: IMessageType<T>): T | undefined;
export function readEnumValueOption<T extends object>(enum: object, enumValueName: string, extensionName: string, extensionType?: IMessageType<T>): T | JsonValue | undefined {
    const optionVal = enumOptionsMap.get(enum)?.valueOptions?.[extensionName];
    if (optionVal === undefined) {
        return optionVal;
    }
    return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}

This same method could be used to provide access to OneofOptions as well:

// generated code
registerOneofOptions(ExampleMessageType, 'my_oneof_name', { ...JsonObjectOptions });

// usage
const myOneofOptions = readOneofOption(ExampleMessageType, 'my_oneof_name', OptionalMessageType);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant