Repository: pyscript/pyscript
File: pyscriptjs/src/plugin.ts (TypeScript)

Code before:
            this.shadow = this.attachShadow({ mode: 'open' });
            this.wrapper = document.createElement('slot');
            this.shadow.appendChild(this.wrapper);
            this.originalInnerHTML = this.innerHTML;
            this.pyElementInstance = pyElementClass(this);
        }

        connectedCallback() {
            const innerHTML = this.pyElementInstance.connect();
            if (typeof innerHTML === 'string') this.innerHTML = innerHTML;
        }
    }

    customElements.define(tag, ProxyCustomElement);
}

// Members of py-config in plug that we want to validate must be one of these types
type BaseConfigObject = string | boolean | number;

/**
 * Validate that parameter the user provided to py-config conforms to the specified validation function;
 * if not, throw an error explaining the bad value.
 * This is the most generic validation function; other validation functions for common situations follow
 * @param options.config - The (extended) AppConfig object from py-config
 * @param {string} options.name - The name of the key in py-config to be checked
 * @param {(b:BaseConfigObject) => boolean} options.validator - the validation function used to test the user-supplied value
 * @param {BaseConfigObject} options.defaultValue - The default value for this parameter, if none is provided
 * @param {string} [options.hintMessage] - The message to show in a user error if the supplied value isn't valid
 */
export function validateConfigParameter(options: {
    config: AppConfig;
    name: string;
    validator: (b: BaseConfigObject) => boolean;
    defaultValue: BaseConfigObject;
    hintMessage?: string;
}) {
    //Validate that the default value is acceptable, at runtime
    if (!options.validator(options.defaultValue)) {
        throw Error(
            `Default value ${JSON.stringify(options.defaultValue)} for ${options.name} is not a valid argument, ` +
                `according to the provided validator function. ${options.hintMessage ? options.hintMessage : ''}`,
        );
    }

    const value = options.config[options.name] as BaseConfigObject;
    if (value !== undefined && !options.validator(value)) {
        //Use default hint message if none is provided:
        const hintOutput = `Invalid value ${JSON.stringify(value)} for config.${options.name}. ${
            options.hintMessage ? options.hintMessage : ''
        }`;
        throw new UserError(ErrorCode.BAD_CONFIG, hintOutput);

Review comment (suggestion):
Is `@param {string} options.name` the correct way of specifying params in the docs?

I ask since -- in other places, for example: `@param filePath` is written i.e. without the type. And name of the variable is written first. The above example I gave is present in `fetchJSPlugin` function in `main.ts`

Not sure what the best standards are, but wanted to highlight regardless...

Code after:
            this.shadow = this.attachShadow({ mode: 'open' });
            this.wrapper = document.createElement('slot');
            this.shadow.appendChild(this.wrapper);
            this.originalInnerHTML = this.innerHTML;
            this.pyElementInstance = pyElementClass(this);
        }

        connectedCallback() {
            const innerHTML = this.pyElementInstance.connect();
            if (typeof innerHTML === 'string') this.innerHTML = innerHTML;
        }
    }

    customElements.define(tag, ProxyCustomElement);
}

// Members of py-config in plug that we want to validate must be one of these types
type BaseConfigObject = string | boolean | number | undefined;

/**
 * Validate that parameter the user provided to py-config conforms to the specified validation function;
 * if not, throw an error explaining the bad value. If no value is provided, set the parameter
 * to the provided default value
 * This is the most generic validation function; other validation functions for common situations follow
 * @param options.config - The (extended) AppConfig object from py-config
 * @param {string} options.name - The name of the key in py-config to be checked
 * @param {(b:BaseConfigObject) => boolean} options.validator - the validation function used to test the user-supplied value
 * @param {BaseConfigObject} options.defaultValue - The default value for this parameter, if none is provided
 * @param {string} [options.hintMessage] - The message to show in a user error if the supplied value isn't valid
 */
export function validateConfigParameter(options: {
    config: AppConfig;
    name: string;
    validator: (b: BaseConfigObject) => boolean;
    defaultValue: BaseConfigObject;
    hintMessage?: string;
}) {
    //Validate that the default value is acceptable, at runtime
    if (!options.validator(options.defaultValue)) {
        throw Error(
            `Default value ${JSON.stringify(options.defaultValue)} for ${options.name} is not a valid argument, ` +
                `according to the provided validator function. ${options.hintMessage ? options.hintMessage : ''}`,
        );
    }

    const value = options.config[options.name] as BaseConfigObject;
    if (value !== undefined && !options.validator(value)) {
        //Use default hint message if none is provided:
        const hintOutput = `Invalid value ${JSON.stringify(value)} for config.${options.name}. ${
            options.hintMessage ? options.hintMessage : ''
        }`;