UNPKG

@hi18n/core

Version:

Message internationalization meets immutability and type-safety - core runtime

1 lines 15.4 kB
{"version":3,"file":"msgfmt-parser-types.mjs","names":[],"sources":["../src/msgfmt-parser-types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */\n\n// The parser algorithm is written to vastly match what is implemented in ./msgfmt-parser.ts, but with a few differences.\n\nimport type { Message } from \"./index.js\";\n\ndeclare const componentPlaceholderSymbol: unique symbol;\nexport type ComponentPlaceholder = typeof componentPlaceholderSymbol;\n\nexport type ParseResult<\n Accum,\n Rem extends string,\n Error extends string | undefined\n> = {\n AccumRev: (x: Accum) => void;\n Rem: Rem;\n Error: Error;\n};\n\nexport type ParseError<Error extends string> = { error: Error };\n\nexport type InferredMessageType<S extends string> = ParseMessageEOF<\n S,\n {}\n> extends ParseResult<infer Accum, any, infer Error>\n ? Error extends string\n ? ParseError<Error>\n : Accum[] extends never[]\n ? unknown\n : Message<Accum>\n : unknown;\n\ntype ValidArgType =\n | \"number\"\n | \"date\"\n | \"time\"\n | \"spellout\"\n | \"ordinal\"\n | \"duration\";\n\ntype ValidArgStyle = {\n number: \"integer\" | \"currency\" | \"percent\";\n date: \"short\" | \"medium\" | \"long\" | \"full\";\n time: \"short\" | \"medium\" | \"long\" | \"full\";\n spellout: never;\n ordinal: never;\n duration: never;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype ParseMessageEOF<S extends string, Accum> = ParseMessage<\n S,\n Accum\n> extends ParseResult<infer Accum, infer Rem, infer Error>\n ? Error extends string\n ? ParseResult<Accum, Rem, Error>\n : Rem extends `${infer RemH}${infer _Rem}`\n ? ParseResult<Accum, Rem, `Found an unmatching ${RemH}`>\n : Rem extends \"\"\n ? ParseResult<Accum, Rem, Error>\n : ParseResult<never, Rem, Error>\n : never;\n\ntype ParseMessage<S extends string, Accum> = S extends\n | `}${string}`\n | `</${string}`\n | \"\"\n ? ParseResult<Accum, S, undefined>\n : S extends `{${infer ST}`\n ? ParseArgument<ST, Accum>\n : S extends `''${infer STT}`\n ? ParseMessage<STT, Accum>\n : S extends `'${infer ST}`\n ? ST extends `${\"{\" | \"}\" | \"#\" | \"|\" | \"<\"}${string}`\n ? ParseQuoted<ST, Accum>\n : ParseMessage<ST, Accum>\n : S extends `<${infer ST}`\n ? ParseElement<ST, Accum>\n : S extends `${string}${infer ST}`\n ? ParseMessage<ST, Accum>\n : ParseResult<never, S, undefined>;\n\n// After \"'\"\ntype ParseQuoted<S extends string, Accum> = S extends `''${infer ST}`\n ? ParseQuoted<ST, Accum>\n : S extends `'${infer ST}`\n ? ParseMessage<ST, Accum>\n : S extends \"\"\n ? ParseResult<Accum, S, \"Unclosed quoted string\">\n : S extends `${string}${infer ST}`\n ? ParseQuoted<ST, Accum>\n : ParseResult<never, S, undefined>;\n\ntype ParseArgument<S extends string, Accum> = NextToken<S> extends Token<\n \"identifier\" | \"number\",\n infer Name,\n infer ST\n>\n ? CheckName<Name> extends ParseError<infer Error>\n ? ParseResult<Accum, S, Error>\n : NextToken<ST> extends Token<\"}\", any, infer STT>\n ? ParseMessage<STT, Accum & Record<CheckName<Name>, string>>\n : NextToken<ST> extends Token<\",\", any, infer STT>\n ? NextToken<STT> extends Token<\"identifier\", \"choice\", any>\n ? ParseResult<Accum, S, \"choice is not supported\">\n : NextToken<STT> extends Token<\"identifier\", \"plural\", infer STTT>\n ? ParsePluralArgument<STTT, CheckName<Name>, Accum>\n : NextToken<STT> extends Token<\n \"identifier\",\n \"select\" | \"selectordinal\",\n any\n >\n ? ParseResult<Accum, S, \"Unimplemented: selectArg\">\n : NextToken<STT> extends Token<\"identifier\", ValidArgType, infer STTT>\n ? NextToken<STTT> extends Token<\"}\", any, infer STTTT>\n ? ParseMessage<\n STTTT,\n Accum & Record<CheckName<Name>, ArgTypeMap[NextToken<STT>[1]]>\n >\n : NextToken<STTT> extends Token<\",\", any, infer STTTT>\n ? NextToken<STTTT> extends Token<\n \"identifier\",\n ValidArgStyle[NextToken<STT>[1]],\n infer STTTTT\n >\n ? NextToken<STTTTT> extends Token<\"}\", any, infer STTTTTT>\n ? ParseMessage<\n STTTTTT,\n Accum & Record<CheckName<Name>, ArgTypeMap[NextToken<STT>[1]]>\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STTTTT>[0]} (expected })`\n >\n : NextToken<STTTT> extends Token<\"identifier\", any, any>\n ? ParseResult<\n Accum,\n S,\n `Invalid argStyle for ${NextToken<STT>[1]}: ${NextToken<STTTT>[1]}`\n >\n : NextToken<STTTT> extends Token<\"::\", any, infer STTTTT>\n ? NextToken<STTTTT> extends Token<\"identifier\", any, infer STTTTTT>\n ? // TODO: parse skeletons\n NextToken<STTTTTT> extends Token<\"}\", any, infer STTTTTTT>\n ? ParseMessage<\n STTTTTTT,\n Accum & Record<CheckName<Name>, ArgTypeMap[NextToken<STT>[1]]>\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STTTTT>[0]} (expected })`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STTTTT>[0]} (expected identifier)`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STTTT>[0]} (expected identifier, ::)`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STTT>[0]} (expected }, ,)`\n >\n : NextToken<STT> extends Token<\"identifier\", any, any>\n ? ParseResult<Accum, S, `Invalid argType: ${NextToken<STT>[1]}`>\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STT>[0]} (expected identifier)`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<ST>[0]} (expected }, ,)`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<S>[0]} (expected number, identifier)`\n >;\n\ntype ParsePluralArgument<\n S extends string,\n Name extends string | number,\n Accum\n> = NextToken<S> extends Token<\",\", any, infer ST>\n ? NextToken<ST> extends Token<\"offset:\", any, infer STT>\n ? NextToken<STT> extends Token<\"number\", infer Offset, infer STTT>\n ? CheckNumber<Offset> extends ParseError<infer Error>\n ? ParseResult<Accum, S, Error>\n : ParsePluralArgument2<STTT, Name, undefined, Accum>\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STT>[0]} (expected number)`\n >\n : NextToken<ST> extends Token<\"identifier\" | \"=\" | \"}\", any, any>\n ? ParsePluralArgument2<ST, Name, undefined, Accum>\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<ST>[0]} (expected offset:, identifier, =, })`\n >\n : ParseResult<Accum, S, `Unexpected token ${NextToken<S>[0]} (expected ,)`>;\n\ntype ParsePluralArgument2<\n S extends string,\n Name extends string | number,\n LastSelector extends string | undefined,\n Accum\n> = NextToken<S> extends Token<\"=\", any, infer ST>\n ? NextToken<ST> extends Token<\"number\", infer Selector, infer STT>\n ? ST extends HasWhitespace\n ? ParseResult<Accum, S, \"No space allowed here\">\n : CheckNumber<Selector> extends ParseError<infer Error>\n ? ParseResult<Accum, S, Error>\n : ParsePluralArgument3<STT, Name, Selector, Accum>\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<ST>[0]} (expected number)`\n >\n : NextToken<S> extends Token<\"identifier\", infer Selector, infer ST>\n ? ParsePluralArgument3<ST, Name, Selector, Accum>\n : NextToken<S> extends Token<\"}\", any, infer ST>\n ? LastSelector extends \"other\"\n ? ParseMessage<ST, Accum & Record<Name, number>>\n : LastSelector extends string\n ? ParseResult<Accum, S, \"Last selector should be other\">\n : ParseResult<Accum, S, \"No branch found\">\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<S>[0]} (expected identifier, =, })`\n >;\n\ntype ParsePluralArgument3<\n S extends string,\n Name extends string | number,\n Selector extends string | undefined,\n Accum\n> = NextToken<S> extends Token<\"{\", any, infer STT>\n ? ParseMessage<STT, Accum> extends ParseResult<\n infer Accum,\n infer Rem,\n infer Error\n >\n ? Error extends string\n ? ParseResult<Accum, Rem, Error>\n : NextToken<Rem> extends Token<\"}\", any, infer RemT>\n ? ParsePluralArgument2<RemT, Name, Selector, Accum>\n : ParseResult<\n Accum,\n Rem,\n `Unexpected token ${NextToken<Rem>[0]} (expected })`\n >\n : never\n : ParseResult<Accum, S, `Unexpected token ${NextToken<S>[0]} (expected {)`>;\n\ntype ParseElement<S extends string, Accum> = NextToken<S> extends Token<\n \"identifier\" | \"number\",\n infer Name,\n infer ST\n>\n ? S extends HasWhitespace\n ? ParseResult<Accum, S, \"No space allowed here\">\n : CheckName<Name> extends ParseError<infer Error>\n ? ParseResult<Accum, S, Error>\n : NextToken<ST> extends Token<\"/\", any, infer STT>\n ? NextToken<STT> extends Token<\">\", any, infer STTT>\n ? STT extends HasWhitespace\n ? ParseResult<Accum, S, \"No space allowed here\">\n : ParseMessage<\n STTT,\n Accum & Record<CheckName<Name>, ComponentPlaceholder>\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<STT>[0]} (expected >)`\n >\n : NextToken<ST> extends Token<\">\", any, infer STT>\n ? ParseMessage<STT, Accum> extends ParseResult<\n infer Accum,\n infer Rem,\n infer Error\n >\n ? Error extends string\n ? ParseResult<Accum, Rem, Error>\n : NextToken<Rem> extends Token<\"<\", any, infer RemT>\n ? NextToken<RemT> extends Token<\"/\", any, infer RemTT>\n ? RemT extends HasWhitespace\n ? ParseResult<Accum, S, \"No space allowed here\">\n : NextToken<RemTT> extends Token<\n \"identifier\" | \"number\",\n infer ClosingName,\n infer RemTTT\n >\n ? RemTT extends HasWhitespace\n ? ParseResult<Accum, S, \"No space allowed here\">\n : NextToken<RemTTT> extends Token<\">\", any, infer RemTTTT>\n ? NameEqual<Name, ClosingName> extends true\n ? ParseMessage<\n RemTTTT,\n Accum & Record<CheckName<Name>, ComponentPlaceholder>\n >\n : ParseResult<\n Accum,\n Rem,\n `Tag ${Name} closed with a different name: ${ClosingName}`\n >\n : ParseResult<\n Accum,\n Rem,\n `Unexpected token ${NextToken<RemTTT>[0]} (expected >)`\n >\n : ParseResult<\n Accum,\n Rem,\n `Unexpected token ${NextToken<RemTT>[0]} (expected number, identifier)`\n >\n : ParseResult<\n Accum,\n Rem,\n `Unexpected token ${NextToken<RemT>[0]} (expected /)`\n >\n : ParseResult<\n Accum,\n Rem,\n `Unexpected token ${NextToken<Rem>[0]} (expected <)`\n >\n : never\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<ST>[0]} (expected /, >)`\n >\n : ParseResult<\n Accum,\n S,\n `Unexpected token ${NextToken<S>[0]} (expected number, identifier)`\n >;\n\ntype CheckName<Name extends string> = Name extends \"0\"\n ? 0\n : Name extends `0${string}`\n ? ParseError<`Invalid number: ${Name}`>\n : Name extends `${Digit}${string}`\n ? CheckNumberImpl<Name>\n : Name;\n\ntype CheckNumber<Name extends string> = Name extends \"0\"\n ? 0\n : Name extends `0${string}`\n ? ParseError<`Invalid number: ${Name}`>\n : Name extends `${Digit}${string}`\n ? CheckNumberImpl<Name>\n : ParseError<`Invalid number: ${Name}`>;\n\ntype CheckNumberImpl<\n Name extends string,\n N extends string = Name\n> = N extends `${infer NH}${infer NT}`\n ? NH extends Digit\n ? CheckNumberImpl<Name, NT>\n : ParseError<`Invalid number: ${Name}`>\n : N extends \"\"\n ? ParseNumber[Name]\n : never;\n\ntype Token<Kind extends string, Value extends string, S extends string> = [\n Kind,\n Value,\n S\n];\n\ntype NextToken<S extends string> =\n SkipWhitespace<S> extends `offset:${infer ST}`\n ? Token<\"offset:\", \"offset:\", ST>\n : SkipWhitespace<S> extends `${Alpha}${string}`\n ? NextWord<SkipWhitespace<S>, \"\", \"identifier\">\n : SkipWhitespace<S> extends `${Digit}${string}`\n ? NextWord<SkipWhitespace<S>, \"\", \"number\">\n : SkipWhitespace<S> extends `::${infer ST}`\n ? Token<\"::\", \"::\", ST>\n : SkipWhitespace<S> extends `${infer SH}${infer ST}`\n ? Token<SH, SH, ST>\n : SkipWhitespace<S> extends \"\"\n ? Token<\"EOF\", \"\", \"\">\n : never;\n\ntype NextWord<\n S extends string,\n Name extends string,\n Kind extends string\n> = S extends `${infer SH}${infer ST}`\n ? SH extends Alpha | Digit\n ? NextWord<ST, `${Name}${SH}`, Kind>\n : Token<Kind, Name, S>\n : S extends \"\"\n ? Token<Kind, Name, S>\n : never;\n\ntype HasWhitespace = `${Whitespace}${string}`;\n\ntype SkipWhitespace<S extends string> = S extends `${Whitespace}${infer ST}`\n ? SkipWhitespace<ST>\n : S;\n\ntype NameEqual<N1 extends string, N2 extends string> = N1 extends N2\n ? N2 extends N1\n ? true\n : false\n : false;\n\ntype ArgTypeMap = {\n number: number;\n date: Date;\n time: Date;\n spellout: number;\n ordinal: number;\n duration: number;\n};\n\ntype Whitespace = \" \" | \"\\n\" | \"\\r\" | \"\\t\";\ntype Digit = \"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\";\ntype Alpha =\n | \"a\"\n | \"b\"\n | \"c\"\n | \"d\"\n | \"e\"\n | \"f\"\n | \"g\"\n | \"h\"\n | \"i\"\n | \"j\"\n | \"k\"\n | \"l\"\n | \"m\"\n | \"n\"\n | \"o\"\n | \"p\"\n | \"q\"\n | \"r\"\n | \"s\"\n | \"t\"\n | \"u\"\n | \"v\"\n | \"w\"\n | \"x\"\n | \"y\"\n | \"z\"\n | \"A\"\n | \"B\"\n | \"C\"\n | \"D\"\n | \"E\"\n | \"F\"\n | \"G\"\n | \"H\"\n | \"I\"\n | \"J\"\n | \"K\"\n | \"L\"\n | \"M\"\n | \"N\"\n | \"O\"\n | \"P\"\n | \"Q\"\n | \"R\"\n | \"S\"\n | \"T\"\n | \"U\"\n | \"V\"\n | \"W\"\n | \"X\"\n | \"Y\"\n | \"Z\"\n | \"_\";\n\ntype ParseNumber = {\n \"0\": 0;\n \"1\": 1;\n \"2\": 2;\n \"3\": 3;\n \"4\": 4;\n \"5\": 5;\n \"6\": 6;\n \"7\": 7;\n \"8\": 8;\n \"9\": 9;\n \"10\": 10;\n \"11\": 11;\n \"12\": 12;\n \"13\": 13;\n \"14\": 14;\n \"15\": 15;\n \"16\": 16;\n [key: string]: number;\n};\n"],"mappings":""}