1import type { ServerProviderSkill } from "@t3tools/contracts";
2
3export type InlineSkill = Pick<ServerProviderSkill, "name" | "displayName">;
4
5function titleCaseWords(value: string): string {
6 const words: string[] = [];
7 for (const segment of value.split(/[\s:_-]+/)) {
8 if (segment.length === 0) continue;
9 words.push(segment.charAt(0).toUpperCase() + segment.slice(1));
10 }
11 return words.join(" ");
12}
13
14export function formatProviderSkillDisplayName(
15 skill: Pick<ServerProviderSkill, "name" | "displayName">,
16): string {
17 const displayName = skill.displayName?.trim();
18 if (displayName) {
19 return displayName;
20 }
21 return titleCaseWords(skill.name);
22}
23
24const SKILL_TOKEN_REGEX =
25 /(^|\s)\p{Sc}(?![0-9][0-9_]*(?:[kKmMbBtT]|[eE][0-9]+)?(?:\s|$))(?=[a-zA-Z0-9:_-]*[a-zA-Z])([a-zA-Z0-9][a-zA-Z0-9:_-]*)(?=\s|$)/gu;
26
27export function* matchInlineSkills(text: string, skills: readonly InlineSkill[]) {
28 for (const match of text.matchAll(SKILL_TOKEN_REGEX)) {
29 const name = match[2] ?? "";
30 const skill = skills.find((candidate) => candidate.name === name);
31 if (!skill) continue;
32 const start = match.index + (match[1]?.length ?? 0);
33 yield { start, end: match.index + match[0].length, skill, rawText: `$${name}` };
34 }
35}