message-compiler.cjs.js 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395
  1. /*!
  2. * @intlify/message-compiler v9.1.9
  3. * (c) 2021 kazuya kawaguchi
  4. * Released under the MIT License.
  5. */
  6. 'use strict';
  7. Object.defineProperty(exports, '__esModule', { value: true });
  8. var shared = require('@intlify/shared');
  9. var sourceMap = require('source-map');
  10. /** @internal */
  11. const errorMessages = {
  12. // tokenizer error messages
  13. [0 /* EXPECTED_TOKEN */]: `Expected token: '{0}'`,
  14. [1 /* INVALID_TOKEN_IN_PLACEHOLDER */]: `Invalid token in placeholder: '{0}'`,
  15. [2 /* UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER */]: `Unterminated single quote in placeholder`,
  16. [3 /* UNKNOWN_ESCAPE_SEQUENCE */]: `Unknown escape sequence: \\{0}`,
  17. [4 /* INVALID_UNICODE_ESCAPE_SEQUENCE */]: `Invalid unicode escape sequence: {0}`,
  18. [5 /* UNBALANCED_CLOSING_BRACE */]: `Unbalanced closing brace`,
  19. [6 /* UNTERMINATED_CLOSING_BRACE */]: `Unterminated closing brace`,
  20. [7 /* EMPTY_PLACEHOLDER */]: `Empty placeholder`,
  21. [8 /* NOT_ALLOW_NEST_PLACEHOLDER */]: `Not allowed nest placeholder`,
  22. [9 /* INVALID_LINKED_FORMAT */]: `Invalid linked format`,
  23. // parser error messages
  24. [10 /* MUST_HAVE_MESSAGES_IN_PLURAL */]: `Plural must have messages`,
  25. [11 /* UNEXPECTED_EMPTY_LINKED_MODIFIER */]: `Unexpected empty linked modifier`,
  26. [12 /* UNEXPECTED_EMPTY_LINKED_KEY */]: `Unexpected empty linked key`,
  27. [13 /* UNEXPECTED_LEXICAL_ANALYSIS */]: `Unexpected lexical analysis in token: '{0}'`
  28. };
  29. function createCompileError(code, loc, options = {}) {
  30. const { domain, messages, args } = options;
  31. const msg = shared.format((messages || errorMessages)[code] || '', ...(args || []))
  32. ;
  33. const error = new SyntaxError(String(msg));
  34. error.code = code;
  35. if (loc) {
  36. error.location = loc;
  37. }
  38. error.domain = domain;
  39. return error;
  40. }
  41. /** @internal */
  42. function defaultOnError(error) {
  43. throw error;
  44. }
  45. const LocationStub = {
  46. start: { line: 1, column: 1, offset: 0 },
  47. end: { line: 1, column: 1, offset: 0 }
  48. };
  49. function createPosition(line, column, offset) {
  50. return { line, column, offset };
  51. }
  52. function createLocation(start, end, source) {
  53. const loc = { start, end };
  54. if (source != null) {
  55. loc.source = source;
  56. }
  57. return loc;
  58. }
  59. const CHAR_SP = ' ';
  60. const CHAR_CR = '\r';
  61. const CHAR_LF = '\n';
  62. const CHAR_LS = String.fromCharCode(0x2028);
  63. const CHAR_PS = String.fromCharCode(0x2029);
  64. function createScanner(str) {
  65. const _buf = str;
  66. let _index = 0;
  67. let _line = 1;
  68. let _column = 1;
  69. let _peekOffset = 0;
  70. const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF;
  71. const isLF = (index) => _buf[index] === CHAR_LF;
  72. const isPS = (index) => _buf[index] === CHAR_PS;
  73. const isLS = (index) => _buf[index] === CHAR_LS;
  74. const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
  75. const index = () => _index;
  76. const line = () => _line;
  77. const column = () => _column;
  78. const peekOffset = () => _peekOffset;
  79. const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
  80. const currentChar = () => charAt(_index);
  81. const currentPeek = () => charAt(_index + _peekOffset);
  82. function next() {
  83. _peekOffset = 0;
  84. if (isLineEnd(_index)) {
  85. _line++;
  86. _column = 0;
  87. }
  88. if (isCRLF(_index)) {
  89. _index++;
  90. }
  91. _index++;
  92. _column++;
  93. return _buf[_index];
  94. }
  95. function peek() {
  96. if (isCRLF(_index + _peekOffset)) {
  97. _peekOffset++;
  98. }
  99. _peekOffset++;
  100. return _buf[_index + _peekOffset];
  101. }
  102. function reset() {
  103. _index = 0;
  104. _line = 1;
  105. _column = 1;
  106. _peekOffset = 0;
  107. }
  108. function resetPeek(offset = 0) {
  109. _peekOffset = offset;
  110. }
  111. function skipToPeek() {
  112. const target = _index + _peekOffset;
  113. // eslint-disable-next-line no-unmodified-loop-condition
  114. while (target !== _index) {
  115. next();
  116. }
  117. _peekOffset = 0;
  118. }
  119. return {
  120. index,
  121. line,
  122. column,
  123. peekOffset,
  124. charAt,
  125. currentChar,
  126. currentPeek,
  127. next,
  128. peek,
  129. reset,
  130. resetPeek,
  131. skipToPeek
  132. };
  133. }
  134. const EOF = undefined;
  135. const LITERAL_DELIMITER = "'";
  136. const ERROR_DOMAIN$1 = 'tokenizer';
  137. function createTokenizer(source, options = {}) {
  138. const location = options.location !== false;
  139. const _scnr = createScanner(source);
  140. const currentOffset = () => _scnr.index();
  141. const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
  142. const _initLoc = currentPosition();
  143. const _initOffset = currentOffset();
  144. const _context = {
  145. currentType: 14 /* EOF */,
  146. offset: _initOffset,
  147. startLoc: _initLoc,
  148. endLoc: _initLoc,
  149. lastType: 14 /* EOF */,
  150. lastOffset: _initOffset,
  151. lastStartLoc: _initLoc,
  152. lastEndLoc: _initLoc,
  153. braceNest: 0,
  154. inLinked: false,
  155. text: ''
  156. };
  157. const context = () => _context;
  158. const { onError } = options;
  159. function emitError(code, pos, offset, ...args) {
  160. const ctx = context();
  161. pos.column += offset;
  162. pos.offset += offset;
  163. if (onError) {
  164. const loc = createLocation(ctx.startLoc, pos);
  165. const err = createCompileError(code, loc, {
  166. domain: ERROR_DOMAIN$1,
  167. args
  168. });
  169. onError(err);
  170. }
  171. }
  172. function getToken(context, type, value) {
  173. context.endLoc = currentPosition();
  174. context.currentType = type;
  175. const token = { type };
  176. if (location) {
  177. token.loc = createLocation(context.startLoc, context.endLoc);
  178. }
  179. if (value != null) {
  180. token.value = value;
  181. }
  182. return token;
  183. }
  184. const getEndToken = (context) => getToken(context, 14 /* EOF */);
  185. function eat(scnr, ch) {
  186. if (scnr.currentChar() === ch) {
  187. scnr.next();
  188. return ch;
  189. }
  190. else {
  191. emitError(0 /* EXPECTED_TOKEN */, currentPosition(), 0, ch);
  192. return '';
  193. }
  194. }
  195. function peekSpaces(scnr) {
  196. let buf = '';
  197. while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) {
  198. buf += scnr.currentPeek();
  199. scnr.peek();
  200. }
  201. return buf;
  202. }
  203. function skipSpaces(scnr) {
  204. const buf = peekSpaces(scnr);
  205. scnr.skipToPeek();
  206. return buf;
  207. }
  208. function isIdentifierStart(ch) {
  209. if (ch === EOF) {
  210. return false;
  211. }
  212. const cc = ch.charCodeAt(0);
  213. return ((cc >= 97 && cc <= 122) || // a-z
  214. (cc >= 65 && cc <= 90) || // A-Z
  215. cc === 95 // _
  216. );
  217. }
  218. function isNumberStart(ch) {
  219. if (ch === EOF) {
  220. return false;
  221. }
  222. const cc = ch.charCodeAt(0);
  223. return cc >= 48 && cc <= 57; // 0-9
  224. }
  225. function isNamedIdentifierStart(scnr, context) {
  226. const { currentType } = context;
  227. if (currentType !== 2 /* BraceLeft */) {
  228. return false;
  229. }
  230. peekSpaces(scnr);
  231. const ret = isIdentifierStart(scnr.currentPeek());
  232. scnr.resetPeek();
  233. return ret;
  234. }
  235. function isListIdentifierStart(scnr, context) {
  236. const { currentType } = context;
  237. if (currentType !== 2 /* BraceLeft */) {
  238. return false;
  239. }
  240. peekSpaces(scnr);
  241. const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek();
  242. const ret = isNumberStart(ch);
  243. scnr.resetPeek();
  244. return ret;
  245. }
  246. function isLiteralStart(scnr, context) {
  247. const { currentType } = context;
  248. if (currentType !== 2 /* BraceLeft */) {
  249. return false;
  250. }
  251. peekSpaces(scnr);
  252. const ret = scnr.currentPeek() === LITERAL_DELIMITER;
  253. scnr.resetPeek();
  254. return ret;
  255. }
  256. function isLinkedDotStart(scnr, context) {
  257. const { currentType } = context;
  258. if (currentType !== 8 /* LinkedAlias */) {
  259. return false;
  260. }
  261. peekSpaces(scnr);
  262. const ret = scnr.currentPeek() === "." /* LinkedDot */;
  263. scnr.resetPeek();
  264. return ret;
  265. }
  266. function isLinkedModifierStart(scnr, context) {
  267. const { currentType } = context;
  268. if (currentType !== 9 /* LinkedDot */) {
  269. return false;
  270. }
  271. peekSpaces(scnr);
  272. const ret = isIdentifierStart(scnr.currentPeek());
  273. scnr.resetPeek();
  274. return ret;
  275. }
  276. function isLinkedDelimiterStart(scnr, context) {
  277. const { currentType } = context;
  278. if (!(currentType === 8 /* LinkedAlias */ ||
  279. currentType === 12 /* LinkedModifier */)) {
  280. return false;
  281. }
  282. peekSpaces(scnr);
  283. const ret = scnr.currentPeek() === ":" /* LinkedDelimiter */;
  284. scnr.resetPeek();
  285. return ret;
  286. }
  287. function isLinkedReferStart(scnr, context) {
  288. const { currentType } = context;
  289. if (currentType !== 10 /* LinkedDelimiter */) {
  290. return false;
  291. }
  292. const fn = () => {
  293. const ch = scnr.currentPeek();
  294. if (ch === "{" /* BraceLeft */) {
  295. return isIdentifierStart(scnr.peek());
  296. }
  297. else if (ch === "@" /* LinkedAlias */ ||
  298. ch === "%" /* Modulo */ ||
  299. ch === "|" /* Pipe */ ||
  300. ch === ":" /* LinkedDelimiter */ ||
  301. ch === "." /* LinkedDot */ ||
  302. ch === CHAR_SP ||
  303. !ch) {
  304. return false;
  305. }
  306. else if (ch === CHAR_LF) {
  307. scnr.peek();
  308. return fn();
  309. }
  310. else {
  311. // other characters
  312. return isIdentifierStart(ch);
  313. }
  314. };
  315. const ret = fn();
  316. scnr.resetPeek();
  317. return ret;
  318. }
  319. function isPluralStart(scnr) {
  320. peekSpaces(scnr);
  321. const ret = scnr.currentPeek() === "|" /* Pipe */;
  322. scnr.resetPeek();
  323. return ret;
  324. }
  325. function isTextStart(scnr, reset = true) {
  326. const fn = (hasSpace = false, prev = '', detectModulo = false) => {
  327. const ch = scnr.currentPeek();
  328. if (ch === "{" /* BraceLeft */) {
  329. return prev === "%" /* Modulo */ ? false : hasSpace;
  330. }
  331. else if (ch === "@" /* LinkedAlias */ || !ch) {
  332. return prev === "%" /* Modulo */ ? true : hasSpace;
  333. }
  334. else if (ch === "%" /* Modulo */) {
  335. scnr.peek();
  336. return fn(hasSpace, "%" /* Modulo */, true);
  337. }
  338. else if (ch === "|" /* Pipe */) {
  339. return prev === "%" /* Modulo */ || detectModulo
  340. ? true
  341. : !(prev === CHAR_SP || prev === CHAR_LF);
  342. }
  343. else if (ch === CHAR_SP) {
  344. scnr.peek();
  345. return fn(true, CHAR_SP, detectModulo);
  346. }
  347. else if (ch === CHAR_LF) {
  348. scnr.peek();
  349. return fn(true, CHAR_LF, detectModulo);
  350. }
  351. else {
  352. return true;
  353. }
  354. };
  355. const ret = fn();
  356. reset && scnr.resetPeek();
  357. return ret;
  358. }
  359. function takeChar(scnr, fn) {
  360. const ch = scnr.currentChar();
  361. if (ch === EOF) {
  362. return EOF;
  363. }
  364. if (fn(ch)) {
  365. scnr.next();
  366. return ch;
  367. }
  368. return null;
  369. }
  370. function takeIdentifierChar(scnr) {
  371. const closure = (ch) => {
  372. const cc = ch.charCodeAt(0);
  373. return ((cc >= 97 && cc <= 122) || // a-z
  374. (cc >= 65 && cc <= 90) || // A-Z
  375. (cc >= 48 && cc <= 57) || // 0-9
  376. cc === 95 || // _
  377. cc === 36 // $
  378. );
  379. };
  380. return takeChar(scnr, closure);
  381. }
  382. function takeDigit(scnr) {
  383. const closure = (ch) => {
  384. const cc = ch.charCodeAt(0);
  385. return cc >= 48 && cc <= 57; // 0-9
  386. };
  387. return takeChar(scnr, closure);
  388. }
  389. function takeHexDigit(scnr) {
  390. const closure = (ch) => {
  391. const cc = ch.charCodeAt(0);
  392. return ((cc >= 48 && cc <= 57) || // 0-9
  393. (cc >= 65 && cc <= 70) || // A-F
  394. (cc >= 97 && cc <= 102)); // a-f
  395. };
  396. return takeChar(scnr, closure);
  397. }
  398. function getDigits(scnr) {
  399. let ch = '';
  400. let num = '';
  401. while ((ch = takeDigit(scnr))) {
  402. num += ch;
  403. }
  404. return num;
  405. }
  406. function readText(scnr) {
  407. let buf = '';
  408. while (true) {
  409. const ch = scnr.currentChar();
  410. if (ch === "{" /* BraceLeft */ ||
  411. ch === "}" /* BraceRight */ ||
  412. ch === "@" /* LinkedAlias */ ||
  413. ch === "|" /* Pipe */ ||
  414. !ch) {
  415. break;
  416. }
  417. else if (ch === "%" /* Modulo */) {
  418. if (isTextStart(scnr)) {
  419. buf += ch;
  420. scnr.next();
  421. }
  422. else {
  423. break;
  424. }
  425. }
  426. else if (ch === CHAR_SP || ch === CHAR_LF) {
  427. if (isTextStart(scnr)) {
  428. buf += ch;
  429. scnr.next();
  430. }
  431. else if (isPluralStart(scnr)) {
  432. break;
  433. }
  434. else {
  435. buf += ch;
  436. scnr.next();
  437. }
  438. }
  439. else {
  440. buf += ch;
  441. scnr.next();
  442. }
  443. }
  444. return buf;
  445. }
  446. function readNamedIdentifier(scnr) {
  447. skipSpaces(scnr);
  448. let ch = '';
  449. let name = '';
  450. while ((ch = takeIdentifierChar(scnr))) {
  451. name += ch;
  452. }
  453. if (scnr.currentChar() === EOF) {
  454. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  455. }
  456. return name;
  457. }
  458. function readListIdentifier(scnr) {
  459. skipSpaces(scnr);
  460. let value = '';
  461. if (scnr.currentChar() === '-') {
  462. scnr.next();
  463. value += `-${getDigits(scnr)}`;
  464. }
  465. else {
  466. value += getDigits(scnr);
  467. }
  468. if (scnr.currentChar() === EOF) {
  469. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  470. }
  471. return value;
  472. }
  473. function readLiteral(scnr) {
  474. skipSpaces(scnr);
  475. eat(scnr, `\'`);
  476. let ch = '';
  477. let literal = '';
  478. const fn = (x) => x !== LITERAL_DELIMITER && x !== CHAR_LF;
  479. while ((ch = takeChar(scnr, fn))) {
  480. if (ch === '\\') {
  481. literal += readEscapeSequence(scnr);
  482. }
  483. else {
  484. literal += ch;
  485. }
  486. }
  487. const current = scnr.currentChar();
  488. if (current === CHAR_LF || current === EOF) {
  489. emitError(2 /* UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER */, currentPosition(), 0);
  490. // TODO: Is it correct really?
  491. if (current === CHAR_LF) {
  492. scnr.next();
  493. eat(scnr, `\'`);
  494. }
  495. return literal;
  496. }
  497. eat(scnr, `\'`);
  498. return literal;
  499. }
  500. function readEscapeSequence(scnr) {
  501. const ch = scnr.currentChar();
  502. switch (ch) {
  503. case '\\':
  504. case `\'`:
  505. scnr.next();
  506. return `\\${ch}`;
  507. case 'u':
  508. return readUnicodeEscapeSequence(scnr, ch, 4);
  509. case 'U':
  510. return readUnicodeEscapeSequence(scnr, ch, 6);
  511. default:
  512. emitError(3 /* UNKNOWN_ESCAPE_SEQUENCE */, currentPosition(), 0, ch);
  513. return '';
  514. }
  515. }
  516. function readUnicodeEscapeSequence(scnr, unicode, digits) {
  517. eat(scnr, unicode);
  518. let sequence = '';
  519. for (let i = 0; i < digits; i++) {
  520. const ch = takeHexDigit(scnr);
  521. if (!ch) {
  522. emitError(4 /* INVALID_UNICODE_ESCAPE_SEQUENCE */, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`);
  523. break;
  524. }
  525. sequence += ch;
  526. }
  527. return `\\${unicode}${sequence}`;
  528. }
  529. function readInvalidIdentifier(scnr) {
  530. skipSpaces(scnr);
  531. let ch = '';
  532. let identifiers = '';
  533. const closure = (ch) => ch !== "{" /* BraceLeft */ &&
  534. ch !== "}" /* BraceRight */ &&
  535. ch !== CHAR_SP &&
  536. ch !== CHAR_LF;
  537. while ((ch = takeChar(scnr, closure))) {
  538. identifiers += ch;
  539. }
  540. return identifiers;
  541. }
  542. function readLinkedModifier(scnr) {
  543. let ch = '';
  544. let name = '';
  545. while ((ch = takeIdentifierChar(scnr))) {
  546. name += ch;
  547. }
  548. return name;
  549. }
  550. function readLinkedRefer(scnr) {
  551. const fn = (detect = false, buf) => {
  552. const ch = scnr.currentChar();
  553. if (ch === "{" /* BraceLeft */ ||
  554. ch === "%" /* Modulo */ ||
  555. ch === "@" /* LinkedAlias */ ||
  556. ch === "|" /* Pipe */ ||
  557. !ch) {
  558. return buf;
  559. }
  560. else if (ch === CHAR_SP) {
  561. return buf;
  562. }
  563. else if (ch === CHAR_LF) {
  564. buf += ch;
  565. scnr.next();
  566. return fn(detect, buf);
  567. }
  568. else {
  569. buf += ch;
  570. scnr.next();
  571. return fn(true, buf);
  572. }
  573. };
  574. return fn(false, '');
  575. }
  576. function readPlural(scnr) {
  577. skipSpaces(scnr);
  578. const plural = eat(scnr, "|" /* Pipe */);
  579. skipSpaces(scnr);
  580. return plural;
  581. }
  582. // TODO: We need refactoring of token parsing ...
  583. function readTokenInPlaceholder(scnr, context) {
  584. let token = null;
  585. const ch = scnr.currentChar();
  586. switch (ch) {
  587. case "{" /* BraceLeft */:
  588. if (context.braceNest >= 1) {
  589. emitError(8 /* NOT_ALLOW_NEST_PLACEHOLDER */, currentPosition(), 0);
  590. }
  591. scnr.next();
  592. token = getToken(context, 2 /* BraceLeft */, "{" /* BraceLeft */);
  593. skipSpaces(scnr);
  594. context.braceNest++;
  595. return token;
  596. case "}" /* BraceRight */:
  597. if (context.braceNest > 0 &&
  598. context.currentType === 2 /* BraceLeft */) {
  599. emitError(7 /* EMPTY_PLACEHOLDER */, currentPosition(), 0);
  600. }
  601. scnr.next();
  602. token = getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
  603. context.braceNest--;
  604. context.braceNest > 0 && skipSpaces(scnr);
  605. if (context.inLinked && context.braceNest === 0) {
  606. context.inLinked = false;
  607. }
  608. return token;
  609. case "@" /* LinkedAlias */:
  610. if (context.braceNest > 0) {
  611. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  612. }
  613. token = readTokenInLinked(scnr, context) || getEndToken(context);
  614. context.braceNest = 0;
  615. return token;
  616. default:
  617. let validNamedIdentifier = true;
  618. let validListIdentifier = true;
  619. let validLiteral = true;
  620. if (isPluralStart(scnr)) {
  621. if (context.braceNest > 0) {
  622. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  623. }
  624. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  625. // reset
  626. context.braceNest = 0;
  627. context.inLinked = false;
  628. return token;
  629. }
  630. if (context.braceNest > 0 &&
  631. (context.currentType === 5 /* Named */ ||
  632. context.currentType === 6 /* List */ ||
  633. context.currentType === 7 /* Literal */)) {
  634. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  635. context.braceNest = 0;
  636. return readToken(scnr, context);
  637. }
  638. if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) {
  639. token = getToken(context, 5 /* Named */, readNamedIdentifier(scnr));
  640. skipSpaces(scnr);
  641. return token;
  642. }
  643. if ((validListIdentifier = isListIdentifierStart(scnr, context))) {
  644. token = getToken(context, 6 /* List */, readListIdentifier(scnr));
  645. skipSpaces(scnr);
  646. return token;
  647. }
  648. if ((validLiteral = isLiteralStart(scnr, context))) {
  649. token = getToken(context, 7 /* Literal */, readLiteral(scnr));
  650. skipSpaces(scnr);
  651. return token;
  652. }
  653. if (!validNamedIdentifier && !validListIdentifier && !validLiteral) {
  654. // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ...
  655. token = getToken(context, 13 /* InvalidPlace */, readInvalidIdentifier(scnr));
  656. emitError(1 /* INVALID_TOKEN_IN_PLACEHOLDER */, currentPosition(), 0, token.value);
  657. skipSpaces(scnr);
  658. return token;
  659. }
  660. break;
  661. }
  662. return token;
  663. }
  664. // TODO: We need refactoring of token parsing ...
  665. function readTokenInLinked(scnr, context) {
  666. const { currentType } = context;
  667. let token = null;
  668. const ch = scnr.currentChar();
  669. if ((currentType === 8 /* LinkedAlias */ ||
  670. currentType === 9 /* LinkedDot */ ||
  671. currentType === 12 /* LinkedModifier */ ||
  672. currentType === 10 /* LinkedDelimiter */) &&
  673. (ch === CHAR_LF || ch === CHAR_SP)) {
  674. emitError(9 /* INVALID_LINKED_FORMAT */, currentPosition(), 0);
  675. }
  676. switch (ch) {
  677. case "@" /* LinkedAlias */:
  678. scnr.next();
  679. token = getToken(context, 8 /* LinkedAlias */, "@" /* LinkedAlias */);
  680. context.inLinked = true;
  681. return token;
  682. case "." /* LinkedDot */:
  683. skipSpaces(scnr);
  684. scnr.next();
  685. return getToken(context, 9 /* LinkedDot */, "." /* LinkedDot */);
  686. case ":" /* LinkedDelimiter */:
  687. skipSpaces(scnr);
  688. scnr.next();
  689. return getToken(context, 10 /* LinkedDelimiter */, ":" /* LinkedDelimiter */);
  690. default:
  691. if (isPluralStart(scnr)) {
  692. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  693. // reset
  694. context.braceNest = 0;
  695. context.inLinked = false;
  696. return token;
  697. }
  698. if (isLinkedDotStart(scnr, context) ||
  699. isLinkedDelimiterStart(scnr, context)) {
  700. skipSpaces(scnr);
  701. return readTokenInLinked(scnr, context);
  702. }
  703. if (isLinkedModifierStart(scnr, context)) {
  704. skipSpaces(scnr);
  705. return getToken(context, 12 /* LinkedModifier */, readLinkedModifier(scnr));
  706. }
  707. if (isLinkedReferStart(scnr, context)) {
  708. skipSpaces(scnr);
  709. if (ch === "{" /* BraceLeft */) {
  710. // scan the placeholder
  711. return readTokenInPlaceholder(scnr, context) || token;
  712. }
  713. else {
  714. return getToken(context, 11 /* LinkedKey */, readLinkedRefer(scnr));
  715. }
  716. }
  717. if (currentType === 8 /* LinkedAlias */) {
  718. emitError(9 /* INVALID_LINKED_FORMAT */, currentPosition(), 0);
  719. }
  720. context.braceNest = 0;
  721. context.inLinked = false;
  722. return readToken(scnr, context);
  723. }
  724. }
  725. // TODO: We need refactoring of token parsing ...
  726. function readToken(scnr, context) {
  727. let token = { type: 14 /* EOF */ };
  728. if (context.braceNest > 0) {
  729. return readTokenInPlaceholder(scnr, context) || getEndToken(context);
  730. }
  731. if (context.inLinked) {
  732. return readTokenInLinked(scnr, context) || getEndToken(context);
  733. }
  734. const ch = scnr.currentChar();
  735. switch (ch) {
  736. case "{" /* BraceLeft */:
  737. return readTokenInPlaceholder(scnr, context) || getEndToken(context);
  738. case "}" /* BraceRight */:
  739. emitError(5 /* UNBALANCED_CLOSING_BRACE */, currentPosition(), 0);
  740. scnr.next();
  741. return getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
  742. case "@" /* LinkedAlias */:
  743. return readTokenInLinked(scnr, context) || getEndToken(context);
  744. default:
  745. if (isPluralStart(scnr)) {
  746. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  747. // reset
  748. context.braceNest = 0;
  749. context.inLinked = false;
  750. return token;
  751. }
  752. if (isTextStart(scnr)) {
  753. return getToken(context, 0 /* Text */, readText(scnr));
  754. }
  755. if (ch === "%" /* Modulo */) {
  756. scnr.next();
  757. return getToken(context, 4 /* Modulo */, "%" /* Modulo */);
  758. }
  759. break;
  760. }
  761. return token;
  762. }
  763. function nextToken() {
  764. const { currentType, offset, startLoc, endLoc } = _context;
  765. _context.lastType = currentType;
  766. _context.lastOffset = offset;
  767. _context.lastStartLoc = startLoc;
  768. _context.lastEndLoc = endLoc;
  769. _context.offset = currentOffset();
  770. _context.startLoc = currentPosition();
  771. if (_scnr.currentChar() === EOF) {
  772. return getToken(_context, 14 /* EOF */);
  773. }
  774. return readToken(_scnr, _context);
  775. }
  776. return {
  777. nextToken,
  778. currentOffset,
  779. currentPosition,
  780. context
  781. };
  782. }
  783. const ERROR_DOMAIN = 'parser';
  784. // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
  785. const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
  786. function fromEscapeSequence(match, codePoint4, codePoint6) {
  787. switch (match) {
  788. case `\\\\`:
  789. return `\\`;
  790. case `\\\'`:
  791. return `\'`;
  792. default: {
  793. const codePoint = parseInt(codePoint4 || codePoint6, 16);
  794. if (codePoint <= 0xd7ff || codePoint >= 0xe000) {
  795. return String.fromCodePoint(codePoint);
  796. }
  797. // invalid ...
  798. // Replace them with U+FFFD REPLACEMENT CHARACTER.
  799. return '�';
  800. }
  801. }
  802. }
  803. function createParser(options = {}) {
  804. const location = options.location !== false;
  805. const { onError } = options;
  806. function emitError(tokenzer, code, start, offset, ...args) {
  807. const end = tokenzer.currentPosition();
  808. end.offset += offset;
  809. end.column += offset;
  810. if (onError) {
  811. const loc = createLocation(start, end);
  812. const err = createCompileError(code, loc, {
  813. domain: ERROR_DOMAIN,
  814. args
  815. });
  816. onError(err);
  817. }
  818. }
  819. function startNode(type, offset, loc) {
  820. const node = {
  821. type,
  822. start: offset,
  823. end: offset
  824. };
  825. if (location) {
  826. node.loc = { start: loc, end: loc };
  827. }
  828. return node;
  829. }
  830. function endNode(node, offset, pos, type) {
  831. node.end = offset;
  832. if (type) {
  833. node.type = type;
  834. }
  835. if (location && node.loc) {
  836. node.loc.end = pos;
  837. }
  838. }
  839. function parseText(tokenizer, value) {
  840. const context = tokenizer.context();
  841. const node = startNode(3 /* Text */, context.offset, context.startLoc);
  842. node.value = value;
  843. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  844. return node;
  845. }
  846. function parseList(tokenizer, index) {
  847. const context = tokenizer.context();
  848. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  849. const node = startNode(5 /* List */, offset, loc);
  850. node.index = parseInt(index, 10);
  851. tokenizer.nextToken(); // skip brach right
  852. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  853. return node;
  854. }
  855. function parseNamed(tokenizer, key) {
  856. const context = tokenizer.context();
  857. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  858. const node = startNode(4 /* Named */, offset, loc);
  859. node.key = key;
  860. tokenizer.nextToken(); // skip brach right
  861. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  862. return node;
  863. }
  864. function parseLiteral(tokenizer, value) {
  865. const context = tokenizer.context();
  866. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  867. const node = startNode(9 /* Literal */, offset, loc);
  868. node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence);
  869. tokenizer.nextToken(); // skip brach right
  870. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  871. return node;
  872. }
  873. function parseLinkedModifier(tokenizer) {
  874. const token = tokenizer.nextToken();
  875. const context = tokenizer.context();
  876. const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc
  877. const node = startNode(8 /* LinkedModifier */, offset, loc);
  878. if (token.type !== 12 /* LinkedModifier */) {
  879. // empty modifier
  880. emitError(tokenizer, 11 /* UNEXPECTED_EMPTY_LINKED_MODIFIER */, context.lastStartLoc, 0);
  881. node.value = '';
  882. endNode(node, offset, loc);
  883. return {
  884. nextConsumeToken: token,
  885. node
  886. };
  887. }
  888. // check token
  889. if (token.value == null) {
  890. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  891. }
  892. node.value = token.value || '';
  893. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  894. return {
  895. node
  896. };
  897. }
  898. function parseLinkedKey(tokenizer, value) {
  899. const context = tokenizer.context();
  900. const node = startNode(7 /* LinkedKey */, context.offset, context.startLoc);
  901. node.value = value;
  902. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  903. return node;
  904. }
  905. function parseLinked(tokenizer) {
  906. const context = tokenizer.context();
  907. const linkedNode = startNode(6 /* Linked */, context.offset, context.startLoc);
  908. let token = tokenizer.nextToken();
  909. if (token.type === 9 /* LinkedDot */) {
  910. const parsed = parseLinkedModifier(tokenizer);
  911. linkedNode.modifier = parsed.node;
  912. token = parsed.nextConsumeToken || tokenizer.nextToken();
  913. }
  914. // asset check token
  915. if (token.type !== 10 /* LinkedDelimiter */) {
  916. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  917. }
  918. token = tokenizer.nextToken();
  919. // skip brace left
  920. if (token.type === 2 /* BraceLeft */) {
  921. token = tokenizer.nextToken();
  922. }
  923. switch (token.type) {
  924. case 11 /* LinkedKey */:
  925. if (token.value == null) {
  926. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  927. }
  928. linkedNode.key = parseLinkedKey(tokenizer, token.value || '');
  929. break;
  930. case 5 /* Named */:
  931. if (token.value == null) {
  932. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  933. }
  934. linkedNode.key = parseNamed(tokenizer, token.value || '');
  935. break;
  936. case 6 /* List */:
  937. if (token.value == null) {
  938. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  939. }
  940. linkedNode.key = parseList(tokenizer, token.value || '');
  941. break;
  942. case 7 /* Literal */:
  943. if (token.value == null) {
  944. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  945. }
  946. linkedNode.key = parseLiteral(tokenizer, token.value || '');
  947. break;
  948. default:
  949. // empty key
  950. emitError(tokenizer, 12 /* UNEXPECTED_EMPTY_LINKED_KEY */, context.lastStartLoc, 0);
  951. const nextContext = tokenizer.context();
  952. const emptyLinkedKeyNode = startNode(7 /* LinkedKey */, nextContext.offset, nextContext.startLoc);
  953. emptyLinkedKeyNode.value = '';
  954. endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc);
  955. linkedNode.key = emptyLinkedKeyNode;
  956. endNode(linkedNode, nextContext.offset, nextContext.startLoc);
  957. return {
  958. nextConsumeToken: token,
  959. node: linkedNode
  960. };
  961. }
  962. endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition());
  963. return {
  964. node: linkedNode
  965. };
  966. }
  967. function parseMessage(tokenizer) {
  968. const context = tokenizer.context();
  969. const startOffset = context.currentType === 1 /* Pipe */
  970. ? tokenizer.currentOffset()
  971. : context.offset;
  972. const startLoc = context.currentType === 1 /* Pipe */
  973. ? context.endLoc
  974. : context.startLoc;
  975. const node = startNode(2 /* Message */, startOffset, startLoc);
  976. node.items = [];
  977. let nextToken = null;
  978. do {
  979. const token = nextToken || tokenizer.nextToken();
  980. nextToken = null;
  981. switch (token.type) {
  982. case 0 /* Text */:
  983. if (token.value == null) {
  984. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  985. }
  986. node.items.push(parseText(tokenizer, token.value || ''));
  987. break;
  988. case 6 /* List */:
  989. if (token.value == null) {
  990. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  991. }
  992. node.items.push(parseList(tokenizer, token.value || ''));
  993. break;
  994. case 5 /* Named */:
  995. if (token.value == null) {
  996. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  997. }
  998. node.items.push(parseNamed(tokenizer, token.value || ''));
  999. break;
  1000. case 7 /* Literal */:
  1001. if (token.value == null) {
  1002. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1003. }
  1004. node.items.push(parseLiteral(tokenizer, token.value || ''));
  1005. break;
  1006. case 8 /* LinkedAlias */:
  1007. const parsed = parseLinked(tokenizer);
  1008. node.items.push(parsed.node);
  1009. nextToken = parsed.nextConsumeToken || null;
  1010. break;
  1011. }
  1012. } while (context.currentType !== 14 /* EOF */ &&
  1013. context.currentType !== 1 /* Pipe */);
  1014. // adjust message node loc
  1015. const endOffset = context.currentType === 1 /* Pipe */
  1016. ? context.lastOffset
  1017. : tokenizer.currentOffset();
  1018. const endLoc = context.currentType === 1 /* Pipe */
  1019. ? context.lastEndLoc
  1020. : tokenizer.currentPosition();
  1021. endNode(node, endOffset, endLoc);
  1022. return node;
  1023. }
  1024. function parsePlural(tokenizer, offset, loc, msgNode) {
  1025. const context = tokenizer.context();
  1026. let hasEmptyMessage = msgNode.items.length === 0;
  1027. const node = startNode(1 /* Plural */, offset, loc);
  1028. node.cases = [];
  1029. node.cases.push(msgNode);
  1030. do {
  1031. const msg = parseMessage(tokenizer);
  1032. if (!hasEmptyMessage) {
  1033. hasEmptyMessage = msg.items.length === 0;
  1034. }
  1035. node.cases.push(msg);
  1036. } while (context.currentType !== 14 /* EOF */);
  1037. if (hasEmptyMessage) {
  1038. emitError(tokenizer, 10 /* MUST_HAVE_MESSAGES_IN_PLURAL */, loc, 0);
  1039. }
  1040. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1041. return node;
  1042. }
  1043. function parseResource(tokenizer) {
  1044. const context = tokenizer.context();
  1045. const { offset, startLoc } = context;
  1046. const msgNode = parseMessage(tokenizer);
  1047. if (context.currentType === 14 /* EOF */) {
  1048. return msgNode;
  1049. }
  1050. else {
  1051. return parsePlural(tokenizer, offset, startLoc, msgNode);
  1052. }
  1053. }
  1054. function parse(source) {
  1055. const tokenizer = createTokenizer(source, shared.assign({}, options));
  1056. const context = tokenizer.context();
  1057. const node = startNode(0 /* Resource */, context.offset, context.startLoc);
  1058. if (location && node.loc) {
  1059. node.loc.source = source;
  1060. }
  1061. node.body = parseResource(tokenizer);
  1062. // assert whether achieved to EOF
  1063. if (context.currentType !== 14 /* EOF */) {
  1064. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, source[context.offset] || '');
  1065. }
  1066. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1067. return node;
  1068. }
  1069. return { parse };
  1070. }
  1071. function getTokenCaption(token) {
  1072. if (token.type === 14 /* EOF */) {
  1073. return 'EOF';
  1074. }
  1075. const name = (token.value || '').replace(/\r?\n/gu, '\\n');
  1076. return name.length > 10 ? name.slice(0, 9) + '…' : name;
  1077. }
  1078. function createTransformer(ast, options = {} // eslint-disable-line
  1079. ) {
  1080. const _context = {
  1081. ast,
  1082. helpers: new Set()
  1083. };
  1084. const context = () => _context;
  1085. const helper = (name) => {
  1086. _context.helpers.add(name);
  1087. return name;
  1088. };
  1089. return { context, helper };
  1090. }
  1091. function traverseNodes(nodes, transformer) {
  1092. for (let i = 0; i < nodes.length; i++) {
  1093. traverseNode(nodes[i], transformer);
  1094. }
  1095. }
  1096. function traverseNode(node, transformer) {
  1097. // TODO: if we need pre-hook of transform, should be implemented to here
  1098. switch (node.type) {
  1099. case 1 /* Plural */:
  1100. traverseNodes(node.cases, transformer);
  1101. transformer.helper("plural" /* PLURAL */);
  1102. break;
  1103. case 2 /* Message */:
  1104. traverseNodes(node.items, transformer);
  1105. break;
  1106. case 6 /* Linked */:
  1107. const linked = node;
  1108. traverseNode(linked.key, transformer);
  1109. transformer.helper("linked" /* LINKED */);
  1110. break;
  1111. case 5 /* List */:
  1112. transformer.helper("interpolate" /* INTERPOLATE */);
  1113. transformer.helper("list" /* LIST */);
  1114. break;
  1115. case 4 /* Named */:
  1116. transformer.helper("interpolate" /* INTERPOLATE */);
  1117. transformer.helper("named" /* NAMED */);
  1118. break;
  1119. }
  1120. // TODO: if we need post-hook of transform, should be implemented to here
  1121. }
  1122. // transform AST
  1123. function transform(ast, options = {} // eslint-disable-line
  1124. ) {
  1125. const transformer = createTransformer(ast);
  1126. transformer.helper("normalize" /* NORMALIZE */);
  1127. // traverse
  1128. ast.body && traverseNode(ast.body, transformer);
  1129. // set meta information
  1130. const context = transformer.context();
  1131. ast.helpers = Array.from(context.helpers);
  1132. }
  1133. function createCodeGenerator(ast, options) {
  1134. const { sourceMap: sourceMap$1, filename, breakLineCode, needIndent: _needIndent } = options;
  1135. const _context = {
  1136. source: ast.loc.source,
  1137. filename,
  1138. code: '',
  1139. column: 1,
  1140. line: 1,
  1141. offset: 0,
  1142. map: undefined,
  1143. breakLineCode,
  1144. needIndent: _needIndent,
  1145. indentLevel: 0
  1146. };
  1147. const context = () => _context;
  1148. function push(code, node) {
  1149. _context.code += code;
  1150. if (_context.map) {
  1151. if (node && node.loc && node.loc !== LocationStub) {
  1152. addMapping(node.loc.start, getMappingName(node));
  1153. }
  1154. advancePositionWithSource(_context, code);
  1155. }
  1156. }
  1157. function _newline(n, withBreakLine = true) {
  1158. const _breakLineCode = withBreakLine ? breakLineCode : '';
  1159. push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
  1160. }
  1161. function indent(withNewLine = true) {
  1162. const level = ++_context.indentLevel;
  1163. withNewLine && _newline(level);
  1164. }
  1165. function deindent(withNewLine = true) {
  1166. const level = --_context.indentLevel;
  1167. withNewLine && _newline(level);
  1168. }
  1169. function newline() {
  1170. _newline(_context.indentLevel);
  1171. }
  1172. const helper = (key) => `_${key}`;
  1173. const needIndent = () => _context.needIndent;
  1174. function addMapping(loc, name) {
  1175. _context.map.addMapping({
  1176. name,
  1177. source: _context.filename,
  1178. original: {
  1179. line: loc.line,
  1180. column: loc.column - 1
  1181. },
  1182. generated: {
  1183. line: _context.line,
  1184. column: _context.column - 1
  1185. }
  1186. });
  1187. }
  1188. if (sourceMap$1) {
  1189. _context.map = new sourceMap.SourceMapGenerator();
  1190. _context.map.setSourceContent(filename, _context.source);
  1191. }
  1192. return {
  1193. context,
  1194. push,
  1195. indent,
  1196. deindent,
  1197. newline,
  1198. helper,
  1199. needIndent
  1200. };
  1201. }
  1202. function generateLinkedNode(generator, node) {
  1203. const { helper } = generator;
  1204. generator.push(`${helper("linked" /* LINKED */)}(`);
  1205. generateNode(generator, node.key);
  1206. if (node.modifier) {
  1207. generator.push(`, `);
  1208. generateNode(generator, node.modifier);
  1209. }
  1210. generator.push(`)`);
  1211. }
  1212. function generateMessageNode(generator, node) {
  1213. const { helper, needIndent } = generator;
  1214. generator.push(`${helper("normalize" /* NORMALIZE */)}([`);
  1215. generator.indent(needIndent());
  1216. const length = node.items.length;
  1217. for (let i = 0; i < length; i++) {
  1218. generateNode(generator, node.items[i]);
  1219. if (i === length - 1) {
  1220. break;
  1221. }
  1222. generator.push(', ');
  1223. }
  1224. generator.deindent(needIndent());
  1225. generator.push('])');
  1226. }
  1227. function generatePluralNode(generator, node) {
  1228. const { helper, needIndent } = generator;
  1229. if (node.cases.length > 1) {
  1230. generator.push(`${helper("plural" /* PLURAL */)}([`);
  1231. generator.indent(needIndent());
  1232. const length = node.cases.length;
  1233. for (let i = 0; i < length; i++) {
  1234. generateNode(generator, node.cases[i]);
  1235. if (i === length - 1) {
  1236. break;
  1237. }
  1238. generator.push(', ');
  1239. }
  1240. generator.deindent(needIndent());
  1241. generator.push(`])`);
  1242. }
  1243. }
  1244. function generateResource(generator, node) {
  1245. if (node.body) {
  1246. generateNode(generator, node.body);
  1247. }
  1248. else {
  1249. generator.push('null');
  1250. }
  1251. }
  1252. function generateNode(generator, node) {
  1253. const { helper } = generator;
  1254. switch (node.type) {
  1255. case 0 /* Resource */:
  1256. generateResource(generator, node);
  1257. break;
  1258. case 1 /* Plural */:
  1259. generatePluralNode(generator, node);
  1260. break;
  1261. case 2 /* Message */:
  1262. generateMessageNode(generator, node);
  1263. break;
  1264. case 6 /* Linked */:
  1265. generateLinkedNode(generator, node);
  1266. break;
  1267. case 8 /* LinkedModifier */:
  1268. generator.push(JSON.stringify(node.value), node);
  1269. break;
  1270. case 7 /* LinkedKey */:
  1271. generator.push(JSON.stringify(node.value), node);
  1272. break;
  1273. case 5 /* List */:
  1274. generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("list" /* LIST */)}(${node.index}))`, node);
  1275. break;
  1276. case 4 /* Named */:
  1277. generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("named" /* NAMED */)}(${JSON.stringify(node.key)}))`, node);
  1278. break;
  1279. case 9 /* Literal */:
  1280. generator.push(JSON.stringify(node.value), node);
  1281. break;
  1282. case 3 /* Text */:
  1283. generator.push(JSON.stringify(node.value), node);
  1284. break;
  1285. default:
  1286. {
  1287. throw new Error(`unhandled codegen node type: ${node.type}`);
  1288. }
  1289. }
  1290. }
  1291. // generate code from AST
  1292. const generate = (ast, options = {} // eslint-disable-line
  1293. ) => {
  1294. const mode = shared.isString(options.mode) ? options.mode : 'normal';
  1295. const filename = shared.isString(options.filename)
  1296. ? options.filename
  1297. : 'message.intl';
  1298. const sourceMap = !!options.sourceMap;
  1299. // prettier-ignore
  1300. const breakLineCode = options.breakLineCode != null
  1301. ? options.breakLineCode
  1302. : mode === 'arrow'
  1303. ? ';'
  1304. : '\n';
  1305. const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
  1306. const helpers = ast.helpers || [];
  1307. const generator = createCodeGenerator(ast, {
  1308. mode,
  1309. filename,
  1310. sourceMap,
  1311. breakLineCode,
  1312. needIndent
  1313. });
  1314. generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
  1315. generator.indent(needIndent);
  1316. if (helpers.length > 0) {
  1317. generator.push(`const { ${helpers.map(s => `${s}: _${s}`).join(', ')} } = ctx`);
  1318. generator.newline();
  1319. }
  1320. generator.push(`return `);
  1321. generateNode(generator, ast);
  1322. generator.deindent(needIndent);
  1323. generator.push(`}`);
  1324. const { code, map } = generator.context();
  1325. return {
  1326. ast,
  1327. code,
  1328. map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
  1329. };
  1330. };
  1331. function getMappingName(node) {
  1332. switch (node.type) {
  1333. case 3 /* Text */:
  1334. return node.value;
  1335. case 5 /* List */:
  1336. return node.index.toString();
  1337. case 4 /* Named */:
  1338. return node.key;
  1339. case 9 /* Literal */:
  1340. return node.value;
  1341. case 8 /* LinkedModifier */:
  1342. return node.value;
  1343. case 7 /* LinkedKey */:
  1344. return node.value;
  1345. default:
  1346. return undefined;
  1347. }
  1348. }
  1349. function advancePositionWithSource(pos, source, numberOfCharacters = source.length) {
  1350. let linesCount = 0;
  1351. let lastNewLinePos = -1;
  1352. for (let i = 0; i < numberOfCharacters; i++) {
  1353. if (source.charCodeAt(i) === 10 /* newline char code */) {
  1354. linesCount++;
  1355. lastNewLinePos = i;
  1356. }
  1357. }
  1358. pos.offset += numberOfCharacters;
  1359. pos.line += linesCount;
  1360. pos.column =
  1361. lastNewLinePos === -1
  1362. ? pos.column + numberOfCharacters
  1363. : numberOfCharacters - lastNewLinePos;
  1364. return pos;
  1365. }
  1366. function baseCompile(source, options = {}) {
  1367. const assignedOptions = shared.assign({}, options);
  1368. // parse source codes
  1369. const parser = createParser(assignedOptions);
  1370. const ast = parser.parse(source);
  1371. // transform ASTs
  1372. transform(ast, assignedOptions);
  1373. // generate javascript codes
  1374. return generate(ast, assignedOptions);
  1375. }
  1376. exports.ERROR_DOMAIN = ERROR_DOMAIN;
  1377. exports.LocationStub = LocationStub;
  1378. exports.baseCompile = baseCompile;
  1379. exports.createCompileError = createCompileError;
  1380. exports.createLocation = createLocation;
  1381. exports.createParser = createParser;
  1382. exports.createPosition = createPosition;
  1383. exports.defaultOnError = defaultOnError;
  1384. exports.errorMessages = errorMessages;