mirror of
https://github.com/wahyd4/heygo.git
synced 2026-08-09 05:15:52 +10:00
102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
export type TemplateInput = {
|
|
targetUrl: string;
|
|
pathParam?: string;
|
|
query: URLSearchParams;
|
|
};
|
|
|
|
export type TemplateParameter = {
|
|
name: string;
|
|
defaultValue?: string;
|
|
raw: string;
|
|
index: number;
|
|
};
|
|
|
|
export class TemplateResolutionError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = 'TemplateResolutionError';
|
|
}
|
|
}
|
|
|
|
const TEMPLATE_PATTERN = /\{([^{}]*)\}/g;
|
|
const PARAMETER_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
const DEFAULT_PREFIX = 'default=';
|
|
|
|
export function parseTemplateParameters(targetUrl: string): TemplateParameter[] {
|
|
return Array.from(targetUrl.matchAll(TEMPLATE_PATTERN), ([raw, content], index) => {
|
|
const { name, defaultValue } = parseParameterContent(content, raw);
|
|
|
|
return { name, defaultValue, raw, index };
|
|
});
|
|
}
|
|
|
|
export function resolveTemplateUrl(input: TemplateInput): string {
|
|
const parameters = parseTemplateParameters(input.targetUrl);
|
|
|
|
if (parameters.length === 0) {
|
|
return input.targetUrl;
|
|
}
|
|
|
|
let parameterIndex = 0;
|
|
const firstParameterName = parameters[0].name;
|
|
|
|
return input.targetUrl.replace(TEMPLATE_PATTERN, () => {
|
|
const parameter = parameters[parameterIndex];
|
|
parameterIndex += 1;
|
|
|
|
const value = resolveParameterValue(parameter, input, firstParameterName);
|
|
return encodeURIComponent(value);
|
|
});
|
|
}
|
|
|
|
function parseParameterContent(content: string, raw: string): Pick<TemplateParameter, 'name' | 'defaultValue'> {
|
|
const commaIndex = content.indexOf(',');
|
|
const rawName = commaIndex === -1 ? content : content.slice(0, commaIndex);
|
|
const name = rawName.trim();
|
|
|
|
if (!PARAMETER_NAME_PATTERN.test(name)) {
|
|
throw new TemplateResolutionError(`Invalid template parameter name "${name}" in placeholder ${raw}`);
|
|
}
|
|
|
|
if (commaIndex === -1) {
|
|
return { name };
|
|
}
|
|
|
|
const defaultPart = content.slice(commaIndex + 1).trim();
|
|
if (!defaultPart.startsWith(DEFAULT_PREFIX)) {
|
|
throw new TemplateResolutionError(`Invalid default for template parameter "${name}" in placeholder ${raw}`);
|
|
}
|
|
|
|
return { name, defaultValue: unquoteDefault(defaultPart.slice(DEFAULT_PREFIX.length).trim()) };
|
|
}
|
|
|
|
function unquoteDefault(value: string): string {
|
|
if (value.length >= 2) {
|
|
const first = value[0];
|
|
const last = value[value.length - 1];
|
|
|
|
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
return value.slice(1, -1);
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function resolveParameterValue(parameter: TemplateParameter, input: TemplateInput, firstParameterName: string): string {
|
|
const queryValue = input.query.get(parameter.name);
|
|
if (queryValue !== null) {
|
|
return queryValue;
|
|
}
|
|
|
|
if (parameter.name === firstParameterName && input.pathParam !== undefined) {
|
|
return input.pathParam;
|
|
}
|
|
|
|
if (parameter.defaultValue !== undefined) {
|
|
return parameter.defaultValue;
|
|
}
|
|
|
|
throw new TemplateResolutionError(`No value provided for template parameter "${parameter.name}"`);
|
|
}
|