Files
zero-fucks-given/packages/services/intl-name/src/formatter.ts
T

79 lines
2.2 KiB
TypeScript

import { CanonicalName } from './name-input-types';
import { INTL_NAME_TOKENS } from './tokens';
export const UNIVERSAL_NAME_PATTERN = 'UNIVERSAL' as const;
function initial(value?: string) {
return (value?.[0] ?? '').toUpperCase();
}
function valueOrEmpty(v?: string) {
return v ?? '';
}
export function formatNameByPattern(pattern: string, ctx: CanonicalName): string {
if (pattern === UNIVERSAL_NAME_PATTERN) {
return [ctx.firstName, ctx.lastName, ctx.patronymic].filter(Boolean).join(' ').trim();
}
const TOKEN_REGEX = /(Pr|Su|FF|LL|PP|MM|F|L|P|M)/g;
const resolveToken = (token: string): string => {
switch (token) {
case INTL_NAME_TOKENS.FIRST.FULL:
return valueOrEmpty(ctx.firstName);
case INTL_NAME_TOKENS.FIRST.INITIAL:
return initial(ctx.firstName);
case INTL_NAME_TOKENS.LAST.FULL:
return valueOrEmpty(ctx.lastName);
case INTL_NAME_TOKENS.LAST.INITIAL:
return initial(ctx.lastName);
case INTL_NAME_TOKENS.MIDDLE.FULL:
return valueOrEmpty(ctx.middleName);
case INTL_NAME_TOKENS.MIDDLE.INITIAL:
return initial(ctx.middleName);
case INTL_NAME_TOKENS.PATRONYMIC.FULL:
return valueOrEmpty(ctx.patronymic);
case INTL_NAME_TOKENS.PATRONYMIC.INITIAL:
return initial(ctx.patronymic);
case INTL_NAME_TOKENS.PREFIX:
return valueOrEmpty(ctx.prefix);
case INTL_NAME_TOKENS.SUFFIX:
return valueOrEmpty(ctx.suffix);
default:
return '';
}
};
const renderTokensWithPresence = (str: string): { text: string; hasValue: boolean } => {
let hasValue = false;
const text = str.replace(TOKEN_REGEX, (token) => {
const value = resolveToken(token);
if (value !== '') hasValue = true;
return value;
});
return { text, hasValue };
};
let out = pattern;
const blockRe = /\{([^{}]*)\}/g;
while (true) {
const before = out;
out = out.replace(blockRe, (_, inner: string) => {
const { text, hasValue } = renderTokensWithPresence(inner);
return hasValue ? text : '';
});
if (out === before) break;
}
out = renderTokensWithPresence(out).text;
return out.replace(/\s+/g, ' ').trim();
}