@intlify/message-compiler
Advanced tools
+165
-206
@@ -1,230 +0,189 @@ | ||
| import type { BaseError } from '@intlify/shared'; | ||
| import type { RawSourceMap } from 'source-map-js'; | ||
| import { RawSourceMap } from "source-map-js"; | ||
| import { BaseError } from "@intlify/shared"; | ||
| export declare function baseCompile(source: string, options?: CompileOptions): CompilerResult; | ||
| export declare type CacheKeyHandler = (source: string) => string; | ||
| export declare interface CodeGenOptions { | ||
| location?: boolean; | ||
| mode?: 'normal' | 'arrow'; | ||
| breakLineCode?: '\n' | ';'; | ||
| needIndent?: boolean; | ||
| onError?: CompileErrorHandler; | ||
| sourceMap?: boolean; | ||
| filename?: string; | ||
| //#region temp/packages/message-compiler/src/location.d.ts | ||
| interface SourceLocation { | ||
| start: Position; | ||
| end: Position; | ||
| source?: string; | ||
| } | ||
| declare interface CodeGenResult { | ||
| code: string; | ||
| ast: ResourceNode; | ||
| map?: RawSourceMap; | ||
| declare const LOCATION_STUB: SourceLocation; | ||
| interface Position { | ||
| offset: number; | ||
| line: number; | ||
| column: number; | ||
| } | ||
| export declare const COMPILE_ERROR_CODES_EXTEND_POINT: number; | ||
| export declare type CompileDomain = 'tokenizer' | 'parser' | 'generator' | 'transformer' | 'optimizer' | 'minifier'; | ||
| export declare interface CompileError extends BaseError, SyntaxError { | ||
| domain?: CompileDomain; | ||
| location?: SourceLocation; | ||
| declare function createPosition(line: number, column: number, offset: number): Position; | ||
| declare function createLocation(start: Position, end: Position, source?: string): SourceLocation; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/nodes.d.ts | ||
| declare const enum NodeTypes { | ||
| Resource = 0, | ||
| Plural = 1, | ||
| Message = 2, | ||
| Text = 3, | ||
| Named = 4, | ||
| List = 5, | ||
| Linked = 6, | ||
| LinkedKey = 7, | ||
| LinkedModifier = 8, | ||
| Literal = 9, | ||
| } | ||
| export declare const CompileErrorCodes: { | ||
| readonly EXPECTED_TOKEN: 1; | ||
| readonly INVALID_TOKEN_IN_PLACEHOLDER: 2; | ||
| readonly UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3; | ||
| readonly UNKNOWN_ESCAPE_SEQUENCE: 4; | ||
| readonly INVALID_UNICODE_ESCAPE_SEQUENCE: 5; | ||
| readonly UNBALANCED_CLOSING_BRACE: 6; | ||
| readonly UNTERMINATED_CLOSING_BRACE: 7; | ||
| readonly EMPTY_PLACEHOLDER: 8; | ||
| readonly NOT_ALLOW_NEST_PLACEHOLDER: 9; | ||
| readonly INVALID_LINKED_FORMAT: 10; | ||
| readonly MUST_HAVE_MESSAGES_IN_PLURAL: 11; | ||
| readonly UNEXPECTED_EMPTY_LINKED_MODIFIER: 12; | ||
| readonly UNEXPECTED_EMPTY_LINKED_KEY: 13; | ||
| readonly UNEXPECTED_LEXICAL_ANALYSIS: 14; | ||
| readonly UNHANDLED_CODEGEN_NODE_TYPE: 15; | ||
| readonly UNHANDLED_MINIFIER_NODE_TYPE: 16; | ||
| }; | ||
| export declare type CompileErrorCodes = (typeof CompileErrorCodes)[keyof typeof CompileErrorCodes]; | ||
| export declare type CompileErrorHandler = (error: CompileError) => void; | ||
| export declare interface CompileErrorOptions { | ||
| domain?: CompileDomain; | ||
| messages?: { | ||
| [code: number]: string; | ||
| }; | ||
| args?: unknown[]; | ||
| type Identifier = string; | ||
| interface Node { | ||
| type: NodeTypes; | ||
| start?: number; | ||
| end?: number; | ||
| loc?: SourceLocation; | ||
| } | ||
| export declare type CompileOptions = { | ||
| optimize?: boolean; | ||
| mangle?: boolean; | ||
| jit?: boolean; | ||
| } & TransformOptions & CodeGenOptions & ParserOptions & TokenizeOptions; | ||
| export declare type CompilerResult = CodeGenResult; | ||
| export declare function createCompileError<T extends number>(code: T, loc: SourceLocation | null, options?: CompileErrorOptions): CompileError; | ||
| export declare function createLocation(start: Position, end: Position, source?: string): SourceLocation; | ||
| export declare function createParser(options?: ParserOptions): Parser; | ||
| export declare function createPosition(line: number, column: number, offset: number): Position; | ||
| /* Excluded from this release type: defaultOnError */ | ||
| export declare const detectHtmlTag: (source: string) => boolean; | ||
| export declare const ERROR_DOMAIN = "parser"; | ||
| /* Excluded from this release type: errorMessages */ | ||
| export declare const enum HelperNameMap { | ||
| LIST = "list", | ||
| NAMED = "named", | ||
| PLURAL = "plural", | ||
| LINKED = "linked", | ||
| MESSAGE = "message", | ||
| TYPE = "type", | ||
| INTERPOLATE = "interpolate", | ||
| NORMALIZE = "normalize", | ||
| VALUES = "values" | ||
| interface ResourceNode extends Node { | ||
| type: NodeTypes.Resource; | ||
| body: MessageNode | PluralNode; | ||
| cacheKey?: string; | ||
| helpers?: string[]; | ||
| } | ||
| export declare type Identifier = string; | ||
| export declare interface LinkedKeyNode extends Node_2 { | ||
| type: NodeTypes.LinkedKey; | ||
| value: string; | ||
| /* Excluded from this release type: v */ | ||
| interface PluralNode extends Node { | ||
| type: NodeTypes.Plural; | ||
| cases: MessageNode[]; | ||
| } | ||
| export declare interface LinkedModifierNode extends Node_2 { | ||
| type: NodeTypes.LinkedModifier; | ||
| value: Identifier; | ||
| /* Excluded from this release type: v */ | ||
| interface MessageNode extends Node { | ||
| type: NodeTypes.Message; | ||
| static?: string; | ||
| items: MessageElementNode[]; | ||
| } | ||
| export declare interface LinkedNode extends Node_2 { | ||
| type: NodeTypes.Linked; | ||
| modifier?: LinkedModifierNode; | ||
| /* Excluded from this release type: m */ | ||
| key: LinkedKeyNode | NamedNode | ListNode | LiteralNode; | ||
| /* Excluded from this release type: k */ | ||
| type MessageElementNode = TextNode | NamedNode | ListNode | LiteralNode | LinkedNode; | ||
| interface TextNode extends Node { | ||
| type: NodeTypes.Text; | ||
| value?: string; | ||
| } | ||
| export declare interface ListNode extends Node_2 { | ||
| type: NodeTypes.List; | ||
| index: number; | ||
| /* Excluded from this release type: i */ | ||
| interface NamedNode extends Node { | ||
| type: NodeTypes.Named; | ||
| key: Identifier; | ||
| modulo?: boolean; | ||
| } | ||
| export declare interface LiteralNode extends Node_2 { | ||
| type: NodeTypes.Literal; | ||
| value?: string; | ||
| /* Excluded from this release type: v */ | ||
| interface ListNode extends Node { | ||
| type: NodeTypes.List; | ||
| index: number; | ||
| } | ||
| export declare const LOCATION_STUB: SourceLocation; | ||
| export declare function mangle(node: Node_2): void; | ||
| declare type MessageElementNode = TextNode | NamedNode | ListNode | LiteralNode | LinkedNode; | ||
| export declare interface MessageNode extends Node_2 { | ||
| type: NodeTypes.Message; | ||
| static?: string; | ||
| /* Excluded from this release type: s */ | ||
| items: MessageElementNode[]; | ||
| /* Excluded from this release type: i */ | ||
| interface LiteralNode extends Node { | ||
| type: NodeTypes.Literal; | ||
| value?: string; | ||
| } | ||
| export declare interface NamedNode extends Node_2 { | ||
| type: NodeTypes.Named; | ||
| key: Identifier; | ||
| modulo?: boolean; | ||
| /* Excluded from this release type: k */ | ||
| interface LinkedNode extends Node { | ||
| type: NodeTypes.Linked; | ||
| modifier?: LinkedModifierNode; | ||
| key: LinkedKeyNode | NamedNode | ListNode | LiteralNode; | ||
| } | ||
| declare interface Node_2 { | ||
| type: NodeTypes; | ||
| /* Excluded from this release type: t */ | ||
| start?: number; | ||
| end?: number; | ||
| loc?: SourceLocation; | ||
| interface LinkedKeyNode extends Node { | ||
| type: NodeTypes.LinkedKey; | ||
| value: string; | ||
| } | ||
| export { Node_2 as Node } | ||
| export declare const enum NodeTypes { | ||
| Resource = 0,// 0 | ||
| Plural = 1, | ||
| Message = 2, | ||
| Text = 3, | ||
| Named = 4, | ||
| List = 5,// 5 | ||
| Linked = 6, | ||
| LinkedKey = 7, | ||
| LinkedModifier = 8, | ||
| Literal = 9 | ||
| interface LinkedModifierNode extends Node { | ||
| type: NodeTypes.LinkedModifier; | ||
| value: Identifier; | ||
| } | ||
| export declare function optimize(ast: ResourceNode): ResourceNode; | ||
| export declare interface Parser { | ||
| parse(source: string): ResourceNode; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/errors.d.ts | ||
| type CompileDomain = "tokenizer" | "parser" | "generator" | "transformer" | "optimizer" | "minifier"; | ||
| interface CompileError extends BaseError, SyntaxError { | ||
| domain?: CompileDomain; | ||
| location?: SourceLocation; | ||
| } | ||
| export declare interface ParserOptions { | ||
| location?: boolean; | ||
| onCacheKey?: (source: string) => string; | ||
| onError?: CompileErrorHandler; | ||
| interface CompileErrorOptions { | ||
| domain?: CompileDomain; | ||
| messages?: { | ||
| [code: number]: string; | ||
| }; | ||
| args?: unknown[]; | ||
| } | ||
| export declare interface PluralNode extends Node_2 { | ||
| type: NodeTypes.Plural; | ||
| cases: MessageNode[]; | ||
| /* Excluded from this release type: c */ | ||
| declare const CompileErrorCodes: { | ||
| readonly EXPECTED_TOKEN: 1; | ||
| readonly INVALID_TOKEN_IN_PLACEHOLDER: 2; | ||
| readonly UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3; | ||
| readonly UNKNOWN_ESCAPE_SEQUENCE: 4; | ||
| readonly INVALID_UNICODE_ESCAPE_SEQUENCE: 5; | ||
| readonly UNBALANCED_CLOSING_BRACE: 6; | ||
| readonly UNTERMINATED_CLOSING_BRACE: 7; | ||
| readonly EMPTY_PLACEHOLDER: 8; | ||
| readonly NOT_ALLOW_NEST_PLACEHOLDER: 9; | ||
| readonly INVALID_LINKED_FORMAT: 10; | ||
| readonly MUST_HAVE_MESSAGES_IN_PLURAL: 11; | ||
| readonly UNEXPECTED_EMPTY_LINKED_MODIFIER: 12; | ||
| readonly UNEXPECTED_EMPTY_LINKED_KEY: 13; | ||
| readonly UNEXPECTED_LEXICAL_ANALYSIS: 14; | ||
| readonly UNHANDLED_CODEGEN_NODE_TYPE: 15; | ||
| readonly UNHANDLED_MINIFIER_NODE_TYPE: 16; | ||
| }; | ||
| declare const COMPILE_ERROR_CODES_EXTEND_POINT: number; | ||
| type CompileErrorCodes = (typeof CompileErrorCodes)[keyof typeof CompileErrorCodes]; | ||
| declare function createCompileError<T extends number>(code: T, loc: SourceLocation | null, options?: CompileErrorOptions): CompileError; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/options.d.ts | ||
| type CompileErrorHandler = (error: CompileError) => void; | ||
| type CacheKeyHandler = (source: string) => string; | ||
| interface TokenizeOptions { | ||
| location?: boolean; | ||
| onError?: CompileErrorHandler; | ||
| } | ||
| export declare interface Position { | ||
| offset: number; | ||
| line: number; | ||
| column: number; | ||
| interface ParserOptions { | ||
| location?: boolean; | ||
| onCacheKey?: (source: string) => string; | ||
| onError?: CompileErrorHandler; | ||
| } | ||
| export declare interface ResourceNode extends Node_2 { | ||
| type: NodeTypes.Resource; | ||
| body: MessageNode | PluralNode; | ||
| /* Excluded from this release type: b */ | ||
| cacheKey?: string; | ||
| helpers?: string[]; | ||
| interface TransformOptions { | ||
| onError?: CompileErrorHandler; | ||
| } | ||
| export declare interface SourceLocation { | ||
| start: Position; | ||
| end: Position; | ||
| source?: string; | ||
| interface CodeGenOptions { | ||
| location?: boolean; | ||
| mode?: "normal" | "arrow"; | ||
| breakLineCode?: "\n" | ";"; | ||
| needIndent?: boolean; | ||
| onError?: CompileErrorHandler; | ||
| sourceMap?: boolean; | ||
| filename?: string; | ||
| } | ||
| export declare interface TextNode extends Node_2 { | ||
| type: NodeTypes.Text; | ||
| value?: string; | ||
| /* Excluded from this release type: v */ | ||
| type CompileOptions = { | ||
| optimize?: boolean; | ||
| mangle?: boolean; | ||
| jit?: boolean; | ||
| } & TransformOptions & CodeGenOptions & ParserOptions & TokenizeOptions; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/generator.d.ts | ||
| interface CodeGenResult { | ||
| code: string; | ||
| ast: ResourceNode; | ||
| map?: RawSourceMap; | ||
| } | ||
| export declare interface TokenizeOptions { | ||
| location?: boolean; | ||
| onError?: CompileErrorHandler; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/compiler.d.ts | ||
| type CompilerResult = CodeGenResult; | ||
| declare function baseCompile(source: string, options?: CompileOptions): CompilerResult; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/helpers.d.ts | ||
| declare const enum HelperNameMap { | ||
| LIST = "list", | ||
| NAMED = "named", | ||
| PLURAL = "plural", | ||
| LINKED = "linked", | ||
| MESSAGE = "message", | ||
| TYPE = "type", | ||
| INTERPOLATE = "interpolate", | ||
| NORMALIZE = "normalize", | ||
| VALUES = "values", | ||
| } | ||
| export declare interface TransformOptions { | ||
| onError?: CompileErrorHandler; | ||
| declare const detectHtmlTag: (source: string) => boolean; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/mangler.d.ts | ||
| declare function mangle(node: Node): void; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/optimizer.d.ts | ||
| declare function optimize(ast: ResourceNode): ResourceNode; | ||
| //#endregion | ||
| //#region temp/packages/message-compiler/src/parser.d.ts | ||
| interface Parser { | ||
| parse(source: string): ResourceNode; | ||
| } | ||
| export { } | ||
| declare const ERROR_DOMAIN = "parser"; | ||
| declare function createParser(options?: ParserOptions): Parser; | ||
| //#endregion | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CacheKeyHandler, CodeGenOptions, CompileDomain, CompileError, CompileErrorCodes, CompileErrorHandler, CompileErrorOptions, CompileOptions, CompilerResult, ERROR_DOMAIN, HelperNameMap, Identifier, LOCATION_STUB, LinkedKeyNode, LinkedModifierNode, LinkedNode, ListNode, LiteralNode, MessageNode, NamedNode, Node, NodeTypes, Parser, ParserOptions, PluralNode, Position, ResourceNode, SourceLocation, TextNode, TokenizeOptions, TransformOptions, baseCompile, createCompileError, createLocation, createParser, createPosition, detectHtmlTag, mangle, optimize }; |
+1216
-1481
@@ -1,1542 +0,1277 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| /** | ||
| * Original Utilities | ||
| * written by kazuya kawaguchi | ||
| */ | ||
| const RE_ARGS = /\{([0-9a-zA-Z]+)\}/g; | ||
| /* eslint-disable */ | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ | ||
| //#region packages/shared/src/utils.ts | ||
| const inBrowser = typeof window !== "undefined"; | ||
| { | ||
| const perf = inBrowser && window.performance; | ||
| if (perf && perf.mark && perf.measure && perf.clearMarks && perf.clearMeasures) {} | ||
| } | ||
| const RE_ARGS = /\{([0-9a-z]+)\}/gi; | ||
| function format(message, ...args) { | ||
| if (args.length === 1 && isObject(args[0])) { | ||
| args = args[0]; | ||
| } | ||
| if (!args || !args.hasOwnProperty) { | ||
| args = {}; | ||
| } | ||
| return message.replace(RE_ARGS, (match, identifier) => { | ||
| return args.hasOwnProperty(identifier) ? args[identifier] : ''; | ||
| }); | ||
| if (args.length === 1 && isObject(args[0])) args = args[0]; | ||
| if (!args || !args.hasOwnProperty) args = {}; | ||
| return message.replace(RE_ARGS, (_match, identifier) => { | ||
| return args.hasOwnProperty(identifier) ? args[identifier] : ""; | ||
| }); | ||
| } | ||
| const assign = Object.assign; | ||
| const isString = (val) => typeof val === 'string'; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const isObject = (val) => val !== null && typeof val === 'object'; | ||
| function join(items, separator = '') { | ||
| return items.reduce((str, item, index) => (index === 0 ? str + item : str + separator + item), ''); | ||
| Array.isArray; | ||
| const isString = (val) => typeof val === "string"; | ||
| const isObject = (val) => val !== null && typeof val === "object"; | ||
| function join(items, separator = "") { | ||
| return items.reduce((str, item, index) => index === 0 ? str + item : str + separator + item, ""); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/nodes.ts | ||
| let NodeTypes = /* @__PURE__ */ function(NodeTypes) { | ||
| NodeTypes[NodeTypes["Resource"] = 0] = "Resource"; | ||
| NodeTypes[NodeTypes["Plural"] = 1] = "Plural"; | ||
| NodeTypes[NodeTypes["Message"] = 2] = "Message"; | ||
| NodeTypes[NodeTypes["Text"] = 3] = "Text"; | ||
| NodeTypes[NodeTypes["Named"] = 4] = "Named"; | ||
| NodeTypes[NodeTypes["List"] = 5] = "List"; | ||
| NodeTypes[NodeTypes["Linked"] = 6] = "Linked"; | ||
| NodeTypes[NodeTypes["LinkedKey"] = 7] = "LinkedKey"; | ||
| NodeTypes[NodeTypes["LinkedModifier"] = 8] = "LinkedModifier"; | ||
| NodeTypes[NodeTypes["Literal"] = 9] = "Literal"; | ||
| return NodeTypes; | ||
| }({}); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/location.ts | ||
| const LOCATION_STUB = { | ||
| start: { line: 1, column: 1, offset: 0 }, | ||
| end: { line: 1, column: 1, offset: 0 } | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function createPosition(line, column, offset) { | ||
| return { line, column, offset }; | ||
| return { | ||
| line, | ||
| column, | ||
| offset | ||
| }; | ||
| } | ||
| function createLocation(start, end, source) { | ||
| const loc = { start, end }; | ||
| if (source != null) { | ||
| loc.source = source; | ||
| } | ||
| return loc; | ||
| const loc = { | ||
| start, | ||
| end | ||
| }; | ||
| if (source != null) loc.source = source; | ||
| return loc; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/helpers.ts | ||
| let HelperNameMap = /* @__PURE__ */ function(HelperNameMap) { | ||
| HelperNameMap["LIST"] = "list"; | ||
| HelperNameMap["NAMED"] = "named"; | ||
| HelperNameMap["PLURAL"] = "plural"; | ||
| HelperNameMap["LINKED"] = "linked"; | ||
| HelperNameMap["MESSAGE"] = "message"; | ||
| HelperNameMap["TYPE"] = "type"; | ||
| HelperNameMap["INTERPOLATE"] = "interpolate"; | ||
| HelperNameMap["NORMALIZE"] = "normalize"; | ||
| HelperNameMap["VALUES"] = "values"; | ||
| return HelperNameMap; | ||
| }({}); | ||
| const RE_HTML_TAG = /<[\w\s=":;#-/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/errors.ts | ||
| const CompileErrorCodes = { | ||
| // tokenizer error codes | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| // parser error codes | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| // generator error codes | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| // minifier error codes | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }; | ||
| // Special value for higher-order compilers to pick up the last code | ||
| // to avoid collision of error codes. | ||
| // This should always be kept as the last item. | ||
| const COMPILE_ERROR_CODES_EXTEND_POINT = 17; | ||
| /** @internal */ | ||
| const errorMessages = { | ||
| // tokenizer error messages | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| // parser error messages | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| // generator error messages | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| // minimizer error messages | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(code, loc, options = {}) { | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || '', ...(args || [])) | ||
| ; | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) { | ||
| error.location = loc; | ||
| } | ||
| error.domain = domain; | ||
| return error; | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || "", ...args || []); | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) error.location = loc; | ||
| error.domain = domain; | ||
| return error; | ||
| } | ||
| /** @internal */ | ||
| function defaultOnError(error) { | ||
| throw error; | ||
| throw error; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/triple-slash-reference | ||
| /// <reference types="source-map-js" /> | ||
| const ERROR_DOMAIN$3 = 'parser'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/generator.ts | ||
| const ERROR_DOMAIN$3 = "parser"; | ||
| function createCodeGenerator(ast, options) { | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: '', | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: undefined, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) { | ||
| _context.source = ast.loc.source; | ||
| } | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ''; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: "", | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) _context.source = ast.loc.source; | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ""; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(generator, node) { | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } | ||
| else { | ||
| generator.push(`, undefined, _type`); | ||
| } | ||
| generator.push(`)`); | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked")}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } else generator.push(`, undefined, _type`); | ||
| generator.push(`)`); | ||
| } | ||
| function generateMessageNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push('])'); | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push("])"); | ||
| } | ||
| function generatePluralNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(generator, node) { | ||
| if (node.body) { | ||
| generateNode(generator, node.body); | ||
| } | ||
| else { | ||
| generator.push('null'); | ||
| } | ||
| if (node.body) generateNode(generator, node.body); | ||
| else generator.push("null"); | ||
| } | ||
| function generateNode(generator, node) { | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1 /* NodeTypes.Plural */: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7 /* NodeTypes.LinkedKey */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5 /* NodeTypes.List */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9 /* NodeTypes.Literal */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3 /* NodeTypes.Text */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: | ||
| { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5: | ||
| generator.push(`${helper("interpolate")}(${helper("list")}(${node.index}))`, node); | ||
| break; | ||
| case 4: | ||
| generator.push(`${helper("interpolate")}(${helper("named")}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| // generate code from AST | ||
| const generate = (ast, options = {}) => { | ||
| const mode = isString(options.mode) ? options.mode : 'normal'; | ||
| const filename = isString(options.filename) | ||
| ? options.filename | ||
| : 'message.intl'; | ||
| const sourceMap = !!options.sourceMap; | ||
| // prettier-ignore | ||
| const breakLineCode = options.breakLineCode != null | ||
| ? options.breakLineCode | ||
| : mode === 'arrow' | ||
| ? ';' | ||
| : '\n'; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow'; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| }; | ||
| const mode = isString(options.mode) ? options.mode : "normal"; | ||
| const filename = isString(options.filename) ? options.filename : "message.intl"; | ||
| const sourceMap = !!options.sourceMap; | ||
| const breakLineCode = options.breakLineCode != null ? options.breakLineCode : mode === "arrow" ? ";" : "\n"; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== "arrow"; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === "normal" ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map((s) => `${s}: _${s}`), ", ")} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| const ERROR_DOMAIN$2 = 'minifier'; | ||
| /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/mangler.ts | ||
| const ERROR_DOMAIN$2 = "minifier"; | ||
| function mangle(node) { | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1 /* NodeTypes.Plural */: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) { | ||
| mangle(cases[i]); | ||
| } | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2 /* NodeTypes.Message */: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) { | ||
| mangle(items[i]); | ||
| } | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3 /* NodeTypes.Text */: | ||
| case 9 /* NodeTypes.Literal */: | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| case 7 /* NodeTypes.LinkedKey */: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4 /* NodeTypes.Named */: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: | ||
| { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| delete node.type; | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) mangle(cases[i]); | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) mangle(items[i]); | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| delete node.type; | ||
| } | ||
| /* eslint-enable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/optimizer.ts | ||
| function optimize(ast) { | ||
| const body = ast.body; | ||
| if (body.type === 2 /* NodeTypes.Message */) { | ||
| optimizeMessageNode(body); | ||
| } | ||
| else { | ||
| body.cases.forEach(c => optimizeMessageNode(c)); | ||
| } | ||
| return ast; | ||
| const body = ast.body; | ||
| if (body.type === 2) optimizeMessageNode(body); | ||
| else body.cases.forEach((c) => optimizeMessageNode(c)); | ||
| return ast; | ||
| } | ||
| function optimizeMessageNode(message) { | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| message.static = item.value; | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) { | ||
| break; | ||
| } | ||
| if (item.value == null) { | ||
| break; | ||
| } | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 || item.type === 9) { | ||
| message.static = item.value; | ||
| delete item.value; | ||
| } | ||
| } else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 || item.type === 9)) break; | ||
| if (item.value == null) break; | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 || item.type === 9) delete item.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| const CHAR_SP = ' '; | ||
| const CHAR_CR = '\r'; | ||
| const CHAR_LF = '\n'; | ||
| const CHAR_LS = String.fromCharCode(0x2028); | ||
| const CHAR_PS = String.fromCharCode(0x2029); | ||
| function createScanner(str) { | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF; | ||
| const isLF = (index) => _buf[index] === CHAR_LF; | ||
| const isPS = (index) => _buf[index] === CHAR_PS; | ||
| const isLS = (index) => _buf[index] === CHAR_LS; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) { | ||
| _index++; | ||
| } | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) { | ||
| _peekOffset++; | ||
| } | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) { | ||
| next(); | ||
| } | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === "\r" && _buf[index + 1] === "\n"; | ||
| const isLF = (index) => _buf[index] === "\n"; | ||
| const isPS = (index) => _buf[index] === "\u2029"; | ||
| const isLS = (index) => _buf[index] === "\u2028"; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? "\n" : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) _index++; | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) _peekOffset++; | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) next(); | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| } | ||
| const EOF = undefined; | ||
| const DOT = '.'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/tokenizer.ts | ||
| const EOF = void 0; | ||
| const DOT = "."; | ||
| const LITERAL_DELIMITER = "'"; | ||
| const ERROR_DOMAIN$1 = 'tokenizer'; | ||
| const ERROR_DOMAIN$1 = "tokenizer"; | ||
| function createTokenizer(source, options = {}) { | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13 /* TokenTypes.EOF */, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13 /* TokenTypes.EOF */, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: '' | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(ctx.startLoc, pos) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) { | ||
| token.loc = createLocation(context.startLoc, context.endLoc); | ||
| } | ||
| if (value != null) { | ||
| token.value = value; | ||
| } | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13 /* TokenTypes.EOF */); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ''; | ||
| while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| cc === 95 // _ | ||
| ); | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek(); | ||
| const ret = isNumberStart(ch); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7 /* TokenTypes.LinkedAlias */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "." /* TokenChars.LinkedDot */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8 /* TokenTypes.LinkedDot */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */)) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":" /* TokenChars.LinkedDelimiter */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| return false; | ||
| } | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return isIdentifierStart(scnr.peek()); | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === ":" /* TokenChars.LinkedDelimiter */ || | ||
| ch === "." /* TokenChars.LinkedDot */ || | ||
| ch === CHAR_SP || | ||
| !ch) { | ||
| return false; | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } | ||
| else { | ||
| // other characters | ||
| return isTextStart(scnr, false); | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|" /* TokenChars.Pipe */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = '') => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || !ch) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "|" /* TokenChars.Pipe */) { | ||
| return !(prev === CHAR_SP || prev === CHAR_LF); | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_SP); | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_LF); | ||
| } | ||
| else { | ||
| return true; | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) { | ||
| return EOF; | ||
| } | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 // $ | ||
| ); | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 || // $ | ||
| cc === 45 // - | ||
| ); | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 48 && cc <= 57) || // 0-9 | ||
| (cc >= 65 && cc <= 70) || // A-F | ||
| (cc >= 97 && cc <= 102)); // a-f | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ''; | ||
| let num = ''; | ||
| while ((ch = takeDigit(scnr))) { | ||
| num += ch; | ||
| } | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ''; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "}" /* TokenChars.BraceRight */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| !ch) { | ||
| break; | ||
| } | ||
| else if (ch === CHAR_SP || ch === CHAR_LF) { | ||
| if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else if (isPluralStart(scnr)) { | ||
| break; | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeNamedIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ''; | ||
| if (scnr.currentChar() === '-') { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } | ||
| else { | ||
| value += getDigits(scnr); | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== CHAR_LF; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| let ch = ''; | ||
| let literal = ''; | ||
| while ((ch = takeChar(scnr, isLiteral))) { | ||
| if (ch === '\\') { | ||
| literal += readEscapeSequence(scnr); | ||
| } | ||
| else { | ||
| literal += ch; | ||
| } | ||
| } | ||
| const current = scnr.currentChar(); | ||
| if (current === CHAR_LF || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| // TODO: Is it correct really? | ||
| if (current === CHAR_LF) { | ||
| scnr.next(); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| } | ||
| return literal; | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case '\\': | ||
| case `\'`: // eslint-disable-line no-useless-escape | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case 'u': | ||
| return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case 'U': | ||
| return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ''; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return (ch !== "{" /* TokenChars.BraceLeft */ && | ||
| ch !== "}" /* TokenChars.BraceRight */ && | ||
| ch !== CHAR_SP && | ||
| ch !== CHAR_LF); | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let identifiers = ''; | ||
| while ((ch = takeChar(scnr, isInvalidIdentifier))) { | ||
| identifiers += ch; | ||
| } | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === "(" /* TokenChars.ParenLeft */ || | ||
| ch === ")" /* TokenChars.ParenRight */ || | ||
| !ch) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_LF || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(''); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|" /* TokenChars.Pipe */); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| if (context.braceNest >= 1) { | ||
| emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 2 /* TokenTypes.BraceLeft */, "{" /* TokenChars.BraceLeft */); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}" /* TokenChars.BraceRight */: | ||
| if (context.braceNest > 0 && | ||
| context.currentType === 2 /* TokenTypes.BraceLeft */) { | ||
| emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) { | ||
| context.inLinked = false; | ||
| } | ||
| return token; | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && | ||
| (context.currentType === 4 /* TokenTypes.Named */ || | ||
| context.currentType === 5 /* TokenTypes.List */ || | ||
| context.currentType === 6 /* TokenTypes.Literal */)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 4 /* TokenTypes.Named */, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validListIdentifier = isListIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 5 /* TokenTypes.List */, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validLiteral = isLiteralStart(scnr, context))) { | ||
| token = getToken(context, 6 /* TokenTypes.Literal */, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ... | ||
| token = getToken(context, 12 /* TokenTypes.InvalidPlace */, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 8 /* TokenTypes.LinkedDot */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */ || | ||
| currentType === 9 /* TokenTypes.LinkedDelimiter */) && | ||
| (ch === CHAR_LF || ch === CHAR_SP)) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| switch (ch) { | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| scnr.next(); | ||
| token = getToken(context, 7 /* TokenTypes.LinkedAlias */, "@" /* TokenChars.LinkedAlias */); | ||
| context.inLinked = true; | ||
| return token; | ||
| case "." /* TokenChars.LinkedDot */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8 /* TokenTypes.LinkedDot */, "." /* TokenChars.LinkedDot */); | ||
| case ":" /* TokenChars.LinkedDelimiter */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9 /* TokenTypes.LinkedDelimiter */, ":" /* TokenChars.LinkedDelimiter */); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || | ||
| isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11 /* TokenTypes.LinkedModifier */, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| // scan the placeholder | ||
| return readTokenInPlaceholder(scnr, context) || token; | ||
| } | ||
| else { | ||
| return getToken(context, 10 /* TokenTypes.LinkedKey */, readLinkedRefer(scnr)); | ||
| } | ||
| } | ||
| if (currentType === 7 /* TokenTypes.LinkedAlias */) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 /* TokenTypes.EOF */ }; | ||
| if (context.braceNest > 0) { | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| } | ||
| if (context.inLinked) { | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| } | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}" /* TokenChars.BraceRight */: | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: { | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) { | ||
| return getToken(context, 0 /* TokenTypes.Text */, readText(scnr)); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) { | ||
| return getToken(_context, 13 /* TokenTypes.EOF */); | ||
| } | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: "" | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(ctx.startLoc, pos) : null, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| })); | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) token.loc = createLocation(context.startLoc, context.endLoc); | ||
| if (value != null) token.value = value; | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ""; | ||
| while (scnr.currentPeek() === " " || scnr.currentPeek() === "\n") { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc === 95; | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isNumberStart(scnr.currentPeek() === "-" ? scnr.peek() : scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "."; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 || currentType === 11)) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9) return false; | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return isIdentifierStart(scnr.peek()); | ||
| else if (ch === "@" || ch === "|" || ch === ":" || ch === "." || ch === " " || !ch) return false; | ||
| else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } else return isTextStart(scnr, false); | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = "") => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return hasSpace; | ||
| else if (ch === "@" || !ch) return hasSpace; | ||
| else if (ch === "|") return !(prev === " " || prev === "\n"); | ||
| else if (ch === " ") { | ||
| scnr.peek(); | ||
| return fn(true, " "); | ||
| } else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(true, "\n"); | ||
| } else return true; | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) return EOF; | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36; | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36 || cc === 45; | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57 || cc >= 65 && cc <= 70 || cc >= 97 && cc <= 102; | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ""; | ||
| let num = ""; | ||
| while (ch = takeDigit(scnr)) num += ch; | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ""; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "\\") { | ||
| const nextCh = scnr.peek(); | ||
| if (nextCh === "{" || nextCh === "}" || nextCh === "@" || nextCh === "|" || nextCh === "\\") { | ||
| buf += ch + nextCh; | ||
| scnr.next(); | ||
| scnr.next(); | ||
| } else { | ||
| scnr.resetPeek(); | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } else if (ch === "{" || ch === "}" || ch === "@" || ch === "|" || !ch) break; | ||
| else if (ch === " " || ch === "\n") if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } else if (isPluralStart(scnr)) break; | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeNamedIdentifierChar(scnr)) name += ch; | ||
| const currentChar = scnr.currentChar(); | ||
| if (currentChar && currentChar !== "}" && currentChar !== EOF && currentChar !== " " && currentChar !== "\n" && currentChar !== " ") { | ||
| const invalidPart = readInvalidIdentifier(scnr); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, name + invalidPart); | ||
| return name + invalidPart; | ||
| } | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ""; | ||
| if (scnr.currentChar() === "-") { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } else value += getDigits(scnr); | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== "\n"; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| eat(scnr, `'`); | ||
| let ch = ""; | ||
| let literal = ""; | ||
| while (ch = takeChar(scnr, isLiteral)) if (ch === "\\") literal += readEscapeSequence(scnr); | ||
| else literal += ch; | ||
| const current = scnr.currentChar(); | ||
| if (current === "\n" || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| if (current === "\n") { | ||
| scnr.next(); | ||
| eat(scnr, `'`); | ||
| } | ||
| return literal; | ||
| } | ||
| eat(scnr, `'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "\\": | ||
| case `'`: | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case "u": return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case "U": return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ""; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return ch !== "{" && ch !== "}" && ch !== " " && ch !== "\n"; | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let identifiers = ""; | ||
| while (ch = takeChar(scnr, isInvalidIdentifier)) identifiers += ch; | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeIdentifierChar(scnr)) name += ch; | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" || ch === "@" || ch === "|" || ch === "(" || ch === ")" || !ch) return buf; | ||
| else if (ch === " ") return buf; | ||
| else if (ch === "\n" || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(""); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|"); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| switch (scnr.currentChar()) { | ||
| case "{": | ||
| if (context.braceNest >= 1) emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 2, "{"); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}": | ||
| if (context.braceNest > 0 && context.currentType === 2) emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 3, "}"); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) context.inLinked = false; | ||
| return token; | ||
| case "@": | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && (context.currentType === 4 || context.currentType === 5 || context.currentType === 6)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if (validNamedIdentifier = isNamedIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 4, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validListIdentifier = isListIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 5, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validLiteral = isLiteralStart(scnr, context)) { | ||
| token = getToken(context, 6, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| token = getToken(context, 12, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 || currentType === 8 || currentType === 11 || currentType === 9) && (ch === "\n" || ch === " ")) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| switch (ch) { | ||
| case "@": | ||
| scnr.next(); | ||
| token = getToken(context, 7, "@"); | ||
| context.inLinked = true; | ||
| return token; | ||
| case ".": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8, "."); | ||
| case ":": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9, ":"); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{") return readTokenInPlaceholder(scnr, context) || token; | ||
| else return getToken(context, 10, readLinkedRefer(scnr)); | ||
| } | ||
| if (currentType === 7) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 }; | ||
| if (context.braceNest > 0) return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| if (context.inLinked) return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| switch (scnr.currentChar()) { | ||
| case "{": return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}": | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3, "}"); | ||
| case "@": return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) return getToken(context, 0, readText(scnr)); | ||
| break; | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) return getToken(_context, 13); | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| } | ||
| const ERROR_DOMAIN = 'parser'; | ||
| // Backslash backslash, backslash quote, uHHHH, UHHHHHH. | ||
| const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/parser.ts | ||
| const ERROR_DOMAIN = "parser"; | ||
| const KNOWN_ESCAPES = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g; | ||
| const TEXT_ESCAPES = /\\([\\@{}|])/g; | ||
| function fromTextEscapeSequence(_match, char) { | ||
| return char; | ||
| } | ||
| function fromEscapeSequence(match, codePoint4, codePoint6) { | ||
| switch (match) { | ||
| case `\\\\`: | ||
| return `\\`; | ||
| // eslint-disable-next-line no-useless-escape | ||
| case `\\\'`: | ||
| // eslint-disable-next-line no-useless-escape | ||
| return `\'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 0xd7ff || codePoint >= 0xe000) { | ||
| return String.fromCodePoint(codePoint); | ||
| } | ||
| // invalid ... | ||
| // Replace them with U+FFFD REPLACEMENT CHARACTER. | ||
| return '�'; | ||
| } | ||
| } | ||
| switch (match) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 55295 || codePoint >= 57344) return String.fromCodePoint(codePoint); | ||
| return "�"; | ||
| } | ||
| } | ||
| } | ||
| function createParser(options = {}) { | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(start, end) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { start: loc, end: loc }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) { | ||
| node.loc.end = pos; | ||
| } | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(5 /* NodeTypes.List */, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(4 /* NodeTypes.Named */, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(9 /* NodeTypes.Literal */, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc | ||
| const node = startNode(8 /* NodeTypes.LinkedModifier */, offset, loc); | ||
| if (token.type !== 11 /* TokenTypes.LinkedModifier */) { | ||
| // empty modifier | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ''; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| // check token | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.value = token.value || ''; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node | ||
| }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7 /* NodeTypes.LinkedKey */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6 /* NodeTypes.Linked */, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8 /* TokenTypes.LinkedDot */) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| // asset check token | ||
| if (token.type !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| token = tokenizer.nextToken(); | ||
| // skip brace left | ||
| if (token.type === 2 /* TokenTypes.BraceLeft */) { | ||
| token = tokenizer.nextToken(); | ||
| } | ||
| switch (token.type) { | ||
| case 10 /* TokenTypes.LinkedKey */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ''); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ''); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseList(tokenizer, token.value || ''); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ''); | ||
| break; | ||
| default: { | ||
| // empty key | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7 /* NodeTypes.LinkedKey */, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ''; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const startOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? tokenizer.currentOffset() | ||
| : context.offset; | ||
| const startLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.endLoc | ||
| : context.startLoc; | ||
| const node = startNode(2 /* NodeTypes.Message */, startOffset, startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0 /* TokenTypes.Text */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseText(tokenizer, token.value || '')); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseList(tokenizer, token.value || '')); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseNamed(tokenizer, token.value || '')); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseLiteral(tokenizer, token.value || '')); | ||
| break; | ||
| case 7 /* TokenTypes.LinkedAlias */: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */ && | ||
| context.currentType !== 1 /* TokenTypes.Pipe */); | ||
| // adjust message node loc | ||
| const endOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastOffset | ||
| : tokenizer.currentOffset(); | ||
| const endLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastEndLoc | ||
| : tokenizer.currentPosition(); | ||
| endNode(node, endOffset, endLoc); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1 /* NodeTypes.Plural */, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) { | ||
| hasEmptyMessage = msg.items.length === 0; | ||
| } | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */); | ||
| if (hasEmptyMessage) { | ||
| emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13 /* TokenTypes.EOF */) { | ||
| return msgNode; | ||
| } | ||
| else { | ||
| return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc); | ||
| if (location && node.loc) { | ||
| node.loc.source = source; | ||
| } | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) { | ||
| node.cacheKey = options.onCacheKey(source); | ||
| } | ||
| // assert whether achieved to EOF | ||
| if (context.currentType !== 13 /* TokenTypes.EOF */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ''); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(start, end) : null, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| })); | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { | ||
| start: loc, | ||
| end: loc | ||
| }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (type) node.type = type; | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) node.loc.end = pos; | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3, context.offset, context.startLoc); | ||
| node.value = value.replace(TEXT_ESCAPES, fromTextEscapeSequence); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(5, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(4, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(9, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; | ||
| const node = startNode(8, offset, loc); | ||
| if (token.type !== 11) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ""; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.value = token.value || ""; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| if (token.type !== 9) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| token = tokenizer.nextToken(); | ||
| if (token.type === 2) token = tokenizer.nextToken(); | ||
| switch (token.type) { | ||
| case 10: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ""); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ""); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseList(tokenizer, token.value || ""); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ""); | ||
| break; | ||
| default: { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ""; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node: linkedNode }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(2, context.currentType === 1 ? tokenizer.currentOffset() : context.offset, context.currentType === 1 ? context.endLoc : context.startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseText(tokenizer, token.value || "")); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseList(tokenizer, token.value || "")); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseNamed(tokenizer, token.value || "")); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseLiteral(tokenizer, token.value || "")); | ||
| break; | ||
| case 7: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 && context.currentType !== 1); | ||
| endNode(node, context.currentType === 1 ? context.lastOffset : tokenizer.currentOffset(), context.currentType === 1 ? context.lastEndLoc : tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) hasEmptyMessage = msg.items.length === 0; | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13); | ||
| if (hasEmptyMessage) emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13) return msgNode; | ||
| else return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0, context.offset, context.startLoc); | ||
| if (location && node.loc) node.loc.source = source; | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) node.cacheKey = options.onCacheKey(source); | ||
| if (context.currentType !== 13) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ""); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| } | ||
| function getTokenCaption(token) { | ||
| if (token.type === 13 /* TokenTypes.EOF */) { | ||
| return 'EOF'; | ||
| } | ||
| const name = (token.value || '').replace(/\r?\n/gu, '\\n'); | ||
| return name.length > 10 ? name.slice(0, 9) + '…' : name; | ||
| if (token.type === 13) return "EOF"; | ||
| const name = (token.value || "").replace(/\r?\n/gu, "\\n"); | ||
| return name.length > 10 ? name.slice(0, 9) + "…" : name; | ||
| } | ||
| function createTransformer(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const _context = { | ||
| ast, | ||
| helpers: new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { context, helper }; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/transformer.ts | ||
| function createTransformer(ast, _options = {}) { | ||
| const _context = { | ||
| ast, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { | ||
| context, | ||
| helper | ||
| }; | ||
| } | ||
| function traverseNodes(nodes, transformer) { | ||
| for (let i = 0; i < nodes.length; i++) { | ||
| traverseNode(nodes[i], transformer); | ||
| } | ||
| for (let i = 0; i < nodes.length; i++) traverseNode(nodes[i], transformer); | ||
| } | ||
| function traverseNode(node, transformer) { | ||
| // TODO: if we need pre-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1 /* NodeTypes.Plural */: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural" /* HelperNameMap.PLURAL */); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| traverseNode(linked.key, transformer); | ||
| transformer.helper("linked" /* HelperNameMap.LINKED */); | ||
| transformer.helper("type" /* HelperNameMap.TYPE */); | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("list" /* HelperNameMap.LIST */); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("named" /* HelperNameMap.NAMED */); | ||
| break; | ||
| } | ||
| // TODO: if we need post-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural"); | ||
| break; | ||
| case 2: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6: | ||
| traverseNode(node.key, transformer); | ||
| transformer.helper("linked"); | ||
| transformer.helper("type"); | ||
| break; | ||
| case 5: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("list"); | ||
| break; | ||
| case 4: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("named"); | ||
| break; | ||
| } | ||
| } | ||
| // transform AST | ||
| function transform(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize" /* HelperNameMap.NORMALIZE */); | ||
| // traverse | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| // set meta information | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| function transform(ast, _options = {}) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize"); | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/compiler.ts | ||
| function baseCompile(source, options = {}) { | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| // parse source codes | ||
| const parser = createParser(assignedOptions); | ||
| const ast = parser.parse(source); | ||
| // TODO: | ||
| // With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible. | ||
| if (!jit) { | ||
| // transform ASTs | ||
| transform(ast, assignedOptions); | ||
| // generate javascript codes | ||
| return generate(ast, assignedOptions); | ||
| } | ||
| else { | ||
| // optimize ASTs | ||
| enableOptimize && optimize(ast); | ||
| // minimize ASTs | ||
| enableMangle && mangle(ast); | ||
| // In JIT mode, no ast transform, no code generation. | ||
| return { ast, code: '' }; | ||
| } | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| const ast = createParser(assignedOptions).parse(source); | ||
| if (!jit) { | ||
| transform(ast, assignedOptions); | ||
| return generate(ast, assignedOptions); | ||
| } else { | ||
| enableOptimize && optimize(ast); | ||
| enableMangle && mangle(ast); | ||
| return { | ||
| ast, | ||
| code: "" | ||
| }; | ||
| } | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; | ||
| //#endregion | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, HelperNameMap, LOCATION_STUB, NodeTypes, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; |
@@ -1,6 +0,788 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| const assign=Object.assign,isString=e=>"string"==typeof e;function join(e,t=""){return e.reduce(((e,n,r)=>0===r?e+n:e+t+n),"")}const LOCATION_STUB={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0}};function createPosition(e,t,n){return{line:e,column:t,offset:n}}function createLocation(e,t,n){const r={start:e,end:t};return null!=n&&(r.source=n),r}const CompileErrorCodes={EXPECTED_TOKEN:1,INVALID_TOKEN_IN_PLACEHOLDER:2,UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER:3,UNKNOWN_ESCAPE_SEQUENCE:4,INVALID_UNICODE_ESCAPE_SEQUENCE:5,UNBALANCED_CLOSING_BRACE:6,UNTERMINATED_CLOSING_BRACE:7,EMPTY_PLACEHOLDER:8,NOT_ALLOW_NEST_PLACEHOLDER:9,INVALID_LINKED_FORMAT:10,MUST_HAVE_MESSAGES_IN_PLURAL:11,UNEXPECTED_EMPTY_LINKED_MODIFIER:12,UNEXPECTED_EMPTY_LINKED_KEY:13,UNEXPECTED_LEXICAL_ANALYSIS:14,UNHANDLED_CODEGEN_NODE_TYPE:15,UNHANDLED_MINIFIER_NODE_TYPE:16},COMPILE_ERROR_CODES_EXTEND_POINT=17,errorMessages={[CompileErrorCodes.EXPECTED_TOKEN]:"Expected token: '{0}'",[CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]:"Invalid token in placeholder: '{0}'",[CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]:"Unterminated single quote in placeholder",[CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]:"Unknown escape sequence: \\{0}",[CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]:"Invalid unicode escape sequence: {0}",[CompileErrorCodes.UNBALANCED_CLOSING_BRACE]:"Unbalanced closing brace",[CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]:"Unterminated closing brace",[CompileErrorCodes.EMPTY_PLACEHOLDER]:"Empty placeholder",[CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]:"Not allowed nest placeholder",[CompileErrorCodes.INVALID_LINKED_FORMAT]:"Invalid linked format",[CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]:"Plural must have messages",[CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]:"Unexpected empty linked modifier",[CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]:"Unexpected empty linked key",[CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]:"Unexpected lexical analysis in token: '{0}'",[CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]:"unhandled codegen node type: '{0}'",[CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]:"unhandled mimifier node type: '{0}'"};function createCompileError(e,t,n={}){const{domain:r,messages:o,args:c}=n,s=new SyntaxError(String(e));return s.code=e,t&&(s.location=t),s.domain=r,s}function defaultOnError(e){throw e}function createCodeGenerator(e,t){const{sourceMap:n,filename:r,breakLineCode:o,needIndent:c}=t,s=!1!==t.location,a={filename:r,code:"",column:1,line:1,offset:0,map:void 0,breakLineCode:o,needIndent:c,indentLevel:0};s&&e.loc&&(a.source=e.loc.source);function i(e,t){a.code+=e}function u(e,t=!0){const n=t?o:"";i(c?n+" ".repeat(e):n)}return{context:()=>a,push:i,indent:function(e=!0){const t=++a.indentLevel;e&&u(t)},deindent:function(e=!0){const t=--a.indentLevel;e&&u(t)},newline:function(){u(a.indentLevel)},helper:e=>`_${e}`,needIndent:()=>a.needIndent}}function generateLinkedNode(e,t){const{helper:n}=e;e.push(`${n("linked")}(`),generateNode(e,t.key),t.modifier?(e.push(", "),generateNode(e,t.modifier),e.push(", _type")):e.push(", undefined, _type"),e.push(")")}function generateMessageNode(e,t){const{helper:n,needIndent:r}=e;e.push(`${n("normalize")}([`),e.indent(r());const o=t.items.length;for(let c=0;c<o&&(generateNode(e,t.items[c]),c!==o-1);c++)e.push(", ");e.deindent(r()),e.push("])")}function generatePluralNode(e,t){const{helper:n,needIndent:r}=e;if(t.cases.length>1){e.push(`${n("plural")}([`),e.indent(r());const o=t.cases.length;for(let n=0;n<o&&(generateNode(e,t.cases[n]),n!==o-1);n++)e.push(", ");e.deindent(r()),e.push("])")}}function generateResource(e,t){t.body?generateNode(e,t.body):e.push("null")}function generateNode(e,t){const{helper:n}=e;switch(t.type){case 0:generateResource(e,t);break;case 1:generatePluralNode(e,t);break;case 2:generateMessageNode(e,t);break;case 6:generateLinkedNode(e,t);break;case 8:case 7:case 9:case 3:e.push(JSON.stringify(t.value),t);break;case 5:e.push(`${n("interpolate")}(${n("list")}(${t.index}))`,t);break;case 4:e.push(`${n("interpolate")}(${n("named")}(${JSON.stringify(t.key)}))`,t)}}const generate=(e,t={})=>{const n=isString(t.mode)?t.mode:"normal",r=isString(t.filename)?t.filename:"message.intl",o=!!t.sourceMap,c=null!=t.breakLineCode?t.breakLineCode:"arrow"===n?";":"\n",s=t.needIndent?t.needIndent:"arrow"!==n,a=e.helpers||[],i=createCodeGenerator(e,{mode:n,filename:r,sourceMap:o,breakLineCode:c,needIndent:s});i.push("normal"===n?"function __msg__ (ctx) {":"(ctx) => {"),i.indent(s),a.length>0&&(i.push(`const { ${join(a.map((e=>`${e}: _${e}`)),", ")} } = ctx`),i.newline()),i.push("return "),generateNode(i,e),i.deindent(s),i.push("}"),delete e.helpers;const{code:u,map:l}=i.context();return{ast:e,code:u,map:l?l.toJSON():void 0}};function mangle(e){switch(e.t=e.type,e.type){case 0:{const t=e;mangle(t.body),t.b=t.body,delete t.body;break}case 1:{const t=e,n=t.cases;for(let e=0;e<n.length;e++)mangle(n[e]);t.c=n,delete t.cases;break}case 2:{const t=e,n=t.items;for(let e=0;e<n.length;e++)mangle(n[e]);t.i=n,delete t.items,t.static&&(t.s=t.static,delete t.static);break}case 3:case 9:case 8:case 7:{const t=e;t.value&&(t.v=t.value,delete t.value);break}case 6:{const t=e;mangle(t.key),t.k=t.key,delete t.key,t.modifier&&(mangle(t.modifier),t.m=t.modifier,delete t.modifier);break}case 5:{const t=e;t.i=t.index,delete t.index;break}case 4:{const t=e;t.k=t.key,delete t.key;break}}delete e.type}function optimize(e){const t=e.body;return 2===t.type?optimizeMessageNode(t):t.cases.forEach((e=>optimizeMessageNode(e))),e}function optimizeMessageNode(e){if(1===e.items.length){const t=e.items[0];3!==t.type&&9!==t.type||(e.static=t.value,delete t.value)}else{const t=[];for(let n=0;n<e.items.length;n++){const r=e.items[n];if(3!==r.type&&9!==r.type)break;if(null==r.value)break;t.push(r.value)}if(t.length===e.items.length){e.static=join(t);for(let t=0;t<e.items.length;t++){const n=e.items[t];3!==n.type&&9!==n.type||delete n.value}}}}const CHAR_SP=" ",CHAR_CR="\r",CHAR_LF="\n",CHAR_LS=String.fromCharCode(8232),CHAR_PS=String.fromCharCode(8233);function createScanner(e){const t=e;let n=0,r=1,o=1,c=0;const s=e=>t[e]===CHAR_CR&&t[e+1]===CHAR_LF,a=e=>t[e]===CHAR_PS,i=e=>t[e]===CHAR_LS,u=e=>s(e)||(e=>t[e]===CHAR_LF)(e)||a(e)||i(e),l=e=>s(e)||a(e)||i(e)?CHAR_LF:t[e];function E(){return c=0,u(n)&&(r++,o=0),s(n)&&n++,n++,o++,t[n]}return{index:()=>n,line:()=>r,column:()=>o,peekOffset:()=>c,charAt:l,currentChar:()=>l(n),currentPeek:()=>l(n+c),next:E,peek:function(){return s(n+c)&&c++,c++,t[n+c]},reset:function(){n=0,r=1,o=1,c=0},resetPeek:function(e=0){c=e},skipToPeek:function(){const e=n+c;for(;e!==n;)E();c=0}}}const EOF=void 0,DOT=".",LITERAL_DELIMITER="'",ERROR_DOMAIN$1="tokenizer";function createTokenizer(e,t={}){const n=!1!==t.location,r=createScanner(e),o=()=>r.index(),c=()=>createPosition(r.line(),r.column(),r.index()),s=c(),a=o(),i={currentType:13,offset:a,startLoc:s,endLoc:s,lastType:13,lastOffset:a,lastStartLoc:s,lastEndLoc:s,braceNest:0,inLinked:!1,text:""},u=()=>i,{onError:l}=t;function E(e,t,r){e.endLoc=c(),e.currentType=t;const o={type:t};return n&&(o.loc=createLocation(e.startLoc,e.endLoc)),null!=r&&(o.value=r),o}const C=e=>E(e,13);function f(e,t){return e.currentChar()===t?(e.next(),t):(CompileErrorCodes.EXPECTED_TOKEN,c(),"")}function d(e){let t="";for(;e.currentPeek()===CHAR_SP||e.currentPeek()===CHAR_LF;)t+=e.currentPeek(),e.peek();return t}function p(e){const t=d(e);return e.skipToPeek(),t}function L(e){if(e===EOF)return!1;const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||95===t}function _(e,t){const{currentType:n}=t;if(2!==n)return!1;d(e);const r=function(e){if(e===EOF)return!1;const t=e.charCodeAt(0);return t>=48&&t<=57}("-"===e.currentPeek()?e.peek():e.currentPeek());return e.resetPeek(),r}function N(e){d(e);const t="|"===e.currentPeek();return e.resetPeek(),t}function A(e,t=!0){const n=(t=!1,r="")=>{const o=e.currentPeek();return"{"===o?t:"@"!==o&&o?"|"===o?!(r===CHAR_SP||r===CHAR_LF):o===CHAR_SP?(e.peek(),n(!0,CHAR_SP)):o!==CHAR_LF||(e.peek(),n(!0,CHAR_LF)):t},r=n();return t&&e.resetPeek(),r}function T(e,t){const n=e.currentChar();return n===EOF?EOF:t(n)?(e.next(),n):null}function m(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t}function k(e){return T(e,m)}function I(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t||45===t}function S(e){return T(e,I)}function P(e){const t=e.charCodeAt(0);return t>=48&&t<=57}function O(e){return T(e,P)}function h(e){const t=e.charCodeAt(0);return t>=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102}function R(e){return T(e,h)}function D(e){let t="",n="";for(;t=O(e);)n+=t;return n}function y(e){return e!==LITERAL_DELIMITER&&e!==CHAR_LF}function g(e){const t=e.currentChar();switch(t){case"\\":case"'":return e.next(),`\\${t}`;case"u":return b(e,t,4);case"U":return b(e,t,6);default:return CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE,c(),""}}function b(e,t,n){f(e,t);let r="";for(let o=0;o<n;o++){const t=R(e);if(!t){CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE,c(),e.currentChar();break}r+=t}return`\\${t}${r}`}function U(e){return"{"!==e&&"}"!==e&&e!==CHAR_SP&&e!==CHAR_LF}function x(e){p(e);const t=f(e,"|");return p(e),t}function v(e,t){let n=null;switch(e.currentChar()){case"{":return t.braceNest>=1&&(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER,c()),e.next(),n=E(t,2,"{"),p(e),t.braceNest++,n;case"}":return t.braceNest>0&&2===t.currentType&&(CompileErrorCodes.EMPTY_PLACEHOLDER,c()),e.next(),n=E(t,3,"}"),t.braceNest--,t.braceNest>0&&p(e),t.inLinked&&0===t.braceNest&&(t.inLinked=!1),n;case"@":return t.braceNest>0&&(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE,c()),n=H(e,t)||C(t),t.braceNest=0,n;default:{let r=!0,o=!0,s=!0;if(N(e))return t.braceNest>0&&(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE,c()),n=E(t,1,x(e)),t.braceNest=0,t.inLinked=!1,n;if(t.braceNest>0&&(4===t.currentType||5===t.currentType||6===t.currentType))return CompileErrorCodes.UNTERMINATED_CLOSING_BRACE,c(),t.braceNest=0,M(e,t);if(r=function(e,t){const{currentType:n}=t;if(2!==n)return!1;d(e);const r=L(e.currentPeek());return e.resetPeek(),r}(e,t))return n=E(t,4,function(e){p(e);let t="",n="";for(;t=S(e);)n+=t;return e.currentChar()===EOF&&(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE,c()),n}(e)),p(e),n;if(o=_(e,t))return n=E(t,5,function(e){p(e);let t="";return"-"===e.currentChar()?(e.next(),t+=`-${D(e)}`):t+=D(e),e.currentChar()===EOF&&(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE,c()),t}(e)),p(e),n;if(s=function(e,t){const{currentType:n}=t;if(2!==n)return!1;d(e);const r=e.currentPeek()===LITERAL_DELIMITER;return e.resetPeek(),r}(e,t))return n=E(t,6,function(e){p(e),f(e,"'");let t="",n="";for(;t=T(e,y);)n+="\\"===t?g(e):t;const r=e.currentChar();return r===CHAR_LF||r===EOF?(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,c(),r===CHAR_LF&&(e.next(),f(e,"'")),n):(f(e,"'"),n)}(e)),p(e),n;if(!r&&!o&&!s)return n=E(t,12,function(e){p(e);let t="",n="";for(;t=T(e,U);)n+=t;return n}(e)),CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER,c(),n.value,p(e),n;break}}return n}function H(e,t){const{currentType:n}=t;let r=null;const o=e.currentChar();switch(7!==n&&8!==n&&11!==n&&9!==n||o!==CHAR_LF&&o!==CHAR_SP||(CompileErrorCodes.INVALID_LINKED_FORMAT,c()),o){case"@":return e.next(),r=E(t,7,"@"),t.inLinked=!0,r;case".":return p(e),e.next(),E(t,8,".");case":":return p(e),e.next(),E(t,9,":");default:return N(e)?(r=E(t,1,x(e)),t.braceNest=0,t.inLinked=!1,r):function(e,t){const{currentType:n}=t;if(7!==n)return!1;d(e);const r="."===e.currentPeek();return e.resetPeek(),r}(e,t)||function(e,t){const{currentType:n}=t;if(7!==n&&11!==n)return!1;d(e);const r=":"===e.currentPeek();return e.resetPeek(),r}(e,t)?(p(e),H(e,t)):function(e,t){const{currentType:n}=t;if(8!==n)return!1;d(e);const r=L(e.currentPeek());return e.resetPeek(),r}(e,t)?(p(e),E(t,11,function(e){let t="",n="";for(;t=k(e);)n+=t;return n}(e))):function(e,t){const{currentType:n}=t;if(9!==n)return!1;const r=()=>{const t=e.currentPeek();return"{"===t?L(e.peek()):!("@"===t||"|"===t||":"===t||"."===t||t===CHAR_SP||!t)&&(t===CHAR_LF?(e.peek(),r()):A(e,!1))},o=r();return e.resetPeek(),o}(e,t)?(p(e),"{"===o?v(e,t)||r:E(t,10,function(e){const t=n=>{const r=e.currentChar();return"{"!==r&&"@"!==r&&"|"!==r&&"("!==r&&")"!==r&&r?r===CHAR_SP?n:(n+=r,e.next(),t(n)):n};return t("")}(e))):(7===n&&(CompileErrorCodes.INVALID_LINKED_FORMAT,c()),t.braceNest=0,t.inLinked=!1,M(e,t))}}function M(e,t){let n={type:13};if(t.braceNest>0)return v(e,t)||C(t);if(t.inLinked)return H(e,t)||C(t);switch(e.currentChar()){case"{":return v(e,t)||C(t);case"}":return CompileErrorCodes.UNBALANCED_CLOSING_BRACE,c(),e.next(),E(t,3,"}");case"@":return H(e,t)||C(t);default:if(N(e))return n=E(t,1,x(e)),t.braceNest=0,t.inLinked=!1,n;if(A(e))return E(t,0,function(e){let t="";for(;;){const n=e.currentChar();if("{"===n||"}"===n||"@"===n||"|"===n||!n)break;if(n===CHAR_SP||n===CHAR_LF)if(A(e))t+=n,e.next();else{if(N(e))break;t+=n,e.next()}else t+=n,e.next()}return t}(e))}return n}return{nextToken:function(){const{currentType:e,offset:t,startLoc:n,endLoc:s}=i;return i.lastType=e,i.lastOffset=t,i.lastStartLoc=n,i.lastEndLoc=s,i.offset=o(),i.startLoc=c(),r.currentChar()===EOF?E(i,13):M(r,i)},currentOffset:o,currentPosition:c,context:u}}const ERROR_DOMAIN="parser",KNOWN_ESCAPES=/(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;function fromEscapeSequence(e,t,n){switch(e){case"\\\\":return"\\";case"\\'":return"'";default:{const e=parseInt(t||n,16);return e<=55295||e>=57344?String.fromCodePoint(e):"�"}}}function createParser(e={}){const t=!1!==e.location,{onError:n}=e;function r(e,n,r){const o={type:e};return t&&(o.start=n,o.end=n,o.loc={start:r,end:r}),o}function o(e,n,r,o){t&&(e.end=n,e.loc&&(e.loc.end=r))}function c(e,t){const n=e.context(),c=r(3,n.offset,n.startLoc);return c.value=t,o(c,e.currentOffset(),e.currentPosition()),c}function s(e,t){const n=e.context(),{lastOffset:c,lastStartLoc:s}=n,a=r(5,c,s);return a.index=parseInt(t,10),e.nextToken(),o(a,e.currentOffset(),e.currentPosition()),a}function a(e,t){const n=e.context(),{lastOffset:c,lastStartLoc:s}=n,a=r(4,c,s);return a.key=t,e.nextToken(),o(a,e.currentOffset(),e.currentPosition()),a}function i(e,t){const n=e.context(),{lastOffset:c,lastStartLoc:s}=n,a=r(9,c,s);return a.value=t.replace(KNOWN_ESCAPES,fromEscapeSequence),e.nextToken(),o(a,e.currentOffset(),e.currentPosition()),a}function u(e){const t=e.context(),n=r(6,t.offset,t.startLoc);let c=e.nextToken();if(8===c.type){const t=function(e){const t=e.nextToken(),n=e.context(),{lastOffset:c,lastStartLoc:s}=n,a=r(8,c,s);return 11!==t.type?(CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER,n.lastStartLoc,a.value="",o(a,c,s),{nextConsumeToken:t,node:a}):(null==t.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,n.lastStartLoc,getTokenCaption(t)),a.value=t.value||"",o(a,e.currentOffset(),e.currentPosition()),{node:a})}(e);n.modifier=t.node,c=t.nextConsumeToken||e.nextToken()}switch(9!==c.type&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(c)),c=e.nextToken(),2===c.type&&(c=e.nextToken()),c.type){case 10:null==c.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(c)),n.key=function(e,t){const n=e.context(),c=r(7,n.offset,n.startLoc);return c.value=t,o(c,e.currentOffset(),e.currentPosition()),c}(e,c.value||"");break;case 4:null==c.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(c)),n.key=a(e,c.value||"");break;case 5:null==c.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(c)),n.key=s(e,c.value||"");break;case 6:null==c.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(c)),n.key=i(e,c.value||"");break;default:{CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY,t.lastStartLoc;const s=e.context(),a=r(7,s.offset,s.startLoc);return a.value="",o(a,s.offset,s.startLoc),n.key=a,o(n,s.offset,s.startLoc),{nextConsumeToken:c,node:n}}}return o(n,e.currentOffset(),e.currentPosition()),{node:n}}function l(e){const t=e.context(),n=r(2,1===t.currentType?e.currentOffset():t.offset,1===t.currentType?t.endLoc:t.startLoc);n.items=[];let l=null;do{const r=l||e.nextToken();switch(l=null,r.type){case 0:null==r.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(r)),n.items.push(c(e,r.value||""));break;case 5:null==r.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(r)),n.items.push(s(e,r.value||""));break;case 4:null==r.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(r)),n.items.push(a(e,r.value||""));break;case 6:null==r.value&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,getTokenCaption(r)),n.items.push(i(e,r.value||""));break;case 7:{const t=u(e);n.items.push(t.node),l=t.nextConsumeToken||null;break}}}while(13!==t.currentType&&1!==t.currentType);return o(n,1===t.currentType?t.lastOffset:e.currentOffset(),1===t.currentType?t.lastEndLoc:e.currentPosition()),n}function E(e){const t=e.context(),{offset:n,startLoc:c}=t,s=l(e);return 13===t.currentType?s:function(e,t,n,c){const s=e.context();let a=0===c.items.length;const i=r(1,t,n);i.cases=[],i.cases.push(c);do{const t=l(e);a||(a=0===t.items.length),i.cases.push(t)}while(13!==s.currentType);return a&&CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL,o(i,e.currentOffset(),e.currentPosition()),i}(e,n,c,s)}return{parse:function(n){const c=createTokenizer(n,assign({},e)),s=c.context(),a=r(0,s.offset,s.startLoc);return t&&a.loc&&(a.loc.source=n),a.body=E(c),e.onCacheKey&&(a.cacheKey=e.onCacheKey(n)),13!==s.currentType&&(CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS,s.lastStartLoc,n[s.offset]),o(a,c.currentOffset(),c.currentPosition()),a}}}function getTokenCaption(e){if(13===e.type)return"EOF";const t=(e.value||"").replace(/\r?\n/gu,"\\n");return t.length>10?t.slice(0,9)+"…":t}function createTransformer(e,t={}){const n={ast:e,helpers:new Set};return{context:()=>n,helper:e=>(n.helpers.add(e),e)}}function traverseNodes(e,t){for(let n=0;n<e.length;n++)traverseNode(e[n],t)}function traverseNode(e,t){switch(e.type){case 1:traverseNodes(e.cases,t),t.helper("plural");break;case 2:traverseNodes(e.items,t);break;case 6:traverseNode(e.key,t),t.helper("linked"),t.helper("type");break;case 5:t.helper("interpolate"),t.helper("list");break;case 4:t.helper("interpolate"),t.helper("named")}}function transform(e,t={}){const n=createTransformer(e);n.helper("normalize"),e.body&&traverseNode(e.body,n);const r=n.context();e.helpers=Array.from(r.helpers)}function baseCompile(e,t={}){const n=assign({},t),r=!!n.jit,o=!!n.mangle,c=null==n.optimize||n.optimize,s=createParser(n).parse(e);return r?(c&&optimize(s),o&&mangle(s),{ast:s,code:""}):(transform(s,n),generate(s,n))}const RE_HTML_TAG=/<\/?[\w\s="/.':;#-\/]+>/,detectHtmlTag=e=>RE_HTML_TAG.test(e);export{COMPILE_ERROR_CODES_EXTEND_POINT,CompileErrorCodes,ERROR_DOMAIN,LOCATION_STUB,baseCompile,createCompileError,createLocation,createParser,createPosition,defaultOnError,detectHtmlTag,errorMessages,mangle,optimize}; | ||
| /** | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ const assign = Object.assign; | ||
| Array.isArray; | ||
| const isString = (e) => typeof e == `string`; | ||
| function join(e, t = ``) { | ||
| return e.reduce((e, n, r) => r === 0 ? e + n : e + t + n, ``); | ||
| } | ||
| let NodeTypes = function(e) { | ||
| return e[e.Resource = 0] = `Resource`, e[e.Plural = 1] = `Plural`, e[e.Message = 2] = `Message`, e[e.Text = 3] = `Text`, e[e.Named = 4] = `Named`, e[e.List = 5] = `List`, e[e.Linked = 6] = `Linked`, e[e.LinkedKey = 7] = `LinkedKey`, e[e.LinkedModifier = 8] = `LinkedModifier`, e[e.Literal = 9] = `Literal`, e; | ||
| }({}); | ||
| const LOCATION_STUB = { | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function createPosition(e, t, n) { | ||
| return { | ||
| line: e, | ||
| column: t, | ||
| offset: n | ||
| }; | ||
| } | ||
| function createLocation(e, t, n) { | ||
| let r = { | ||
| start: e, | ||
| end: t | ||
| }; | ||
| return n != null && (r.source = n), r; | ||
| } | ||
| let HelperNameMap = function(e) { | ||
| return e.LIST = `list`, e.NAMED = `named`, e.PLURAL = `plural`, e.LINKED = `linked`, e.MESSAGE = `message`, e.TYPE = `type`, e.INTERPOLATE = `interpolate`, e.NORMALIZE = `normalize`, e.VALUES = `values`, e; | ||
| }({}); | ||
| const RE_HTML_TAG = /<[\w\s=":;#-/]+>/, detectHtmlTag = (e) => RE_HTML_TAG.test(e), CompileErrorCodes = { | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }, COMPILE_ERROR_CODES_EXTEND_POINT = 17, errorMessages = { | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(e, t, n = {}) { | ||
| let { domain: r, messages: i, args: a } = n, o = SyntaxError(String(e)); | ||
| return o.code = e, t && (o.location = t), o.domain = r, o; | ||
| } | ||
| function defaultOnError(e) { | ||
| throw e; | ||
| } | ||
| function createCodeGenerator(e, t) { | ||
| let { sourceMap: n, filename: r, breakLineCode: i, needIndent: a } = t, o = t.location !== !1, s = { | ||
| filename: r, | ||
| code: ``, | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode: i, | ||
| needIndent: a, | ||
| indentLevel: 0 | ||
| }; | ||
| o && e.loc && (s.source = e.loc.source); | ||
| let c = () => s; | ||
| function l(e, t) { | ||
| s.code += e; | ||
| } | ||
| function u(e, t = !0) { | ||
| let n = t ? i : ``; | ||
| l(a ? n + ` `.repeat(e) : n); | ||
| } | ||
| function d(e = !0) { | ||
| let t = ++s.indentLevel; | ||
| e && u(t); | ||
| } | ||
| function f(e = !0) { | ||
| let t = --s.indentLevel; | ||
| e && u(t); | ||
| } | ||
| function p() { | ||
| u(s.indentLevel); | ||
| } | ||
| return { | ||
| context: c, | ||
| push: l, | ||
| indent: d, | ||
| deindent: f, | ||
| newline: p, | ||
| helper: (e) => `_${e}`, | ||
| needIndent: () => s.needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(e, t) { | ||
| let { helper: n } = e; | ||
| e.push(`${n(`linked`)}(`), generateNode(e, t.key), t.modifier ? (e.push(`, `), generateNode(e, t.modifier), e.push(`, _type`)) : e.push(`, undefined, _type`), e.push(`)`); | ||
| } | ||
| function generateMessageNode(e, t) { | ||
| let { helper: n, needIndent: r } = e; | ||
| e.push(`${n(`normalize`)}([`), e.indent(r()); | ||
| let i = t.items.length; | ||
| for (let n = 0; n < i && (generateNode(e, t.items[n]), n !== i - 1); n++) e.push(`, `); | ||
| e.deindent(r()), e.push(`])`); | ||
| } | ||
| function generatePluralNode(e, t) { | ||
| let { helper: n, needIndent: r } = e; | ||
| if (t.cases.length > 1) { | ||
| e.push(`${n(`plural`)}([`), e.indent(r()); | ||
| let i = t.cases.length; | ||
| for (let n = 0; n < i && (generateNode(e, t.cases[n]), n !== i - 1); n++) e.push(`, `); | ||
| e.deindent(r()), e.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(e, t) { | ||
| t.body ? generateNode(e, t.body) : e.push(`null`); | ||
| } | ||
| function generateNode(e, t) { | ||
| let { helper: n } = e; | ||
| switch (t.type) { | ||
| case 0: | ||
| generateResource(e, t); | ||
| break; | ||
| case 1: | ||
| generatePluralNode(e, t); | ||
| break; | ||
| case 2: | ||
| generateMessageNode(e, t); | ||
| break; | ||
| case 6: | ||
| generateLinkedNode(e, t); | ||
| break; | ||
| case 8: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 7: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 5: | ||
| e.push(`${n(`interpolate`)}(${n(`list`)}(${t.index}))`, t); | ||
| break; | ||
| case 4: | ||
| e.push(`${n(`interpolate`)}(${n(`named`)}(${JSON.stringify(t.key)}))`, t); | ||
| break; | ||
| case 9: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 3: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| default: | ||
| } | ||
| } | ||
| const generate = (e, t = {}) => { | ||
| let i = isString(t.mode) ? t.mode : `normal`, a = isString(t.filename) ? t.filename : `message.intl`, o = !!t.sourceMap, s = t.breakLineCode == null ? i === `arrow` ? `;` : ` | ||
| ` : t.breakLineCode, c = t.needIndent ? t.needIndent : i !== `arrow`, l = e.helpers || [], u = createCodeGenerator(e, { | ||
| mode: i, | ||
| filename: a, | ||
| sourceMap: o, | ||
| breakLineCode: s, | ||
| needIndent: c | ||
| }); | ||
| u.push(i === `normal` ? `function __msg__ (ctx) {` : `(ctx) => {`), u.indent(c), l.length > 0 && (u.push(`const { ${join(l.map((e) => `${e}: _${e}`), `, `)} } = ctx`), u.newline()), u.push(`return `), generateNode(u, e), u.deindent(c), u.push(`}`), delete e.helpers; | ||
| let { code: d, map: f } = u.context(); | ||
| return { | ||
| ast: e, | ||
| code: d, | ||
| map: f ? f.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| function mangle(e) { | ||
| switch (e.t = e.type, e.type) { | ||
| case 0: { | ||
| let t = e; | ||
| mangle(t.body), t.b = t.body, delete t.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| let t = e, n = t.cases; | ||
| for (let e = 0; e < n.length; e++) mangle(n[e]); | ||
| t.c = n, delete t.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| let t = e, n = t.items; | ||
| for (let e = 0; e < n.length; e++) mangle(n[e]); | ||
| t.i = n, delete t.items, t.static && (t.s = t.static, delete t.static); | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| let t = e; | ||
| t.value && (t.v = t.value, delete t.value); | ||
| break; | ||
| } | ||
| case 6: { | ||
| let t = e; | ||
| mangle(t.key), t.k = t.key, delete t.key, t.modifier && (mangle(t.modifier), t.m = t.modifier, delete t.modifier); | ||
| break; | ||
| } | ||
| case 5: { | ||
| let t = e; | ||
| t.i = t.index, delete t.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| let t = e; | ||
| t.k = t.key, delete t.key; | ||
| break; | ||
| } | ||
| default: | ||
| } | ||
| delete e.type; | ||
| } | ||
| function optimize(e) { | ||
| let t = e.body; | ||
| return t.type === 2 ? optimizeMessageNode(t) : t.cases.forEach((e) => optimizeMessageNode(e)), e; | ||
| } | ||
| function optimizeMessageNode(e) { | ||
| if (e.items.length === 1) { | ||
| let t = e.items[0]; | ||
| (t.type === 3 || t.type === 9) && (e.static = t.value, delete t.value); | ||
| } else { | ||
| let t = []; | ||
| for (let n = 0; n < e.items.length; n++) { | ||
| let r = e.items[n]; | ||
| if (!(r.type === 3 || r.type === 9) || r.value == null) break; | ||
| t.push(r.value); | ||
| } | ||
| if (t.length === e.items.length) { | ||
| e.static = join(t); | ||
| for (let t = 0; t < e.items.length; t++) { | ||
| let n = e.items[t]; | ||
| (n.type === 3 || n.type === 9) && delete n.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function createScanner(e) { | ||
| let t = e, n = 0, r = 1, i = 1, a = 0, o = (e) => t[e] === `\r` && t[e + 1] === ` | ||
| `, s = (e) => t[e] === ` | ||
| `, c = (e) => t[e] === `\u2029`, l = (e) => t[e] === `\u2028`, u = (e) => o(e) || s(e) || c(e) || l(e), d = () => n, f = () => r, p = () => i, m = () => a, h = (e) => o(e) || c(e) || l(e) ? ` | ||
| ` : t[e], g = () => h(n), _ = () => h(n + a); | ||
| function v() { | ||
| return a = 0, u(n) && (r++, i = 0), o(n) && n++, n++, i++, t[n]; | ||
| } | ||
| function y() { | ||
| return o(n + a) && a++, a++, t[n + a]; | ||
| } | ||
| function b() { | ||
| n = 0, r = 1, i = 1, a = 0; | ||
| } | ||
| function x(e = 0) { | ||
| a = e; | ||
| } | ||
| function S() { | ||
| let e = n + a; | ||
| for (; e !== n;) v(); | ||
| a = 0; | ||
| } | ||
| return { | ||
| index: d, | ||
| line: f, | ||
| column: p, | ||
| peekOffset: m, | ||
| charAt: h, | ||
| currentChar: g, | ||
| currentPeek: _, | ||
| next: v, | ||
| peek: y, | ||
| reset: b, | ||
| resetPeek: x, | ||
| skipToPeek: S | ||
| }; | ||
| } | ||
| function createTokenizer(e, t = {}) { | ||
| let n = t.location !== !1, r = createScanner(e), i = () => r.index(), a = () => createPosition(r.line(), r.column(), r.index()), c = a(), l = i(), u = { | ||
| currentType: 13, | ||
| offset: l, | ||
| startLoc: c, | ||
| endLoc: c, | ||
| lastType: 13, | ||
| lastOffset: l, | ||
| lastStartLoc: c, | ||
| lastEndLoc: c, | ||
| braceNest: 0, | ||
| inLinked: !1, | ||
| text: `` | ||
| }, f = () => u, { onError: p } = t; | ||
| function m(e, t, r) { | ||
| e.endLoc = a(), e.currentType = t; | ||
| let i = { type: t }; | ||
| return n && (i.loc = createLocation(e.startLoc, e.endLoc)), r != null && (i.value = r), i; | ||
| } | ||
| let h = (e) => m(e, 13); | ||
| function g(e, t) { | ||
| return e.currentChar() === t ? (e.next(), t) : (CompileErrorCodes.EXPECTED_TOKEN, a(), ``); | ||
| } | ||
| function _(e) { | ||
| let t = ``; | ||
| for (; e.currentPeek() === ` ` || e.currentPeek() === ` | ||
| `;) t += e.currentPeek(), e.peek(); | ||
| return t; | ||
| } | ||
| function v(e) { | ||
| let t = _(e); | ||
| return e.skipToPeek(), t; | ||
| } | ||
| function y(e) { | ||
| if (e === void 0) return !1; | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t === 95; | ||
| } | ||
| function b(e) { | ||
| if (e === void 0) return !1; | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57; | ||
| } | ||
| function x(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| _(e); | ||
| let r = y(e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function S(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| _(e); | ||
| let r = b(e.currentPeek() === `-` ? e.peek() : e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function C(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| _(e); | ||
| let r = e.currentPeek() === `'`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function w(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 7) return !1; | ||
| _(e); | ||
| let r = e.currentPeek() === `.`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function T(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 8) return !1; | ||
| _(e); | ||
| let r = y(e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function E(e, t) { | ||
| let { currentType: n } = t; | ||
| if (!(n === 7 || n === 11)) return !1; | ||
| _(e); | ||
| let r = e.currentPeek() === `:`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function D(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 9) return !1; | ||
| let r = () => { | ||
| let t = e.currentPeek(); | ||
| return t === `{` ? y(e.peek()) : t === `@` || t === `|` || t === `:` || t === `.` || t === ` ` || !t ? !1 : t === ` | ||
| ` ? (e.peek(), r()) : k(e, !1); | ||
| }, i = r(); | ||
| return e.resetPeek(), i; | ||
| } | ||
| function O(e) { | ||
| _(e); | ||
| let t = e.currentPeek() === `|`; | ||
| return e.resetPeek(), t; | ||
| } | ||
| function k(e, t = !0) { | ||
| let n = (t = !1, r = ``) => { | ||
| let i = e.currentPeek(); | ||
| return i === `{` || i === `@` || !i ? t : i === `|` ? !(r === ` ` || r === ` | ||
| `) : i === ` ` ? (e.peek(), n(!0, ` `)) : i === ` | ||
| ` ? (e.peek(), n(!0, ` | ||
| `)) : !0; | ||
| }, r = n(); | ||
| return t && e.resetPeek(), r; | ||
| } | ||
| function A(e, t) { | ||
| let n = e.currentChar(); | ||
| if (n !== void 0) return t(n) ? (e.next(), n) : null; | ||
| } | ||
| function j(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t >= 48 && t <= 57 || t === 95 || t === 36; | ||
| } | ||
| function M(e) { | ||
| return A(e, j); | ||
| } | ||
| function ee(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t >= 48 && t <= 57 || t === 95 || t === 36 || t === 45; | ||
| } | ||
| function N(e) { | ||
| return A(e, ee); | ||
| } | ||
| function P(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57; | ||
| } | ||
| function F(e) { | ||
| return A(e, P); | ||
| } | ||
| function I(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57 || t >= 65 && t <= 70 || t >= 97 && t <= 102; | ||
| } | ||
| function L(e) { | ||
| return A(e, I); | ||
| } | ||
| function R(e) { | ||
| let t = ``, n = ``; | ||
| for (; t = F(e);) n += t; | ||
| return n; | ||
| } | ||
| function z(e) { | ||
| let t = ``; | ||
| for (;;) { | ||
| let n = e.currentChar(); | ||
| if (n === `\\`) { | ||
| let r = e.peek(); | ||
| r === `{` || r === `}` || r === `@` || r === `|` || r === `\\` ? (t += n + r, e.next(), e.next()) : (e.resetPeek(), t += n, e.next()); | ||
| } else if (n === `{` || n === `}` || n === `@` || n === `|` || !n) break; | ||
| else if (n === ` ` || n === ` | ||
| `) if (k(e)) t += n, e.next(); | ||
| else if (O(e)) break; | ||
| else t += n, e.next(); | ||
| else t += n, e.next(); | ||
| } | ||
| return t; | ||
| } | ||
| function B(e) { | ||
| v(e); | ||
| let t = ``, n = ``; | ||
| for (; t = N(e);) n += t; | ||
| let r = e.currentChar(); | ||
| if (r && r !== `}` && r !== void 0 && r !== ` ` && r !== ` | ||
| ` && r !== ` `) { | ||
| let t = q(e); | ||
| return CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, a(), n + t, n + t; | ||
| } | ||
| return e.currentChar() === void 0 && (CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, a()), n; | ||
| } | ||
| function V(e) { | ||
| v(e); | ||
| let t = ``; | ||
| return e.currentChar() === `-` ? (e.next(), t += `-${R(e)}`) : t += R(e), e.currentChar() === void 0 && (CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, a()), t; | ||
| } | ||
| function H(e) { | ||
| return e !== `'` && e !== ` | ||
| `; | ||
| } | ||
| function U(e) { | ||
| v(e), g(e, `'`); | ||
| let t = ``, n = ``; | ||
| for (; t = A(e, H);) t === `\\` ? n += W(e) : n += t; | ||
| let r = e.currentChar(); | ||
| return r === ` | ||
| ` || r === void 0 ? (CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, a(), r === ` | ||
| ` && (e.next(), g(e, `'`)), n) : (g(e, `'`), n); | ||
| } | ||
| function W(e) { | ||
| let t = e.currentChar(); | ||
| switch (t) { | ||
| case `\\`: | ||
| case `'`: return e.next(), `\\${t}`; | ||
| case `u`: return G(e, t, 4); | ||
| case `U`: return G(e, t, 6); | ||
| default: return CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, a(), ``; | ||
| } | ||
| } | ||
| function G(e, t, n) { | ||
| g(e, t); | ||
| let r = ``; | ||
| for (let i = 0; i < n; i++) { | ||
| let n = L(e); | ||
| if (!n) { | ||
| CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, a(), `${t}${r}${e.currentChar()}`; | ||
| break; | ||
| } | ||
| r += n; | ||
| } | ||
| return `\\${t}${r}`; | ||
| } | ||
| function K(e) { | ||
| return e !== `{` && e !== `}` && e !== ` ` && e !== ` | ||
| `; | ||
| } | ||
| function q(e) { | ||
| v(e); | ||
| let t = ``, n = ``; | ||
| for (; t = A(e, K);) n += t; | ||
| return n; | ||
| } | ||
| function J(e) { | ||
| let t = ``, n = ``; | ||
| for (; t = M(e);) n += t; | ||
| return n; | ||
| } | ||
| function Y(e) { | ||
| let t = (n) => { | ||
| let r = e.currentChar(); | ||
| return r === `{` || r === `@` || r === `|` || r === `(` || r === `)` || !r || r === ` ` ? n : (n += r, e.next(), t(n)); | ||
| }; | ||
| return t(``); | ||
| } | ||
| function X(e) { | ||
| v(e); | ||
| let t = g(e, `|`); | ||
| return v(e), t; | ||
| } | ||
| function Z(e, t) { | ||
| let n = null; | ||
| switch (e.currentChar()) { | ||
| case `{`: return t.braceNest >= 1 && (CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, a()), e.next(), n = m(t, 2, `{`), v(e), t.braceNest++, n; | ||
| case `}`: return t.braceNest > 0 && t.currentType === 2 && (CompileErrorCodes.EMPTY_PLACEHOLDER, a()), e.next(), n = m(t, 3, `}`), t.braceNest--, t.braceNest > 0 && v(e), t.inLinked && t.braceNest === 0 && (t.inLinked = !1), n; | ||
| case `@`: return t.braceNest > 0 && (CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, a()), n = Q(e, t) || h(t), t.braceNest = 0, n; | ||
| default: { | ||
| let r = !0, i = !0, o = !0; | ||
| if (O(e)) return t.braceNest > 0 && (CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, a()), n = m(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, n; | ||
| if (t.braceNest > 0 && (t.currentType === 4 || t.currentType === 5 || t.currentType === 6)) return CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, a(), t.braceNest = 0, $(e, t); | ||
| if (r = x(e, t)) return n = m(t, 4, B(e)), v(e), n; | ||
| if (i = S(e, t)) return n = m(t, 5, V(e)), v(e), n; | ||
| if (o = C(e, t)) return n = m(t, 6, U(e)), v(e), n; | ||
| if (!r && !i && !o) return n = m(t, 12, q(e)), CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, a(), n.value, v(e), n; | ||
| break; | ||
| } | ||
| } | ||
| return n; | ||
| } | ||
| function Q(e, t) { | ||
| let { currentType: n } = t, r = null, i = e.currentChar(); | ||
| switch ((n === 7 || n === 8 || n === 11 || n === 9) && (i === ` | ||
| ` || i === ` `) && (CompileErrorCodes.INVALID_LINKED_FORMAT, a()), i) { | ||
| case `@`: return e.next(), r = m(t, 7, `@`), t.inLinked = !0, r; | ||
| case `.`: return v(e), e.next(), m(t, 8, `.`); | ||
| case `:`: return v(e), e.next(), m(t, 9, `:`); | ||
| default: return O(e) ? (r = m(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, r) : w(e, t) || E(e, t) ? (v(e), Q(e, t)) : T(e, t) ? (v(e), m(t, 11, J(e))) : D(e, t) ? (v(e), i === `{` ? Z(e, t) || r : m(t, 10, Y(e))) : (n === 7 && (CompileErrorCodes.INVALID_LINKED_FORMAT, a()), t.braceNest = 0, t.inLinked = !1, $(e, t)); | ||
| } | ||
| } | ||
| function $(e, t) { | ||
| let n = { type: 13 }; | ||
| if (t.braceNest > 0) return Z(e, t) || h(t); | ||
| if (t.inLinked) return Q(e, t) || h(t); | ||
| switch (e.currentChar()) { | ||
| case `{`: return Z(e, t) || h(t); | ||
| case `}`: return CompileErrorCodes.UNBALANCED_CLOSING_BRACE, a(), e.next(), m(t, 3, `}`); | ||
| case `@`: return Q(e, t) || h(t); | ||
| default: | ||
| if (O(e)) return n = m(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, n; | ||
| if (k(e)) return m(t, 0, z(e)); | ||
| break; | ||
| } | ||
| return n; | ||
| } | ||
| function te() { | ||
| let { currentType: e, offset: t, startLoc: n, endLoc: o } = u; | ||
| return u.lastType = e, u.lastOffset = t, u.lastStartLoc = n, u.lastEndLoc = o, u.offset = i(), u.startLoc = a(), r.currentChar() === void 0 ? m(u, 13) : $(r, u); | ||
| } | ||
| return { | ||
| nextToken: te, | ||
| currentOffset: i, | ||
| currentPosition: a, | ||
| context: f | ||
| }; | ||
| } | ||
| const ERROR_DOMAIN = `parser`, KNOWN_ESCAPES = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g, TEXT_ESCAPES = /\\([\\@{}|])/g; | ||
| function fromTextEscapeSequence(e, t) { | ||
| return t; | ||
| } | ||
| function fromEscapeSequence(e, t, n) { | ||
| switch (e) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| let e = parseInt(t || n, 16); | ||
| return e <= 55295 || e >= 57344 ? String.fromCodePoint(e) : `�`; | ||
| } | ||
| } | ||
| } | ||
| function createParser(t = {}) { | ||
| let n = t.location !== !1, { onError: r } = t; | ||
| function i(e, t, r) { | ||
| let i = { type: e }; | ||
| return n && (i.start = t, i.end = t, i.loc = { | ||
| start: r, | ||
| end: r | ||
| }), i; | ||
| } | ||
| function a(e, t, r, i) { | ||
| i && (e.type = i), n && (e.end = t, e.loc && (e.loc.end = r)); | ||
| } | ||
| function o(e, t) { | ||
| let n = e.context(), r = i(3, n.offset, n.startLoc); | ||
| return r.value = t.replace(TEXT_ESCAPES, fromTextEscapeSequence), a(r, e.currentOffset(), e.currentPosition()), r; | ||
| } | ||
| function s(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), o = i(5, n, r); | ||
| return o.index = parseInt(t, 10), e.nextToken(), a(o, e.currentOffset(), e.currentPosition()), o; | ||
| } | ||
| function c(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), o = i(4, n, r); | ||
| return o.key = t, e.nextToken(), a(o, e.currentOffset(), e.currentPosition()), o; | ||
| } | ||
| function l(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), o = i(9, n, r); | ||
| return o.value = t.replace(KNOWN_ESCAPES, fromEscapeSequence), e.nextToken(), a(o, e.currentOffset(), e.currentPosition()), o; | ||
| } | ||
| function u(e) { | ||
| let t = e.nextToken(), n = e.context(), { lastOffset: r, lastStartLoc: o } = n, s = i(8, r, o); | ||
| return t.type === 11 ? (t.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, n.lastStartLoc, getTokenCaption(t)), s.value = t.value || ``, a(s, e.currentOffset(), e.currentPosition()), { node: s }) : (CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, n.lastStartLoc, s.value = ``, a(s, r, o), { | ||
| nextConsumeToken: t, | ||
| node: s | ||
| }); | ||
| } | ||
| function f(e, t) { | ||
| let n = e.context(), r = i(7, n.offset, n.startLoc); | ||
| return r.value = t, a(r, e.currentOffset(), e.currentPosition()), r; | ||
| } | ||
| function p(e) { | ||
| let t = e.context(), n = i(6, t.offset, t.startLoc), r = e.nextToken(); | ||
| if (r.type === 8) { | ||
| let t = u(e); | ||
| n.modifier = t.node, r = t.nextConsumeToken || e.nextToken(); | ||
| } | ||
| switch (r.type !== 9 && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(r)), r = e.nextToken(), r.type === 2 && (r = e.nextToken()), r.type) { | ||
| case 10: | ||
| r.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(r)), n.key = f(e, r.value || ``); | ||
| break; | ||
| case 4: | ||
| r.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(r)), n.key = c(e, r.value || ``); | ||
| break; | ||
| case 5: | ||
| r.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(r)), n.key = s(e, r.value || ``); | ||
| break; | ||
| case 6: | ||
| r.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(r)), n.key = l(e, r.value || ``); | ||
| break; | ||
| default: { | ||
| CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, t.lastStartLoc; | ||
| let o = e.context(), s = i(7, o.offset, o.startLoc); | ||
| return s.value = ``, a(s, o.offset, o.startLoc), n.key = s, a(n, o.offset, o.startLoc), { | ||
| nextConsumeToken: r, | ||
| node: n | ||
| }; | ||
| } | ||
| } | ||
| return a(n, e.currentOffset(), e.currentPosition()), { node: n }; | ||
| } | ||
| function m(e) { | ||
| let t = e.context(), n = i(2, t.currentType === 1 ? e.currentOffset() : t.offset, t.currentType === 1 ? t.endLoc : t.startLoc); | ||
| n.items = []; | ||
| let r = null; | ||
| do { | ||
| let i = r || e.nextToken(); | ||
| switch (r = null, i.type) { | ||
| case 0: | ||
| i.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(i)), n.items.push(o(e, i.value || ``)); | ||
| break; | ||
| case 5: | ||
| i.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(i)), n.items.push(s(e, i.value || ``)); | ||
| break; | ||
| case 4: | ||
| i.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(i)), n.items.push(c(e, i.value || ``)); | ||
| break; | ||
| case 6: | ||
| i.value == null && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, getTokenCaption(i)), n.items.push(l(e, i.value || ``)); | ||
| break; | ||
| case 7: { | ||
| let t = p(e); | ||
| n.items.push(t.node), r = t.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (t.currentType !== 13 && t.currentType !== 1); | ||
| return a(n, t.currentType === 1 ? t.lastOffset : e.currentOffset(), t.currentType === 1 ? t.lastEndLoc : e.currentPosition()), n; | ||
| } | ||
| function h(e, t, n, r) { | ||
| let o = e.context(), s = r.items.length === 0, c = i(1, t, n); | ||
| c.cases = [], c.cases.push(r); | ||
| do { | ||
| let t = m(e); | ||
| s || (s = t.items.length === 0), c.cases.push(t); | ||
| } while (o.currentType !== 13); | ||
| return s && CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, a(c, e.currentOffset(), e.currentPosition()), c; | ||
| } | ||
| function g(e) { | ||
| let t = e.context(), { offset: n, startLoc: r } = t, i = m(e); | ||
| return t.currentType === 13 ? i : h(e, n, r, i); | ||
| } | ||
| function _(r) { | ||
| let o = createTokenizer(r, assign({}, t)), s = o.context(), c = i(0, s.offset, s.startLoc); | ||
| return n && c.loc && (c.loc.source = r), c.body = g(o), t.onCacheKey && (c.cacheKey = t.onCacheKey(r)), s.currentType !== 13 && (CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, s.lastStartLoc, r[s.offset]), a(c, o.currentOffset(), o.currentPosition()), c; | ||
| } | ||
| return { parse: _ }; | ||
| } | ||
| function getTokenCaption(e) { | ||
| if (e.type === 13) return `EOF`; | ||
| let t = (e.value || ``).replace(/\r?\n/gu, `\\n`); | ||
| return t.length > 10 ? t.slice(0, 9) + `…` : t; | ||
| } | ||
| function createTransformer(e, t = {}) { | ||
| let n = { | ||
| ast: e, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| return { | ||
| context: () => n, | ||
| helper: (e) => (n.helpers.add(e), e) | ||
| }; | ||
| } | ||
| function traverseNodes(e, t) { | ||
| for (let n = 0; n < e.length; n++) traverseNode(e[n], t); | ||
| } | ||
| function traverseNode(e, t) { | ||
| switch (e.type) { | ||
| case 1: | ||
| traverseNodes(e.cases, t), t.helper(`plural`); | ||
| break; | ||
| case 2: | ||
| traverseNodes(e.items, t); | ||
| break; | ||
| case 6: | ||
| traverseNode(e.key, t), t.helper(`linked`), t.helper(`type`); | ||
| break; | ||
| case 5: | ||
| t.helper(`interpolate`), t.helper(`list`); | ||
| break; | ||
| case 4: | ||
| t.helper(`interpolate`), t.helper(`named`); | ||
| break; | ||
| } | ||
| } | ||
| function transform(e, t = {}) { | ||
| let n = createTransformer(e); | ||
| n.helper(`normalize`), e.body && traverseNode(e.body, n); | ||
| let r = n.context(); | ||
| e.helpers = Array.from(r.helpers); | ||
| } | ||
| function baseCompile(t, n = {}) { | ||
| let r = assign({}, n), i = !!r.jit, a = !!r.mangle, o = r.optimize == null ? !0 : r.optimize, s = createParser(r).parse(t); | ||
| return i ? (o && optimize(s), a && mangle(s), { | ||
| ast: s, | ||
| code: `` | ||
| }) : (transform(s, r), generate(s, r)); | ||
| } | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, HelperNameMap, LOCATION_STUB, NodeTypes, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; |
@@ -1,1 +0,1 @@ | ||
| export * from '../dist/message-compiler.js' | ||
| export * from './message-compiler.js' |
+1295
-1561
@@ -1,1562 +0,1296 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| var IntlifyMessageCompiler = (function (exports) { | ||
| 'use strict'; | ||
| /** | ||
| * Original Utilities | ||
| * written by kazuya kawaguchi | ||
| */ | ||
| const RE_ARGS = /\{([0-9a-zA-Z]+)\}/g; | ||
| /* eslint-disable */ | ||
| function format(message, ...args) { | ||
| if (args.length === 1 && isObject(args[0])) { | ||
| args = args[0]; | ||
| } | ||
| if (!args || !args.hasOwnProperty) { | ||
| args = {}; | ||
| } | ||
| return message.replace(RE_ARGS, (match, identifier) => { | ||
| return args.hasOwnProperty(identifier) ? args[identifier] : ''; | ||
| }); | ||
| } | ||
| const assign = Object.assign; | ||
| const isString = (val) => typeof val === 'string'; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const isObject = (val) => val !== null && typeof val === 'object'; | ||
| function join(items, separator = '') { | ||
| return items.reduce((str, item, index) => (index === 0 ? str + item : str + separator + item), ''); | ||
| } | ||
| const LOCATION_STUB = { | ||
| start: { line: 1, column: 1, offset: 0 }, | ||
| end: { line: 1, column: 1, offset: 0 } | ||
| }; | ||
| function createPosition(line, column, offset) { | ||
| return { line, column, offset }; | ||
| } | ||
| function createLocation(start, end, source) { | ||
| const loc = { start, end }; | ||
| if (source != null) { | ||
| loc.source = source; | ||
| } | ||
| return loc; | ||
| } | ||
| const CompileErrorCodes = { | ||
| // tokenizer error codes | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| // parser error codes | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| // generator error codes | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| // minifier error codes | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }; | ||
| // Special value for higher-order compilers to pick up the last code | ||
| // to avoid collision of error codes. | ||
| // This should always be kept as the last item. | ||
| const COMPILE_ERROR_CODES_EXTEND_POINT = 17; | ||
| /** @internal */ | ||
| const errorMessages = { | ||
| // tokenizer error messages | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| // parser error messages | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| // generator error messages | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| // minimizer error messages | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(code, loc, options = {}) { | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || '', ...(args || [])) | ||
| ; | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) { | ||
| error.location = loc; | ||
| } | ||
| error.domain = domain; | ||
| return error; | ||
| } | ||
| /** @internal */ | ||
| function defaultOnError(error) { | ||
| throw error; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/triple-slash-reference | ||
| /// <reference types="source-map-js" /> | ||
| const ERROR_DOMAIN$3 = 'parser'; | ||
| function createCodeGenerator(ast, options) { | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: '', | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: undefined, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) { | ||
| _context.source = ast.loc.source; | ||
| } | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ''; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(generator, node) { | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } | ||
| else { | ||
| generator.push(`, undefined, _type`); | ||
| } | ||
| generator.push(`)`); | ||
| } | ||
| function generateMessageNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push('])'); | ||
| } | ||
| function generatePluralNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(generator, node) { | ||
| if (node.body) { | ||
| generateNode(generator, node.body); | ||
| } | ||
| else { | ||
| generator.push('null'); | ||
| } | ||
| } | ||
| function generateNode(generator, node) { | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1 /* NodeTypes.Plural */: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7 /* NodeTypes.LinkedKey */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5 /* NodeTypes.List */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9 /* NodeTypes.Literal */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3 /* NodeTypes.Text */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: | ||
| { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| // generate code from AST | ||
| const generate = (ast, options = {}) => { | ||
| const mode = isString(options.mode) ? options.mode : 'normal'; | ||
| const filename = isString(options.filename) | ||
| ? options.filename | ||
| : 'message.intl'; | ||
| const sourceMap = !!options.sourceMap; | ||
| // prettier-ignore | ||
| const breakLineCode = options.breakLineCode != null | ||
| ? options.breakLineCode | ||
| : mode === 'arrow' | ||
| ? ';' | ||
| : '\n'; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow'; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| }; | ||
| }; | ||
| const ERROR_DOMAIN$2 = 'minifier'; | ||
| /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
| function mangle(node) { | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1 /* NodeTypes.Plural */: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) { | ||
| mangle(cases[i]); | ||
| } | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2 /* NodeTypes.Message */: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) { | ||
| mangle(items[i]); | ||
| } | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3 /* NodeTypes.Text */: | ||
| case 9 /* NodeTypes.Literal */: | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| case 7 /* NodeTypes.LinkedKey */: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4 /* NodeTypes.Named */: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: | ||
| { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| delete node.type; | ||
| } | ||
| /* eslint-enable @typescript-eslint/no-explicit-any */ | ||
| function optimize(ast) { | ||
| const body = ast.body; | ||
| if (body.type === 2 /* NodeTypes.Message */) { | ||
| optimizeMessageNode(body); | ||
| } | ||
| else { | ||
| body.cases.forEach(c => optimizeMessageNode(c)); | ||
| } | ||
| return ast; | ||
| } | ||
| function optimizeMessageNode(message) { | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| message.static = item.value; | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) { | ||
| break; | ||
| } | ||
| if (item.value == null) { | ||
| break; | ||
| } | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| const CHAR_SP = ' '; | ||
| const CHAR_CR = '\r'; | ||
| const CHAR_LF = '\n'; | ||
| const CHAR_LS = String.fromCharCode(0x2028); | ||
| const CHAR_PS = String.fromCharCode(0x2029); | ||
| function createScanner(str) { | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF; | ||
| const isLF = (index) => _buf[index] === CHAR_LF; | ||
| const isPS = (index) => _buf[index] === CHAR_PS; | ||
| const isLS = (index) => _buf[index] === CHAR_LS; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) { | ||
| _index++; | ||
| } | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) { | ||
| _peekOffset++; | ||
| } | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) { | ||
| next(); | ||
| } | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| } | ||
| const EOF = undefined; | ||
| const DOT = '.'; | ||
| const LITERAL_DELIMITER = "'"; | ||
| const ERROR_DOMAIN$1 = 'tokenizer'; | ||
| function createTokenizer(source, options = {}) { | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13 /* TokenTypes.EOF */, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13 /* TokenTypes.EOF */, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: '' | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(ctx.startLoc, pos) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) { | ||
| token.loc = createLocation(context.startLoc, context.endLoc); | ||
| } | ||
| if (value != null) { | ||
| token.value = value; | ||
| } | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13 /* TokenTypes.EOF */); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ''; | ||
| while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| cc === 95 // _ | ||
| ); | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek(); | ||
| const ret = isNumberStart(ch); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7 /* TokenTypes.LinkedAlias */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "." /* TokenChars.LinkedDot */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8 /* TokenTypes.LinkedDot */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */)) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":" /* TokenChars.LinkedDelimiter */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| return false; | ||
| } | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return isIdentifierStart(scnr.peek()); | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === ":" /* TokenChars.LinkedDelimiter */ || | ||
| ch === "." /* TokenChars.LinkedDot */ || | ||
| ch === CHAR_SP || | ||
| !ch) { | ||
| return false; | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } | ||
| else { | ||
| // other characters | ||
| return isTextStart(scnr, false); | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|" /* TokenChars.Pipe */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = '') => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || !ch) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "|" /* TokenChars.Pipe */) { | ||
| return !(prev === CHAR_SP || prev === CHAR_LF); | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_SP); | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_LF); | ||
| } | ||
| else { | ||
| return true; | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) { | ||
| return EOF; | ||
| } | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 // $ | ||
| ); | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 || // $ | ||
| cc === 45 // - | ||
| ); | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 48 && cc <= 57) || // 0-9 | ||
| (cc >= 65 && cc <= 70) || // A-F | ||
| (cc >= 97 && cc <= 102)); // a-f | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ''; | ||
| let num = ''; | ||
| while ((ch = takeDigit(scnr))) { | ||
| num += ch; | ||
| } | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ''; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "}" /* TokenChars.BraceRight */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| !ch) { | ||
| break; | ||
| } | ||
| else if (ch === CHAR_SP || ch === CHAR_LF) { | ||
| if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else if (isPluralStart(scnr)) { | ||
| break; | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeNamedIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ''; | ||
| if (scnr.currentChar() === '-') { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } | ||
| else { | ||
| value += getDigits(scnr); | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== CHAR_LF; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| let ch = ''; | ||
| let literal = ''; | ||
| while ((ch = takeChar(scnr, isLiteral))) { | ||
| if (ch === '\\') { | ||
| literal += readEscapeSequence(scnr); | ||
| } | ||
| else { | ||
| literal += ch; | ||
| } | ||
| } | ||
| const current = scnr.currentChar(); | ||
| if (current === CHAR_LF || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| // TODO: Is it correct really? | ||
| if (current === CHAR_LF) { | ||
| scnr.next(); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| } | ||
| return literal; | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case '\\': | ||
| case `\'`: // eslint-disable-line no-useless-escape | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case 'u': | ||
| return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case 'U': | ||
| return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ''; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return (ch !== "{" /* TokenChars.BraceLeft */ && | ||
| ch !== "}" /* TokenChars.BraceRight */ && | ||
| ch !== CHAR_SP && | ||
| ch !== CHAR_LF); | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let identifiers = ''; | ||
| while ((ch = takeChar(scnr, isInvalidIdentifier))) { | ||
| identifiers += ch; | ||
| } | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === "(" /* TokenChars.ParenLeft */ || | ||
| ch === ")" /* TokenChars.ParenRight */ || | ||
| !ch) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_LF || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(''); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|" /* TokenChars.Pipe */); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| if (context.braceNest >= 1) { | ||
| emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 2 /* TokenTypes.BraceLeft */, "{" /* TokenChars.BraceLeft */); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}" /* TokenChars.BraceRight */: | ||
| if (context.braceNest > 0 && | ||
| context.currentType === 2 /* TokenTypes.BraceLeft */) { | ||
| emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) { | ||
| context.inLinked = false; | ||
| } | ||
| return token; | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && | ||
| (context.currentType === 4 /* TokenTypes.Named */ || | ||
| context.currentType === 5 /* TokenTypes.List */ || | ||
| context.currentType === 6 /* TokenTypes.Literal */)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 4 /* TokenTypes.Named */, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validListIdentifier = isListIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 5 /* TokenTypes.List */, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validLiteral = isLiteralStart(scnr, context))) { | ||
| token = getToken(context, 6 /* TokenTypes.Literal */, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ... | ||
| token = getToken(context, 12 /* TokenTypes.InvalidPlace */, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 8 /* TokenTypes.LinkedDot */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */ || | ||
| currentType === 9 /* TokenTypes.LinkedDelimiter */) && | ||
| (ch === CHAR_LF || ch === CHAR_SP)) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| switch (ch) { | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| scnr.next(); | ||
| token = getToken(context, 7 /* TokenTypes.LinkedAlias */, "@" /* TokenChars.LinkedAlias */); | ||
| context.inLinked = true; | ||
| return token; | ||
| case "." /* TokenChars.LinkedDot */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8 /* TokenTypes.LinkedDot */, "." /* TokenChars.LinkedDot */); | ||
| case ":" /* TokenChars.LinkedDelimiter */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9 /* TokenTypes.LinkedDelimiter */, ":" /* TokenChars.LinkedDelimiter */); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || | ||
| isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11 /* TokenTypes.LinkedModifier */, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| // scan the placeholder | ||
| return readTokenInPlaceholder(scnr, context) || token; | ||
| } | ||
| else { | ||
| return getToken(context, 10 /* TokenTypes.LinkedKey */, readLinkedRefer(scnr)); | ||
| } | ||
| } | ||
| if (currentType === 7 /* TokenTypes.LinkedAlias */) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 /* TokenTypes.EOF */ }; | ||
| if (context.braceNest > 0) { | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| } | ||
| if (context.inLinked) { | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| } | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}" /* TokenChars.BraceRight */: | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: { | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) { | ||
| return getToken(context, 0 /* TokenTypes.Text */, readText(scnr)); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) { | ||
| return getToken(_context, 13 /* TokenTypes.EOF */); | ||
| } | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| } | ||
| const ERROR_DOMAIN = 'parser'; | ||
| // Backslash backslash, backslash quote, uHHHH, UHHHHHH. | ||
| const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g; | ||
| function fromEscapeSequence(match, codePoint4, codePoint6) { | ||
| switch (match) { | ||
| case `\\\\`: | ||
| return `\\`; | ||
| // eslint-disable-next-line no-useless-escape | ||
| case `\\\'`: | ||
| // eslint-disable-next-line no-useless-escape | ||
| return `\'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 0xd7ff || codePoint >= 0xe000) { | ||
| return String.fromCodePoint(codePoint); | ||
| } | ||
| // invalid ... | ||
| // Replace them with U+FFFD REPLACEMENT CHARACTER. | ||
| return '�'; | ||
| } | ||
| } | ||
| } | ||
| function createParser(options = {}) { | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(start, end) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { start: loc, end: loc }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) { | ||
| node.loc.end = pos; | ||
| } | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(5 /* NodeTypes.List */, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(4 /* NodeTypes.Named */, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(9 /* NodeTypes.Literal */, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc | ||
| const node = startNode(8 /* NodeTypes.LinkedModifier */, offset, loc); | ||
| if (token.type !== 11 /* TokenTypes.LinkedModifier */) { | ||
| // empty modifier | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ''; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| // check token | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.value = token.value || ''; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node | ||
| }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7 /* NodeTypes.LinkedKey */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6 /* NodeTypes.Linked */, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8 /* TokenTypes.LinkedDot */) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| // asset check token | ||
| if (token.type !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| token = tokenizer.nextToken(); | ||
| // skip brace left | ||
| if (token.type === 2 /* TokenTypes.BraceLeft */) { | ||
| token = tokenizer.nextToken(); | ||
| } | ||
| switch (token.type) { | ||
| case 10 /* TokenTypes.LinkedKey */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ''); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ''); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseList(tokenizer, token.value || ''); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ''); | ||
| break; | ||
| default: { | ||
| // empty key | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7 /* NodeTypes.LinkedKey */, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ''; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const startOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? tokenizer.currentOffset() | ||
| : context.offset; | ||
| const startLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.endLoc | ||
| : context.startLoc; | ||
| const node = startNode(2 /* NodeTypes.Message */, startOffset, startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0 /* TokenTypes.Text */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseText(tokenizer, token.value || '')); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseList(tokenizer, token.value || '')); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseNamed(tokenizer, token.value || '')); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseLiteral(tokenizer, token.value || '')); | ||
| break; | ||
| case 7 /* TokenTypes.LinkedAlias */: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */ && | ||
| context.currentType !== 1 /* TokenTypes.Pipe */); | ||
| // adjust message node loc | ||
| const endOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastOffset | ||
| : tokenizer.currentOffset(); | ||
| const endLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastEndLoc | ||
| : tokenizer.currentPosition(); | ||
| endNode(node, endOffset, endLoc); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1 /* NodeTypes.Plural */, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) { | ||
| hasEmptyMessage = msg.items.length === 0; | ||
| } | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */); | ||
| if (hasEmptyMessage) { | ||
| emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13 /* TokenTypes.EOF */) { | ||
| return msgNode; | ||
| } | ||
| else { | ||
| return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc); | ||
| if (location && node.loc) { | ||
| node.loc.source = source; | ||
| } | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) { | ||
| node.cacheKey = options.onCacheKey(source); | ||
| } | ||
| // assert whether achieved to EOF | ||
| if (context.currentType !== 13 /* TokenTypes.EOF */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ''); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| } | ||
| function getTokenCaption(token) { | ||
| if (token.type === 13 /* TokenTypes.EOF */) { | ||
| return 'EOF'; | ||
| } | ||
| const name = (token.value || '').replace(/\r?\n/gu, '\\n'); | ||
| return name.length > 10 ? name.slice(0, 9) + '…' : name; | ||
| } | ||
| function createTransformer(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const _context = { | ||
| ast, | ||
| helpers: new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { context, helper }; | ||
| } | ||
| function traverseNodes(nodes, transformer) { | ||
| for (let i = 0; i < nodes.length; i++) { | ||
| traverseNode(nodes[i], transformer); | ||
| } | ||
| } | ||
| function traverseNode(node, transformer) { | ||
| // TODO: if we need pre-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1 /* NodeTypes.Plural */: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural" /* HelperNameMap.PLURAL */); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| traverseNode(linked.key, transformer); | ||
| transformer.helper("linked" /* HelperNameMap.LINKED */); | ||
| transformer.helper("type" /* HelperNameMap.TYPE */); | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("list" /* HelperNameMap.LIST */); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("named" /* HelperNameMap.NAMED */); | ||
| break; | ||
| } | ||
| // TODO: if we need post-hook of transform, should be implemented to here | ||
| } | ||
| // transform AST | ||
| function transform(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize" /* HelperNameMap.NORMALIZE */); | ||
| // traverse | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| // set meta information | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| } | ||
| function baseCompile(source, options = {}) { | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| // parse source codes | ||
| const parser = createParser(assignedOptions); | ||
| const ast = parser.parse(source); | ||
| // TODO: | ||
| // With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible. | ||
| if (!jit) { | ||
| // transform ASTs | ||
| transform(ast, assignedOptions); | ||
| // generate javascript codes | ||
| return generate(ast, assignedOptions); | ||
| } | ||
| else { | ||
| // optimize ASTs | ||
| enableOptimize && optimize(ast); | ||
| // minimize ASTs | ||
| enableMangle && mangle(ast); | ||
| // In JIT mode, no ast transform, no code generation. | ||
| return { ast, code: '' }; | ||
| } | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| exports.COMPILE_ERROR_CODES_EXTEND_POINT = COMPILE_ERROR_CODES_EXTEND_POINT; | ||
| exports.CompileErrorCodes = CompileErrorCodes; | ||
| exports.ERROR_DOMAIN = ERROR_DOMAIN; | ||
| exports.LOCATION_STUB = LOCATION_STUB; | ||
| exports.baseCompile = baseCompile; | ||
| exports.createCompileError = createCompileError; | ||
| exports.createLocation = createLocation; | ||
| exports.createParser = createParser; | ||
| exports.createPosition = createPosition; | ||
| exports.defaultOnError = defaultOnError; | ||
| exports.detectHtmlTag = detectHtmlTag; | ||
| exports.errorMessages = errorMessages; | ||
| exports.mangle = mangle; | ||
| exports.optimize = optimize; | ||
| return exports; | ||
| /** | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ | ||
| var IntlifyMessageCompiler = (function(exports) { | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| //#region packages/shared/src/utils.ts | ||
| const inBrowser = typeof window !== "undefined"; | ||
| { | ||
| const perf = inBrowser && window.performance; | ||
| if (perf && perf.mark && perf.measure && perf.clearMarks && perf.clearMeasures) {} | ||
| } | ||
| const RE_ARGS = /\{([0-9a-z]+)\}/gi; | ||
| function format(message, ...args) { | ||
| if (args.length === 1 && isObject(args[0])) args = args[0]; | ||
| if (!args || !args.hasOwnProperty) args = {}; | ||
| return message.replace(RE_ARGS, (_match, identifier) => { | ||
| return args.hasOwnProperty(identifier) ? args[identifier] : ""; | ||
| }); | ||
| } | ||
| const assign = Object.assign; | ||
| Array.isArray; | ||
| const isString = (val) => typeof val === "string"; | ||
| const isObject = (val) => val !== null && typeof val === "object"; | ||
| function join(items, separator = "") { | ||
| return items.reduce((str, item, index) => index === 0 ? str + item : str + separator + item, ""); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/nodes.ts | ||
| let NodeTypes = /* @__PURE__ */ function(NodeTypes) { | ||
| NodeTypes[NodeTypes["Resource"] = 0] = "Resource"; | ||
| NodeTypes[NodeTypes["Plural"] = 1] = "Plural"; | ||
| NodeTypes[NodeTypes["Message"] = 2] = "Message"; | ||
| NodeTypes[NodeTypes["Text"] = 3] = "Text"; | ||
| NodeTypes[NodeTypes["Named"] = 4] = "Named"; | ||
| NodeTypes[NodeTypes["List"] = 5] = "List"; | ||
| NodeTypes[NodeTypes["Linked"] = 6] = "Linked"; | ||
| NodeTypes[NodeTypes["LinkedKey"] = 7] = "LinkedKey"; | ||
| NodeTypes[NodeTypes["LinkedModifier"] = 8] = "LinkedModifier"; | ||
| NodeTypes[NodeTypes["Literal"] = 9] = "Literal"; | ||
| return NodeTypes; | ||
| }({}); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/location.ts | ||
| const LOCATION_STUB = { | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function createPosition(line, column, offset) { | ||
| return { | ||
| line, | ||
| column, | ||
| offset | ||
| }; | ||
| } | ||
| function createLocation(start, end, source) { | ||
| const loc = { | ||
| start, | ||
| end | ||
| }; | ||
| if (source != null) loc.source = source; | ||
| return loc; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/helpers.ts | ||
| let HelperNameMap = /* @__PURE__ */ function(HelperNameMap) { | ||
| HelperNameMap["LIST"] = "list"; | ||
| HelperNameMap["NAMED"] = "named"; | ||
| HelperNameMap["PLURAL"] = "plural"; | ||
| HelperNameMap["LINKED"] = "linked"; | ||
| HelperNameMap["MESSAGE"] = "message"; | ||
| HelperNameMap["TYPE"] = "type"; | ||
| HelperNameMap["INTERPOLATE"] = "interpolate"; | ||
| HelperNameMap["NORMALIZE"] = "normalize"; | ||
| HelperNameMap["VALUES"] = "values"; | ||
| return HelperNameMap; | ||
| }({}); | ||
| const RE_HTML_TAG = /<[\w\s=":;#-/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/errors.ts | ||
| const CompileErrorCodes = { | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }; | ||
| const COMPILE_ERROR_CODES_EXTEND_POINT = 17; | ||
| /** @internal */ | ||
| const errorMessages = { | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(code, loc, options = {}) { | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || "", ...args || []); | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) error.location = loc; | ||
| error.domain = domain; | ||
| return error; | ||
| } | ||
| /** @internal */ | ||
| function defaultOnError(error) { | ||
| throw error; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/generator.ts | ||
| const ERROR_DOMAIN$3 = "parser"; | ||
| function createCodeGenerator(ast, options) { | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: "", | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) _context.source = ast.loc.source; | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ""; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(generator, node) { | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked")}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } else generator.push(`, undefined, _type`); | ||
| generator.push(`)`); | ||
| } | ||
| function generateMessageNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push("])"); | ||
| } | ||
| function generatePluralNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(generator, node) { | ||
| if (node.body) generateNode(generator, node.body); | ||
| else generator.push("null"); | ||
| } | ||
| function generateNode(generator, node) { | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5: | ||
| generator.push(`${helper("interpolate")}(${helper("list")}(${node.index}))`, node); | ||
| break; | ||
| case 4: | ||
| generator.push(`${helper("interpolate")}(${helper("named")}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| const generate = (ast, options = {}) => { | ||
| const mode = isString(options.mode) ? options.mode : "normal"; | ||
| const filename = isString(options.filename) ? options.filename : "message.intl"; | ||
| const sourceMap = !!options.sourceMap; | ||
| const breakLineCode = options.breakLineCode != null ? options.breakLineCode : mode === "arrow" ? ";" : "\n"; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== "arrow"; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === "normal" ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map((s) => `${s}: _${s}`), ", ")} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/mangler.ts | ||
| const ERROR_DOMAIN$2 = "minifier"; | ||
| function mangle(node) { | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) mangle(cases[i]); | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) mangle(items[i]); | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| delete node.type; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/optimizer.ts | ||
| function optimize(ast) { | ||
| const body = ast.body; | ||
| if (body.type === 2) optimizeMessageNode(body); | ||
| else body.cases.forEach((c) => optimizeMessageNode(c)); | ||
| return ast; | ||
| } | ||
| function optimizeMessageNode(message) { | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 || item.type === 9) { | ||
| message.static = item.value; | ||
| delete item.value; | ||
| } | ||
| } else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 || item.type === 9)) break; | ||
| if (item.value == null) break; | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 || item.type === 9) delete item.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function createScanner(str) { | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === "\r" && _buf[index + 1] === "\n"; | ||
| const isLF = (index) => _buf[index] === "\n"; | ||
| const isPS = (index) => _buf[index] === "\u2029"; | ||
| const isLS = (index) => _buf[index] === "\u2028"; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? "\n" : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) _index++; | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) _peekOffset++; | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) next(); | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/tokenizer.ts | ||
| const EOF = void 0; | ||
| const DOT = "."; | ||
| const LITERAL_DELIMITER = "'"; | ||
| const ERROR_DOMAIN$1 = "tokenizer"; | ||
| function createTokenizer(source, options = {}) { | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: "" | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(ctx.startLoc, pos) : null, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| })); | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) token.loc = createLocation(context.startLoc, context.endLoc); | ||
| if (value != null) token.value = value; | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ""; | ||
| while (scnr.currentPeek() === " " || scnr.currentPeek() === "\n") { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc === 95; | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isNumberStart(scnr.currentPeek() === "-" ? scnr.peek() : scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "."; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 || currentType === 11)) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9) return false; | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return isIdentifierStart(scnr.peek()); | ||
| else if (ch === "@" || ch === "|" || ch === ":" || ch === "." || ch === " " || !ch) return false; | ||
| else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } else return isTextStart(scnr, false); | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = "") => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return hasSpace; | ||
| else if (ch === "@" || !ch) return hasSpace; | ||
| else if (ch === "|") return !(prev === " " || prev === "\n"); | ||
| else if (ch === " ") { | ||
| scnr.peek(); | ||
| return fn(true, " "); | ||
| } else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(true, "\n"); | ||
| } else return true; | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) return EOF; | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36; | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36 || cc === 45; | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57 || cc >= 65 && cc <= 70 || cc >= 97 && cc <= 102; | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ""; | ||
| let num = ""; | ||
| while (ch = takeDigit(scnr)) num += ch; | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ""; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "\\") { | ||
| const nextCh = scnr.peek(); | ||
| if (nextCh === "{" || nextCh === "}" || nextCh === "@" || nextCh === "|" || nextCh === "\\") { | ||
| buf += ch + nextCh; | ||
| scnr.next(); | ||
| scnr.next(); | ||
| } else { | ||
| scnr.resetPeek(); | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } else if (ch === "{" || ch === "}" || ch === "@" || ch === "|" || !ch) break; | ||
| else if (ch === " " || ch === "\n") if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } else if (isPluralStart(scnr)) break; | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeNamedIdentifierChar(scnr)) name += ch; | ||
| const currentChar = scnr.currentChar(); | ||
| if (currentChar && currentChar !== "}" && currentChar !== EOF && currentChar !== " " && currentChar !== "\n" && currentChar !== " ") { | ||
| const invalidPart = readInvalidIdentifier(scnr); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, name + invalidPart); | ||
| return name + invalidPart; | ||
| } | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ""; | ||
| if (scnr.currentChar() === "-") { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } else value += getDigits(scnr); | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== "\n"; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| eat(scnr, `'`); | ||
| let ch = ""; | ||
| let literal = ""; | ||
| while (ch = takeChar(scnr, isLiteral)) if (ch === "\\") literal += readEscapeSequence(scnr); | ||
| else literal += ch; | ||
| const current = scnr.currentChar(); | ||
| if (current === "\n" || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| if (current === "\n") { | ||
| scnr.next(); | ||
| eat(scnr, `'`); | ||
| } | ||
| return literal; | ||
| } | ||
| eat(scnr, `'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "\\": | ||
| case `'`: | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case "u": return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case "U": return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ""; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return ch !== "{" && ch !== "}" && ch !== " " && ch !== "\n"; | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let identifiers = ""; | ||
| while (ch = takeChar(scnr, isInvalidIdentifier)) identifiers += ch; | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeIdentifierChar(scnr)) name += ch; | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" || ch === "@" || ch === "|" || ch === "(" || ch === ")" || !ch) return buf; | ||
| else if (ch === " ") return buf; | ||
| else if (ch === "\n" || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(""); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|"); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| switch (scnr.currentChar()) { | ||
| case "{": | ||
| if (context.braceNest >= 1) emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 2, "{"); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}": | ||
| if (context.braceNest > 0 && context.currentType === 2) emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 3, "}"); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) context.inLinked = false; | ||
| return token; | ||
| case "@": | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && (context.currentType === 4 || context.currentType === 5 || context.currentType === 6)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if (validNamedIdentifier = isNamedIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 4, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validListIdentifier = isListIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 5, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validLiteral = isLiteralStart(scnr, context)) { | ||
| token = getToken(context, 6, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| token = getToken(context, 12, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 || currentType === 8 || currentType === 11 || currentType === 9) && (ch === "\n" || ch === " ")) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| switch (ch) { | ||
| case "@": | ||
| scnr.next(); | ||
| token = getToken(context, 7, "@"); | ||
| context.inLinked = true; | ||
| return token; | ||
| case ".": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8, "."); | ||
| case ":": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9, ":"); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{") return readTokenInPlaceholder(scnr, context) || token; | ||
| else return getToken(context, 10, readLinkedRefer(scnr)); | ||
| } | ||
| if (currentType === 7) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 }; | ||
| if (context.braceNest > 0) return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| if (context.inLinked) return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| switch (scnr.currentChar()) { | ||
| case "{": return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}": | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3, "}"); | ||
| case "@": return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) return getToken(context, 0, readText(scnr)); | ||
| break; | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) return getToken(_context, 13); | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/parser.ts | ||
| const ERROR_DOMAIN = "parser"; | ||
| const KNOWN_ESCAPES = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g; | ||
| const TEXT_ESCAPES = /\\([\\@{}|])/g; | ||
| function fromTextEscapeSequence(_match, char) { | ||
| return char; | ||
| } | ||
| function fromEscapeSequence(match, codePoint4, codePoint6) { | ||
| switch (match) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 55295 || codePoint >= 57344) return String.fromCodePoint(codePoint); | ||
| return "�"; | ||
| } | ||
| } | ||
| } | ||
| function createParser(options = {}) { | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(start, end) : null, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| })); | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { | ||
| start: loc, | ||
| end: loc | ||
| }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (type) node.type = type; | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) node.loc.end = pos; | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3, context.offset, context.startLoc); | ||
| node.value = value.replace(TEXT_ESCAPES, fromTextEscapeSequence); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(5, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(4, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(9, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; | ||
| const node = startNode(8, offset, loc); | ||
| if (token.type !== 11) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ""; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.value = token.value || ""; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| if (token.type !== 9) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| token = tokenizer.nextToken(); | ||
| if (token.type === 2) token = tokenizer.nextToken(); | ||
| switch (token.type) { | ||
| case 10: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ""); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ""); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseList(tokenizer, token.value || ""); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ""); | ||
| break; | ||
| default: { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ""; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node: linkedNode }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(2, context.currentType === 1 ? tokenizer.currentOffset() : context.offset, context.currentType === 1 ? context.endLoc : context.startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseText(tokenizer, token.value || "")); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseList(tokenizer, token.value || "")); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseNamed(tokenizer, token.value || "")); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseLiteral(tokenizer, token.value || "")); | ||
| break; | ||
| case 7: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 && context.currentType !== 1); | ||
| endNode(node, context.currentType === 1 ? context.lastOffset : tokenizer.currentOffset(), context.currentType === 1 ? context.lastEndLoc : tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) hasEmptyMessage = msg.items.length === 0; | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13); | ||
| if (hasEmptyMessage) emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13) return msgNode; | ||
| else return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0, context.offset, context.startLoc); | ||
| if (location && node.loc) node.loc.source = source; | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) node.cacheKey = options.onCacheKey(source); | ||
| if (context.currentType !== 13) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ""); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| } | ||
| function getTokenCaption(token) { | ||
| if (token.type === 13) return "EOF"; | ||
| const name = (token.value || "").replace(/\r?\n/gu, "\\n"); | ||
| return name.length > 10 ? name.slice(0, 9) + "…" : name; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/transformer.ts | ||
| function createTransformer(ast, _options = {}) { | ||
| const _context = { | ||
| ast, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { | ||
| context, | ||
| helper | ||
| }; | ||
| } | ||
| function traverseNodes(nodes, transformer) { | ||
| for (let i = 0; i < nodes.length; i++) traverseNode(nodes[i], transformer); | ||
| } | ||
| function traverseNode(node, transformer) { | ||
| switch (node.type) { | ||
| case 1: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural"); | ||
| break; | ||
| case 2: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6: | ||
| traverseNode(node.key, transformer); | ||
| transformer.helper("linked"); | ||
| transformer.helper("type"); | ||
| break; | ||
| case 5: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("list"); | ||
| break; | ||
| case 4: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("named"); | ||
| break; | ||
| } | ||
| } | ||
| function transform(ast, _options = {}) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize"); | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/compiler.ts | ||
| function baseCompile(source, options = {}) { | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| const ast = createParser(assignedOptions).parse(source); | ||
| if (!jit) { | ||
| transform(ast, assignedOptions); | ||
| return generate(ast, assignedOptions); | ||
| } else { | ||
| enableOptimize && optimize(ast); | ||
| enableMangle && mangle(ast); | ||
| return { | ||
| ast, | ||
| code: "" | ||
| }; | ||
| } | ||
| } | ||
| //#endregion | ||
| exports.COMPILE_ERROR_CODES_EXTEND_POINT = COMPILE_ERROR_CODES_EXTEND_POINT; | ||
| exports.CompileErrorCodes = CompileErrorCodes; | ||
| exports.ERROR_DOMAIN = ERROR_DOMAIN; | ||
| exports.HelperNameMap = HelperNameMap; | ||
| exports.LOCATION_STUB = LOCATION_STUB; | ||
| exports.NodeTypes = NodeTypes; | ||
| exports.baseCompile = baseCompile; | ||
| exports.createCompileError = createCompileError; | ||
| exports.createLocation = createLocation; | ||
| exports.createParser = createParser; | ||
| exports.createPosition = createPosition; | ||
| exports.defaultOnError = defaultOnError; | ||
| exports.detectHtmlTag = detectHtmlTag; | ||
| exports.errorMessages = errorMessages; | ||
| exports.mangle = mangle; | ||
| exports.optimize = optimize; | ||
| return exports; | ||
| })({}); |
@@ -1,6 +0,803 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| var IntlifyMessageCompiler=function(e){"use strict";const t=Object.assign,n=e=>"string"==typeof e;function r(e,t=""){return e.reduce(((e,n,r)=>0===r?e+n:e+t+n),"")}function c(e,t,n){return{line:e,column:t,offset:n}}function o(e,t,n){const r={start:e,end:t};return null!=n&&(r.source=n),r}const s={EXPECTED_TOKEN:1,INVALID_TOKEN_IN_PLACEHOLDER:2,UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER:3,UNKNOWN_ESCAPE_SEQUENCE:4,INVALID_UNICODE_ESCAPE_SEQUENCE:5,UNBALANCED_CLOSING_BRACE:6,UNTERMINATED_CLOSING_BRACE:7,EMPTY_PLACEHOLDER:8,NOT_ALLOW_NEST_PLACEHOLDER:9,INVALID_LINKED_FORMAT:10,MUST_HAVE_MESSAGES_IN_PLURAL:11,UNEXPECTED_EMPTY_LINKED_MODIFIER:12,UNEXPECTED_EMPTY_LINKED_KEY:13,UNEXPECTED_LEXICAL_ANALYSIS:14,UNHANDLED_CODEGEN_NODE_TYPE:15,UNHANDLED_MINIFIER_NODE_TYPE:16},u={[s.EXPECTED_TOKEN]:"Expected token: '{0}'",[s.INVALID_TOKEN_IN_PLACEHOLDER]:"Invalid token in placeholder: '{0}'",[s.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]:"Unterminated single quote in placeholder",[s.UNKNOWN_ESCAPE_SEQUENCE]:"Unknown escape sequence: \\{0}",[s.INVALID_UNICODE_ESCAPE_SEQUENCE]:"Invalid unicode escape sequence: {0}",[s.UNBALANCED_CLOSING_BRACE]:"Unbalanced closing brace",[s.UNTERMINATED_CLOSING_BRACE]:"Unterminated closing brace",[s.EMPTY_PLACEHOLDER]:"Empty placeholder",[s.NOT_ALLOW_NEST_PLACEHOLDER]:"Not allowed nest placeholder",[s.INVALID_LINKED_FORMAT]:"Invalid linked format",[s.MUST_HAVE_MESSAGES_IN_PLURAL]:"Plural must have messages",[s.UNEXPECTED_EMPTY_LINKED_MODIFIER]:"Unexpected empty linked modifier",[s.UNEXPECTED_EMPTY_LINKED_KEY]:"Unexpected empty linked key",[s.UNEXPECTED_LEXICAL_ANALYSIS]:"Unexpected lexical analysis in token: '{0}'",[s.UNHANDLED_CODEGEN_NODE_TYPE]:"unhandled codegen node type: '{0}'",[s.UNHANDLED_MINIFIER_NODE_TYPE]:"unhandled mimifier node type: '{0}'"};function a(e,t,n={}){const{domain:r,messages:c,args:o}=n,s=new SyntaxError(String(e));return s.code=e,t&&(s.location=t),s.domain=r,s}function i(e,t){const{helper:n}=e;switch(t.type){case 0:!function(e,t){t.body?i(e,t.body):e.push("null")}(e,t);break;case 1:!function(e,t){const{helper:n,needIndent:r}=e;if(t.cases.length>1){e.push(`${n("plural")}([`),e.indent(r());const c=t.cases.length;for(let n=0;n<c&&(i(e,t.cases[n]),n!==c-1);n++)e.push(", ");e.deindent(r()),e.push("])")}}(e,t);break;case 2:!function(e,t){const{helper:n,needIndent:r}=e;e.push(`${n("normalize")}([`),e.indent(r());const c=t.items.length;for(let o=0;o<c&&(i(e,t.items[o]),o!==c-1);o++)e.push(", ");e.deindent(r()),e.push("])")}(e,t);break;case 6:!function(e,t){const{helper:n}=e;e.push(`${n("linked")}(`),i(e,t.key),t.modifier?(e.push(", "),i(e,t.modifier),e.push(", _type")):e.push(", undefined, _type"),e.push(")")}(e,t);break;case 8:case 7:case 9:case 3:e.push(JSON.stringify(t.value),t);break;case 5:e.push(`${n("interpolate")}(${n("list")}(${t.index}))`,t);break;case 4:e.push(`${n("interpolate")}(${n("named")}(${JSON.stringify(t.key)}))`,t)}}function l(e){switch(e.t=e.type,e.type){case 0:{const t=e;l(t.body),t.b=t.body,delete t.body;break}case 1:{const t=e,n=t.cases;for(let e=0;e<n.length;e++)l(n[e]);t.c=n,delete t.cases;break}case 2:{const t=e,n=t.items;for(let e=0;e<n.length;e++)l(n[e]);t.i=n,delete t.items,t.static&&(t.s=t.static,delete t.static);break}case 3:case 9:case 8:case 7:{const t=e;t.value&&(t.v=t.value,delete t.value);break}case 6:{const t=e;l(t.key),t.k=t.key,delete t.key,t.modifier&&(l(t.modifier),t.m=t.modifier,delete t.modifier);break}case 5:{const t=e;t.i=t.index,delete t.index;break}case 4:{const t=e;t.k=t.key,delete t.key;break}}delete e.type}function E(e){const t=e.body;return 2===t.type?f(t):t.cases.forEach((e=>f(e))),e}function f(e){if(1===e.items.length){const t=e.items[0];3!==t.type&&9!==t.type||(e.static=t.value,delete t.value)}else{const t=[];for(let n=0;n<e.items.length;n++){const r=e.items[n];if(3!==r.type&&9!==r.type)break;if(null==r.value)break;t.push(r.value)}if(t.length===e.items.length){e.static=r(t);for(let t=0;t<e.items.length;t++){const n=e.items[t];3!==n.type&&9!==n.type||delete n.value}}}}const L=" ",d="\r",N="\n",_=String.fromCharCode(8232),p=String.fromCharCode(8233);function C(e){const t=e;let n=0,r=1,c=1,o=0;const s=e=>t[e]===d&&t[e+1]===N,u=e=>t[e]===p,a=e=>t[e]===_,i=e=>s(e)||(e=>t[e]===N)(e)||u(e)||a(e),l=e=>s(e)||u(e)||a(e)?N:t[e];function E(){return o=0,i(n)&&(r++,c=0),s(n)&&n++,n++,c++,t[n]}return{index:()=>n,line:()=>r,column:()=>c,peekOffset:()=>o,charAt:l,currentChar:()=>l(n),currentPeek:()=>l(n+o),next:E,peek:function(){return s(n+o)&&o++,o++,t[n+o]},reset:function(){n=0,r=1,c=1,o=0},resetPeek:function(e=0){o=e},skipToPeek:function(){const e=n+o;for(;e!==n;)E();o=0}}}const A=void 0,T="'";function k(e,t={}){const n=!1!==t.location,r=C(e),u=()=>r.index(),a=()=>c(r.line(),r.column(),r.index()),i=a(),l=u(),E={currentType:13,offset:l,startLoc:i,endLoc:i,lastType:13,lastOffset:l,lastStartLoc:i,lastEndLoc:i,braceNest:0,inLinked:!1,text:""},f=()=>E,{onError:d}=t;function _(e,t,r){e.endLoc=a(),e.currentType=t;const c={type:t};return n&&(c.loc=o(e.startLoc,e.endLoc)),null!=r&&(c.value=r),c}const p=e=>_(e,13);function k(e,t){return e.currentChar()===t?(e.next(),t):(s.EXPECTED_TOKEN,a(),"")}function I(e){let t="";for(;e.currentPeek()===L||e.currentPeek()===N;)t+=e.currentPeek(),e.peek();return t}function h(e){const t=I(e);return e.skipToPeek(),t}function P(e){if(e===A)return!1;const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||95===t}function S(e,t){const{currentType:n}=t;if(2!==n)return!1;I(e);const r=function(e){if(e===A)return!1;const t=e.charCodeAt(0);return t>=48&&t<=57}("-"===e.currentPeek()?e.peek():e.currentPeek());return e.resetPeek(),r}function y(e){I(e);const t="|"===e.currentPeek();return e.resetPeek(),t}function D(e,t=!0){const n=(t=!1,r="")=>{const c=e.currentPeek();return"{"===c?t:"@"!==c&&c?"|"===c?!(r===L||r===N):c===L?(e.peek(),n(!0,L)):c!==N||(e.peek(),n(!0,N)):t},r=n();return t&&e.resetPeek(),r}function O(e,t){const n=e.currentChar();return n===A?A:t(n)?(e.next(),n):null}function m(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t}function b(e){return O(e,m)}function U(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t||45===t}function x(e){return O(e,U)}function R(e){const t=e.charCodeAt(0);return t>=48&&t<=57}function v(e){return O(e,R)}function M(e){const t=e.charCodeAt(0);return t>=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102}function g(e){return O(e,M)}function X(e){let t="",n="";for(;t=v(e);)n+=t;return n}function Y(e){return e!==T&&e!==N}function K(e){const t=e.currentChar();switch(t){case"\\":case"'":return e.next(),`\\${t}`;case"u":return w(e,t,4);case"U":return w(e,t,6);default:return s.UNKNOWN_ESCAPE_SEQUENCE,a(),""}}function w(e,t,n){k(e,t);let r="";for(let c=0;c<n;c++){const t=g(e);if(!t){s.INVALID_UNICODE_ESCAPE_SEQUENCE,a(),e.currentChar();break}r+=t}return`\\${t}${r}`}function H(e){return"{"!==e&&"}"!==e&&e!==L&&e!==N}function G(e){h(e);const t=k(e,"|");return h(e),t}function $(e,t){let n=null;switch(e.currentChar()){case"{":return t.braceNest>=1&&(s.NOT_ALLOW_NEST_PLACEHOLDER,a()),e.next(),n=_(t,2,"{"),h(e),t.braceNest++,n;case"}":return t.braceNest>0&&2===t.currentType&&(s.EMPTY_PLACEHOLDER,a()),e.next(),n=_(t,3,"}"),t.braceNest--,t.braceNest>0&&h(e),t.inLinked&&0===t.braceNest&&(t.inLinked=!1),n;case"@":return t.braceNest>0&&(s.UNTERMINATED_CLOSING_BRACE,a()),n=B(e,t)||p(t),t.braceNest=0,n;default:{let r=!0,c=!0,o=!0;if(y(e))return t.braceNest>0&&(s.UNTERMINATED_CLOSING_BRACE,a()),n=_(t,1,G(e)),t.braceNest=0,t.inLinked=!1,n;if(t.braceNest>0&&(4===t.currentType||5===t.currentType||6===t.currentType))return s.UNTERMINATED_CLOSING_BRACE,a(),t.braceNest=0,V(e,t);if(r=function(e,t){const{currentType:n}=t;if(2!==n)return!1;I(e);const r=P(e.currentPeek());return e.resetPeek(),r}(e,t))return n=_(t,4,function(e){h(e);let t="",n="";for(;t=x(e);)n+=t;return e.currentChar()===A&&(s.UNTERMINATED_CLOSING_BRACE,a()),n}(e)),h(e),n;if(c=S(e,t))return n=_(t,5,function(e){h(e);let t="";return"-"===e.currentChar()?(e.next(),t+=`-${X(e)}`):t+=X(e),e.currentChar()===A&&(s.UNTERMINATED_CLOSING_BRACE,a()),t}(e)),h(e),n;if(o=function(e,t){const{currentType:n}=t;if(2!==n)return!1;I(e);const r=e.currentPeek()===T;return e.resetPeek(),r}(e,t))return n=_(t,6,function(e){h(e),k(e,"'");let t="",n="";for(;t=O(e,Y);)n+="\\"===t?K(e):t;const r=e.currentChar();return r===N||r===A?(s.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,a(),r===N&&(e.next(),k(e,"'")),n):(k(e,"'"),n)}(e)),h(e),n;if(!r&&!c&&!o)return n=_(t,12,function(e){h(e);let t="",n="";for(;t=O(e,H);)n+=t;return n}(e)),s.INVALID_TOKEN_IN_PLACEHOLDER,a(),n.value,h(e),n;break}}return n}function B(e,t){const{currentType:n}=t;let r=null;const c=e.currentChar();switch(7!==n&&8!==n&&11!==n&&9!==n||c!==N&&c!==L||(s.INVALID_LINKED_FORMAT,a()),c){case"@":return e.next(),r=_(t,7,"@"),t.inLinked=!0,r;case".":return h(e),e.next(),_(t,8,".");case":":return h(e),e.next(),_(t,9,":");default:return y(e)?(r=_(t,1,G(e)),t.braceNest=0,t.inLinked=!1,r):function(e,t){const{currentType:n}=t;if(7!==n)return!1;I(e);const r="."===e.currentPeek();return e.resetPeek(),r}(e,t)||function(e,t){const{currentType:n}=t;if(7!==n&&11!==n)return!1;I(e);const r=":"===e.currentPeek();return e.resetPeek(),r}(e,t)?(h(e),B(e,t)):function(e,t){const{currentType:n}=t;if(8!==n)return!1;I(e);const r=P(e.currentPeek());return e.resetPeek(),r}(e,t)?(h(e),_(t,11,function(e){let t="",n="";for(;t=b(e);)n+=t;return n}(e))):function(e,t){const{currentType:n}=t;if(9!==n)return!1;const r=()=>{const t=e.currentPeek();return"{"===t?P(e.peek()):!("@"===t||"|"===t||":"===t||"."===t||t===L||!t)&&(t===N?(e.peek(),r()):D(e,!1))},c=r();return e.resetPeek(),c}(e,t)?(h(e),"{"===c?$(e,t)||r:_(t,10,function(e){const t=n=>{const r=e.currentChar();return"{"!==r&&"@"!==r&&"|"!==r&&"("!==r&&")"!==r&&r?r===L?n:(n+=r,e.next(),t(n)):n};return t("")}(e))):(7===n&&(s.INVALID_LINKED_FORMAT,a()),t.braceNest=0,t.inLinked=!1,V(e,t))}}function V(e,t){let n={type:13};if(t.braceNest>0)return $(e,t)||p(t);if(t.inLinked)return B(e,t)||p(t);switch(e.currentChar()){case"{":return $(e,t)||p(t);case"}":return s.UNBALANCED_CLOSING_BRACE,a(),e.next(),_(t,3,"}");case"@":return B(e,t)||p(t);default:if(y(e))return n=_(t,1,G(e)),t.braceNest=0,t.inLinked=!1,n;if(D(e))return _(t,0,function(e){let t="";for(;;){const n=e.currentChar();if("{"===n||"}"===n||"@"===n||"|"===n||!n)break;if(n===L||n===N)if(D(e))t+=n,e.next();else{if(y(e))break;t+=n,e.next()}else t+=n,e.next()}return t}(e))}return n}return{nextToken:function(){const{currentType:e,offset:t,startLoc:n,endLoc:c}=E;return E.lastType=e,E.lastOffset=t,E.lastStartLoc=n,E.lastEndLoc=c,E.offset=u(),E.startLoc=a(),r.currentChar()===A?_(E,13):V(r,E)},currentOffset:u,currentPosition:a,context:f}}const I="parser",h=/(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;function P(e,t,n){switch(e){case"\\\\":return"\\";case"\\'":return"'";default:{const e=parseInt(t||n,16);return e<=55295||e>=57344?String.fromCodePoint(e):"�"}}}function S(e={}){const n=!1!==e.location,{onError:r}=e;function c(e,t,r){const c={type:e};return n&&(c.start=t,c.end=t,c.loc={start:r,end:r}),c}function o(e,t,r,c){n&&(e.end=t,e.loc&&(e.loc.end=r))}function u(e,t){const n=e.context(),r=c(3,n.offset,n.startLoc);return r.value=t,o(r,e.currentOffset(),e.currentPosition()),r}function a(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:s}=n,u=c(5,r,s);return u.index=parseInt(t,10),e.nextToken(),o(u,e.currentOffset(),e.currentPosition()),u}function i(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:s}=n,u=c(4,r,s);return u.key=t,e.nextToken(),o(u,e.currentOffset(),e.currentPosition()),u}function l(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:s}=n,u=c(9,r,s);return u.value=t.replace(h,P),e.nextToken(),o(u,e.currentOffset(),e.currentPosition()),u}function E(e){const t=e.context(),n=c(6,t.offset,t.startLoc);let r=e.nextToken();if(8===r.type){const t=function(e){const t=e.nextToken(),n=e.context(),{lastOffset:r,lastStartLoc:u}=n,a=c(8,r,u);return 11!==t.type?(s.UNEXPECTED_EMPTY_LINKED_MODIFIER,n.lastStartLoc,a.value="",o(a,r,u),{nextConsumeToken:t,node:a}):(null==t.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,n.lastStartLoc,y(t)),a.value=t.value||"",o(a,e.currentOffset(),e.currentPosition()),{node:a})}(e);n.modifier=t.node,r=t.nextConsumeToken||e.nextToken()}switch(9!==r.type&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(r)),r=e.nextToken(),2===r.type&&(r=e.nextToken()),r.type){case 10:null==r.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(r)),n.key=function(e,t){const n=e.context(),r=c(7,n.offset,n.startLoc);return r.value=t,o(r,e.currentOffset(),e.currentPosition()),r}(e,r.value||"");break;case 4:null==r.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(r)),n.key=i(e,r.value||"");break;case 5:null==r.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(r)),n.key=a(e,r.value||"");break;case 6:null==r.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(r)),n.key=l(e,r.value||"");break;default:{s.UNEXPECTED_EMPTY_LINKED_KEY,t.lastStartLoc;const u=e.context(),a=c(7,u.offset,u.startLoc);return a.value="",o(a,u.offset,u.startLoc),n.key=a,o(n,u.offset,u.startLoc),{nextConsumeToken:r,node:n}}}return o(n,e.currentOffset(),e.currentPosition()),{node:n}}function f(e){const t=e.context(),n=c(2,1===t.currentType?e.currentOffset():t.offset,1===t.currentType?t.endLoc:t.startLoc);n.items=[];let r=null;do{const c=r||e.nextToken();switch(r=null,c.type){case 0:null==c.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(c)),n.items.push(u(e,c.value||""));break;case 5:null==c.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(c)),n.items.push(a(e,c.value||""));break;case 4:null==c.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(c)),n.items.push(i(e,c.value||""));break;case 6:null==c.value&&(s.UNEXPECTED_LEXICAL_ANALYSIS,t.lastStartLoc,y(c)),n.items.push(l(e,c.value||""));break;case 7:{const t=E(e);n.items.push(t.node),r=t.nextConsumeToken||null;break}}}while(13!==t.currentType&&1!==t.currentType);return o(n,1===t.currentType?t.lastOffset:e.currentOffset(),1===t.currentType?t.lastEndLoc:e.currentPosition()),n}function L(e){const t=e.context(),{offset:n,startLoc:r}=t,u=f(e);return 13===t.currentType?u:function(e,t,n,r){const u=e.context();let a=0===r.items.length;const i=c(1,t,n);i.cases=[],i.cases.push(r);do{const t=f(e);a||(a=0===t.items.length),i.cases.push(t)}while(13!==u.currentType);return a&&s.MUST_HAVE_MESSAGES_IN_PLURAL,o(i,e.currentOffset(),e.currentPosition()),i}(e,n,r,u)}return{parse:function(r){const u=k(r,t({},e)),a=u.context(),i=c(0,a.offset,a.startLoc);return n&&i.loc&&(i.loc.source=r),i.body=L(u),e.onCacheKey&&(i.cacheKey=e.onCacheKey(r)),13!==a.currentType&&(s.UNEXPECTED_LEXICAL_ANALYSIS,a.lastStartLoc,r[a.offset]),o(i,u.currentOffset(),u.currentPosition()),i}}}function y(e){if(13===e.type)return"EOF";const t=(e.value||"").replace(/\r?\n/gu,"\\n");return t.length>10?t.slice(0,9)+"…":t}function D(e,t){for(let n=0;n<e.length;n++)O(e[n],t)}function O(e,t){switch(e.type){case 1:D(e.cases,t),t.helper("plural");break;case 2:D(e.items,t);break;case 6:O(e.key,t),t.helper("linked"),t.helper("type");break;case 5:t.helper("interpolate"),t.helper("list");break;case 4:t.helper("interpolate"),t.helper("named")}}function m(e,t={}){const n=function(e,t={}){const n={ast:e,helpers:new Set};return{context:()=>n,helper:e=>(n.helpers.add(e),e)}}(e);n.helper("normalize"),e.body&&O(e.body,n);const r=n.context();e.helpers=Array.from(r.helpers)}const b=/<\/?[\w\s="/.':;#-\/]+>/;return e.COMPILE_ERROR_CODES_EXTEND_POINT=17,e.CompileErrorCodes=s,e.ERROR_DOMAIN=I,e.LOCATION_STUB={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0}},e.baseCompile=function(e,c={}){const o=t({},c),s=!!o.jit,u=!!o.mangle,a=null==o.optimize||o.optimize,f=S(o).parse(e);return s?(a&&E(f),u&&l(f),{ast:f,code:""}):(m(f,o),((e,t={})=>{const c=n(t.mode)?t.mode:"normal",o=n(t.filename)?t.filename:"message.intl",s=!!t.sourceMap,u=null!=t.breakLineCode?t.breakLineCode:"arrow"===c?";":"\n",a=t.needIndent?t.needIndent:"arrow"!==c,l=e.helpers||[],E=function(e,t){const{sourceMap:n,filename:r,breakLineCode:c,needIndent:o}=t,s=!1!==t.location,u={filename:r,code:"",column:1,line:1,offset:0,map:void 0,breakLineCode:c,needIndent:o,indentLevel:0};function a(e,t){u.code+=e}function i(e,t=!0){const n=t?c:"";a(o?n+" ".repeat(e):n)}return s&&e.loc&&(u.source=e.loc.source),{context:()=>u,push:a,indent:function(e=!0){const t=++u.indentLevel;e&&i(t)},deindent:function(e=!0){const t=--u.indentLevel;e&&i(t)},newline:function(){i(u.indentLevel)},helper:e=>`_${e}`,needIndent:()=>u.needIndent}}(e,{mode:c,filename:o,sourceMap:s,breakLineCode:u,needIndent:a});E.push("normal"===c?"function __msg__ (ctx) {":"(ctx) => {"),E.indent(a),l.length>0&&(E.push(`const { ${r(l.map((e=>`${e}: _${e}`)),", ")} } = ctx`),E.newline()),E.push("return "),i(E,e),E.deindent(a),E.push("}"),delete e.helpers;const{code:f,map:L}=E.context();return{ast:e,code:f,map:L?L.toJSON():void 0}})(f,o))},e.createCompileError=a,e.createLocation=o,e.createParser=S,e.createPosition=c,e.defaultOnError=function(e){throw e},e.detectHtmlTag=e=>b.test(e),e.errorMessages=u,e.mangle=l,e.optimize=E,e}({}); | ||
| /** | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ var IntlifyMessageCompiler = (function(e) { | ||
| Object.defineProperty(e, Symbol.toStringTag, { value: `Module` }); | ||
| let t = Object.assign; | ||
| Array.isArray; | ||
| let n = (e) => typeof e == `string`; | ||
| function r(e, t = ``) { | ||
| return e.reduce((e, n, r) => r === 0 ? e + n : e + t + n, ``); | ||
| } | ||
| let i = function(e) { | ||
| return e[e.Resource = 0] = `Resource`, e[e.Plural = 1] = `Plural`, e[e.Message = 2] = `Message`, e[e.Text = 3] = `Text`, e[e.Named = 4] = `Named`, e[e.List = 5] = `List`, e[e.Linked = 6] = `Linked`, e[e.LinkedKey = 7] = `LinkedKey`, e[e.LinkedModifier = 8] = `LinkedModifier`, e[e.Literal = 9] = `Literal`, e; | ||
| }({}), a = { | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function o(e, t, n) { | ||
| return { | ||
| line: e, | ||
| column: t, | ||
| offset: n | ||
| }; | ||
| } | ||
| function s(e, t, n) { | ||
| let r = { | ||
| start: e, | ||
| end: t | ||
| }; | ||
| return n != null && (r.source = n), r; | ||
| } | ||
| let c = function(e) { | ||
| return e.LIST = `list`, e.NAMED = `named`, e.PLURAL = `plural`, e.LINKED = `linked`, e.MESSAGE = `message`, e.TYPE = `type`, e.INTERPOLATE = `interpolate`, e.NORMALIZE = `normalize`, e.VALUES = `values`, e; | ||
| }({}), l = /<[\w\s=":;#-/]+>/, u = (e) => l.test(e), d = { | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }, f = { | ||
| [d.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [d.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [d.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [d.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [d.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [d.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [d.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [d.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [d.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [d.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [d.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [d.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [d.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [d.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [d.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [d.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function p(e, t, n = {}) { | ||
| let { domain: r, messages: i, args: a } = n, o = SyntaxError(String(e)); | ||
| return o.code = e, t && (o.location = t), o.domain = r, o; | ||
| } | ||
| function m(e) { | ||
| throw e; | ||
| } | ||
| function h(e, t) { | ||
| let { sourceMap: n, filename: r, breakLineCode: i, needIndent: a } = t, o = t.location !== !1, s = { | ||
| filename: r, | ||
| code: ``, | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode: i, | ||
| needIndent: a, | ||
| indentLevel: 0 | ||
| }; | ||
| o && e.loc && (s.source = e.loc.source); | ||
| let c = () => s; | ||
| function l(e, t) { | ||
| s.code += e; | ||
| } | ||
| function u(e, t = !0) { | ||
| let n = t ? i : ``; | ||
| l(a ? n + ` `.repeat(e) : n); | ||
| } | ||
| function d(e = !0) { | ||
| let t = ++s.indentLevel; | ||
| e && u(t); | ||
| } | ||
| function f(e = !0) { | ||
| let t = --s.indentLevel; | ||
| e && u(t); | ||
| } | ||
| function p() { | ||
| u(s.indentLevel); | ||
| } | ||
| return { | ||
| context: c, | ||
| push: l, | ||
| indent: d, | ||
| deindent: f, | ||
| newline: p, | ||
| helper: (e) => `_${e}`, | ||
| needIndent: () => s.needIndent | ||
| }; | ||
| } | ||
| function g(e, t) { | ||
| let { helper: n } = e; | ||
| e.push(`${n(`linked`)}(`), b(e, t.key), t.modifier ? (e.push(`, `), b(e, t.modifier), e.push(`, _type`)) : e.push(`, undefined, _type`), e.push(`)`); | ||
| } | ||
| function _(e, t) { | ||
| let { helper: n, needIndent: r } = e; | ||
| e.push(`${n(`normalize`)}([`), e.indent(r()); | ||
| let i = t.items.length; | ||
| for (let n = 0; n < i && (b(e, t.items[n]), n !== i - 1); n++) e.push(`, `); | ||
| e.deindent(r()), e.push(`])`); | ||
| } | ||
| function v(e, t) { | ||
| let { helper: n, needIndent: r } = e; | ||
| if (t.cases.length > 1) { | ||
| e.push(`${n(`plural`)}([`), e.indent(r()); | ||
| let i = t.cases.length; | ||
| for (let n = 0; n < i && (b(e, t.cases[n]), n !== i - 1); n++) e.push(`, `); | ||
| e.deindent(r()), e.push(`])`); | ||
| } | ||
| } | ||
| function y(e, t) { | ||
| t.body ? b(e, t.body) : e.push(`null`); | ||
| } | ||
| function b(e, t) { | ||
| let { helper: n } = e; | ||
| switch (t.type) { | ||
| case 0: | ||
| y(e, t); | ||
| break; | ||
| case 1: | ||
| v(e, t); | ||
| break; | ||
| case 2: | ||
| _(e, t); | ||
| break; | ||
| case 6: | ||
| g(e, t); | ||
| break; | ||
| case 8: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 7: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 5: | ||
| e.push(`${n(`interpolate`)}(${n(`list`)}(${t.index}))`, t); | ||
| break; | ||
| case 4: | ||
| e.push(`${n(`interpolate`)}(${n(`named`)}(${JSON.stringify(t.key)}))`, t); | ||
| break; | ||
| case 9: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| case 3: | ||
| e.push(JSON.stringify(t.value), t); | ||
| break; | ||
| default: | ||
| } | ||
| } | ||
| let x = (e, t = {}) => { | ||
| let i = n(t.mode) ? t.mode : `normal`, a = n(t.filename) ? t.filename : `message.intl`, o = !!t.sourceMap, s = t.breakLineCode == null ? i === `arrow` ? `;` : ` | ||
| ` : t.breakLineCode, c = t.needIndent ? t.needIndent : i !== `arrow`, l = e.helpers || [], u = h(e, { | ||
| mode: i, | ||
| filename: a, | ||
| sourceMap: o, | ||
| breakLineCode: s, | ||
| needIndent: c | ||
| }); | ||
| u.push(i === `normal` ? `function __msg__ (ctx) {` : `(ctx) => {`), u.indent(c), l.length > 0 && (u.push(`const { ${r(l.map((e) => `${e}: _${e}`), `, `)} } = ctx`), u.newline()), u.push(`return `), b(u, e), u.deindent(c), u.push(`}`), delete e.helpers; | ||
| let { code: d, map: f } = u.context(); | ||
| return { | ||
| ast: e, | ||
| code: d, | ||
| map: f ? f.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| function S(e) { | ||
| switch (e.t = e.type, e.type) { | ||
| case 0: { | ||
| let t = e; | ||
| S(t.body), t.b = t.body, delete t.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| let t = e, n = t.cases; | ||
| for (let e = 0; e < n.length; e++) S(n[e]); | ||
| t.c = n, delete t.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| let t = e, n = t.items; | ||
| for (let e = 0; e < n.length; e++) S(n[e]); | ||
| t.i = n, delete t.items, t.static && (t.s = t.static, delete t.static); | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| let t = e; | ||
| t.value && (t.v = t.value, delete t.value); | ||
| break; | ||
| } | ||
| case 6: { | ||
| let t = e; | ||
| S(t.key), t.k = t.key, delete t.key, t.modifier && (S(t.modifier), t.m = t.modifier, delete t.modifier); | ||
| break; | ||
| } | ||
| case 5: { | ||
| let t = e; | ||
| t.i = t.index, delete t.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| let t = e; | ||
| t.k = t.key, delete t.key; | ||
| break; | ||
| } | ||
| default: | ||
| } | ||
| delete e.type; | ||
| } | ||
| function C(e) { | ||
| let t = e.body; | ||
| return t.type === 2 ? w(t) : t.cases.forEach((e) => w(e)), e; | ||
| } | ||
| function w(e) { | ||
| if (e.items.length === 1) { | ||
| let t = e.items[0]; | ||
| (t.type === 3 || t.type === 9) && (e.static = t.value, delete t.value); | ||
| } else { | ||
| let t = []; | ||
| for (let n = 0; n < e.items.length; n++) { | ||
| let r = e.items[n]; | ||
| if (!(r.type === 3 || r.type === 9) || r.value == null) break; | ||
| t.push(r.value); | ||
| } | ||
| if (t.length === e.items.length) { | ||
| e.static = r(t); | ||
| for (let t = 0; t < e.items.length; t++) { | ||
| let n = e.items[t]; | ||
| (n.type === 3 || n.type === 9) && delete n.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function ee(e) { | ||
| let t = e, n = 0, r = 1, i = 1, a = 0, o = (e) => t[e] === `\r` && t[e + 1] === ` | ||
| `, s = (e) => t[e] === ` | ||
| `, c = (e) => t[e] === `\u2029`, l = (e) => t[e] === `\u2028`, u = (e) => o(e) || s(e) || c(e) || l(e), d = () => n, f = () => r, p = () => i, m = () => a, h = (e) => o(e) || c(e) || l(e) ? ` | ||
| ` : t[e], g = () => h(n), _ = () => h(n + a); | ||
| function v() { | ||
| return a = 0, u(n) && (r++, i = 0), o(n) && n++, n++, i++, t[n]; | ||
| } | ||
| function y() { | ||
| return o(n + a) && a++, a++, t[n + a]; | ||
| } | ||
| function b() { | ||
| n = 0, r = 1, i = 1, a = 0; | ||
| } | ||
| function x(e = 0) { | ||
| a = e; | ||
| } | ||
| function S() { | ||
| let e = n + a; | ||
| for (; e !== n;) v(); | ||
| a = 0; | ||
| } | ||
| return { | ||
| index: d, | ||
| line: f, | ||
| column: p, | ||
| peekOffset: m, | ||
| charAt: h, | ||
| currentChar: g, | ||
| currentPeek: _, | ||
| next: v, | ||
| peek: y, | ||
| reset: b, | ||
| resetPeek: x, | ||
| skipToPeek: S | ||
| }; | ||
| } | ||
| function T(e, t = {}) { | ||
| let n = t.location !== !1, r = ee(e), i = () => r.index(), a = () => o(r.line(), r.column(), r.index()), c = a(), l = i(), u = { | ||
| currentType: 13, | ||
| offset: l, | ||
| startLoc: c, | ||
| endLoc: c, | ||
| lastType: 13, | ||
| lastOffset: l, | ||
| lastStartLoc: c, | ||
| lastEndLoc: c, | ||
| braceNest: 0, | ||
| inLinked: !1, | ||
| text: `` | ||
| }, f = () => u, { onError: m } = t; | ||
| function h(e, t, r, ...i) { | ||
| let a = f(); | ||
| t.column += r, t.offset += r, m && m(p(e, n ? s(a.startLoc, t) : null, { | ||
| domain: `tokenizer`, | ||
| args: i | ||
| })); | ||
| } | ||
| function g(e, t, r) { | ||
| e.endLoc = a(), e.currentType = t; | ||
| let i = { type: t }; | ||
| return n && (i.loc = s(e.startLoc, e.endLoc)), r != null && (i.value = r), i; | ||
| } | ||
| let _ = (e) => g(e, 13); | ||
| function v(e, t) { | ||
| return e.currentChar() === t ? (e.next(), t) : (h(d.EXPECTED_TOKEN, a(), 0, t), ``); | ||
| } | ||
| function y(e) { | ||
| let t = ``; | ||
| for (; e.currentPeek() === ` ` || e.currentPeek() === ` | ||
| `;) t += e.currentPeek(), e.peek(); | ||
| return t; | ||
| } | ||
| function b(e) { | ||
| let t = y(e); | ||
| return e.skipToPeek(), t; | ||
| } | ||
| function x(e) { | ||
| if (e === void 0) return !1; | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t === 95; | ||
| } | ||
| function S(e) { | ||
| if (e === void 0) return !1; | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57; | ||
| } | ||
| function C(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| y(e); | ||
| let r = x(e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function w(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| y(e); | ||
| let r = S(e.currentPeek() === `-` ? e.peek() : e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function T(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 2) return !1; | ||
| y(e); | ||
| let r = e.currentPeek() === `'`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function E(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 7) return !1; | ||
| y(e); | ||
| let r = e.currentPeek() === `.`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function D(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 8) return !1; | ||
| y(e); | ||
| let r = x(e.currentPeek()); | ||
| return e.resetPeek(), r; | ||
| } | ||
| function O(e, t) { | ||
| let { currentType: n } = t; | ||
| if (!(n === 7 || n === 11)) return !1; | ||
| y(e); | ||
| let r = e.currentPeek() === `:`; | ||
| return e.resetPeek(), r; | ||
| } | ||
| function k(e, t) { | ||
| let { currentType: n } = t; | ||
| if (n !== 9) return !1; | ||
| let r = () => { | ||
| let t = e.currentPeek(); | ||
| return t === `{` ? x(e.peek()) : t === `@` || t === `|` || t === `:` || t === `.` || t === ` ` || !t ? !1 : t === ` | ||
| ` ? (e.peek(), r()) : j(e, !1); | ||
| }, i = r(); | ||
| return e.resetPeek(), i; | ||
| } | ||
| function A(e) { | ||
| y(e); | ||
| let t = e.currentPeek() === `|`; | ||
| return e.resetPeek(), t; | ||
| } | ||
| function j(e, t = !0) { | ||
| let n = (t = !1, r = ``) => { | ||
| let i = e.currentPeek(); | ||
| return i === `{` || i === `@` || !i ? t : i === `|` ? !(r === ` ` || r === ` | ||
| `) : i === ` ` ? (e.peek(), n(!0, ` `)) : i === ` | ||
| ` ? (e.peek(), n(!0, ` | ||
| `)) : !0; | ||
| }, r = n(); | ||
| return t && e.resetPeek(), r; | ||
| } | ||
| function M(e, t) { | ||
| let n = e.currentChar(); | ||
| if (n !== void 0) return t(n) ? (e.next(), n) : null; | ||
| } | ||
| function N(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t >= 48 && t <= 57 || t === 95 || t === 36; | ||
| } | ||
| function P(e) { | ||
| return M(e, N); | ||
| } | ||
| function F(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 97 && t <= 122 || t >= 65 && t <= 90 || t >= 48 && t <= 57 || t === 95 || t === 36 || t === 45; | ||
| } | ||
| function I(e) { | ||
| return M(e, F); | ||
| } | ||
| function L(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57; | ||
| } | ||
| function R(e) { | ||
| return M(e, L); | ||
| } | ||
| function z(e) { | ||
| let t = e.charCodeAt(0); | ||
| return t >= 48 && t <= 57 || t >= 65 && t <= 70 || t >= 97 && t <= 102; | ||
| } | ||
| function B(e) { | ||
| return M(e, z); | ||
| } | ||
| function V(e) { | ||
| let t = ``, n = ``; | ||
| for (; t = R(e);) n += t; | ||
| return n; | ||
| } | ||
| function H(e) { | ||
| let t = ``; | ||
| for (;;) { | ||
| let n = e.currentChar(); | ||
| if (n === `\\`) { | ||
| let r = e.peek(); | ||
| r === `{` || r === `}` || r === `@` || r === `|` || r === `\\` ? (t += n + r, e.next(), e.next()) : (e.resetPeek(), t += n, e.next()); | ||
| } else if (n === `{` || n === `}` || n === `@` || n === `|` || !n) break; | ||
| else if (n === ` ` || n === ` | ||
| `) if (j(e)) t += n, e.next(); | ||
| else if (A(e)) break; | ||
| else t += n, e.next(); | ||
| else t += n, e.next(); | ||
| } | ||
| return t; | ||
| } | ||
| function U(e) { | ||
| b(e); | ||
| let t = ``, n = ``; | ||
| for (; t = I(e);) n += t; | ||
| let r = e.currentChar(); | ||
| if (r && r !== `}` && r !== void 0 && r !== ` ` && r !== ` | ||
| ` && r !== ` `) { | ||
| let t = Y(e); | ||
| return h(d.INVALID_TOKEN_IN_PLACEHOLDER, a(), 0, n + t), n + t; | ||
| } | ||
| return e.currentChar() === void 0 && h(d.UNTERMINATED_CLOSING_BRACE, a(), 0), n; | ||
| } | ||
| function W(e) { | ||
| b(e); | ||
| let t = ``; | ||
| return e.currentChar() === `-` ? (e.next(), t += `-${V(e)}`) : t += V(e), e.currentChar() === void 0 && h(d.UNTERMINATED_CLOSING_BRACE, a(), 0), t; | ||
| } | ||
| function G(e) { | ||
| return e !== `'` && e !== ` | ||
| `; | ||
| } | ||
| function K(e) { | ||
| b(e), v(e, `'`); | ||
| let t = ``, n = ``; | ||
| for (; t = M(e, G);) t === `\\` ? n += q(e) : n += t; | ||
| let r = e.currentChar(); | ||
| return r === ` | ||
| ` || r === void 0 ? (h(d.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, a(), 0), r === ` | ||
| ` && (e.next(), v(e, `'`)), n) : (v(e, `'`), n); | ||
| } | ||
| function q(e) { | ||
| let t = e.currentChar(); | ||
| switch (t) { | ||
| case `\\`: | ||
| case `'`: return e.next(), `\\${t}`; | ||
| case `u`: return J(e, t, 4); | ||
| case `U`: return J(e, t, 6); | ||
| default: return h(d.UNKNOWN_ESCAPE_SEQUENCE, a(), 0, t), ``; | ||
| } | ||
| } | ||
| function J(e, t, n) { | ||
| v(e, t); | ||
| let r = ``; | ||
| for (let i = 0; i < n; i++) { | ||
| let n = B(e); | ||
| if (!n) { | ||
| h(d.INVALID_UNICODE_ESCAPE_SEQUENCE, a(), 0, `\\${t}${r}${e.currentChar()}`); | ||
| break; | ||
| } | ||
| r += n; | ||
| } | ||
| return `\\${t}${r}`; | ||
| } | ||
| function te(e) { | ||
| return e !== `{` && e !== `}` && e !== ` ` && e !== ` | ||
| `; | ||
| } | ||
| function Y(e) { | ||
| b(e); | ||
| let t = ``, n = ``; | ||
| for (; t = M(e, te);) n += t; | ||
| return n; | ||
| } | ||
| function ne(e) { | ||
| let t = ``, n = ``; | ||
| for (; t = P(e);) n += t; | ||
| return n; | ||
| } | ||
| function re(e) { | ||
| let t = (n) => { | ||
| let r = e.currentChar(); | ||
| return r === `{` || r === `@` || r === `|` || r === `(` || r === `)` || !r || r === ` ` ? n : (n += r, e.next(), t(n)); | ||
| }; | ||
| return t(``); | ||
| } | ||
| function X(e) { | ||
| b(e); | ||
| let t = v(e, `|`); | ||
| return b(e), t; | ||
| } | ||
| function Z(e, t) { | ||
| let n = null; | ||
| switch (e.currentChar()) { | ||
| case `{`: return t.braceNest >= 1 && h(d.NOT_ALLOW_NEST_PLACEHOLDER, a(), 0), e.next(), n = g(t, 2, `{`), b(e), t.braceNest++, n; | ||
| case `}`: return t.braceNest > 0 && t.currentType === 2 && h(d.EMPTY_PLACEHOLDER, a(), 0), e.next(), n = g(t, 3, `}`), t.braceNest--, t.braceNest > 0 && b(e), t.inLinked && t.braceNest === 0 && (t.inLinked = !1), n; | ||
| case `@`: return t.braceNest > 0 && h(d.UNTERMINATED_CLOSING_BRACE, a(), 0), n = Q(e, t) || _(t), t.braceNest = 0, n; | ||
| default: { | ||
| let r = !0, i = !0, o = !0; | ||
| if (A(e)) return t.braceNest > 0 && h(d.UNTERMINATED_CLOSING_BRACE, a(), 0), n = g(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, n; | ||
| if (t.braceNest > 0 && (t.currentType === 4 || t.currentType === 5 || t.currentType === 6)) return h(d.UNTERMINATED_CLOSING_BRACE, a(), 0), t.braceNest = 0, $(e, t); | ||
| if (r = C(e, t)) return n = g(t, 4, U(e)), b(e), n; | ||
| if (i = w(e, t)) return n = g(t, 5, W(e)), b(e), n; | ||
| if (o = T(e, t)) return n = g(t, 6, K(e)), b(e), n; | ||
| if (!r && !i && !o) return n = g(t, 12, Y(e)), h(d.INVALID_TOKEN_IN_PLACEHOLDER, a(), 0, n.value), b(e), n; | ||
| break; | ||
| } | ||
| } | ||
| return n; | ||
| } | ||
| function Q(e, t) { | ||
| let { currentType: n } = t, r = null, i = e.currentChar(); | ||
| switch ((n === 7 || n === 8 || n === 11 || n === 9) && (i === ` | ||
| ` || i === ` `) && h(d.INVALID_LINKED_FORMAT, a(), 0), i) { | ||
| case `@`: return e.next(), r = g(t, 7, `@`), t.inLinked = !0, r; | ||
| case `.`: return b(e), e.next(), g(t, 8, `.`); | ||
| case `:`: return b(e), e.next(), g(t, 9, `:`); | ||
| default: return A(e) ? (r = g(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, r) : E(e, t) || O(e, t) ? (b(e), Q(e, t)) : D(e, t) ? (b(e), g(t, 11, ne(e))) : k(e, t) ? (b(e), i === `{` ? Z(e, t) || r : g(t, 10, re(e))) : (n === 7 && h(d.INVALID_LINKED_FORMAT, a(), 0), t.braceNest = 0, t.inLinked = !1, $(e, t)); | ||
| } | ||
| } | ||
| function $(e, t) { | ||
| let n = { type: 13 }; | ||
| if (t.braceNest > 0) return Z(e, t) || _(t); | ||
| if (t.inLinked) return Q(e, t) || _(t); | ||
| switch (e.currentChar()) { | ||
| case `{`: return Z(e, t) || _(t); | ||
| case `}`: return h(d.UNBALANCED_CLOSING_BRACE, a(), 0), e.next(), g(t, 3, `}`); | ||
| case `@`: return Q(e, t) || _(t); | ||
| default: | ||
| if (A(e)) return n = g(t, 1, X(e)), t.braceNest = 0, t.inLinked = !1, n; | ||
| if (j(e)) return g(t, 0, H(e)); | ||
| break; | ||
| } | ||
| return n; | ||
| } | ||
| function ie() { | ||
| let { currentType: e, offset: t, startLoc: n, endLoc: o } = u; | ||
| return u.lastType = e, u.lastOffset = t, u.lastStartLoc = n, u.lastEndLoc = o, u.offset = i(), u.startLoc = a(), r.currentChar() === void 0 ? g(u, 13) : $(r, u); | ||
| } | ||
| return { | ||
| nextToken: ie, | ||
| currentOffset: i, | ||
| currentPosition: a, | ||
| context: f | ||
| }; | ||
| } | ||
| let E = `parser`, D = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g, O = /\\([\\@{}|])/g; | ||
| function k(e, t) { | ||
| return t; | ||
| } | ||
| function A(e, t, n) { | ||
| switch (e) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| let e = parseInt(t || n, 16); | ||
| return e <= 55295 || e >= 57344 ? String.fromCodePoint(e) : `�`; | ||
| } | ||
| } | ||
| } | ||
| function j(e = {}) { | ||
| let n = e.location !== !1, { onError: r } = e; | ||
| function i(e, t, i, a, ...o) { | ||
| let c = e.currentPosition(); | ||
| c.offset += a, c.column += a, r && r(p(t, n ? s(i, c) : null, { | ||
| domain: E, | ||
| args: o | ||
| })); | ||
| } | ||
| function a(e, t, r) { | ||
| let i = { type: e }; | ||
| return n && (i.start = t, i.end = t, i.loc = { | ||
| start: r, | ||
| end: r | ||
| }), i; | ||
| } | ||
| function o(e, t, r, i) { | ||
| i && (e.type = i), n && (e.end = t, e.loc && (e.loc.end = r)); | ||
| } | ||
| function c(e, t) { | ||
| let n = e.context(), r = a(3, n.offset, n.startLoc); | ||
| return r.value = t.replace(O, k), o(r, e.currentOffset(), e.currentPosition()), r; | ||
| } | ||
| function l(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), i = a(5, n, r); | ||
| return i.index = parseInt(t, 10), e.nextToken(), o(i, e.currentOffset(), e.currentPosition()), i; | ||
| } | ||
| function u(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), i = a(4, n, r); | ||
| return i.key = t, e.nextToken(), o(i, e.currentOffset(), e.currentPosition()), i; | ||
| } | ||
| function f(e, t) { | ||
| let { lastOffset: n, lastStartLoc: r } = e.context(), i = a(9, n, r); | ||
| return i.value = t.replace(D, A), e.nextToken(), o(i, e.currentOffset(), e.currentPosition()), i; | ||
| } | ||
| function m(e) { | ||
| let t = e.nextToken(), n = e.context(), { lastOffset: r, lastStartLoc: s } = n, c = a(8, r, s); | ||
| return t.type === 11 ? (t.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, n.lastStartLoc, 0, M(t)), c.value = t.value || ``, o(c, e.currentOffset(), e.currentPosition()), { node: c }) : (i(e, d.UNEXPECTED_EMPTY_LINKED_MODIFIER, n.lastStartLoc, 0), c.value = ``, o(c, r, s), { | ||
| nextConsumeToken: t, | ||
| node: c | ||
| }); | ||
| } | ||
| function h(e, t) { | ||
| let n = e.context(), r = a(7, n.offset, n.startLoc); | ||
| return r.value = t, o(r, e.currentOffset(), e.currentPosition()), r; | ||
| } | ||
| function g(e) { | ||
| let t = e.context(), n = a(6, t.offset, t.startLoc), r = e.nextToken(); | ||
| if (r.type === 8) { | ||
| let t = m(e); | ||
| n.modifier = t.node, r = t.nextConsumeToken || e.nextToken(); | ||
| } | ||
| switch (r.type !== 9 && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(r)), r = e.nextToken(), r.type === 2 && (r = e.nextToken()), r.type) { | ||
| case 10: | ||
| r.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(r)), n.key = h(e, r.value || ``); | ||
| break; | ||
| case 4: | ||
| r.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(r)), n.key = u(e, r.value || ``); | ||
| break; | ||
| case 5: | ||
| r.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(r)), n.key = l(e, r.value || ``); | ||
| break; | ||
| case 6: | ||
| r.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(r)), n.key = f(e, r.value || ``); | ||
| break; | ||
| default: { | ||
| i(e, d.UNEXPECTED_EMPTY_LINKED_KEY, t.lastStartLoc, 0); | ||
| let s = e.context(), c = a(7, s.offset, s.startLoc); | ||
| return c.value = ``, o(c, s.offset, s.startLoc), n.key = c, o(n, s.offset, s.startLoc), { | ||
| nextConsumeToken: r, | ||
| node: n | ||
| }; | ||
| } | ||
| } | ||
| return o(n, e.currentOffset(), e.currentPosition()), { node: n }; | ||
| } | ||
| function _(e) { | ||
| let t = e.context(), n = a(2, t.currentType === 1 ? e.currentOffset() : t.offset, t.currentType === 1 ? t.endLoc : t.startLoc); | ||
| n.items = []; | ||
| let r = null; | ||
| do { | ||
| let a = r || e.nextToken(); | ||
| switch (r = null, a.type) { | ||
| case 0: | ||
| a.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(a)), n.items.push(c(e, a.value || ``)); | ||
| break; | ||
| case 5: | ||
| a.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(a)), n.items.push(l(e, a.value || ``)); | ||
| break; | ||
| case 4: | ||
| a.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(a)), n.items.push(u(e, a.value || ``)); | ||
| break; | ||
| case 6: | ||
| a.value == null && i(e, d.UNEXPECTED_LEXICAL_ANALYSIS, t.lastStartLoc, 0, M(a)), n.items.push(f(e, a.value || ``)); | ||
| break; | ||
| case 7: { | ||
| let t = g(e); | ||
| n.items.push(t.node), r = t.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (t.currentType !== 13 && t.currentType !== 1); | ||
| return o(n, t.currentType === 1 ? t.lastOffset : e.currentOffset(), t.currentType === 1 ? t.lastEndLoc : e.currentPosition()), n; | ||
| } | ||
| function v(e, t, n, r) { | ||
| let s = e.context(), c = r.items.length === 0, l = a(1, t, n); | ||
| l.cases = [], l.cases.push(r); | ||
| do { | ||
| let t = _(e); | ||
| c || (c = t.items.length === 0), l.cases.push(t); | ||
| } while (s.currentType !== 13); | ||
| return c && i(e, d.MUST_HAVE_MESSAGES_IN_PLURAL, n, 0), o(l, e.currentOffset(), e.currentPosition()), l; | ||
| } | ||
| function y(e) { | ||
| let t = e.context(), { offset: n, startLoc: r } = t, i = _(e); | ||
| return t.currentType === 13 ? i : v(e, n, r, i); | ||
| } | ||
| function b(r) { | ||
| let s = T(r, t({}, e)), c = s.context(), l = a(0, c.offset, c.startLoc); | ||
| return n && l.loc && (l.loc.source = r), l.body = y(s), e.onCacheKey && (l.cacheKey = e.onCacheKey(r)), c.currentType !== 13 && i(s, d.UNEXPECTED_LEXICAL_ANALYSIS, c.lastStartLoc, 0, r[c.offset] || ``), o(l, s.currentOffset(), s.currentPosition()), l; | ||
| } | ||
| return { parse: b }; | ||
| } | ||
| function M(e) { | ||
| if (e.type === 13) return `EOF`; | ||
| let t = (e.value || ``).replace(/\r?\n/gu, `\\n`); | ||
| return t.length > 10 ? t.slice(0, 9) + `…` : t; | ||
| } | ||
| function N(e, t = {}) { | ||
| let n = { | ||
| ast: e, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| return { | ||
| context: () => n, | ||
| helper: (e) => (n.helpers.add(e), e) | ||
| }; | ||
| } | ||
| function P(e, t) { | ||
| for (let n = 0; n < e.length; n++) F(e[n], t); | ||
| } | ||
| function F(e, t) { | ||
| switch (e.type) { | ||
| case 1: | ||
| P(e.cases, t), t.helper(`plural`); | ||
| break; | ||
| case 2: | ||
| P(e.items, t); | ||
| break; | ||
| case 6: | ||
| F(e.key, t), t.helper(`linked`), t.helper(`type`); | ||
| break; | ||
| case 5: | ||
| t.helper(`interpolate`), t.helper(`list`); | ||
| break; | ||
| case 4: | ||
| t.helper(`interpolate`), t.helper(`named`); | ||
| break; | ||
| } | ||
| } | ||
| function I(e, t = {}) { | ||
| let n = N(e); | ||
| n.helper(`normalize`), e.body && F(e.body, n); | ||
| let r = n.context(); | ||
| e.helpers = Array.from(r.helpers); | ||
| } | ||
| function L(e, n = {}) { | ||
| let r = t({}, n), i = !!r.jit, a = !!r.mangle, o = r.optimize == null ? !0 : r.optimize, s = j(r).parse(e); | ||
| return i ? (o && C(s), a && S(s), { | ||
| ast: s, | ||
| code: `` | ||
| }) : (I(s, r), x(s, r)); | ||
| } | ||
| return e.COMPILE_ERROR_CODES_EXTEND_POINT = 17, e.CompileErrorCodes = d, e.ERROR_DOMAIN = E, e.HelperNameMap = c, e.LOCATION_STUB = a, e.NodeTypes = i, e.baseCompile = L, e.createCompileError = p, e.createLocation = s, e.createParser = j, e.createPosition = o, e.defaultOnError = m, e.detectHtmlTag = u, e.errorMessages = f, e.mangle = S, e.optimize = C, e; | ||
| })({}); |
+1200
-1464
@@ -1,1520 +0,1256 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| import { format, isString, join, assign } from '@intlify/shared'; | ||
| /** | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ | ||
| import { assign, format, isString, join } from "@intlify/shared"; | ||
| //#region packages/message-compiler/src/nodes.ts | ||
| let NodeTypes = /* @__PURE__ */ function(NodeTypes) { | ||
| NodeTypes[NodeTypes["Resource"] = 0] = "Resource"; | ||
| NodeTypes[NodeTypes["Plural"] = 1] = "Plural"; | ||
| NodeTypes[NodeTypes["Message"] = 2] = "Message"; | ||
| NodeTypes[NodeTypes["Text"] = 3] = "Text"; | ||
| NodeTypes[NodeTypes["Named"] = 4] = "Named"; | ||
| NodeTypes[NodeTypes["List"] = 5] = "List"; | ||
| NodeTypes[NodeTypes["Linked"] = 6] = "Linked"; | ||
| NodeTypes[NodeTypes["LinkedKey"] = 7] = "LinkedKey"; | ||
| NodeTypes[NodeTypes["LinkedModifier"] = 8] = "LinkedModifier"; | ||
| NodeTypes[NodeTypes["Literal"] = 9] = "Literal"; | ||
| return NodeTypes; | ||
| }({}); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/location.ts | ||
| const LOCATION_STUB = { | ||
| start: { line: 1, column: 1, offset: 0 }, | ||
| end: { line: 1, column: 1, offset: 0 } | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function createPosition(line, column, offset) { | ||
| return { line, column, offset }; | ||
| return { | ||
| line, | ||
| column, | ||
| offset | ||
| }; | ||
| } | ||
| function createLocation(start, end, source) { | ||
| const loc = { start, end }; | ||
| if (source != null) { | ||
| loc.source = source; | ||
| } | ||
| return loc; | ||
| const loc = { | ||
| start, | ||
| end | ||
| }; | ||
| if (source != null) loc.source = source; | ||
| return loc; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/helpers.ts | ||
| let HelperNameMap = /* @__PURE__ */ function(HelperNameMap) { | ||
| HelperNameMap["LIST"] = "list"; | ||
| HelperNameMap["NAMED"] = "named"; | ||
| HelperNameMap["PLURAL"] = "plural"; | ||
| HelperNameMap["LINKED"] = "linked"; | ||
| HelperNameMap["MESSAGE"] = "message"; | ||
| HelperNameMap["TYPE"] = "type"; | ||
| HelperNameMap["INTERPOLATE"] = "interpolate"; | ||
| HelperNameMap["NORMALIZE"] = "normalize"; | ||
| HelperNameMap["VALUES"] = "values"; | ||
| return HelperNameMap; | ||
| }({}); | ||
| const RE_HTML_TAG = /<[\w\s=":;#-/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/errors.ts | ||
| const CompileErrorCodes = { | ||
| // tokenizer error codes | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| // parser error codes | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| // generator error codes | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| // minifier error codes | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }; | ||
| // Special value for higher-order compilers to pick up the last code | ||
| // to avoid collision of error codes. | ||
| // This should always be kept as the last item. | ||
| const COMPILE_ERROR_CODES_EXTEND_POINT = 17; | ||
| /** @internal */ | ||
| const errorMessages = { | ||
| // tokenizer error messages | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| // parser error messages | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| // generator error messages | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| // minimizer error messages | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(code, loc, options = {}) { | ||
| const { domain, messages, args } = options; | ||
| const msg = (process.env.NODE_ENV !== 'production') | ||
| ? format((messages || errorMessages)[code] || '', ...(args || [])) | ||
| : code; | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) { | ||
| error.location = loc; | ||
| } | ||
| error.domain = domain; | ||
| return error; | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || "", ...args || []); | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) error.location = loc; | ||
| error.domain = domain; | ||
| return error; | ||
| } | ||
| /** @internal */ | ||
| function defaultOnError(error) { | ||
| throw error; | ||
| throw error; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/triple-slash-reference | ||
| /// <reference types="source-map-js" /> | ||
| const ERROR_DOMAIN$3 = 'parser'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/generator.ts | ||
| const ERROR_DOMAIN$3 = "parser"; | ||
| function createCodeGenerator(ast, options) { | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: '', | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: undefined, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) { | ||
| _context.source = ast.loc.source; | ||
| } | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ''; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: "", | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) _context.source = ast.loc.source; | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ""; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(generator, node) { | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } | ||
| else { | ||
| generator.push(`, undefined, _type`); | ||
| } | ||
| generator.push(`)`); | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked")}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } else generator.push(`, undefined, _type`); | ||
| generator.push(`)`); | ||
| } | ||
| function generateMessageNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push('])'); | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push("])"); | ||
| } | ||
| function generatePluralNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(generator, node) { | ||
| if (node.body) { | ||
| generateNode(generator, node.body); | ||
| } | ||
| else { | ||
| generator.push('null'); | ||
| } | ||
| if (node.body) generateNode(generator, node.body); | ||
| else generator.push("null"); | ||
| } | ||
| function generateNode(generator, node) { | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1 /* NodeTypes.Plural */: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7 /* NodeTypes.LinkedKey */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5 /* NodeTypes.List */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9 /* NodeTypes.Literal */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3 /* NodeTypes.Text */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: | ||
| if ((process.env.NODE_ENV !== 'production')) { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5: | ||
| generator.push(`${helper("interpolate")}(${helper("list")}(${node.index}))`, node); | ||
| break; | ||
| case 4: | ||
| generator.push(`${helper("interpolate")}(${helper("named")}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| // generate code from AST | ||
| const generate = (ast, options = {}) => { | ||
| const mode = isString(options.mode) ? options.mode : 'normal'; | ||
| const filename = isString(options.filename) | ||
| ? options.filename | ||
| : 'message.intl'; | ||
| const sourceMap = !!options.sourceMap; | ||
| // prettier-ignore | ||
| const breakLineCode = options.breakLineCode != null | ||
| ? options.breakLineCode | ||
| : mode === 'arrow' | ||
| ? ';' | ||
| : '\n'; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow'; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| }; | ||
| const mode = isString(options.mode) ? options.mode : "normal"; | ||
| const filename = isString(options.filename) ? options.filename : "message.intl"; | ||
| const sourceMap = !!options.sourceMap; | ||
| const breakLineCode = options.breakLineCode != null ? options.breakLineCode : mode === "arrow" ? ";" : "\n"; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== "arrow"; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === "normal" ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map((s) => `${s}: _${s}`), ", ")} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| const ERROR_DOMAIN$2 = 'minifier'; | ||
| /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/mangler.ts | ||
| const ERROR_DOMAIN$2 = "minifier"; | ||
| function mangle(node) { | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1 /* NodeTypes.Plural */: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) { | ||
| mangle(cases[i]); | ||
| } | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2 /* NodeTypes.Message */: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) { | ||
| mangle(items[i]); | ||
| } | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3 /* NodeTypes.Text */: | ||
| case 9 /* NodeTypes.Literal */: | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| case 7 /* NodeTypes.LinkedKey */: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4 /* NodeTypes.Named */: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: | ||
| if ((process.env.NODE_ENV !== 'production')) { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| delete node.type; | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) mangle(cases[i]); | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) mangle(items[i]); | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| delete node.type; | ||
| } | ||
| /* eslint-enable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/optimizer.ts | ||
| function optimize(ast) { | ||
| const body = ast.body; | ||
| if (body.type === 2 /* NodeTypes.Message */) { | ||
| optimizeMessageNode(body); | ||
| } | ||
| else { | ||
| body.cases.forEach(c => optimizeMessageNode(c)); | ||
| } | ||
| return ast; | ||
| const body = ast.body; | ||
| if (body.type === 2) optimizeMessageNode(body); | ||
| else body.cases.forEach((c) => optimizeMessageNode(c)); | ||
| return ast; | ||
| } | ||
| function optimizeMessageNode(message) { | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| message.static = item.value; | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) { | ||
| break; | ||
| } | ||
| if (item.value == null) { | ||
| break; | ||
| } | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 || item.type === 9) { | ||
| message.static = item.value; | ||
| delete item.value; | ||
| } | ||
| } else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 || item.type === 9)) break; | ||
| if (item.value == null) break; | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 || item.type === 9) delete item.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| const CHAR_SP = ' '; | ||
| const CHAR_CR = '\r'; | ||
| const CHAR_LF = '\n'; | ||
| const CHAR_LS = String.fromCharCode(0x2028); | ||
| const CHAR_PS = String.fromCharCode(0x2029); | ||
| function createScanner(str) { | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF; | ||
| const isLF = (index) => _buf[index] === CHAR_LF; | ||
| const isPS = (index) => _buf[index] === CHAR_PS; | ||
| const isLS = (index) => _buf[index] === CHAR_LS; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) { | ||
| _index++; | ||
| } | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) { | ||
| _peekOffset++; | ||
| } | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) { | ||
| next(); | ||
| } | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === "\r" && _buf[index + 1] === "\n"; | ||
| const isLF = (index) => _buf[index] === "\n"; | ||
| const isPS = (index) => _buf[index] === "\u2029"; | ||
| const isLS = (index) => _buf[index] === "\u2028"; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? "\n" : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) _index++; | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) _peekOffset++; | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) next(); | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| } | ||
| const EOF = undefined; | ||
| const DOT = '.'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/tokenizer.ts | ||
| const EOF = void 0; | ||
| const DOT = "."; | ||
| const LITERAL_DELIMITER = "'"; | ||
| const ERROR_DOMAIN$1 = 'tokenizer'; | ||
| const ERROR_DOMAIN$1 = "tokenizer"; | ||
| function createTokenizer(source, options = {}) { | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13 /* TokenTypes.EOF */, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13 /* TokenTypes.EOF */, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: '' | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(ctx.startLoc, pos) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) { | ||
| token.loc = createLocation(context.startLoc, context.endLoc); | ||
| } | ||
| if (value != null) { | ||
| token.value = value; | ||
| } | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13 /* TokenTypes.EOF */); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ''; | ||
| while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| cc === 95 // _ | ||
| ); | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek(); | ||
| const ret = isNumberStart(ch); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7 /* TokenTypes.LinkedAlias */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "." /* TokenChars.LinkedDot */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8 /* TokenTypes.LinkedDot */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */)) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":" /* TokenChars.LinkedDelimiter */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| return false; | ||
| } | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return isIdentifierStart(scnr.peek()); | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === ":" /* TokenChars.LinkedDelimiter */ || | ||
| ch === "." /* TokenChars.LinkedDot */ || | ||
| ch === CHAR_SP || | ||
| !ch) { | ||
| return false; | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } | ||
| else { | ||
| // other characters | ||
| return isTextStart(scnr, false); | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|" /* TokenChars.Pipe */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = '') => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || !ch) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "|" /* TokenChars.Pipe */) { | ||
| return !(prev === CHAR_SP || prev === CHAR_LF); | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_SP); | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_LF); | ||
| } | ||
| else { | ||
| return true; | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) { | ||
| return EOF; | ||
| } | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 // $ | ||
| ); | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 || // $ | ||
| cc === 45 // - | ||
| ); | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 48 && cc <= 57) || // 0-9 | ||
| (cc >= 65 && cc <= 70) || // A-F | ||
| (cc >= 97 && cc <= 102)); // a-f | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ''; | ||
| let num = ''; | ||
| while ((ch = takeDigit(scnr))) { | ||
| num += ch; | ||
| } | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ''; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "}" /* TokenChars.BraceRight */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| !ch) { | ||
| break; | ||
| } | ||
| else if (ch === CHAR_SP || ch === CHAR_LF) { | ||
| if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else if (isPluralStart(scnr)) { | ||
| break; | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeNamedIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ''; | ||
| if (scnr.currentChar() === '-') { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } | ||
| else { | ||
| value += getDigits(scnr); | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== CHAR_LF; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| let ch = ''; | ||
| let literal = ''; | ||
| while ((ch = takeChar(scnr, isLiteral))) { | ||
| if (ch === '\\') { | ||
| literal += readEscapeSequence(scnr); | ||
| } | ||
| else { | ||
| literal += ch; | ||
| } | ||
| } | ||
| const current = scnr.currentChar(); | ||
| if (current === CHAR_LF || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| // TODO: Is it correct really? | ||
| if (current === CHAR_LF) { | ||
| scnr.next(); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| } | ||
| return literal; | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case '\\': | ||
| case `\'`: // eslint-disable-line no-useless-escape | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case 'u': | ||
| return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case 'U': | ||
| return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ''; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return (ch !== "{" /* TokenChars.BraceLeft */ && | ||
| ch !== "}" /* TokenChars.BraceRight */ && | ||
| ch !== CHAR_SP && | ||
| ch !== CHAR_LF); | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let identifiers = ''; | ||
| while ((ch = takeChar(scnr, isInvalidIdentifier))) { | ||
| identifiers += ch; | ||
| } | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === "(" /* TokenChars.ParenLeft */ || | ||
| ch === ")" /* TokenChars.ParenRight */ || | ||
| !ch) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_LF || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(''); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|" /* TokenChars.Pipe */); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| if (context.braceNest >= 1) { | ||
| emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 2 /* TokenTypes.BraceLeft */, "{" /* TokenChars.BraceLeft */); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}" /* TokenChars.BraceRight */: | ||
| if (context.braceNest > 0 && | ||
| context.currentType === 2 /* TokenTypes.BraceLeft */) { | ||
| emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) { | ||
| context.inLinked = false; | ||
| } | ||
| return token; | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && | ||
| (context.currentType === 4 /* TokenTypes.Named */ || | ||
| context.currentType === 5 /* TokenTypes.List */ || | ||
| context.currentType === 6 /* TokenTypes.Literal */)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 4 /* TokenTypes.Named */, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validListIdentifier = isListIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 5 /* TokenTypes.List */, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validLiteral = isLiteralStart(scnr, context))) { | ||
| token = getToken(context, 6 /* TokenTypes.Literal */, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ... | ||
| token = getToken(context, 12 /* TokenTypes.InvalidPlace */, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 8 /* TokenTypes.LinkedDot */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */ || | ||
| currentType === 9 /* TokenTypes.LinkedDelimiter */) && | ||
| (ch === CHAR_LF || ch === CHAR_SP)) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| switch (ch) { | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| scnr.next(); | ||
| token = getToken(context, 7 /* TokenTypes.LinkedAlias */, "@" /* TokenChars.LinkedAlias */); | ||
| context.inLinked = true; | ||
| return token; | ||
| case "." /* TokenChars.LinkedDot */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8 /* TokenTypes.LinkedDot */, "." /* TokenChars.LinkedDot */); | ||
| case ":" /* TokenChars.LinkedDelimiter */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9 /* TokenTypes.LinkedDelimiter */, ":" /* TokenChars.LinkedDelimiter */); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || | ||
| isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11 /* TokenTypes.LinkedModifier */, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| // scan the placeholder | ||
| return readTokenInPlaceholder(scnr, context) || token; | ||
| } | ||
| else { | ||
| return getToken(context, 10 /* TokenTypes.LinkedKey */, readLinkedRefer(scnr)); | ||
| } | ||
| } | ||
| if (currentType === 7 /* TokenTypes.LinkedAlias */) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 /* TokenTypes.EOF */ }; | ||
| if (context.braceNest > 0) { | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| } | ||
| if (context.inLinked) { | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| } | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}" /* TokenChars.BraceRight */: | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: { | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) { | ||
| return getToken(context, 0 /* TokenTypes.Text */, readText(scnr)); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) { | ||
| return getToken(_context, 13 /* TokenTypes.EOF */); | ||
| } | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: "" | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(ctx.startLoc, pos) : null, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| })); | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) token.loc = createLocation(context.startLoc, context.endLoc); | ||
| if (value != null) token.value = value; | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ""; | ||
| while (scnr.currentPeek() === " " || scnr.currentPeek() === "\n") { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc === 95; | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isNumberStart(scnr.currentPeek() === "-" ? scnr.peek() : scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "."; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 || currentType === 11)) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9) return false; | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return isIdentifierStart(scnr.peek()); | ||
| else if (ch === "@" || ch === "|" || ch === ":" || ch === "." || ch === " " || !ch) return false; | ||
| else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } else return isTextStart(scnr, false); | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = "") => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return hasSpace; | ||
| else if (ch === "@" || !ch) return hasSpace; | ||
| else if (ch === "|") return !(prev === " " || prev === "\n"); | ||
| else if (ch === " ") { | ||
| scnr.peek(); | ||
| return fn(true, " "); | ||
| } else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(true, "\n"); | ||
| } else return true; | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) return EOF; | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36; | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36 || cc === 45; | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57 || cc >= 65 && cc <= 70 || cc >= 97 && cc <= 102; | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ""; | ||
| let num = ""; | ||
| while (ch = takeDigit(scnr)) num += ch; | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ""; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "\\") { | ||
| const nextCh = scnr.peek(); | ||
| if (nextCh === "{" || nextCh === "}" || nextCh === "@" || nextCh === "|" || nextCh === "\\") { | ||
| buf += ch + nextCh; | ||
| scnr.next(); | ||
| scnr.next(); | ||
| } else { | ||
| scnr.resetPeek(); | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } else if (ch === "{" || ch === "}" || ch === "@" || ch === "|" || !ch) break; | ||
| else if (ch === " " || ch === "\n") if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } else if (isPluralStart(scnr)) break; | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeNamedIdentifierChar(scnr)) name += ch; | ||
| const currentChar = scnr.currentChar(); | ||
| if (currentChar && currentChar !== "}" && currentChar !== EOF && currentChar !== " " && currentChar !== "\n" && currentChar !== " ") { | ||
| const invalidPart = readInvalidIdentifier(scnr); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, name + invalidPart); | ||
| return name + invalidPart; | ||
| } | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ""; | ||
| if (scnr.currentChar() === "-") { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } else value += getDigits(scnr); | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== "\n"; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| eat(scnr, `'`); | ||
| let ch = ""; | ||
| let literal = ""; | ||
| while (ch = takeChar(scnr, isLiteral)) if (ch === "\\") literal += readEscapeSequence(scnr); | ||
| else literal += ch; | ||
| const current = scnr.currentChar(); | ||
| if (current === "\n" || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| if (current === "\n") { | ||
| scnr.next(); | ||
| eat(scnr, `'`); | ||
| } | ||
| return literal; | ||
| } | ||
| eat(scnr, `'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "\\": | ||
| case `'`: | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case "u": return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case "U": return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ""; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return ch !== "{" && ch !== "}" && ch !== " " && ch !== "\n"; | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let identifiers = ""; | ||
| while (ch = takeChar(scnr, isInvalidIdentifier)) identifiers += ch; | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeIdentifierChar(scnr)) name += ch; | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" || ch === "@" || ch === "|" || ch === "(" || ch === ")" || !ch) return buf; | ||
| else if (ch === " ") return buf; | ||
| else if (ch === "\n" || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(""); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|"); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| switch (scnr.currentChar()) { | ||
| case "{": | ||
| if (context.braceNest >= 1) emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 2, "{"); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}": | ||
| if (context.braceNest > 0 && context.currentType === 2) emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 3, "}"); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) context.inLinked = false; | ||
| return token; | ||
| case "@": | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && (context.currentType === 4 || context.currentType === 5 || context.currentType === 6)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if (validNamedIdentifier = isNamedIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 4, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validListIdentifier = isListIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 5, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validLiteral = isLiteralStart(scnr, context)) { | ||
| token = getToken(context, 6, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| token = getToken(context, 12, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 || currentType === 8 || currentType === 11 || currentType === 9) && (ch === "\n" || ch === " ")) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| switch (ch) { | ||
| case "@": | ||
| scnr.next(); | ||
| token = getToken(context, 7, "@"); | ||
| context.inLinked = true; | ||
| return token; | ||
| case ".": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8, "."); | ||
| case ":": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9, ":"); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{") return readTokenInPlaceholder(scnr, context) || token; | ||
| else return getToken(context, 10, readLinkedRefer(scnr)); | ||
| } | ||
| if (currentType === 7) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 }; | ||
| if (context.braceNest > 0) return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| if (context.inLinked) return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| switch (scnr.currentChar()) { | ||
| case "{": return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}": | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3, "}"); | ||
| case "@": return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) return getToken(context, 0, readText(scnr)); | ||
| break; | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) return getToken(_context, 13); | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| } | ||
| const ERROR_DOMAIN = 'parser'; | ||
| // Backslash backslash, backslash quote, uHHHH, UHHHHHH. | ||
| const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/parser.ts | ||
| const ERROR_DOMAIN = "parser"; | ||
| const KNOWN_ESCAPES = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g; | ||
| const TEXT_ESCAPES = /\\([\\@{}|])/g; | ||
| function fromTextEscapeSequence(_match, char) { | ||
| return char; | ||
| } | ||
| function fromEscapeSequence(match, codePoint4, codePoint6) { | ||
| switch (match) { | ||
| case `\\\\`: | ||
| return `\\`; | ||
| // eslint-disable-next-line no-useless-escape | ||
| case `\\\'`: | ||
| // eslint-disable-next-line no-useless-escape | ||
| return `\'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 0xd7ff || codePoint >= 0xe000) { | ||
| return String.fromCodePoint(codePoint); | ||
| } | ||
| // invalid ... | ||
| // Replace them with U+FFFD REPLACEMENT CHARACTER. | ||
| return '�'; | ||
| } | ||
| } | ||
| switch (match) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 55295 || codePoint >= 57344) return String.fromCodePoint(codePoint); | ||
| return "�"; | ||
| } | ||
| } | ||
| } | ||
| function createParser(options = {}) { | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(start, end) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { start: loc, end: loc }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) { | ||
| node.loc.end = pos; | ||
| } | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(5 /* NodeTypes.List */, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(4 /* NodeTypes.Named */, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(9 /* NodeTypes.Literal */, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc | ||
| const node = startNode(8 /* NodeTypes.LinkedModifier */, offset, loc); | ||
| if (token.type !== 11 /* TokenTypes.LinkedModifier */) { | ||
| // empty modifier | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ''; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| // check token | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.value = token.value || ''; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node | ||
| }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7 /* NodeTypes.LinkedKey */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6 /* NodeTypes.Linked */, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8 /* TokenTypes.LinkedDot */) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| // asset check token | ||
| if (token.type !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| token = tokenizer.nextToken(); | ||
| // skip brace left | ||
| if (token.type === 2 /* TokenTypes.BraceLeft */) { | ||
| token = tokenizer.nextToken(); | ||
| } | ||
| switch (token.type) { | ||
| case 10 /* TokenTypes.LinkedKey */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ''); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ''); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseList(tokenizer, token.value || ''); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ''); | ||
| break; | ||
| default: { | ||
| // empty key | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7 /* NodeTypes.LinkedKey */, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ''; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const startOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? tokenizer.currentOffset() | ||
| : context.offset; | ||
| const startLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.endLoc | ||
| : context.startLoc; | ||
| const node = startNode(2 /* NodeTypes.Message */, startOffset, startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0 /* TokenTypes.Text */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseText(tokenizer, token.value || '')); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseList(tokenizer, token.value || '')); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseNamed(tokenizer, token.value || '')); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseLiteral(tokenizer, token.value || '')); | ||
| break; | ||
| case 7 /* TokenTypes.LinkedAlias */: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */ && | ||
| context.currentType !== 1 /* TokenTypes.Pipe */); | ||
| // adjust message node loc | ||
| const endOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastOffset | ||
| : tokenizer.currentOffset(); | ||
| const endLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastEndLoc | ||
| : tokenizer.currentPosition(); | ||
| endNode(node, endOffset, endLoc); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1 /* NodeTypes.Plural */, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) { | ||
| hasEmptyMessage = msg.items.length === 0; | ||
| } | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */); | ||
| if (hasEmptyMessage) { | ||
| emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13 /* TokenTypes.EOF */) { | ||
| return msgNode; | ||
| } | ||
| else { | ||
| return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc); | ||
| if (location && node.loc) { | ||
| node.loc.source = source; | ||
| } | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) { | ||
| node.cacheKey = options.onCacheKey(source); | ||
| } | ||
| // assert whether achieved to EOF | ||
| if (context.currentType !== 13 /* TokenTypes.EOF */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ''); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(start, end) : null, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| })); | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { | ||
| start: loc, | ||
| end: loc | ||
| }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (type) node.type = type; | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) node.loc.end = pos; | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3, context.offset, context.startLoc); | ||
| node.value = value.replace(TEXT_ESCAPES, fromTextEscapeSequence); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(5, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(4, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(9, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; | ||
| const node = startNode(8, offset, loc); | ||
| if (token.type !== 11) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ""; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.value = token.value || ""; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| if (token.type !== 9) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| token = tokenizer.nextToken(); | ||
| if (token.type === 2) token = tokenizer.nextToken(); | ||
| switch (token.type) { | ||
| case 10: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ""); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ""); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseList(tokenizer, token.value || ""); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ""); | ||
| break; | ||
| default: { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ""; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node: linkedNode }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(2, context.currentType === 1 ? tokenizer.currentOffset() : context.offset, context.currentType === 1 ? context.endLoc : context.startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseText(tokenizer, token.value || "")); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseList(tokenizer, token.value || "")); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseNamed(tokenizer, token.value || "")); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseLiteral(tokenizer, token.value || "")); | ||
| break; | ||
| case 7: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 && context.currentType !== 1); | ||
| endNode(node, context.currentType === 1 ? context.lastOffset : tokenizer.currentOffset(), context.currentType === 1 ? context.lastEndLoc : tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) hasEmptyMessage = msg.items.length === 0; | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13); | ||
| if (hasEmptyMessage) emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13) return msgNode; | ||
| else return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0, context.offset, context.startLoc); | ||
| if (location && node.loc) node.loc.source = source; | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) node.cacheKey = options.onCacheKey(source); | ||
| if (context.currentType !== 13) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ""); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| } | ||
| function getTokenCaption(token) { | ||
| if (token.type === 13 /* TokenTypes.EOF */) { | ||
| return 'EOF'; | ||
| } | ||
| const name = (token.value || '').replace(/\r?\n/gu, '\\n'); | ||
| return name.length > 10 ? name.slice(0, 9) + '…' : name; | ||
| if (token.type === 13) return "EOF"; | ||
| const name = (token.value || "").replace(/\r?\n/gu, "\\n"); | ||
| return name.length > 10 ? name.slice(0, 9) + "…" : name; | ||
| } | ||
| function createTransformer(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const _context = { | ||
| ast, | ||
| helpers: new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { context, helper }; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/transformer.ts | ||
| function createTransformer(ast, _options = {}) { | ||
| const _context = { | ||
| ast, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { | ||
| context, | ||
| helper | ||
| }; | ||
| } | ||
| function traverseNodes(nodes, transformer) { | ||
| for (let i = 0; i < nodes.length; i++) { | ||
| traverseNode(nodes[i], transformer); | ||
| } | ||
| for (let i = 0; i < nodes.length; i++) traverseNode(nodes[i], transformer); | ||
| } | ||
| function traverseNode(node, transformer) { | ||
| // TODO: if we need pre-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1 /* NodeTypes.Plural */: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural" /* HelperNameMap.PLURAL */); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| traverseNode(linked.key, transformer); | ||
| transformer.helper("linked" /* HelperNameMap.LINKED */); | ||
| transformer.helper("type" /* HelperNameMap.TYPE */); | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("list" /* HelperNameMap.LIST */); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("named" /* HelperNameMap.NAMED */); | ||
| break; | ||
| } | ||
| // TODO: if we need post-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural"); | ||
| break; | ||
| case 2: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6: | ||
| traverseNode(node.key, transformer); | ||
| transformer.helper("linked"); | ||
| transformer.helper("type"); | ||
| break; | ||
| case 5: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("list"); | ||
| break; | ||
| case 4: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("named"); | ||
| break; | ||
| } | ||
| } | ||
| // transform AST | ||
| function transform(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize" /* HelperNameMap.NORMALIZE */); | ||
| // traverse | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| // set meta information | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| function transform(ast, _options = {}) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize"); | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/compiler.ts | ||
| function baseCompile(source, options = {}) { | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| // parse source codes | ||
| const parser = createParser(assignedOptions); | ||
| const ast = parser.parse(source); | ||
| // TODO: | ||
| // With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible. | ||
| if (!jit) { | ||
| // transform ASTs | ||
| transform(ast, assignedOptions); | ||
| // generate javascript codes | ||
| return generate(ast, assignedOptions); | ||
| } | ||
| else { | ||
| // optimize ASTs | ||
| enableOptimize && optimize(ast); | ||
| // minimize ASTs | ||
| enableMangle && mangle(ast); | ||
| // In JIT mode, no ast transform, no code generation. | ||
| return { ast, code: '' }; | ||
| } | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| const ast = createParser(assignedOptions).parse(source); | ||
| if (!jit) { | ||
| transform(ast, assignedOptions); | ||
| return generate(ast, assignedOptions); | ||
| } else { | ||
| enableOptimize && optimize(ast); | ||
| enableMangle && mangle(ast); | ||
| return { | ||
| ast, | ||
| code: "" | ||
| }; | ||
| } | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; | ||
| //#endregion | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, HelperNameMap, LOCATION_STUB, NodeTypes, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; |
+1242
-1517
@@ -1,1577 +0,1302 @@ | ||
| /*! | ||
| * message-compiler v12.0.0-alpha.3 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * Released under the MIT License. | ||
| */ | ||
| import { format, isString, join, assign } from '@intlify/shared'; | ||
| import { SourceMapGenerator } from 'source-map-js'; | ||
| /** | ||
| * @intlify/message-compiler v12.0.0-alpha.4 | ||
| * (c) 2016-present kazuya kawaguchi and contributors | ||
| * @license MIT | ||
| **/ | ||
| import { assign, format, isString, join } from "@intlify/shared"; | ||
| import { SourceMapGenerator } from "source-map-js"; | ||
| //#region packages/message-compiler/src/nodes.ts | ||
| let NodeTypes = /* @__PURE__ */ function(NodeTypes) { | ||
| NodeTypes[NodeTypes["Resource"] = 0] = "Resource"; | ||
| NodeTypes[NodeTypes["Plural"] = 1] = "Plural"; | ||
| NodeTypes[NodeTypes["Message"] = 2] = "Message"; | ||
| NodeTypes[NodeTypes["Text"] = 3] = "Text"; | ||
| NodeTypes[NodeTypes["Named"] = 4] = "Named"; | ||
| NodeTypes[NodeTypes["List"] = 5] = "List"; | ||
| NodeTypes[NodeTypes["Linked"] = 6] = "Linked"; | ||
| NodeTypes[NodeTypes["LinkedKey"] = 7] = "LinkedKey"; | ||
| NodeTypes[NodeTypes["LinkedModifier"] = 8] = "LinkedModifier"; | ||
| NodeTypes[NodeTypes["Literal"] = 9] = "Literal"; | ||
| return NodeTypes; | ||
| }({}); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/location.ts | ||
| const LOCATION_STUB = { | ||
| start: { line: 1, column: 1, offset: 0 }, | ||
| end: { line: 1, column: 1, offset: 0 } | ||
| start: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| }, | ||
| end: { | ||
| line: 1, | ||
| column: 1, | ||
| offset: 0 | ||
| } | ||
| }; | ||
| function createPosition(line, column, offset) { | ||
| return { line, column, offset }; | ||
| return { | ||
| line, | ||
| column, | ||
| offset | ||
| }; | ||
| } | ||
| function createLocation(start, end, source) { | ||
| const loc = { start, end }; | ||
| if (source != null) { | ||
| loc.source = source; | ||
| } | ||
| return loc; | ||
| const loc = { | ||
| start, | ||
| end | ||
| }; | ||
| if (source != null) loc.source = source; | ||
| return loc; | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/helpers.ts | ||
| let HelperNameMap = /* @__PURE__ */ function(HelperNameMap) { | ||
| HelperNameMap["LIST"] = "list"; | ||
| HelperNameMap["NAMED"] = "named"; | ||
| HelperNameMap["PLURAL"] = "plural"; | ||
| HelperNameMap["LINKED"] = "linked"; | ||
| HelperNameMap["MESSAGE"] = "message"; | ||
| HelperNameMap["TYPE"] = "type"; | ||
| HelperNameMap["INTERPOLATE"] = "interpolate"; | ||
| HelperNameMap["NORMALIZE"] = "normalize"; | ||
| HelperNameMap["VALUES"] = "values"; | ||
| return HelperNameMap; | ||
| }({}); | ||
| const RE_HTML_TAG = /<[\w\s=":;#-/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| //#endregion | ||
| //#region packages/message-compiler/src/errors.ts | ||
| const CompileErrorCodes = { | ||
| // tokenizer error codes | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| // parser error codes | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| // generator error codes | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| // minifier error codes | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| EXPECTED_TOKEN: 1, | ||
| INVALID_TOKEN_IN_PLACEHOLDER: 2, | ||
| UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER: 3, | ||
| UNKNOWN_ESCAPE_SEQUENCE: 4, | ||
| INVALID_UNICODE_ESCAPE_SEQUENCE: 5, | ||
| UNBALANCED_CLOSING_BRACE: 6, | ||
| UNTERMINATED_CLOSING_BRACE: 7, | ||
| EMPTY_PLACEHOLDER: 8, | ||
| NOT_ALLOW_NEST_PLACEHOLDER: 9, | ||
| INVALID_LINKED_FORMAT: 10, | ||
| MUST_HAVE_MESSAGES_IN_PLURAL: 11, | ||
| UNEXPECTED_EMPTY_LINKED_MODIFIER: 12, | ||
| UNEXPECTED_EMPTY_LINKED_KEY: 13, | ||
| UNEXPECTED_LEXICAL_ANALYSIS: 14, | ||
| UNHANDLED_CODEGEN_NODE_TYPE: 15, | ||
| UNHANDLED_MINIFIER_NODE_TYPE: 16 | ||
| }; | ||
| // Special value for higher-order compilers to pick up the last code | ||
| // to avoid collision of error codes. | ||
| // This should always be kept as the last item. | ||
| const COMPILE_ERROR_CODES_EXTEND_POINT = 17; | ||
| /** @internal */ | ||
| const errorMessages = { | ||
| // tokenizer error messages | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| // parser error messages | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| // generator error messages | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| // minimizer error messages | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| [CompileErrorCodes.EXPECTED_TOKEN]: `Expected token: '{0}'`, | ||
| [CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER]: `Invalid token in placeholder: '{0}'`, | ||
| [CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER]: `Unterminated single quote in placeholder`, | ||
| [CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE]: `Unknown escape sequence: \\{0}`, | ||
| [CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE]: `Invalid unicode escape sequence: {0}`, | ||
| [CompileErrorCodes.UNBALANCED_CLOSING_BRACE]: `Unbalanced closing brace`, | ||
| [CompileErrorCodes.UNTERMINATED_CLOSING_BRACE]: `Unterminated closing brace`, | ||
| [CompileErrorCodes.EMPTY_PLACEHOLDER]: `Empty placeholder`, | ||
| [CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER]: `Not allowed nest placeholder`, | ||
| [CompileErrorCodes.INVALID_LINKED_FORMAT]: `Invalid linked format`, | ||
| [CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL]: `Plural must have messages`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER]: `Unexpected empty linked modifier`, | ||
| [CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY]: `Unexpected empty linked key`, | ||
| [CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS]: `Unexpected lexical analysis in token: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE]: `unhandled codegen node type: '{0}'`, | ||
| [CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE]: `unhandled mimifier node type: '{0}'` | ||
| }; | ||
| function createCompileError(code, loc, options = {}) { | ||
| const { domain, messages, args } = options; | ||
| const msg = (process.env.NODE_ENV !== 'production') | ||
| ? format((messages || errorMessages)[code] || '', ...(args || [])) | ||
| : code; | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) { | ||
| error.location = loc; | ||
| } | ||
| error.domain = domain; | ||
| return error; | ||
| const { domain, messages, args } = options; | ||
| const msg = format((messages || errorMessages)[code] || "", ...args || []); | ||
| const error = new SyntaxError(String(msg)); | ||
| error.code = code; | ||
| if (loc) error.location = loc; | ||
| error.domain = domain; | ||
| return error; | ||
| } | ||
| /** @internal */ | ||
| function defaultOnError(error) { | ||
| throw error; | ||
| throw error; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/triple-slash-reference | ||
| /// <reference types="source-map-js" /> | ||
| const ERROR_DOMAIN$3 = 'parser'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/generator.ts | ||
| const ERROR_DOMAIN$3 = "parser"; | ||
| function createCodeGenerator(ast, options) { | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: '', | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: undefined, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) { | ||
| _context.source = ast.loc.source; | ||
| } | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| if (_context.map) { | ||
| if (node && node.loc && node.loc !== LOCATION_STUB) { | ||
| addMapping(node.loc.start, getMappingName(node)); | ||
| } | ||
| advancePositionWithSource(_context, code); | ||
| } | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ''; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| function addMapping(loc, name) { | ||
| _context.map.addMapping({ | ||
| name, | ||
| source: _context.filename, | ||
| original: { | ||
| line: loc.line, | ||
| column: loc.column - 1 | ||
| }, | ||
| generated: { | ||
| line: _context.line, | ||
| column: _context.column - 1 | ||
| } | ||
| }); | ||
| } | ||
| if (location && sourceMap) { | ||
| _context.map = new SourceMapGenerator(); | ||
| _context.map.setSourceContent(filename, _context.source); | ||
| } | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options; | ||
| const location = options.location !== false; | ||
| const _context = { | ||
| filename, | ||
| code: "", | ||
| column: 1, | ||
| line: 1, | ||
| offset: 0, | ||
| map: void 0, | ||
| breakLineCode, | ||
| needIndent: _needIndent, | ||
| indentLevel: 0 | ||
| }; | ||
| if (location && ast.loc) _context.source = ast.loc.source; | ||
| const context = () => _context; | ||
| function push(code, node) { | ||
| _context.code += code; | ||
| if (_context.map) { | ||
| if (node && node.loc && node.loc !== LOCATION_STUB) addMapping(node.loc.start, getMappingName(node)); | ||
| advancePositionWithSource(_context, code); | ||
| } | ||
| } | ||
| function _newline(n, withBreakLine = true) { | ||
| const _breakLineCode = withBreakLine ? breakLineCode : ""; | ||
| push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode); | ||
| } | ||
| function indent(withNewLine = true) { | ||
| const level = ++_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function deindent(withNewLine = true) { | ||
| const level = --_context.indentLevel; | ||
| withNewLine && _newline(level); | ||
| } | ||
| function newline() { | ||
| _newline(_context.indentLevel); | ||
| } | ||
| const helper = (key) => `_${key}`; | ||
| const needIndent = () => _context.needIndent; | ||
| function addMapping(loc, name) { | ||
| _context.map.addMapping({ | ||
| name, | ||
| source: _context.filename, | ||
| original: { | ||
| line: loc.line, | ||
| column: loc.column - 1 | ||
| }, | ||
| generated: { | ||
| line: _context.line, | ||
| column: _context.column - 1 | ||
| } | ||
| }); | ||
| } | ||
| if (location && sourceMap) { | ||
| _context.map = new SourceMapGenerator(); | ||
| _context.map.setSourceContent(filename, _context.source); | ||
| } | ||
| return { | ||
| context, | ||
| push, | ||
| indent, | ||
| deindent, | ||
| newline, | ||
| helper, | ||
| needIndent | ||
| }; | ||
| } | ||
| function generateLinkedNode(generator, node) { | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked" /* HelperNameMap.LINKED */)}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } | ||
| else { | ||
| generator.push(`, undefined, _type`); | ||
| } | ||
| generator.push(`)`); | ||
| const { helper } = generator; | ||
| generator.push(`${helper("linked")}(`); | ||
| generateNode(generator, node.key); | ||
| if (node.modifier) { | ||
| generator.push(`, `); | ||
| generateNode(generator, node.modifier); | ||
| generator.push(`, _type`); | ||
| } else generator.push(`, undefined, _type`); | ||
| generator.push(`)`); | ||
| } | ||
| function generateMessageNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize" /* HelperNameMap.NORMALIZE */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push('])'); | ||
| const { helper, needIndent } = generator; | ||
| generator.push(`${helper("normalize")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.items.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.items[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push("])"); | ||
| } | ||
| function generatePluralNode(generator, node) { | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural" /* HelperNameMap.PLURAL */)}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) { | ||
| break; | ||
| } | ||
| generator.push(', '); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| const { helper, needIndent } = generator; | ||
| if (node.cases.length > 1) { | ||
| generator.push(`${helper("plural")}([`); | ||
| generator.indent(needIndent()); | ||
| const length = node.cases.length; | ||
| for (let i = 0; i < length; i++) { | ||
| generateNode(generator, node.cases[i]); | ||
| if (i === length - 1) break; | ||
| generator.push(", "); | ||
| } | ||
| generator.deindent(needIndent()); | ||
| generator.push(`])`); | ||
| } | ||
| } | ||
| function generateResource(generator, node) { | ||
| if (node.body) { | ||
| generateNode(generator, node.body); | ||
| } | ||
| else { | ||
| generator.push('null'); | ||
| } | ||
| if (node.body) generateNode(generator, node.body); | ||
| else generator.push("null"); | ||
| } | ||
| function generateNode(generator, node) { | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1 /* NodeTypes.Plural */: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7 /* NodeTypes.LinkedKey */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5 /* NodeTypes.List */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("list" /* HelperNameMap.LIST */)}(${node.index}))`, node); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| generator.push(`${helper("interpolate" /* HelperNameMap.INTERPOLATE */)}(${helper("named" /* HelperNameMap.NAMED */)}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9 /* NodeTypes.Literal */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3 /* NodeTypes.Text */: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: | ||
| if ((process.env.NODE_ENV !== 'production')) { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| const { helper } = generator; | ||
| switch (node.type) { | ||
| case 0: | ||
| generateResource(generator, node); | ||
| break; | ||
| case 1: | ||
| generatePluralNode(generator, node); | ||
| break; | ||
| case 2: | ||
| generateMessageNode(generator, node); | ||
| break; | ||
| case 6: | ||
| generateLinkedNode(generator, node); | ||
| break; | ||
| case 8: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 7: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 5: | ||
| generator.push(`${helper("interpolate")}(${helper("list")}(${node.index}))`, node); | ||
| break; | ||
| case 4: | ||
| generator.push(`${helper("interpolate")}(${helper("named")}(${JSON.stringify(node.key)}))`, node); | ||
| break; | ||
| case 9: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| case 3: | ||
| generator.push(JSON.stringify(node.value), node); | ||
| break; | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_CODEGEN_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$3, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| // generate code from AST | ||
| const generate = (ast, options = {}) => { | ||
| const mode = isString(options.mode) ? options.mode : 'normal'; | ||
| const filename = isString(options.filename) | ||
| ? options.filename | ||
| : 'message.intl'; | ||
| const sourceMap = !!options.sourceMap; | ||
| // prettier-ignore | ||
| const breakLineCode = options.breakLineCode != null | ||
| ? options.breakLineCode | ||
| : mode === 'arrow' | ||
| ? ';' | ||
| : '\n'; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow'; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map(s => `${s}: _${s}`), ', ')} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| }; | ||
| const mode = isString(options.mode) ? options.mode : "normal"; | ||
| const filename = isString(options.filename) ? options.filename : "message.intl"; | ||
| const sourceMap = !!options.sourceMap; | ||
| const breakLineCode = options.breakLineCode != null ? options.breakLineCode : mode === "arrow" ? ";" : "\n"; | ||
| const needIndent = options.needIndent ? options.needIndent : mode !== "arrow"; | ||
| const helpers = ast.helpers || []; | ||
| const generator = createCodeGenerator(ast, { | ||
| mode, | ||
| filename, | ||
| sourceMap, | ||
| breakLineCode, | ||
| needIndent | ||
| }); | ||
| generator.push(mode === "normal" ? `function __msg__ (ctx) {` : `(ctx) => {`); | ||
| generator.indent(needIndent); | ||
| if (helpers.length > 0) { | ||
| generator.push(`const { ${join(helpers.map((s) => `${s}: _${s}`), ", ")} } = ctx`); | ||
| generator.newline(); | ||
| } | ||
| generator.push(`return `); | ||
| generateNode(generator, ast); | ||
| generator.deindent(needIndent); | ||
| generator.push(`}`); | ||
| delete ast.helpers; | ||
| const { code, map } = generator.context(); | ||
| return { | ||
| ast, | ||
| code, | ||
| map: map ? map.toJSON() : void 0 | ||
| }; | ||
| }; | ||
| function getMappingName(node) { | ||
| switch (node.type) { | ||
| case 3 /* NodeTypes.Text */: | ||
| case 9 /* NodeTypes.Literal */: | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| case 7 /* NodeTypes.LinkedKey */: | ||
| return node.value; | ||
| case 5 /* NodeTypes.List */: | ||
| return node.index.toString(); | ||
| case 4 /* NodeTypes.Named */: | ||
| return node.key; | ||
| default: | ||
| return undefined; | ||
| } | ||
| switch (node.type) { | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: return node.value; | ||
| case 5: return node.index.toString(); | ||
| case 4: return node.key; | ||
| default: return; | ||
| } | ||
| } | ||
| function advancePositionWithSource(pos, source, numberOfCharacters = source.length) { | ||
| let linesCount = 0; | ||
| let lastNewLinePos = -1; | ||
| for (let i = 0; i < numberOfCharacters; i++) { | ||
| if (source.charCodeAt(i) === 10 /* newline char code */) { | ||
| linesCount++; | ||
| lastNewLinePos = i; | ||
| } | ||
| } | ||
| pos.offset += numberOfCharacters; | ||
| pos.line += linesCount; | ||
| pos.column = | ||
| lastNewLinePos === -1 | ||
| ? pos.column + numberOfCharacters | ||
| : numberOfCharacters - lastNewLinePos; | ||
| return pos; | ||
| let linesCount = 0; | ||
| let lastNewLinePos = -1; | ||
| for (let i = 0; i < numberOfCharacters; i++) if (source.charCodeAt(i) === 10) { | ||
| linesCount++; | ||
| lastNewLinePos = i; | ||
| } | ||
| pos.offset += numberOfCharacters; | ||
| pos.line += linesCount; | ||
| pos.column = lastNewLinePos === -1 ? pos.column + numberOfCharacters : numberOfCharacters - lastNewLinePos; | ||
| return pos; | ||
| } | ||
| const ERROR_DOMAIN$2 = 'minifier'; | ||
| /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/mangler.ts | ||
| const ERROR_DOMAIN$2 = "minifier"; | ||
| function mangle(node) { | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0 /* NodeTypes.Resource */: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1 /* NodeTypes.Plural */: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) { | ||
| mangle(cases[i]); | ||
| } | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2 /* NodeTypes.Message */: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) { | ||
| mangle(items[i]); | ||
| } | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3 /* NodeTypes.Text */: | ||
| case 9 /* NodeTypes.Literal */: | ||
| case 8 /* NodeTypes.LinkedModifier */: | ||
| case 7 /* NodeTypes.LinkedKey */: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4 /* NodeTypes.Named */: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: | ||
| if ((process.env.NODE_ENV !== 'production')) { | ||
| throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| } | ||
| delete node.type; | ||
| node.t = node.type; | ||
| switch (node.type) { | ||
| case 0: { | ||
| const resource = node; | ||
| mangle(resource.body); | ||
| resource.b = resource.body; | ||
| delete resource.body; | ||
| break; | ||
| } | ||
| case 1: { | ||
| const plural = node; | ||
| const cases = plural.cases; | ||
| for (let i = 0; i < cases.length; i++) mangle(cases[i]); | ||
| plural.c = cases; | ||
| delete plural.cases; | ||
| break; | ||
| } | ||
| case 2: { | ||
| const message = node; | ||
| const items = message.items; | ||
| for (let i = 0; i < items.length; i++) mangle(items[i]); | ||
| message.i = items; | ||
| delete message.items; | ||
| if (message.static) { | ||
| message.s = message.static; | ||
| delete message.static; | ||
| } | ||
| break; | ||
| } | ||
| case 3: | ||
| case 9: | ||
| case 8: | ||
| case 7: { | ||
| const valueNode = node; | ||
| if (valueNode.value) { | ||
| valueNode.v = valueNode.value; | ||
| delete valueNode.value; | ||
| } | ||
| break; | ||
| } | ||
| case 6: { | ||
| const linked = node; | ||
| mangle(linked.key); | ||
| linked.k = linked.key; | ||
| delete linked.key; | ||
| if (linked.modifier) { | ||
| mangle(linked.modifier); | ||
| linked.m = linked.modifier; | ||
| delete linked.modifier; | ||
| } | ||
| break; | ||
| } | ||
| case 5: { | ||
| const list = node; | ||
| list.i = list.index; | ||
| delete list.index; | ||
| break; | ||
| } | ||
| case 4: { | ||
| const named = node; | ||
| named.k = named.key; | ||
| delete named.key; | ||
| break; | ||
| } | ||
| default: throw createCompileError(CompileErrorCodes.UNHANDLED_MINIFIER_NODE_TYPE, null, { | ||
| domain: ERROR_DOMAIN$2, | ||
| args: [node.type] | ||
| }); | ||
| } | ||
| delete node.type; | ||
| } | ||
| /* eslint-enable @typescript-eslint/no-explicit-any */ | ||
| //#endregion | ||
| //#region packages/message-compiler/src/optimizer.ts | ||
| function optimize(ast) { | ||
| const body = ast.body; | ||
| if (body.type === 2 /* NodeTypes.Message */) { | ||
| optimizeMessageNode(body); | ||
| } | ||
| else { | ||
| body.cases.forEach(c => optimizeMessageNode(c)); | ||
| } | ||
| return ast; | ||
| const body = ast.body; | ||
| if (body.type === 2) optimizeMessageNode(body); | ||
| else body.cases.forEach((c) => optimizeMessageNode(c)); | ||
| return ast; | ||
| } | ||
| function optimizeMessageNode(message) { | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| message.static = item.value; | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */)) { | ||
| break; | ||
| } | ||
| if (item.value == null) { | ||
| break; | ||
| } | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 /* NodeTypes.Text */ || item.type === 9 /* NodeTypes.Literal */) { | ||
| delete item.value; // optimization for size | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (message.items.length === 1) { | ||
| const item = message.items[0]; | ||
| if (item.type === 3 || item.type === 9) { | ||
| message.static = item.value; | ||
| delete item.value; | ||
| } | ||
| } else { | ||
| const values = []; | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (!(item.type === 3 || item.type === 9)) break; | ||
| if (item.value == null) break; | ||
| values.push(item.value); | ||
| } | ||
| if (values.length === message.items.length) { | ||
| message.static = join(values); | ||
| for (let i = 0; i < message.items.length; i++) { | ||
| const item = message.items[i]; | ||
| if (item.type === 3 || item.type === 9) delete item.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| const CHAR_SP = ' '; | ||
| const CHAR_CR = '\r'; | ||
| const CHAR_LF = '\n'; | ||
| const CHAR_LS = String.fromCharCode(0x2028); | ||
| const CHAR_PS = String.fromCharCode(0x2029); | ||
| function createScanner(str) { | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF; | ||
| const isLF = (index) => _buf[index] === CHAR_LF; | ||
| const isPS = (index) => _buf[index] === CHAR_PS; | ||
| const isLS = (index) => _buf[index] === CHAR_LS; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) { | ||
| _index++; | ||
| } | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) { | ||
| _peekOffset++; | ||
| } | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) { | ||
| next(); | ||
| } | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| const _buf = str; | ||
| let _index = 0; | ||
| let _line = 1; | ||
| let _column = 1; | ||
| let _peekOffset = 0; | ||
| const isCRLF = (index) => _buf[index] === "\r" && _buf[index + 1] === "\n"; | ||
| const isLF = (index) => _buf[index] === "\n"; | ||
| const isPS = (index) => _buf[index] === "\u2029"; | ||
| const isLS = (index) => _buf[index] === "\u2028"; | ||
| const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index); | ||
| const index = () => _index; | ||
| const line = () => _line; | ||
| const column = () => _column; | ||
| const peekOffset = () => _peekOffset; | ||
| const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? "\n" : _buf[offset]; | ||
| const currentChar = () => charAt(_index); | ||
| const currentPeek = () => charAt(_index + _peekOffset); | ||
| function next() { | ||
| _peekOffset = 0; | ||
| if (isLineEnd(_index)) { | ||
| _line++; | ||
| _column = 0; | ||
| } | ||
| if (isCRLF(_index)) _index++; | ||
| _index++; | ||
| _column++; | ||
| return _buf[_index]; | ||
| } | ||
| function peek() { | ||
| if (isCRLF(_index + _peekOffset)) _peekOffset++; | ||
| _peekOffset++; | ||
| return _buf[_index + _peekOffset]; | ||
| } | ||
| function reset() { | ||
| _index = 0; | ||
| _line = 1; | ||
| _column = 1; | ||
| _peekOffset = 0; | ||
| } | ||
| function resetPeek(offset = 0) { | ||
| _peekOffset = offset; | ||
| } | ||
| function skipToPeek() { | ||
| const target = _index + _peekOffset; | ||
| while (target !== _index) next(); | ||
| _peekOffset = 0; | ||
| } | ||
| return { | ||
| index, | ||
| line, | ||
| column, | ||
| peekOffset, | ||
| charAt, | ||
| currentChar, | ||
| currentPeek, | ||
| next, | ||
| peek, | ||
| reset, | ||
| resetPeek, | ||
| skipToPeek | ||
| }; | ||
| } | ||
| const EOF = undefined; | ||
| const DOT = '.'; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/tokenizer.ts | ||
| const EOF = void 0; | ||
| const DOT = "."; | ||
| const LITERAL_DELIMITER = "'"; | ||
| const ERROR_DOMAIN$1 = 'tokenizer'; | ||
| const ERROR_DOMAIN$1 = "tokenizer"; | ||
| function createTokenizer(source, options = {}) { | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13 /* TokenTypes.EOF */, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13 /* TokenTypes.EOF */, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: '' | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(ctx.startLoc, pos) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) { | ||
| token.loc = createLocation(context.startLoc, context.endLoc); | ||
| } | ||
| if (value != null) { | ||
| token.value = value; | ||
| } | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13 /* TokenTypes.EOF */); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ''; | ||
| while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| cc === 95 // _ | ||
| ); | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) { | ||
| return false; | ||
| } | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek(); | ||
| const ret = isNumberStart(ch); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2 /* TokenTypes.BraceLeft */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7 /* TokenTypes.LinkedAlias */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "." /* TokenChars.LinkedDot */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8 /* TokenTypes.LinkedDot */) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */)) { | ||
| return false; | ||
| } | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":" /* TokenChars.LinkedDelimiter */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| return false; | ||
| } | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return isIdentifierStart(scnr.peek()); | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === ":" /* TokenChars.LinkedDelimiter */ || | ||
| ch === "." /* TokenChars.LinkedDot */ || | ||
| ch === CHAR_SP || | ||
| !ch) { | ||
| return false; | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } | ||
| else { | ||
| // other characters | ||
| return isTextStart(scnr, false); | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|" /* TokenChars.Pipe */; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = '') => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "@" /* TokenChars.LinkedAlias */ || !ch) { | ||
| return hasSpace; | ||
| } | ||
| else if (ch === "|" /* TokenChars.Pipe */) { | ||
| return !(prev === CHAR_SP || prev === CHAR_LF); | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_SP); | ||
| } | ||
| else if (ch === CHAR_LF) { | ||
| scnr.peek(); | ||
| return fn(true, CHAR_LF); | ||
| } | ||
| else { | ||
| return true; | ||
| } | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) { | ||
| return EOF; | ||
| } | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 // $ | ||
| ); | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 97 && cc <= 122) || // a-z | ||
| (cc >= 65 && cc <= 90) || // A-Z | ||
| (cc >= 48 && cc <= 57) || // 0-9 | ||
| cc === 95 || // _ | ||
| cc === 36 || // $ | ||
| cc === 45 // - | ||
| ); | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; // 0-9 | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return ((cc >= 48 && cc <= 57) || // 0-9 | ||
| (cc >= 65 && cc <= 70) || // A-F | ||
| (cc >= 97 && cc <= 102)); // a-f | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ''; | ||
| let num = ''; | ||
| while ((ch = takeDigit(scnr))) { | ||
| num += ch; | ||
| } | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ''; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "}" /* TokenChars.BraceRight */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| !ch) { | ||
| break; | ||
| } | ||
| else if (ch === CHAR_SP || ch === CHAR_LF) { | ||
| if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else if (isPluralStart(scnr)) { | ||
| break; | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeNamedIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ''; | ||
| if (scnr.currentChar() === '-') { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } | ||
| else { | ||
| value += getDigits(scnr); | ||
| } | ||
| if (scnr.currentChar() === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== CHAR_LF; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| let ch = ''; | ||
| let literal = ''; | ||
| while ((ch = takeChar(scnr, isLiteral))) { | ||
| if (ch === '\\') { | ||
| literal += readEscapeSequence(scnr); | ||
| } | ||
| else { | ||
| literal += ch; | ||
| } | ||
| } | ||
| const current = scnr.currentChar(); | ||
| if (current === CHAR_LF || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| // TODO: Is it correct really? | ||
| if (current === CHAR_LF) { | ||
| scnr.next(); | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| } | ||
| return literal; | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| eat(scnr, `\'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case '\\': | ||
| case `\'`: // eslint-disable-line no-useless-escape | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case 'u': | ||
| return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case 'U': | ||
| return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ''; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ''; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return (ch !== "{" /* TokenChars.BraceLeft */ && | ||
| ch !== "}" /* TokenChars.BraceRight */ && | ||
| ch !== CHAR_SP && | ||
| ch !== CHAR_LF); | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ''; | ||
| let identifiers = ''; | ||
| while ((ch = takeChar(scnr, isInvalidIdentifier))) { | ||
| identifiers += ch; | ||
| } | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ''; | ||
| let name = ''; | ||
| while ((ch = takeIdentifierChar(scnr))) { | ||
| name += ch; | ||
| } | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" /* TokenChars.BraceLeft */ || | ||
| ch === "@" /* TokenChars.LinkedAlias */ || | ||
| ch === "|" /* TokenChars.Pipe */ || | ||
| ch === "(" /* TokenChars.ParenLeft */ || | ||
| ch === ")" /* TokenChars.ParenRight */ || | ||
| !ch) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_SP) { | ||
| return buf; | ||
| } | ||
| else if (ch === CHAR_LF || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(''); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|" /* TokenChars.Pipe */); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| if (context.braceNest >= 1) { | ||
| emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 2 /* TokenTypes.BraceLeft */, "{" /* TokenChars.BraceLeft */); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}" /* TokenChars.BraceRight */: | ||
| if (context.braceNest > 0 && | ||
| context.currentType === 2 /* TokenTypes.BraceLeft */) { | ||
| emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| } | ||
| scnr.next(); | ||
| token = getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) { | ||
| context.inLinked = false; | ||
| } | ||
| return token; | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| } | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && | ||
| (context.currentType === 4 /* TokenTypes.Named */ || | ||
| context.currentType === 5 /* TokenTypes.List */ || | ||
| context.currentType === 6 /* TokenTypes.Literal */)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 4 /* TokenTypes.Named */, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validListIdentifier = isListIdentifierStart(scnr, context))) { | ||
| token = getToken(context, 5 /* TokenTypes.List */, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if ((validLiteral = isLiteralStart(scnr, context))) { | ||
| token = getToken(context, 6 /* TokenTypes.Literal */, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ... | ||
| token = getToken(context, 12 /* TokenTypes.InvalidPlace */, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 /* TokenTypes.LinkedAlias */ || | ||
| currentType === 8 /* TokenTypes.LinkedDot */ || | ||
| currentType === 11 /* TokenTypes.LinkedModifier */ || | ||
| currentType === 9 /* TokenTypes.LinkedDelimiter */) && | ||
| (ch === CHAR_LF || ch === CHAR_SP)) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| switch (ch) { | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| scnr.next(); | ||
| token = getToken(context, 7 /* TokenTypes.LinkedAlias */, "@" /* TokenChars.LinkedAlias */); | ||
| context.inLinked = true; | ||
| return token; | ||
| case "." /* TokenChars.LinkedDot */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8 /* TokenTypes.LinkedDot */, "." /* TokenChars.LinkedDot */); | ||
| case ":" /* TokenChars.LinkedDelimiter */: | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9 /* TokenTypes.LinkedDelimiter */, ":" /* TokenChars.LinkedDelimiter */); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || | ||
| isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11 /* TokenTypes.LinkedModifier */, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{" /* TokenChars.BraceLeft */) { | ||
| // scan the placeholder | ||
| return readTokenInPlaceholder(scnr, context) || token; | ||
| } | ||
| else { | ||
| return getToken(context, 10 /* TokenTypes.LinkedKey */, readLinkedRefer(scnr)); | ||
| } | ||
| } | ||
| if (currentType === 7 /* TokenTypes.LinkedAlias */) { | ||
| emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| } | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| // TODO: We need refactoring of token parsing ... | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 /* TokenTypes.EOF */ }; | ||
| if (context.braceNest > 0) { | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| } | ||
| if (context.inLinked) { | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| } | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "{" /* TokenChars.BraceLeft */: | ||
| return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}" /* TokenChars.BraceRight */: | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3 /* TokenTypes.BraceRight */, "}" /* TokenChars.BraceRight */); | ||
| case "@" /* TokenChars.LinkedAlias */: | ||
| return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: { | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1 /* TokenTypes.Pipe */, readPlural(scnr)); | ||
| // reset | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) { | ||
| return getToken(context, 0 /* TokenTypes.Text */, readText(scnr)); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) { | ||
| return getToken(_context, 13 /* TokenTypes.EOF */); | ||
| } | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| const location = options.location !== false; | ||
| const _scnr = createScanner(source); | ||
| const currentOffset = () => _scnr.index(); | ||
| const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index()); | ||
| const _initLoc = currentPosition(); | ||
| const _initOffset = currentOffset(); | ||
| const _context = { | ||
| currentType: 13, | ||
| offset: _initOffset, | ||
| startLoc: _initLoc, | ||
| endLoc: _initLoc, | ||
| lastType: 13, | ||
| lastOffset: _initOffset, | ||
| lastStartLoc: _initLoc, | ||
| lastEndLoc: _initLoc, | ||
| braceNest: 0, | ||
| inLinked: false, | ||
| text: "" | ||
| }; | ||
| const context = () => _context; | ||
| const { onError } = options; | ||
| function emitError(code, pos, offset, ...args) { | ||
| const ctx = context(); | ||
| pos.column += offset; | ||
| pos.offset += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(ctx.startLoc, pos) : null, { | ||
| domain: ERROR_DOMAIN$1, | ||
| args | ||
| })); | ||
| } | ||
| function getToken(context, type, value) { | ||
| context.endLoc = currentPosition(); | ||
| context.currentType = type; | ||
| const token = { type }; | ||
| if (location) token.loc = createLocation(context.startLoc, context.endLoc); | ||
| if (value != null) token.value = value; | ||
| return token; | ||
| } | ||
| const getEndToken = (context) => getToken(context, 13); | ||
| function eat(scnr, ch) { | ||
| if (scnr.currentChar() === ch) { | ||
| scnr.next(); | ||
| return ch; | ||
| } else { | ||
| emitError(CompileErrorCodes.EXPECTED_TOKEN, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function peekSpaces(scnr) { | ||
| let buf = ""; | ||
| while (scnr.currentPeek() === " " || scnr.currentPeek() === "\n") { | ||
| buf += scnr.currentPeek(); | ||
| scnr.peek(); | ||
| } | ||
| return buf; | ||
| } | ||
| function skipSpaces(scnr) { | ||
| const buf = peekSpaces(scnr); | ||
| scnr.skipToPeek(); | ||
| return buf; | ||
| } | ||
| function isIdentifierStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc === 95; | ||
| } | ||
| function isNumberStart(ch) { | ||
| if (ch === EOF) return false; | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function isNamedIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isListIdentifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isNumberStart(scnr.currentPeek() === "-" ? scnr.peek() : scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLiteralStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 2) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === LITERAL_DELIMITER; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDotStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 7) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "."; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedModifierStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 8) return false; | ||
| peekSpaces(scnr); | ||
| const ret = isIdentifierStart(scnr.currentPeek()); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedDelimiterStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (!(currentType === 7 || currentType === 11)) return false; | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === ":"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isLinkedReferStart(scnr, context) { | ||
| const { currentType } = context; | ||
| if (currentType !== 9) return false; | ||
| const fn = () => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return isIdentifierStart(scnr.peek()); | ||
| else if (ch === "@" || ch === "|" || ch === ":" || ch === "." || ch === " " || !ch) return false; | ||
| else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(); | ||
| } else return isTextStart(scnr, false); | ||
| }; | ||
| const ret = fn(); | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isPluralStart(scnr) { | ||
| peekSpaces(scnr); | ||
| const ret = scnr.currentPeek() === "|"; | ||
| scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function isTextStart(scnr, reset = true) { | ||
| const fn = (hasSpace = false, prev = "") => { | ||
| const ch = scnr.currentPeek(); | ||
| if (ch === "{") return hasSpace; | ||
| else if (ch === "@" || !ch) return hasSpace; | ||
| else if (ch === "|") return !(prev === " " || prev === "\n"); | ||
| else if (ch === " ") { | ||
| scnr.peek(); | ||
| return fn(true, " "); | ||
| } else if (ch === "\n") { | ||
| scnr.peek(); | ||
| return fn(true, "\n"); | ||
| } else return true; | ||
| }; | ||
| const ret = fn(); | ||
| reset && scnr.resetPeek(); | ||
| return ret; | ||
| } | ||
| function takeChar(scnr, fn) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === EOF) return EOF; | ||
| if (fn(ch)) { | ||
| scnr.next(); | ||
| return ch; | ||
| } | ||
| return null; | ||
| } | ||
| function isIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36; | ||
| } | ||
| function takeIdentifierChar(scnr) { | ||
| return takeChar(scnr, isIdentifier); | ||
| } | ||
| function isNamedIdentifier(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 97 && cc <= 122 || cc >= 65 && cc <= 90 || cc >= 48 && cc <= 57 || cc === 95 || cc === 36 || cc === 45; | ||
| } | ||
| function takeNamedIdentifierChar(scnr) { | ||
| return takeChar(scnr, isNamedIdentifier); | ||
| } | ||
| function isDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57; | ||
| } | ||
| function takeDigit(scnr) { | ||
| return takeChar(scnr, isDigit); | ||
| } | ||
| function isHexDigit(ch) { | ||
| const cc = ch.charCodeAt(0); | ||
| return cc >= 48 && cc <= 57 || cc >= 65 && cc <= 70 || cc >= 97 && cc <= 102; | ||
| } | ||
| function takeHexDigit(scnr) { | ||
| return takeChar(scnr, isHexDigit); | ||
| } | ||
| function getDigits(scnr) { | ||
| let ch = ""; | ||
| let num = ""; | ||
| while (ch = takeDigit(scnr)) num += ch; | ||
| return num; | ||
| } | ||
| function readText(scnr) { | ||
| let buf = ""; | ||
| while (true) { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "\\") { | ||
| const nextCh = scnr.peek(); | ||
| if (nextCh === "{" || nextCh === "}" || nextCh === "@" || nextCh === "|" || nextCh === "\\") { | ||
| buf += ch + nextCh; | ||
| scnr.next(); | ||
| scnr.next(); | ||
| } else { | ||
| scnr.resetPeek(); | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } else if (ch === "{" || ch === "}" || ch === "@" || ch === "|" || !ch) break; | ||
| else if (ch === " " || ch === "\n") if (isTextStart(scnr)) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } else if (isPluralStart(scnr)) break; | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| } | ||
| } | ||
| return buf; | ||
| } | ||
| function readNamedIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeNamedIdentifierChar(scnr)) name += ch; | ||
| const currentChar = scnr.currentChar(); | ||
| if (currentChar && currentChar !== "}" && currentChar !== EOF && currentChar !== " " && currentChar !== "\n" && currentChar !== " ") { | ||
| const invalidPart = readInvalidIdentifier(scnr); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, name + invalidPart); | ||
| return name + invalidPart; | ||
| } | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return name; | ||
| } | ||
| function readListIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let value = ""; | ||
| if (scnr.currentChar() === "-") { | ||
| scnr.next(); | ||
| value += `-${getDigits(scnr)}`; | ||
| } else value += getDigits(scnr); | ||
| if (scnr.currentChar() === EOF) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| return value; | ||
| } | ||
| function isLiteral(ch) { | ||
| return ch !== LITERAL_DELIMITER && ch !== "\n"; | ||
| } | ||
| function readLiteral(scnr) { | ||
| skipSpaces(scnr); | ||
| eat(scnr, `'`); | ||
| let ch = ""; | ||
| let literal = ""; | ||
| while (ch = takeChar(scnr, isLiteral)) if (ch === "\\") literal += readEscapeSequence(scnr); | ||
| else literal += ch; | ||
| const current = scnr.currentChar(); | ||
| if (current === "\n" || current === EOF) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER, currentPosition(), 0); | ||
| if (current === "\n") { | ||
| scnr.next(); | ||
| eat(scnr, `'`); | ||
| } | ||
| return literal; | ||
| } | ||
| eat(scnr, `'`); | ||
| return literal; | ||
| } | ||
| function readEscapeSequence(scnr) { | ||
| const ch = scnr.currentChar(); | ||
| switch (ch) { | ||
| case "\\": | ||
| case `'`: | ||
| scnr.next(); | ||
| return `\\${ch}`; | ||
| case "u": return readUnicodeEscapeSequence(scnr, ch, 4); | ||
| case "U": return readUnicodeEscapeSequence(scnr, ch, 6); | ||
| default: | ||
| emitError(CompileErrorCodes.UNKNOWN_ESCAPE_SEQUENCE, currentPosition(), 0, ch); | ||
| return ""; | ||
| } | ||
| } | ||
| function readUnicodeEscapeSequence(scnr, unicode, digits) { | ||
| eat(scnr, unicode); | ||
| let sequence = ""; | ||
| for (let i = 0; i < digits; i++) { | ||
| const ch = takeHexDigit(scnr); | ||
| if (!ch) { | ||
| emitError(CompileErrorCodes.INVALID_UNICODE_ESCAPE_SEQUENCE, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`); | ||
| break; | ||
| } | ||
| sequence += ch; | ||
| } | ||
| return `\\${unicode}${sequence}`; | ||
| } | ||
| function isInvalidIdentifier(ch) { | ||
| return ch !== "{" && ch !== "}" && ch !== " " && ch !== "\n"; | ||
| } | ||
| function readInvalidIdentifier(scnr) { | ||
| skipSpaces(scnr); | ||
| let ch = ""; | ||
| let identifiers = ""; | ||
| while (ch = takeChar(scnr, isInvalidIdentifier)) identifiers += ch; | ||
| return identifiers; | ||
| } | ||
| function readLinkedModifier(scnr) { | ||
| let ch = ""; | ||
| let name = ""; | ||
| while (ch = takeIdentifierChar(scnr)) name += ch; | ||
| return name; | ||
| } | ||
| function readLinkedRefer(scnr) { | ||
| const fn = (buf) => { | ||
| const ch = scnr.currentChar(); | ||
| if (ch === "{" || ch === "@" || ch === "|" || ch === "(" || ch === ")" || !ch) return buf; | ||
| else if (ch === " ") return buf; | ||
| else if (ch === "\n" || ch === DOT) { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } else { | ||
| buf += ch; | ||
| scnr.next(); | ||
| return fn(buf); | ||
| } | ||
| }; | ||
| return fn(""); | ||
| } | ||
| function readPlural(scnr) { | ||
| skipSpaces(scnr); | ||
| const plural = eat(scnr, "|"); | ||
| skipSpaces(scnr); | ||
| return plural; | ||
| } | ||
| function readTokenInPlaceholder(scnr, context) { | ||
| let token = null; | ||
| switch (scnr.currentChar()) { | ||
| case "{": | ||
| if (context.braceNest >= 1) emitError(CompileErrorCodes.NOT_ALLOW_NEST_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 2, "{"); | ||
| skipSpaces(scnr); | ||
| context.braceNest++; | ||
| return token; | ||
| case "}": | ||
| if (context.braceNest > 0 && context.currentType === 2) emitError(CompileErrorCodes.EMPTY_PLACEHOLDER, currentPosition(), 0); | ||
| scnr.next(); | ||
| token = getToken(context, 3, "}"); | ||
| context.braceNest--; | ||
| context.braceNest > 0 && skipSpaces(scnr); | ||
| if (context.inLinked && context.braceNest === 0) context.inLinked = false; | ||
| return token; | ||
| case "@": | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = readTokenInLinked(scnr, context) || getEndToken(context); | ||
| context.braceNest = 0; | ||
| return token; | ||
| default: { | ||
| let validNamedIdentifier = true; | ||
| let validListIdentifier = true; | ||
| let validLiteral = true; | ||
| if (isPluralStart(scnr)) { | ||
| if (context.braceNest > 0) emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (context.braceNest > 0 && (context.currentType === 4 || context.currentType === 5 || context.currentType === 6)) { | ||
| emitError(CompileErrorCodes.UNTERMINATED_CLOSING_BRACE, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| return readToken(scnr, context); | ||
| } | ||
| if (validNamedIdentifier = isNamedIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 4, readNamedIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validListIdentifier = isListIdentifierStart(scnr, context)) { | ||
| token = getToken(context, 5, readListIdentifier(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (validLiteral = isLiteralStart(scnr, context)) { | ||
| token = getToken(context, 6, readLiteral(scnr)); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| if (!validNamedIdentifier && !validListIdentifier && !validLiteral) { | ||
| token = getToken(context, 12, readInvalidIdentifier(scnr)); | ||
| emitError(CompileErrorCodes.INVALID_TOKEN_IN_PLACEHOLDER, currentPosition(), 0, token.value); | ||
| skipSpaces(scnr); | ||
| return token; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| return token; | ||
| } | ||
| function readTokenInLinked(scnr, context) { | ||
| const { currentType } = context; | ||
| let token = null; | ||
| const ch = scnr.currentChar(); | ||
| if ((currentType === 7 || currentType === 8 || currentType === 11 || currentType === 9) && (ch === "\n" || ch === " ")) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| switch (ch) { | ||
| case "@": | ||
| scnr.next(); | ||
| token = getToken(context, 7, "@"); | ||
| context.inLinked = true; | ||
| return token; | ||
| case ".": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 8, "."); | ||
| case ":": | ||
| skipSpaces(scnr); | ||
| scnr.next(); | ||
| return getToken(context, 9, ":"); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isLinkedDotStart(scnr, context) || isLinkedDelimiterStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return readTokenInLinked(scnr, context); | ||
| } | ||
| if (isLinkedModifierStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| return getToken(context, 11, readLinkedModifier(scnr)); | ||
| } | ||
| if (isLinkedReferStart(scnr, context)) { | ||
| skipSpaces(scnr); | ||
| if (ch === "{") return readTokenInPlaceholder(scnr, context) || token; | ||
| else return getToken(context, 10, readLinkedRefer(scnr)); | ||
| } | ||
| if (currentType === 7) emitError(CompileErrorCodes.INVALID_LINKED_FORMAT, currentPosition(), 0); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return readToken(scnr, context); | ||
| } | ||
| } | ||
| function readToken(scnr, context) { | ||
| let token = { type: 13 }; | ||
| if (context.braceNest > 0) return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| if (context.inLinked) return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| switch (scnr.currentChar()) { | ||
| case "{": return readTokenInPlaceholder(scnr, context) || getEndToken(context); | ||
| case "}": | ||
| emitError(CompileErrorCodes.UNBALANCED_CLOSING_BRACE, currentPosition(), 0); | ||
| scnr.next(); | ||
| return getToken(context, 3, "}"); | ||
| case "@": return readTokenInLinked(scnr, context) || getEndToken(context); | ||
| default: | ||
| if (isPluralStart(scnr)) { | ||
| token = getToken(context, 1, readPlural(scnr)); | ||
| context.braceNest = 0; | ||
| context.inLinked = false; | ||
| return token; | ||
| } | ||
| if (isTextStart(scnr)) return getToken(context, 0, readText(scnr)); | ||
| break; | ||
| } | ||
| return token; | ||
| } | ||
| function nextToken() { | ||
| const { currentType, offset, startLoc, endLoc } = _context; | ||
| _context.lastType = currentType; | ||
| _context.lastOffset = offset; | ||
| _context.lastStartLoc = startLoc; | ||
| _context.lastEndLoc = endLoc; | ||
| _context.offset = currentOffset(); | ||
| _context.startLoc = currentPosition(); | ||
| if (_scnr.currentChar() === EOF) return getToken(_context, 13); | ||
| return readToken(_scnr, _context); | ||
| } | ||
| return { | ||
| nextToken, | ||
| currentOffset, | ||
| currentPosition, | ||
| context | ||
| }; | ||
| } | ||
| const ERROR_DOMAIN = 'parser'; | ||
| // Backslash backslash, backslash quote, uHHHH, UHHHHHH. | ||
| const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/parser.ts | ||
| const ERROR_DOMAIN = "parser"; | ||
| const KNOWN_ESCAPES = /\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6})/g; | ||
| const TEXT_ESCAPES = /\\([\\@{}|])/g; | ||
| function fromTextEscapeSequence(_match, char) { | ||
| return char; | ||
| } | ||
| function fromEscapeSequence(match, codePoint4, codePoint6) { | ||
| switch (match) { | ||
| case `\\\\`: | ||
| return `\\`; | ||
| // eslint-disable-next-line no-useless-escape | ||
| case `\\\'`: | ||
| // eslint-disable-next-line no-useless-escape | ||
| return `\'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 0xd7ff || codePoint >= 0xe000) { | ||
| return String.fromCodePoint(codePoint); | ||
| } | ||
| // invalid ... | ||
| // Replace them with U+FFFD REPLACEMENT CHARACTER. | ||
| return '�'; | ||
| } | ||
| } | ||
| switch (match) { | ||
| case `\\\\`: return `\\`; | ||
| case `\\'`: return `'`; | ||
| default: { | ||
| const codePoint = parseInt(codePoint4 || codePoint6, 16); | ||
| if (codePoint <= 55295 || codePoint >= 57344) return String.fromCodePoint(codePoint); | ||
| return "�"; | ||
| } | ||
| } | ||
| } | ||
| function createParser(options = {}) { | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) { | ||
| const loc = location ? createLocation(start, end) : null; | ||
| const err = createCompileError(code, loc, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| }); | ||
| onError(err); | ||
| } | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { start: loc, end: loc }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) { | ||
| node.loc.end = pos; | ||
| } | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(5 /* NodeTypes.List */, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(4 /* NodeTypes.Named */, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc | ||
| const node = startNode(9 /* NodeTypes.Literal */, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); // skip brach right | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc | ||
| const node = startNode(8 /* NodeTypes.LinkedModifier */, offset, loc); | ||
| if (token.type !== 11 /* TokenTypes.LinkedModifier */) { | ||
| // empty modifier | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ''; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| // check token | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.value = token.value || ''; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node | ||
| }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7 /* NodeTypes.LinkedKey */, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6 /* NodeTypes.Linked */, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8 /* TokenTypes.LinkedDot */) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| // asset check token | ||
| if (token.type !== 9 /* TokenTypes.LinkedDelimiter */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| token = tokenizer.nextToken(); | ||
| // skip brace left | ||
| if (token.type === 2 /* TokenTypes.BraceLeft */) { | ||
| token = tokenizer.nextToken(); | ||
| } | ||
| switch (token.type) { | ||
| case 10 /* TokenTypes.LinkedKey */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ''); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ''); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseList(tokenizer, token.value || ''); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ''); | ||
| break; | ||
| default: { | ||
| // empty key | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7 /* NodeTypes.LinkedKey */, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ''; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const startOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? tokenizer.currentOffset() | ||
| : context.offset; | ||
| const startLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.endLoc | ||
| : context.startLoc; | ||
| const node = startNode(2 /* NodeTypes.Message */, startOffset, startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0 /* TokenTypes.Text */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseText(tokenizer, token.value || '')); | ||
| break; | ||
| case 5 /* TokenTypes.List */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseList(tokenizer, token.value || '')); | ||
| break; | ||
| case 4 /* TokenTypes.Named */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseNamed(tokenizer, token.value || '')); | ||
| break; | ||
| case 6 /* TokenTypes.Literal */: | ||
| if (token.value == null) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| } | ||
| node.items.push(parseLiteral(tokenizer, token.value || '')); | ||
| break; | ||
| case 7 /* TokenTypes.LinkedAlias */: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */ && | ||
| context.currentType !== 1 /* TokenTypes.Pipe */); | ||
| // adjust message node loc | ||
| const endOffset = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastOffset | ||
| : tokenizer.currentOffset(); | ||
| const endLoc = context.currentType === 1 /* TokenTypes.Pipe */ | ||
| ? context.lastEndLoc | ||
| : tokenizer.currentPosition(); | ||
| endNode(node, endOffset, endLoc); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1 /* NodeTypes.Plural */, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) { | ||
| hasEmptyMessage = msg.items.length === 0; | ||
| } | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13 /* TokenTypes.EOF */); | ||
| if (hasEmptyMessage) { | ||
| emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13 /* TokenTypes.EOF */) { | ||
| return msgNode; | ||
| } | ||
| else { | ||
| return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0 /* NodeTypes.Resource */, context.offset, context.startLoc); | ||
| if (location && node.loc) { | ||
| node.loc.source = source; | ||
| } | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) { | ||
| node.cacheKey = options.onCacheKey(source); | ||
| } | ||
| // assert whether achieved to EOF | ||
| if (context.currentType !== 13 /* TokenTypes.EOF */) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ''); | ||
| } | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| const location = options.location !== false; | ||
| const { onError } = options; | ||
| function emitError(tokenzer, code, start, offset, ...args) { | ||
| const end = tokenzer.currentPosition(); | ||
| end.offset += offset; | ||
| end.column += offset; | ||
| if (onError) onError(createCompileError(code, location ? createLocation(start, end) : null, { | ||
| domain: ERROR_DOMAIN, | ||
| args | ||
| })); | ||
| } | ||
| function startNode(type, offset, loc) { | ||
| const node = { type }; | ||
| if (location) { | ||
| node.start = offset; | ||
| node.end = offset; | ||
| node.loc = { | ||
| start: loc, | ||
| end: loc | ||
| }; | ||
| } | ||
| return node; | ||
| } | ||
| function endNode(node, offset, pos, type) { | ||
| if (type) node.type = type; | ||
| if (location) { | ||
| node.end = offset; | ||
| if (node.loc) node.loc.end = pos; | ||
| } | ||
| } | ||
| function parseText(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(3, context.offset, context.startLoc); | ||
| node.value = value.replace(TEXT_ESCAPES, fromTextEscapeSequence); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseList(tokenizer, index) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(5, offset, loc); | ||
| node.index = parseInt(index, 10); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseNamed(tokenizer, key) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(4, offset, loc); | ||
| node.key = key; | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLiteral(tokenizer, value) { | ||
| const { lastOffset: offset, lastStartLoc: loc } = tokenizer.context(); | ||
| const node = startNode(9, offset, loc); | ||
| node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence); | ||
| tokenizer.nextToken(); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinkedModifier(tokenizer) { | ||
| const token = tokenizer.nextToken(); | ||
| const context = tokenizer.context(); | ||
| const { lastOffset: offset, lastStartLoc: loc } = context; | ||
| const node = startNode(8, offset, loc); | ||
| if (token.type !== 11) { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_MODIFIER, context.lastStartLoc, 0); | ||
| node.value = ""; | ||
| endNode(node, offset, loc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node | ||
| }; | ||
| } | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.value = token.value || ""; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node }; | ||
| } | ||
| function parseLinkedKey(tokenizer, value) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(7, context.offset, context.startLoc); | ||
| node.value = value; | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseLinked(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const linkedNode = startNode(6, context.offset, context.startLoc); | ||
| let token = tokenizer.nextToken(); | ||
| if (token.type === 8) { | ||
| const parsed = parseLinkedModifier(tokenizer); | ||
| linkedNode.modifier = parsed.node; | ||
| token = parsed.nextConsumeToken || tokenizer.nextToken(); | ||
| } | ||
| if (token.type !== 9) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| token = tokenizer.nextToken(); | ||
| if (token.type === 2) token = tokenizer.nextToken(); | ||
| switch (token.type) { | ||
| case 10: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLinkedKey(tokenizer, token.value || ""); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseNamed(tokenizer, token.value || ""); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseList(tokenizer, token.value || ""); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| linkedNode.key = parseLiteral(tokenizer, token.value || ""); | ||
| break; | ||
| default: { | ||
| emitError(tokenizer, CompileErrorCodes.UNEXPECTED_EMPTY_LINKED_KEY, context.lastStartLoc, 0); | ||
| const nextContext = tokenizer.context(); | ||
| const emptyLinkedKeyNode = startNode(7, nextContext.offset, nextContext.startLoc); | ||
| emptyLinkedKeyNode.value = ""; | ||
| endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc); | ||
| linkedNode.key = emptyLinkedKeyNode; | ||
| endNode(linkedNode, nextContext.offset, nextContext.startLoc); | ||
| return { | ||
| nextConsumeToken: token, | ||
| node: linkedNode | ||
| }; | ||
| } | ||
| } | ||
| endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return { node: linkedNode }; | ||
| } | ||
| function parseMessage(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const node = startNode(2, context.currentType === 1 ? tokenizer.currentOffset() : context.offset, context.currentType === 1 ? context.endLoc : context.startLoc); | ||
| node.items = []; | ||
| let nextToken = null; | ||
| do { | ||
| const token = nextToken || tokenizer.nextToken(); | ||
| nextToken = null; | ||
| switch (token.type) { | ||
| case 0: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseText(tokenizer, token.value || "")); | ||
| break; | ||
| case 5: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseList(tokenizer, token.value || "")); | ||
| break; | ||
| case 4: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseNamed(tokenizer, token.value || "")); | ||
| break; | ||
| case 6: | ||
| if (token.value == null) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, getTokenCaption(token)); | ||
| node.items.push(parseLiteral(tokenizer, token.value || "")); | ||
| break; | ||
| case 7: { | ||
| const parsed = parseLinked(tokenizer); | ||
| node.items.push(parsed.node); | ||
| nextToken = parsed.nextConsumeToken || null; | ||
| break; | ||
| } | ||
| } | ||
| } while (context.currentType !== 13 && context.currentType !== 1); | ||
| endNode(node, context.currentType === 1 ? context.lastOffset : tokenizer.currentOffset(), context.currentType === 1 ? context.lastEndLoc : tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parsePlural(tokenizer, offset, loc, msgNode) { | ||
| const context = tokenizer.context(); | ||
| let hasEmptyMessage = msgNode.items.length === 0; | ||
| const node = startNode(1, offset, loc); | ||
| node.cases = []; | ||
| node.cases.push(msgNode); | ||
| do { | ||
| const msg = parseMessage(tokenizer); | ||
| if (!hasEmptyMessage) hasEmptyMessage = msg.items.length === 0; | ||
| node.cases.push(msg); | ||
| } while (context.currentType !== 13); | ||
| if (hasEmptyMessage) emitError(tokenizer, CompileErrorCodes.MUST_HAVE_MESSAGES_IN_PLURAL, loc, 0); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| function parseResource(tokenizer) { | ||
| const context = tokenizer.context(); | ||
| const { offset, startLoc } = context; | ||
| const msgNode = parseMessage(tokenizer); | ||
| if (context.currentType === 13) return msgNode; | ||
| else return parsePlural(tokenizer, offset, startLoc, msgNode); | ||
| } | ||
| function parse(source) { | ||
| const tokenizer = createTokenizer(source, assign({}, options)); | ||
| const context = tokenizer.context(); | ||
| const node = startNode(0, context.offset, context.startLoc); | ||
| if (location && node.loc) node.loc.source = source; | ||
| node.body = parseResource(tokenizer); | ||
| if (options.onCacheKey) node.cacheKey = options.onCacheKey(source); | ||
| if (context.currentType !== 13) emitError(tokenizer, CompileErrorCodes.UNEXPECTED_LEXICAL_ANALYSIS, context.lastStartLoc, 0, source[context.offset] || ""); | ||
| endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition()); | ||
| return node; | ||
| } | ||
| return { parse }; | ||
| } | ||
| function getTokenCaption(token) { | ||
| if (token.type === 13 /* TokenTypes.EOF */) { | ||
| return 'EOF'; | ||
| } | ||
| const name = (token.value || '').replace(/\r?\n/gu, '\\n'); | ||
| return name.length > 10 ? name.slice(0, 9) + '…' : name; | ||
| if (token.type === 13) return "EOF"; | ||
| const name = (token.value || "").replace(/\r?\n/gu, "\\n"); | ||
| return name.length > 10 ? name.slice(0, 9) + "…" : name; | ||
| } | ||
| function createTransformer(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const _context = { | ||
| ast, | ||
| helpers: new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { context, helper }; | ||
| //#endregion | ||
| //#region packages/message-compiler/src/transformer.ts | ||
| function createTransformer(ast, _options = {}) { | ||
| const _context = { | ||
| ast, | ||
| helpers: /* @__PURE__ */ new Set() | ||
| }; | ||
| const context = () => _context; | ||
| const helper = (name) => { | ||
| _context.helpers.add(name); | ||
| return name; | ||
| }; | ||
| return { | ||
| context, | ||
| helper | ||
| }; | ||
| } | ||
| function traverseNodes(nodes, transformer) { | ||
| for (let i = 0; i < nodes.length; i++) { | ||
| traverseNode(nodes[i], transformer); | ||
| } | ||
| for (let i = 0; i < nodes.length; i++) traverseNode(nodes[i], transformer); | ||
| } | ||
| function traverseNode(node, transformer) { | ||
| // TODO: if we need pre-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1 /* NodeTypes.Plural */: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural" /* HelperNameMap.PLURAL */); | ||
| break; | ||
| case 2 /* NodeTypes.Message */: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6 /* NodeTypes.Linked */: { | ||
| const linked = node; | ||
| traverseNode(linked.key, transformer); | ||
| transformer.helper("linked" /* HelperNameMap.LINKED */); | ||
| transformer.helper("type" /* HelperNameMap.TYPE */); | ||
| break; | ||
| } | ||
| case 5 /* NodeTypes.List */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("list" /* HelperNameMap.LIST */); | ||
| break; | ||
| case 4 /* NodeTypes.Named */: | ||
| transformer.helper("interpolate" /* HelperNameMap.INTERPOLATE */); | ||
| transformer.helper("named" /* HelperNameMap.NAMED */); | ||
| break; | ||
| } | ||
| // TODO: if we need post-hook of transform, should be implemented to here | ||
| switch (node.type) { | ||
| case 1: | ||
| traverseNodes(node.cases, transformer); | ||
| transformer.helper("plural"); | ||
| break; | ||
| case 2: | ||
| traverseNodes(node.items, transformer); | ||
| break; | ||
| case 6: | ||
| traverseNode(node.key, transformer); | ||
| transformer.helper("linked"); | ||
| transformer.helper("type"); | ||
| break; | ||
| case 5: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("list"); | ||
| break; | ||
| case 4: | ||
| transformer.helper("interpolate"); | ||
| transformer.helper("named"); | ||
| break; | ||
| } | ||
| } | ||
| // transform AST | ||
| function transform(ast, options = {} // eslint-disable-line | ||
| ) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize" /* HelperNameMap.NORMALIZE */); | ||
| // traverse | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| // set meta information | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| function transform(ast, _options = {}) { | ||
| const transformer = createTransformer(ast); | ||
| transformer.helper("normalize"); | ||
| ast.body && traverseNode(ast.body, transformer); | ||
| const context = transformer.context(); | ||
| ast.helpers = Array.from(context.helpers); | ||
| } | ||
| //#endregion | ||
| //#region packages/message-compiler/src/compiler.ts | ||
| function baseCompile(source, options = {}) { | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| // parse source codes | ||
| const parser = createParser(assignedOptions); | ||
| const ast = parser.parse(source); | ||
| // TODO: | ||
| // With the introduction of Jit compilation, code generation is no longer necessary. This function may no longer be needed since tree-shaking is not possible. | ||
| if (!jit) { | ||
| // transform ASTs | ||
| transform(ast, assignedOptions); | ||
| // generate javascript codes | ||
| return generate(ast, assignedOptions); | ||
| } | ||
| else { | ||
| // optimize ASTs | ||
| enableOptimize && optimize(ast); | ||
| // minimize ASTs | ||
| enableMangle && mangle(ast); | ||
| // In JIT mode, no ast transform, no code generation. | ||
| return { ast, code: '' }; | ||
| } | ||
| const assignedOptions = assign({}, options); | ||
| const jit = !!assignedOptions.jit; | ||
| const enableMangle = !!assignedOptions.mangle; | ||
| const enableOptimize = assignedOptions.optimize == null ? true : assignedOptions.optimize; | ||
| const ast = createParser(assignedOptions).parse(source); | ||
| if (!jit) { | ||
| transform(ast, assignedOptions); | ||
| return generate(ast, assignedOptions); | ||
| } else { | ||
| enableOptimize && optimize(ast); | ||
| enableMangle && mangle(ast); | ||
| return { | ||
| ast, | ||
| code: "" | ||
| }; | ||
| } | ||
| } | ||
| // eslint-disable-next-line no-useless-escape | ||
| const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/; | ||
| const detectHtmlTag = (source) => RE_HTML_TAG.test(source); | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, LOCATION_STUB, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; | ||
| //#endregion | ||
| export { COMPILE_ERROR_CODES_EXTEND_POINT, CompileErrorCodes, ERROR_DOMAIN, HelperNameMap, LOCATION_STUB, NodeTypes, baseCompile, createCompileError, createLocation, createParser, createPosition, defaultOnError, detectHtmlTag, errorMessages, mangle, optimize }; |
+38
-38
| { | ||
| "name": "@intlify/message-compiler", | ||
| "version": "12.0.0-alpha.3", | ||
| "description": "@intlify/message-compiler", | ||
| "keywords": [ | ||
| "compiler", | ||
| "i18n", | ||
| "internationalization", | ||
| "intlify", | ||
| "message-format" | ||
| ], | ||
| "license": "MIT", | ||
| "version": "12.0.0-alpha.4", | ||
| "author": { | ||
@@ -17,3 +9,7 @@ "name": "kazuya kawaguchi", | ||
| }, | ||
| "homepage": "https://github.com/intlify/vue-i18n/tree/master/packages/message-compiler#readme", | ||
| "license": "MIT", | ||
| "funding": "https://github.com/sponsors/kazupon", | ||
| "bugs": { | ||
| "url": "https://github.com/intlify/vue-i18n/issues" | ||
| }, | ||
| "repository": { | ||
@@ -24,5 +20,18 @@ "type": "git", | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/intlify/vue-i18n/issues" | ||
| "keywords": [ | ||
| "compiler", | ||
| "i18n", | ||
| "internationalization", | ||
| "intlify", | ||
| "message-format" | ||
| ], | ||
| "homepage": "https://github.com/intlify/vue-i18n/tree/master/packages/message-compiler#readme", | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "engines": { | ||
| "node": ">= 22" | ||
| }, | ||
| "type": "module", | ||
| "sideEffects": false, | ||
| "files": [ | ||
@@ -34,25 +43,5 @@ "dist" | ||
| "jsdelivr": "dist/message-compiler.global.js", | ||
| "types": "dist/message-compiler.d.ts", | ||
| "dependencies": { | ||
| "source-map-js": "^1.0.2", | ||
| "@intlify/shared": "12.0.0-alpha.3" | ||
| }, | ||
| "engines": { | ||
| "node": ">= 16" | ||
| }, | ||
| "buildOptions": { | ||
| "name": "IntlifyMessageCompiler", | ||
| "formats": [ | ||
| "mjs", | ||
| "mjs-node", | ||
| "browser", | ||
| "global" | ||
| ], | ||
| "enableFullBundleForEsmBrowser": true | ||
| }, | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/message-compiler.d.ts", | ||
| "import": "./dist/message-compiler.js", | ||
| "browser": "./dist/message-compiler.esm-browser.js", | ||
| "node": { | ||
@@ -64,3 +53,5 @@ "import": { | ||
| } | ||
| } | ||
| }, | ||
| "import": "./dist/message-compiler.js", | ||
| "browser": "./dist/message-compiler.esm-browser.js" | ||
| }, | ||
@@ -70,8 +61,17 @@ "./dist/*": "./dist/*", | ||
| }, | ||
| "funding": "https://github.com/sponsors/kazupon", | ||
| "publishConfig": { | ||
| "access": "public" | ||
| "types": "dist/message-compiler.d.ts", | ||
| "dependencies": { | ||
| "source-map-js": "^1.0.2", | ||
| "@intlify/shared": "12.0.0-alpha.4" | ||
| }, | ||
| "sideEffects": false, | ||
| "type": "module" | ||
| "buildOptions": { | ||
| "name": "IntlifyMessageCompiler", | ||
| "formats": [ | ||
| "mjs", | ||
| "mjs-node", | ||
| "browser", | ||
| "global" | ||
| ], | ||
| "enableFullBundleForEsmBrowser": true | ||
| } | ||
| } |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
6913
6.62%2
-33.33%0
-100%222002
-19.87%+ Added
- Removed