//#region src/features/messages/format.d.ts /** * The ICU argument types a macro can author, and the named styles each accepts. * * A style may also be a skeleton, which is where the formats these names have * no word for live; see {@link validateArgumentStyle}. * * `currency` is deliberately absent from `number`: MF1 has nowhere to write the * code, so `{price, number, currency}` formats as a bare number. Currency * belongs to a skeleton, `::currency/EUR`, which the formatter does honour. * * `spellout`, RBNF `ordinal` and `choice` are absent by decision: the first two * are ICU4J/ICU4C rule-based formats with no `Intl` equivalent, and the third * is deprecated in ICU itself in favour of `plural`. */ declare const ARGUMENT_STYLES: { readonly number: readonly ["integer", "percent"]; readonly date: readonly ["short", "medium", "long", "full"]; readonly time: readonly ["short", "medium", "long", "full"]; }; type ArgumentType = keyof typeof ARGUMENT_STYLES; declare const ARGUMENT_TYPES: ArgumentType[]; declare function isArgumentType(kind: string): kind is ArgumentType; /** * Reject an argument style the formatter cannot honour, while the style is * still attached to a file and a line. * * A style is a bare string in the source and in the catalogue, so nothing * between here and the runtime has an opinion about it. Left unchecked, a typo * like `{d, date, meduim}` only misformats once it reaches a user. * * Three forms are accepted: a named style, a `::`-prefixed skeleton, and, for * a number, a literal pattern such as `#,##0.00`. */ declare function validateArgumentStyle(type: ArgumentType, style: string): void; //#endregion //#region src/features/messages/identifier.d.ts declare const AUTO_INCREMENT_IDENTIFIER: unique symbol; /** * The ICU case a branch is written as. * * Under `plural` and `ordinal` a number names an exact value, spelled `=0`, and * so is distinct from the CLDR category that would otherwise match it. `select` * has no such syntax, so a numeric key stays bare and matches both `0` and * `'0'`. * * Digits are read literally rather than coerced: `''`, `' '` and `'+0'` all * coerce to `=0`, which would pass for a key selecting zero and leave the * author's own key out of the catalogue. */ declare function getBranchCase(kind: string, identifier: string | typeof AUTO_INCREMENT_IDENTIFIER): string; /** * Reject a branch key ICU cannot express, while the key is still attached to a * file and a line. * * A hyphenated string union is ordinary application code: it typechecks, * builds, and extracts to a normal-looking catalogue entry, and the only sign * of trouble is a parse error at format time. */ declare function validateBranchIdentifier(kind: string, identifier: string | typeof AUTO_INCREMENT_IDENTIFIER): void; /** * Decides whether two placeholders sharing a name are the same placeholder, and * so may share it. Only the syntax that produced them can answer that, so the * caller supplies the comparison; by default nothing is interchangeable. */ type PlaceholderEquivalence = (a: any, b: any) => boolean; declare function assignSequenceIdentifiers(message: Message, sequence?: { current: number; }, equivalent?: PlaceholderEquivalence): void; //#endregion //#region src/features/messages/types.d.ts declare abstract class Base { toICUString(this: Message): string; toHashString(this: Message): string; } declare class LiteralMessage extends Base { readonly text: string; constructor(text: string); } /** * An ICU argument type and style, e.g. `{n, number, percent}`. A style is * optional: `{n, number}` is the type's default formatting. * * Both are kept as the ICU strings they are written as, rather than as `Intl` * options, because the catalogue is the source of truth and only the ICU * spelling round-trips back out of it. */ interface ArgumentFormat { type: ArgumentType; style?: string; } declare class ArgumentMessage extends Base { identifier: string | typeof AUTO_INCREMENT_IDENTIFIER; readonly expression: any; readonly format?: ArgumentFormat | undefined; constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, expression: any, format?: ArgumentFormat | undefined); } declare class ElementMessage extends Base { identifier: string | typeof AUTO_INCREMENT_IDENTIFIER; readonly children: Message[]; readonly expression: any; constructor(identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, children: Message[], expression: any); } declare class ChoiceMessage extends Base { readonly kind: string; identifier: string | typeof AUTO_INCREMENT_IDENTIFIER; readonly branches: { identifier: string | typeof AUTO_INCREMENT_IDENTIFIER; readonly value: Message; }[]; readonly expression: any; /** * Subtracted from the selector before `#` is formatted, so "You and 2 * others" can select on a total of three. Only `plural` and `ordinal` * accept one; `select` has no number to offset. */ readonly offset?: number | undefined; constructor(kind: string, identifier: string | typeof AUTO_INCREMENT_IDENTIFIER, branches: { identifier: string | typeof AUTO_INCREMENT_IDENTIFIER; readonly value: Message; }[], expression: any, /** * Subtracted from the selector before `#` is formatted, so "You and 2 * others" can select on a total of three. Only `plural` and `ordinal` * accept one; `select` has no number to offset. */ offset?: number | undefined); } declare class CompositeMessage extends Base { readonly descriptor: { id?: string; context?: string; }; readonly comments: string[]; readonly references: string[]; readonly children: Message[]; readonly accessor: any; readonly whitespace?: boolean | undefined; constructor(descriptor: { id?: string; context?: string; }, comments: string[], references: string[], children: Message[], accessor: any, whitespace?: boolean | undefined); } type Message = LiteralMessage | ArgumentMessage | ElementMessage | ChoiceMessage | CompositeMessage; //#endregion //#region src/features/messages/convert.d.ts declare function convertMessageToIcu(message: Message): string; //#endregion //#region src/features/messages/escape.d.ts /** * Quoting for text that has to survive a message format unchanged. * * This lives beside the converter rather than in a transform because it belongs * to the format being written, not the syntax being read: a literal is the same * literal whether it came from a template literal or from JSX. */ /** * Escape literal text so ICU MessageFormat 1 reads it as the text it is. * * MF1 escapes with an apostrophe: a run wrapped in one is taken literally, and a * doubled apostrophe is a single apostrophe. An apostrophe only opens a quoted * run when a character that needs quoting follows it, so `'#'` is a real escape * inside a plural and three literal characters anywhere else, which is why * `hash` has to be told rather than assumed. * * @param text Literal text as the author wrote it * @param hash Whether `#` stands for a number here, i.e. whether some `plural` * or `ordinal` encloses this text */ declare function escapeIcuLiteral(text: string, hash?: boolean): string; //#endregion //#region src/features/messages/hash.d.ts /** * Hashed in userland rather than with `node:crypto`, because this runs wherever * a bundler runs it. `createHash` is one of the entry points `unenv` leaves * unimplemented, "[unenv] crypto.createHash is not implemented yet!", so a * plugin reaching for it throws in a Nitro or workerd build. The Web Crypto * equivalent, `subtle.digest`, is async, and an id is resolved from a * synchronous extraction pass. */ declare function generateHash(input: string, context?: string): string; //#endregion export { ARGUMENT_STYLES, ARGUMENT_TYPES, AUTO_INCREMENT_IDENTIFIER, ArgumentFormat, ArgumentMessage, ArgumentType, ChoiceMessage, CompositeMessage, ElementMessage, LiteralMessage, Message, PlaceholderEquivalence, assignSequenceIdentifiers, convertMessageToIcu, escapeIcuLiteral, generateHash, getBranchCase, isArgumentType, validateArgumentStyle, validateBranchIdentifier };