/
githubmirror
/
babel
Обзор
Документация
Войти
/
githubmirror
/
babel
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/babel-template/src/builder.ts
120 строк
4 KB
liuxingbaoyu
Enable `strictNullChecks` for more packages (#17828)
27 фев 2026, 20:06
Не верифицирован
27 фев 2026, 20:06
4fcbae7
Код
Авторство
О чём код?
import { merge, validate } from "./options.ts"; import type { TemplateOpts, PublicOpts, PublicReplacements, } from "./options.ts"; import type { Formatter } from "./formatters.ts"; import stringTemplate from "./string.ts"; import literalTemplate from "./literal.ts"; export type TemplateBuilder<T> = { // Build a new builder, merging the given options with the previous ones. (opts: PublicOpts): TemplateBuilder<T>; // Building from a string produces an AST builder function by default. (tpl: string, opts?: PublicOpts): (replacements?: PublicReplacements) => T; // Building from a template literal produces an AST builder function by default. ( tpl: TemplateStringsArray, ...args: unknown[] ): (replacements?: PublicReplacements) => T; // Allow users to explicitly create templates that produce ASTs, skipping // the need for an intermediate function. ast: { (tpl: string, opts?: PublicOpts): T; (tpl: TemplateStringsArray, ...args: unknown[]): T; }; }; // Prebuild the options that will be used when parsing a `.ast` template. // These do not use a pattern because there is no way for users to pass in // replacement patterns to begin with, and disabling pattern matching means // users have more flexibility in what type of content they have in their // template JS. const NO_PLACEHOLDER: TemplateOpts = validate({ placeholderPattern: false, }); export default function createTemplateBuilder<T>( formatter: Formatter<T>, defaultOpts?: TemplateOpts, ): TemplateBuilder<T> { const templateFnCache = new WeakMap(); const templateAstCache = new WeakMap(); const cachedOpts = defaultOpts || validate(null); return Object.assign( ((tpl, ...args) => { if (typeof tpl === "string") { if (args.length > 1) throw new Error("Unexpected extra params."); return extendedTrace( stringTemplate(formatter, tpl, merge(cachedOpts, validate(args[0]))), ); } else if (Array.isArray(tpl)) { let builder = templateFnCache.get(tpl); if (!builder) { builder = literalTemplate(formatter, tpl, cachedOpts); templateFnCache.set(tpl, builder); } return extendedTrace(builder(args)); } else if (typeof tpl === "object" && tpl) { if (args.length > 0) throw new Error("Unexpected extra params."); return createTemplateBuilder( formatter, merge(cachedOpts, validate(tpl)), ); } throw new Error(`Unexpected template param ${typeof tpl}`); }) as TemplateBuilder<T>, { ast: (tpl: string | string[], ...args: unknown[]) => { if (typeof tpl === "string") { if (args.length > 1) throw new Error("Unexpected extra params."); return stringTemplate( formatter, tpl, merge(merge(cachedOpts, validate(args[0])), NO_PLACEHOLDER), )(); } else if (Array.isArray(tpl)) { let builder = templateAstCache.get(tpl); if (!builder) { builder = literalTemplate( formatter, tpl, merge(cachedOpts, NO_PLACEHOLDER), ); templateAstCache.set(tpl, builder); } return builder(args)(); } throw new Error(`Unexpected template param ${typeof tpl}`); }, }, ); } function extendedTrace<Arg, Result>( fn: (_: Arg) => Result, ): (_: Arg) => Result { // Since we lazy parse the template, we get the current stack so we have the // original stack to append if it errors when parsing const rootErr = new Error(); return (arg: Arg) => { try { return fn(arg); } catch (err) { // We slice off the top 3 items in the stack to remove the call to // 'extendedTrace', and the anonymous builder function, with the final // stripped line being the error message itself since we threw it // in the first place and it doesn't matter. err.stack += `\n =============\n${rootErr.stack!.split("\n").slice(3).join("\n")}`; throw err; } }; }