Last active
May 7, 2023 06:50
-
-
Save BLamy/4b4c369ab4a0915bf61f99e46516fc86 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const messages = [ | |
system(`this is a system message | |
It will end up typed as a literal because It is called as a function | |
`), | |
user`typed as | |
a string This`, | |
assistant(` | |
will also | |
be typed | |
as a literal`) | |
] | |
console.log(messages) | |
// ^? | |
//---------------------------------- | |
// implementation | |
//---------------------------------- | |
export function system<T extends string>( | |
literals: TemplateStringsArray | T, | |
...placeholders: unknown[] | |
) { | |
return { | |
role: "system" as const, | |
content: dedent(literals, ...placeholders), | |
}; | |
} | |
export function user<T extends string>( | |
literals: TemplateStringsArray | T, | |
...placeholders: unknown[] | |
) { | |
return { | |
role: "user" as const, | |
content: dedent(literals, ...placeholders), | |
}; | |
} | |
export function assistant<T extends string>( | |
literals: TemplateStringsArray | T, | |
...placeholders: unknown[] | |
) { | |
return { | |
role: "assistant" as const, | |
content: dedent(literals, ...placeholders), | |
}; | |
} | |
export function dedent<T extends string>( | |
templ: TemplateStringsArray | T, | |
...values: unknown[] | |
): typeof templ extends TemplateStringsArray ? string : T { | |
let strings = Array.from(typeof templ === "string" ? [templ] : templ); | |
// 1. Remove trailing whitespace. | |
strings[strings.length - 1] = strings[strings.length - 1].replace( | |
/\r?\n([\t ]*)$/, | |
"" | |
); | |
// 2. Find all line breaks to determine the highest common indentation level. | |
const indentLengths = strings.reduce<number[]>((arr, str) => { | |
const matches = str.match(/\n([\t ]+|(?!\s).)/g); | |
if (matches) { | |
return arr.concat( | |
matches.map((match) => match.match(/[\t ]/g)?.length ?? 0) | |
); | |
} | |
return arr; | |
}, []); | |
// 3. Remove the common indentation from all strings. | |
if (indentLengths.length) { | |
const pattern = new RegExp(`\n[\t ]{${Math.min(...indentLengths)}}`, "g"); | |
strings = strings.map((str) => str.replace(pattern, "\n")); | |
} | |
// 4. Remove leading whitespace. | |
strings[0] = strings[0].replace(/^\r?\n/, ""); | |
// 5. Perform interpolation. | |
let string = strings[0]; | |
values.forEach((value, i) => { | |
// 5.1 Read current indentation level | |
const endentations = string.match(/(?:^|\n)( *)$/); | |
const endentation = endentations ? endentations[1] : ""; | |
let indentedValue = value; | |
// 5.2 Add indentation to values with multiline strings | |
if (typeof value === "string" && value.includes("\n")) { | |
indentedValue = String(value) | |
.split("\n") | |
.map((str, i) => { | |
return i === 0 ? str : `${endentation}${str}`; | |
}) | |
.join("\n"); | |
} | |
string += indentedValue + strings[i + 1]; | |
}); | |
return string as any; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TS Playground Demo