@khanacademy/perseus-editor 2.3.7 → 2.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2659 @@
1
+ /* eslint-disable */
2
+
3
+ //
4
+ // NOTE(kevinb): This file was originally part of mhchem.js, but
5
+ // was extracted so that it could be mocked for testing purposes.
6
+ //
7
+
8
+ //
9
+ // This is the main function for handing the \ce and \pu commands.
10
+ // It takes the argument to \ce or \pu and returns the corresponding TeX string.
11
+ //
12
+
13
+ export const chemParse = function (tokens, stateMachine) {
14
+ // Recreate the argument string from KaTeX's array of tokens.
15
+ let str = "";
16
+ let expectedLoc = tokens[tokens.length - 1].loc.start;
17
+ for (let i = tokens.length - 1; i >= 0; i--) {
18
+ if (tokens[i].loc.start > expectedLoc) {
19
+ // context.consumeArgs has eaten a space.
20
+ str += " ";
21
+ expectedLoc = tokens[i].loc.start;
22
+ }
23
+ str += tokens[i].text;
24
+ expectedLoc += tokens[i].text.length;
25
+ }
26
+ const tex = texify.go(mhchemParser.go(str, stateMachine));
27
+ return tex;
28
+ };
29
+
30
+ //
31
+ // Core parser for mhchem syntax (recursive)
32
+ //
33
+ /** @type {MhchemParser} */
34
+ var mhchemParser = {
35
+ //
36
+ // Parses mchem \ce syntax
37
+ //
38
+ // Call like
39
+ // go("H2O");
40
+ //
41
+ go: function (input, stateMachine) {
42
+ if (!input) {
43
+ return [];
44
+ }
45
+ if (stateMachine === undefined) {
46
+ stateMachine = "ce";
47
+ }
48
+ let state = "0";
49
+
50
+ //
51
+ // String buffers for parsing:
52
+ //
53
+ // buffer.a == amount
54
+ // buffer.o == element
55
+ // buffer.b == left-side superscript
56
+ // buffer.p == left-side subscript
57
+ // buffer.q == right-side subscript
58
+ // buffer.d == right-side superscript
59
+ //
60
+ // buffer.r == arrow
61
+ // buffer.rdt == arrow, script above, type
62
+ // buffer.rd == arrow, script above, content
63
+ // buffer.rqt == arrow, script below, type
64
+ // buffer.rq == arrow, script below, content
65
+ //
66
+ // buffer.text_
67
+ // buffer.rm
68
+ // etc.
69
+ //
70
+ // buffer.parenthesisLevel == int, starting at 0
71
+ // buffer.sb == bool, space before
72
+ // buffer.beginsWithBond == bool
73
+ //
74
+ // These letters are also used as state names.
75
+ //
76
+ // Other states:
77
+ // 0 == begin of main part (arrow/operator unlikely)
78
+ // 1 == next entity
79
+ // 2 == next entity (arrow/operator unlikely)
80
+ // 3 == next atom
81
+ // c == macro
82
+ //
83
+ /** @type {Buffer} */
84
+ const buffer = {};
85
+ buffer["parenthesisLevel"] = 0;
86
+
87
+ input = input.replace(/\n/g, " ");
88
+ input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-");
89
+ input = input.replace(/[\u2026]/g, "...");
90
+
91
+ //
92
+ // Looks through mhchemParser.transitions, to execute a matching action
93
+ // (recursive)
94
+ //
95
+ let lastInput;
96
+ let watchdog = 10;
97
+ /** @type {ParserOutput[]} */
98
+ const output = [];
99
+ while (true) {
100
+ if (lastInput !== input) {
101
+ watchdog = 10;
102
+ lastInput = input;
103
+ } else {
104
+ watchdog--;
105
+ }
106
+ //
107
+ // Find actions in transition table
108
+ //
109
+ const machine = mhchemParser.stateMachines[stateMachine];
110
+ const t = machine.transitions[state] || machine.transitions["*"];
111
+ iterateTransitions: for (let i = 0; i < t.length; i++) {
112
+ const matches = mhchemParser.patterns.match_(
113
+ t[i].pattern,
114
+ input,
115
+ );
116
+ if (matches) {
117
+ //
118
+ // Execute actions
119
+ //
120
+ const task = t[i].task;
121
+ for (let iA = 0; iA < task.action_.length; iA++) {
122
+ var o;
123
+ //
124
+ // Find and execute action
125
+ //
126
+ if (machine.actions[task.action_[iA].type_]) {
127
+ o = machine.actions[task.action_[iA].type_](
128
+ buffer,
129
+ matches.match_,
130
+ task.action_[iA].option,
131
+ );
132
+ } else if (
133
+ mhchemParser.actions[task.action_[iA].type_]
134
+ ) {
135
+ o = mhchemParser.actions[task.action_[iA].type_](
136
+ buffer,
137
+ matches.match_,
138
+ task.action_[iA].option,
139
+ );
140
+ } else {
141
+ throw [
142
+ "MhchemBugA",
143
+ "mhchem bug A. Please report. (" +
144
+ task.action_[iA].type_ +
145
+ ")",
146
+ ]; // Trying to use non-existing action
147
+ }
148
+ //
149
+ // Add output
150
+ //
151
+ mhchemParser.concatArray(output, o);
152
+ }
153
+ //
154
+ // Set next state,
155
+ // Shorten input,
156
+ // Continue with next character
157
+ // (= apply only one transition per position)
158
+ //
159
+ state = task.nextState || state;
160
+ if (input.length > 0) {
161
+ if (!task.revisit) {
162
+ input = matches.remainder;
163
+ }
164
+ if (!task.toContinue) {
165
+ break iterateTransitions;
166
+ }
167
+ } else {
168
+ return output;
169
+ }
170
+ }
171
+ }
172
+ //
173
+ // Prevent infinite loop
174
+ //
175
+ if (watchdog <= 0) {
176
+ throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character
177
+ }
178
+ }
179
+ },
180
+ concatArray: function (a, b) {
181
+ if (b) {
182
+ if (Array.isArray(b)) {
183
+ for (let iB = 0; iB < b.length; iB++) {
184
+ a.push(b[iB]);
185
+ }
186
+ } else {
187
+ a.push(b);
188
+ }
189
+ }
190
+ },
191
+
192
+ patterns: {
193
+ //
194
+ // Matching patterns
195
+ // either regexps or function that return null or {match_:"a", remainder:"bc"}
196
+ //
197
+ patterns: {
198
+ // property names must not look like integers ("2") for correct property traversal order, later on
199
+ empty: /^$/,
200
+ else: /^./,
201
+ else2: /^./,
202
+ space: /^\s/,
203
+ "space A": /^\s(?=[A-Z\\$])/,
204
+ space$: /^\s$/,
205
+ "a-z": /^[a-z]/,
206
+ x: /^x/,
207
+ x$: /^x$/,
208
+ i$: /^i$/,
209
+ letters:
210
+ /^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/,
211
+ "\\greek":
212
+ /^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/,
213
+ "one lowercase latin letter $": /^(?:([a-z])(?:$|[^a-zA-Z]))$/,
214
+ "$one lowercase latin letter$ $":
215
+ /^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,
216
+ "one lowercase greek letter $":
217
+ /^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/,
218
+ digits: /^[0-9]+/,
219
+ "-9.,9": /^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,
220
+ "-9.,9 no missing 0": /^[+\-]?[0-9]+(?:[.,][0-9]+)?/,
221
+ "(-)(9.,9)(e)(99)": function (input) {
222
+ const m = input.match(
223
+ /^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/,
224
+ );
225
+ if (m && m[0]) {
226
+ return {
227
+ match_: m.splice(1),
228
+ remainder: input.substr(m[0].length),
229
+ };
230
+ }
231
+ return null;
232
+ },
233
+ "(-)(9)^(-9)": function (input) {
234
+ const m = input.match(
235
+ /^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/,
236
+ );
237
+ if (m && m[0]) {
238
+ return {
239
+ match_: m.splice(1),
240
+ remainder: input.substr(m[0].length),
241
+ };
242
+ }
243
+ return null;
244
+ },
245
+ "state of aggregation $": function (input) {
246
+ // ... or crystal system
247
+ const a = mhchemParser.patterns.findObserveGroups(
248
+ input,
249
+ "",
250
+ /^\([a-z]{1,3}(?=[\),])/,
251
+ ")",
252
+ "",
253
+ ); // (aq), (aq,$\infty$), (aq, sat)
254
+ if (a && a.remainder.match(/^($|[\s,;\)\]\}])/)) {
255
+ return a;
256
+ } // AND end of 'phrase'
257
+ const m = input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/); // OR crystal system ($o$) (\ca$c$)
258
+ if (m) {
259
+ return {match_: m[0], remainder: input.substr(m[0].length)};
260
+ }
261
+ return null;
262
+ },
263
+ "_{(state of aggregation)}$": /^_\{(\([a-z]{1,3}\))\}/,
264
+ "{[(": /^(?:\\\{|\[|\()/,
265
+ ")]}": /^(?:\)|\]|\\\})/,
266
+ ", ": /^[,;]\s*/,
267
+ ",": /^[,;]/,
268
+ ".": /^[.]/,
269
+ ". ": /^([.\u22C5\u00B7\u2022])\s*/,
270
+ "...": /^\.\.\.(?=$|[^.])/,
271
+ "* ": /^([*])\s*/,
272
+ "^{(...)}": function (input) {
273
+ return mhchemParser.patterns.findObserveGroups(
274
+ input,
275
+ "^{",
276
+ "",
277
+ "",
278
+ "}",
279
+ );
280
+ },
281
+ "^($...$)": function (input) {
282
+ return mhchemParser.patterns.findObserveGroups(
283
+ input,
284
+ "^",
285
+ "$",
286
+ "$",
287
+ "",
288
+ );
289
+ },
290
+ "^a": /^\^([0-9]+|[^\\_])/,
291
+ "^\\x{}{}": function (input) {
292
+ return mhchemParser.patterns.findObserveGroups(
293
+ input,
294
+ "^",
295
+ /^\\[a-zA-Z]+\{/,
296
+ "}",
297
+ "",
298
+ "",
299
+ "{",
300
+ "}",
301
+ "",
302
+ true,
303
+ );
304
+ },
305
+ "^\\x{}": function (input) {
306
+ return mhchemParser.patterns.findObserveGroups(
307
+ input,
308
+ "^",
309
+ /^\\[a-zA-Z]+\{/,
310
+ "}",
311
+ "",
312
+ );
313
+ },
314
+ "^\\x": /^\^(\\[a-zA-Z]+)\s*/,
315
+ "^(-1)": /^\^(-?\d+)/,
316
+ "'": /^'/,
317
+ "_{(...)}": function (input) {
318
+ return mhchemParser.patterns.findObserveGroups(
319
+ input,
320
+ "_{",
321
+ "",
322
+ "",
323
+ "}",
324
+ );
325
+ },
326
+ "_($...$)": function (input) {
327
+ return mhchemParser.patterns.findObserveGroups(
328
+ input,
329
+ "_",
330
+ "$",
331
+ "$",
332
+ "",
333
+ );
334
+ },
335
+ _9: /^_([+\-]?[0-9]+|[^\\])/,
336
+ "_\\x{}{}": function (input) {
337
+ return mhchemParser.patterns.findObserveGroups(
338
+ input,
339
+ "_",
340
+ /^\\[a-zA-Z]+\{/,
341
+ "}",
342
+ "",
343
+ "",
344
+ "{",
345
+ "}",
346
+ "",
347
+ true,
348
+ );
349
+ },
350
+ "_\\x{}": function (input) {
351
+ return mhchemParser.patterns.findObserveGroups(
352
+ input,
353
+ "_",
354
+ /^\\[a-zA-Z]+\{/,
355
+ "}",
356
+ "",
357
+ );
358
+ },
359
+ "_\\x": /^_(\\[a-zA-Z]+)\s*/,
360
+ "^_": /^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,
361
+ "{}": /^\{\}/,
362
+ "{...}": function (input) {
363
+ return mhchemParser.patterns.findObserveGroups(
364
+ input,
365
+ "",
366
+ "{",
367
+ "}",
368
+ "",
369
+ );
370
+ },
371
+ "{(...)}": function (input) {
372
+ return mhchemParser.patterns.findObserveGroups(
373
+ input,
374
+ "{",
375
+ "",
376
+ "",
377
+ "}",
378
+ );
379
+ },
380
+ "$...$": function (input) {
381
+ return mhchemParser.patterns.findObserveGroups(
382
+ input,
383
+ "",
384
+ "$",
385
+ "$",
386
+ "",
387
+ );
388
+ },
389
+ "${(...)}$": function (input) {
390
+ return mhchemParser.patterns.findObserveGroups(
391
+ input,
392
+ "${",
393
+ "",
394
+ "",
395
+ "}$",
396
+ );
397
+ },
398
+ "$(...)$": function (input) {
399
+ return mhchemParser.patterns.findObserveGroups(
400
+ input,
401
+ "$",
402
+ "",
403
+ "",
404
+ "$",
405
+ );
406
+ },
407
+ "=<>": /^[=<>]/,
408
+ "#": /^[#\u2261]/,
409
+ "+": /^\+/,
410
+ "-$": /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation
411
+ "-9": /^-(?=[0-9])/,
412
+ "- orbital overlap": /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,
413
+ "-": /^-/,
414
+ "pm-operator": /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,
415
+ operator:
416
+ /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,
417
+ arrowUpDown: /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,
418
+ "\\bond{(...)}": function (input) {
419
+ return mhchemParser.patterns.findObserveGroups(
420
+ input,
421
+ "\\bond{",
422
+ "",
423
+ "",
424
+ "}",
425
+ );
426
+ },
427
+ "->": /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,
428
+ CMT: /^[CMT](?=\[)/,
429
+ "[(...)]": function (input) {
430
+ return mhchemParser.patterns.findObserveGroups(
431
+ input,
432
+ "[",
433
+ "",
434
+ "",
435
+ "]",
436
+ );
437
+ },
438
+ "1st-level escape": /^(&|\\\\|\\hline)\s*/,
439
+ "\\,": /^(?:\\[,\ ;:])/, // \\x - but output no space before
440
+ "\\x{}{}": function (input) {
441
+ return mhchemParser.patterns.findObserveGroups(
442
+ input,
443
+ "",
444
+ /^\\[a-zA-Z]+\{/,
445
+ "}",
446
+ "",
447
+ "",
448
+ "{",
449
+ "}",
450
+ "",
451
+ true,
452
+ );
453
+ },
454
+ "\\x{}": function (input) {
455
+ return mhchemParser.patterns.findObserveGroups(
456
+ input,
457
+ "",
458
+ /^\\[a-zA-Z]+\{/,
459
+ "}",
460
+ "",
461
+ );
462
+ },
463
+ "\\ca": /^\\ca(?:\s+|(?![a-zA-Z]))/,
464
+ "\\x": /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,
465
+ orbital: /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway
466
+ others: /^[\/~|]/,
467
+ "\\frac{(...)}": function (input) {
468
+ return mhchemParser.patterns.findObserveGroups(
469
+ input,
470
+ "\\frac{",
471
+ "",
472
+ "",
473
+ "}",
474
+ "{",
475
+ "",
476
+ "",
477
+ "}",
478
+ );
479
+ },
480
+ "\\overset{(...)}": function (input) {
481
+ return mhchemParser.patterns.findObserveGroups(
482
+ input,
483
+ "\\overset{",
484
+ "",
485
+ "",
486
+ "}",
487
+ "{",
488
+ "",
489
+ "",
490
+ "}",
491
+ );
492
+ },
493
+ "\\underset{(...)}": function (input) {
494
+ return mhchemParser.patterns.findObserveGroups(
495
+ input,
496
+ "\\underset{",
497
+ "",
498
+ "",
499
+ "}",
500
+ "{",
501
+ "",
502
+ "",
503
+ "}",
504
+ );
505
+ },
506
+ "\\underbrace{(...)}": function (input) {
507
+ return mhchemParser.patterns.findObserveGroups(
508
+ input,
509
+ "\\underbrace{",
510
+ "",
511
+ "",
512
+ "}_",
513
+ "{",
514
+ "",
515
+ "",
516
+ "}",
517
+ );
518
+ },
519
+ "\\color{(...)}0": function (input) {
520
+ return mhchemParser.patterns.findObserveGroups(
521
+ input,
522
+ "\\color{",
523
+ "",
524
+ "",
525
+ "}",
526
+ );
527
+ },
528
+ "\\color{(...)}{(...)}1": function (input) {
529
+ return mhchemParser.patterns.findObserveGroups(
530
+ input,
531
+ "\\color{",
532
+ "",
533
+ "",
534
+ "}",
535
+ "{",
536
+ "",
537
+ "",
538
+ "}",
539
+ );
540
+ },
541
+ "\\color(...){(...)}2": function (input) {
542
+ return mhchemParser.patterns.findObserveGroups(
543
+ input,
544
+ "\\color",
545
+ "\\",
546
+ "",
547
+ /^(?=\{)/,
548
+ "{",
549
+ "",
550
+ "",
551
+ "}",
552
+ );
553
+ },
554
+ "\\ce{(...)}": function (input) {
555
+ return mhchemParser.patterns.findObserveGroups(
556
+ input,
557
+ "\\ce{",
558
+ "",
559
+ "",
560
+ "}",
561
+ );
562
+ },
563
+ oxidation$: /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,
564
+ "d-oxidation$": /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge
565
+ "roman numeral": /^[IVX]+/,
566
+ "1/2$": /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,
567
+ amount: function (input) {
568
+ let match;
569
+ // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing
570
+ match = input.match(
571
+ /^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/,
572
+ );
573
+ if (match) {
574
+ return {
575
+ match_: match[0],
576
+ remainder: input.substr(match[0].length),
577
+ };
578
+ }
579
+ const a = mhchemParser.patterns.findObserveGroups(
580
+ input,
581
+ "",
582
+ "$",
583
+ "$",
584
+ "",
585
+ );
586
+ if (a) {
587
+ // e.g. $2n-1$, $-$
588
+ match = a.match_.match(
589
+ /^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/,
590
+ );
591
+ if (match) {
592
+ return {
593
+ match_: match[0],
594
+ remainder: input.substr(match[0].length),
595
+ };
596
+ }
597
+ }
598
+ return null;
599
+ },
600
+ amount2: function (input) {
601
+ return this["amount"](input);
602
+ },
603
+ "(KV letters),": /^(?:[A-Z][a-z]{0,2}|i)(?=,)/,
604
+ formula$: function (input) {
605
+ if (input.match(/^\([a-z]+\)$/)) {
606
+ return null;
607
+ } // state of aggregation = no formula
608
+ const match = input.match(
609
+ /^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/,
610
+ );
611
+ if (match) {
612
+ return {
613
+ match_: match[0],
614
+ remainder: input.substr(match[0].length),
615
+ };
616
+ }
617
+ return null;
618
+ },
619
+ uprightEntities: /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,
620
+ "/": /^\s*(\/)\s*/,
621
+ "//": /^\s*(\/\/)\s*/,
622
+ "*": /^\s*[*.]\s*/,
623
+ },
624
+ findObserveGroups: function (
625
+ input,
626
+ begExcl,
627
+ begIncl,
628
+ endIncl,
629
+ endExcl,
630
+ beg2Excl,
631
+ beg2Incl,
632
+ end2Incl,
633
+ end2Excl,
634
+ combine,
635
+ ) {
636
+ /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */
637
+ const _match = function (input, pattern) {
638
+ if (typeof pattern === "string") {
639
+ if (input.indexOf(pattern) !== 0) {
640
+ return null;
641
+ }
642
+ return pattern;
643
+ }
644
+ const match = input.match(pattern);
645
+ if (!match) {
646
+ return null;
647
+ }
648
+ return match[0];
649
+ };
650
+ /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */
651
+ const _findObserveGroups = function (input, i, endChars) {
652
+ let braces = 0;
653
+ while (i < input.length) {
654
+ const a = input.charAt(i);
655
+ const match = _match(input.substr(i), endChars);
656
+ if (match !== null && braces === 0) {
657
+ return {
658
+ endMatchBegin: i,
659
+ endMatchEnd: i + match.length,
660
+ };
661
+ }
662
+ if (a === "{") {
663
+ braces++;
664
+ } else if (a === "}") {
665
+ if (braces === 0) {
666
+ throw [
667
+ "ExtraCloseMissingOpen",
668
+ "Extra close brace or missing open brace",
669
+ ];
670
+ } else {
671
+ braces--;
672
+ }
673
+ }
674
+ i++;
675
+ }
676
+ if (braces > 0) {
677
+ return null;
678
+ }
679
+ return null;
680
+ };
681
+ let match = _match(input, begExcl);
682
+ if (match === null) {
683
+ return null;
684
+ }
685
+ input = input.substr(match.length);
686
+ match = _match(input, begIncl);
687
+ if (match === null) {
688
+ return null;
689
+ }
690
+ const e = _findObserveGroups(
691
+ input,
692
+ match.length,
693
+ endIncl || endExcl,
694
+ );
695
+ if (e === null) {
696
+ return null;
697
+ }
698
+ const match1 = input.substring(
699
+ 0,
700
+ endIncl ? e.endMatchEnd : e.endMatchBegin,
701
+ );
702
+ if (!(beg2Excl || beg2Incl)) {
703
+ return {
704
+ match_: match1,
705
+ remainder: input.substr(e.endMatchEnd),
706
+ };
707
+ }
708
+ const group2 = this.findObserveGroups(
709
+ input.substr(e.endMatchEnd),
710
+ beg2Excl,
711
+ beg2Incl,
712
+ end2Incl,
713
+ end2Excl,
714
+ );
715
+ if (group2 === null) {
716
+ return null;
717
+ }
718
+ /** @type {string[]} */
719
+ const matchRet = [match1, group2.match_];
720
+ return {
721
+ match_: combine ? matchRet.join("") : matchRet,
722
+ remainder: group2.remainder,
723
+ };
724
+ },
725
+
726
+ //
727
+ // Matching function
728
+ // e.g. match("a", input) will look for the regexp called "a" and see if it matches
729
+ // returns null or {match_:"a", remainder:"bc"}
730
+ //
731
+ match_: function (m, input) {
732
+ const pattern = mhchemParser.patterns.patterns[m];
733
+ if (pattern === undefined) {
734
+ throw [
735
+ "MhchemBugP",
736
+ "mhchem bug P. Please report. (" + m + ")",
737
+ ]; // Trying to use non-existing pattern
738
+ } else if (typeof pattern === "function") {
739
+ return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser
740
+ } else {
741
+ // RegExp
742
+ const match = input.match(pattern);
743
+ if (match) {
744
+ let mm;
745
+ if (match[2]) {
746
+ mm = [match[1], match[2]];
747
+ } else if (match[1]) {
748
+ mm = match[1];
749
+ } else {
750
+ mm = match[0];
751
+ }
752
+ return {
753
+ match_: mm,
754
+ remainder: input.substr(match[0].length),
755
+ };
756
+ }
757
+ return null;
758
+ }
759
+ },
760
+ },
761
+
762
+ //
763
+ // Generic state machine actions
764
+ //
765
+ actions: {
766
+ "a=": function (buffer, m) {
767
+ buffer.a = (buffer.a || "") + m;
768
+ },
769
+ "b=": function (buffer, m) {
770
+ buffer.b = (buffer.b || "") + m;
771
+ },
772
+ "p=": function (buffer, m) {
773
+ buffer.p = (buffer.p || "") + m;
774
+ },
775
+ "o=": function (buffer, m) {
776
+ buffer.o = (buffer.o || "") + m;
777
+ },
778
+ "q=": function (buffer, m) {
779
+ buffer.q = (buffer.q || "") + m;
780
+ },
781
+ "d=": function (buffer, m) {
782
+ buffer.d = (buffer.d || "") + m;
783
+ },
784
+ "rm=": function (buffer, m) {
785
+ buffer.rm = (buffer.rm || "") + m;
786
+ },
787
+ "text=": function (buffer, m) {
788
+ buffer.text_ = (buffer.text_ || "") + m;
789
+ },
790
+ insert: function (buffer, m, a) {
791
+ return {type_: a};
792
+ },
793
+ "insert+p1": function (buffer, m, a) {
794
+ return {type_: a, p1: m};
795
+ },
796
+ "insert+p1+p2": function (buffer, m, a) {
797
+ return {type_: a, p1: m[0], p2: m[1]};
798
+ },
799
+ copy: function (buffer, m) {
800
+ return m;
801
+ },
802
+ rm: function (buffer, m) {
803
+ return {type_: "rm", p1: m || ""};
804
+ },
805
+ text: function (buffer, m) {
806
+ return mhchemParser.go(m, "text");
807
+ },
808
+ "{text}": function (buffer, m) {
809
+ const ret = ["{"];
810
+ mhchemParser.concatArray(ret, mhchemParser.go(m, "text"));
811
+ ret.push("}");
812
+ return ret;
813
+ },
814
+ "tex-math": function (buffer, m) {
815
+ return mhchemParser.go(m, "tex-math");
816
+ },
817
+ "tex-math tight": function (buffer, m) {
818
+ return mhchemParser.go(m, "tex-math tight");
819
+ },
820
+ bond: function (buffer, m, k) {
821
+ return {type_: "bond", kind_: k || m};
822
+ },
823
+ "color0-output": function (buffer, m) {
824
+ return {type_: "color0", color: m[0]};
825
+ },
826
+ ce: function (buffer, m) {
827
+ return mhchemParser.go(m);
828
+ },
829
+ "1/2": function (buffer, m) {
830
+ /** @type {ParserOutput[]} */
831
+ const ret = [];
832
+ if (m.match(/^[+\-]/)) {
833
+ ret.push(m.substr(0, 1));
834
+ m = m.substr(1);
835
+ }
836
+ const n = m.match(
837
+ /^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/,
838
+ );
839
+ n[1] = n[1].replace(/\$/g, "");
840
+ ret.push({type_: "frac", p1: n[1], p2: n[2]});
841
+ if (n[3]) {
842
+ n[3] = n[3].replace(/\$/g, "");
843
+ ret.push({type_: "tex-math", p1: n[3]});
844
+ }
845
+ return ret;
846
+ },
847
+ "9,9": function (buffer, m) {
848
+ return mhchemParser.go(m, "9,9");
849
+ },
850
+ },
851
+ //
852
+ // createTransitions
853
+ // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] }
854
+ // with expansion of 'a|b' to 'a' and 'b' (at 2 places)
855
+ //
856
+ createTransitions: function (o) {
857
+ let pattern;
858
+ let state;
859
+ /** @type {string[]} */
860
+ let stateArray;
861
+ let i;
862
+ //
863
+ // 1. Collect all states
864
+ //
865
+ /** @type {Transitions} */
866
+ const transitions = {};
867
+ for (pattern in o) {
868
+ for (state in o[pattern]) {
869
+ stateArray = state.split("|");
870
+ o[pattern][state].stateArray = stateArray;
871
+ for (i = 0; i < stateArray.length; i++) {
872
+ transitions[stateArray[i]] = [];
873
+ }
874
+ }
875
+ }
876
+ //
877
+ // 2. Fill states
878
+ //
879
+ for (pattern in o) {
880
+ for (state in o[pattern]) {
881
+ stateArray = o[pattern][state].stateArray || [];
882
+ for (i = 0; i < stateArray.length; i++) {
883
+ //
884
+ // 2a. Normalize actions into array: 'text=' ==> [{type_:'text='}]
885
+ // (Note to myself: Resolving the function here would be problematic. It would need .bind (for *this*) and currying (for *option*).)
886
+ //
887
+ /** @type {any} */
888
+ const p = o[pattern][state];
889
+ if (p.action_) {
890
+ p.action_ = [].concat(p.action_);
891
+ for (let k = 0; k < p.action_.length; k++) {
892
+ if (typeof p.action_[k] === "string") {
893
+ p.action_[k] = {type_: p.action_[k]};
894
+ }
895
+ }
896
+ } else {
897
+ p.action_ = [];
898
+ }
899
+ //
900
+ // 2.b Multi-insert
901
+ //
902
+ const patternArray = pattern.split("|");
903
+ for (let j = 0; j < patternArray.length; j++) {
904
+ if (stateArray[i] === "*") {
905
+ // insert into all
906
+ for (const t in transitions) {
907
+ transitions[t].push({
908
+ pattern: patternArray[j],
909
+ task: p,
910
+ });
911
+ }
912
+ } else {
913
+ transitions[stateArray[i]].push({
914
+ pattern: patternArray[j],
915
+ task: p,
916
+ });
917
+ }
918
+ }
919
+ }
920
+ }
921
+ }
922
+ return transitions;
923
+ },
924
+ stateMachines: {},
925
+ };
926
+
927
+ //
928
+ // Definition of state machines
929
+ //
930
+ mhchemParser.stateMachines = {
931
+ //
932
+ // \ce state machines
933
+ //
934
+ //#region ce
935
+ ce: {
936
+ // main parser
937
+ transitions: mhchemParser.createTransitions({
938
+ empty: {
939
+ "*": {action_: "output"},
940
+ },
941
+ else: {
942
+ "0|1|2": {
943
+ action_: "beginsWithBond=false",
944
+ revisit: true,
945
+ toContinue: true,
946
+ },
947
+ },
948
+ oxidation$: {
949
+ "0": {action_: "oxidation-output"},
950
+ },
951
+ CMT: {
952
+ r: {action_: "rdt=", nextState: "rt"},
953
+ rd: {action_: "rqt=", nextState: "rdt"},
954
+ },
955
+ arrowUpDown: {
956
+ "0|1|2|as": {
957
+ action_: ["sb=false", "output", "operator"],
958
+ nextState: "1",
959
+ },
960
+ },
961
+ uprightEntities: {
962
+ "0|1|2": {action_: ["o=", "output"], nextState: "1"},
963
+ },
964
+ orbital: {
965
+ "0|1|2|3": {action_: "o=", nextState: "o"},
966
+ },
967
+ "->": {
968
+ "0|1|2|3": {action_: "r=", nextState: "r"},
969
+ "a|as": {action_: ["output", "r="], nextState: "r"},
970
+ "*": {action_: ["output", "r="], nextState: "r"},
971
+ },
972
+ "+": {
973
+ o: {action_: "d= kv", nextState: "d"},
974
+ "d|D": {action_: "d=", nextState: "d"},
975
+ q: {action_: "d=", nextState: "qd"},
976
+ "qd|qD": {action_: "d=", nextState: "qd"},
977
+ dq: {action_: ["output", "d="], nextState: "d"},
978
+ "3": {
979
+ action_: ["sb=false", "output", "operator"],
980
+ nextState: "0",
981
+ },
982
+ },
983
+ amount: {
984
+ "0|2": {action_: "a=", nextState: "a"},
985
+ },
986
+ "pm-operator": {
987
+ "0|1|2|a|as": {
988
+ action_: [
989
+ "sb=false",
990
+ "output",
991
+ {type_: "operator", option: "\\pm"},
992
+ ],
993
+ nextState: "0",
994
+ },
995
+ },
996
+ operator: {
997
+ "0|1|2|a|as": {
998
+ action_: ["sb=false", "output", "operator"],
999
+ nextState: "0",
1000
+ },
1001
+ },
1002
+ "-$": {
1003
+ "o|q": {action_: ["charge or bond", "output"], nextState: "qd"},
1004
+ d: {action_: "d=", nextState: "d"},
1005
+ D: {
1006
+ action_: ["output", {type_: "bond", option: "-"}],
1007
+ nextState: "3",
1008
+ },
1009
+ q: {action_: "d=", nextState: "qd"},
1010
+ qd: {action_: "d=", nextState: "qd"},
1011
+ "qD|dq": {
1012
+ action_: ["output", {type_: "bond", option: "-"}],
1013
+ nextState: "3",
1014
+ },
1015
+ },
1016
+ "-9": {
1017
+ "3|o": {
1018
+ action_: ["output", {type_: "insert", option: "hyphen"}],
1019
+ nextState: "3",
1020
+ },
1021
+ },
1022
+ "- orbital overlap": {
1023
+ o: {
1024
+ action_: ["output", {type_: "insert", option: "hyphen"}],
1025
+ nextState: "2",
1026
+ },
1027
+ d: {
1028
+ action_: ["output", {type_: "insert", option: "hyphen"}],
1029
+ nextState: "2",
1030
+ },
1031
+ },
1032
+ "-": {
1033
+ "0|1|2": {
1034
+ action_: [
1035
+ {type_: "output", option: 1},
1036
+ "beginsWithBond=true",
1037
+ {type_: "bond", option: "-"},
1038
+ ],
1039
+ nextState: "3",
1040
+ },
1041
+ "3": {action_: {type_: "bond", option: "-"}},
1042
+ a: {
1043
+ action_: ["output", {type_: "insert", option: "hyphen"}],
1044
+ nextState: "2",
1045
+ },
1046
+ as: {
1047
+ action_: [
1048
+ {type_: "output", option: 2},
1049
+ {type_: "bond", option: "-"},
1050
+ ],
1051
+ nextState: "3",
1052
+ },
1053
+ b: {action_: "b="},
1054
+ o: {
1055
+ action_: {type_: "- after o/d", option: false},
1056
+ nextState: "2",
1057
+ },
1058
+ q: {
1059
+ action_: {type_: "- after o/d", option: false},
1060
+ nextState: "2",
1061
+ },
1062
+ "d|qd|dq": {
1063
+ action_: {type_: "- after o/d", option: true},
1064
+ nextState: "2",
1065
+ },
1066
+ "D|qD|p": {
1067
+ action_: ["output", {type_: "bond", option: "-"}],
1068
+ nextState: "3",
1069
+ },
1070
+ },
1071
+ amount2: {
1072
+ "1|3": {action_: "a=", nextState: "a"},
1073
+ },
1074
+ letters: {
1075
+ "0|1|2|3|a|as|b|p|bp|o": {action_: "o=", nextState: "o"},
1076
+ "q|dq": {action_: ["output", "o="], nextState: "o"},
1077
+ "d|D|qd|qD": {action_: "o after d", nextState: "o"},
1078
+ },
1079
+ digits: {
1080
+ o: {action_: "q=", nextState: "q"},
1081
+ "d|D": {action_: "q=", nextState: "dq"},
1082
+ q: {action_: ["output", "o="], nextState: "o"},
1083
+ a: {action_: "o=", nextState: "o"},
1084
+ },
1085
+ "space A": {
1086
+ "b|p|bp": {},
1087
+ },
1088
+ space: {
1089
+ a: {nextState: "as"},
1090
+ "0": {action_: "sb=false"},
1091
+ "1|2": {action_: "sb=true"},
1092
+ "r|rt|rd|rdt|rdq": {action_: "output", nextState: "0"},
1093
+ "*": {action_: ["output", "sb=true"], nextState: "1"},
1094
+ },
1095
+ "1st-level escape": {
1096
+ "1|2": {
1097
+ action_: [
1098
+ "output",
1099
+ {type_: "insert+p1", option: "1st-level escape"},
1100
+ ],
1101
+ },
1102
+ "*": {
1103
+ action_: [
1104
+ "output",
1105
+ {type_: "insert+p1", option: "1st-level escape"},
1106
+ ],
1107
+ nextState: "0",
1108
+ },
1109
+ },
1110
+ "[(...)]": {
1111
+ "r|rt": {action_: "rd=", nextState: "rd"},
1112
+ "rd|rdt": {action_: "rq=", nextState: "rdq"},
1113
+ },
1114
+ "...": {
1115
+ "o|d|D|dq|qd|qD": {
1116
+ action_: ["output", {type_: "bond", option: "..."}],
1117
+ nextState: "3",
1118
+ },
1119
+ "*": {
1120
+ action_: [
1121
+ {type_: "output", option: 1},
1122
+ {type_: "insert", option: "ellipsis"},
1123
+ ],
1124
+ nextState: "1",
1125
+ },
1126
+ },
1127
+ ". |* ": {
1128
+ "*": {
1129
+ action_: [
1130
+ "output",
1131
+ {type_: "insert", option: "addition compound"},
1132
+ ],
1133
+ nextState: "1",
1134
+ },
1135
+ },
1136
+ "state of aggregation $": {
1137
+ "*": {
1138
+ action_: ["output", "state of aggregation"],
1139
+ nextState: "1",
1140
+ },
1141
+ },
1142
+ "{[(": {
1143
+ "a|as|o": {
1144
+ action_: ["o=", "output", "parenthesisLevel++"],
1145
+ nextState: "2",
1146
+ },
1147
+ "0|1|2|3": {
1148
+ action_: ["o=", "output", "parenthesisLevel++"],
1149
+ nextState: "2",
1150
+ },
1151
+ "*": {
1152
+ action_: ["output", "o=", "output", "parenthesisLevel++"],
1153
+ nextState: "2",
1154
+ },
1155
+ },
1156
+ ")]}": {
1157
+ "0|1|2|3|b|p|bp|o": {
1158
+ action_: ["o=", "parenthesisLevel--"],
1159
+ nextState: "o",
1160
+ },
1161
+ "a|as|d|D|q|qd|qD|dq": {
1162
+ action_: ["output", "o=", "parenthesisLevel--"],
1163
+ nextState: "o",
1164
+ },
1165
+ },
1166
+ ", ": {
1167
+ "*": {action_: ["output", "comma"], nextState: "0"},
1168
+ },
1169
+ "^_": {
1170
+ // ^ and _ without a sensible argument
1171
+ "*": {},
1172
+ },
1173
+ "^{(...)}|^($...$)": {
1174
+ "0|1|2|as": {action_: "b=", nextState: "b"},
1175
+ p: {action_: "b=", nextState: "bp"},
1176
+ "3|o": {action_: "d= kv", nextState: "D"},
1177
+ q: {action_: "d=", nextState: "qD"},
1178
+ "d|D|qd|qD|dq": {action_: ["output", "d="], nextState: "D"},
1179
+ },
1180
+ "^a|^\\x{}{}|^\\x{}|^\\x|'": {
1181
+ "0|1|2|as": {action_: "b=", nextState: "b"},
1182
+ p: {action_: "b=", nextState: "bp"},
1183
+ "3|o": {action_: "d= kv", nextState: "d"},
1184
+ q: {action_: "d=", nextState: "qd"},
1185
+ "d|qd|D|qD": {action_: "d="},
1186
+ dq: {action_: ["output", "d="], nextState: "d"},
1187
+ },
1188
+ "_{(state of aggregation)}$": {
1189
+ "d|D|q|qd|qD|dq": {action_: ["output", "q="], nextState: "q"},
1190
+ },
1191
+ "_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x": {
1192
+ "0|1|2|as": {action_: "p=", nextState: "p"},
1193
+ b: {action_: "p=", nextState: "bp"},
1194
+ "3|o": {action_: "q=", nextState: "q"},
1195
+ "d|D": {action_: "q=", nextState: "dq"},
1196
+ "q|qd|qD|dq": {action_: ["output", "q="], nextState: "q"},
1197
+ },
1198
+ "=<>": {
1199
+ "0|1|2|3|a|as|o|q|d|D|qd|qD|dq": {
1200
+ action_: [{type_: "output", option: 2}, "bond"],
1201
+ nextState: "3",
1202
+ },
1203
+ },
1204
+ "#": {
1205
+ "0|1|2|3|a|as|o": {
1206
+ action_: [
1207
+ {type_: "output", option: 2},
1208
+ {type_: "bond", option: "#"},
1209
+ ],
1210
+ nextState: "3",
1211
+ },
1212
+ },
1213
+ "{}": {
1214
+ "*": {action_: {type_: "output", option: 1}, nextState: "1"},
1215
+ },
1216
+ "{...}": {
1217
+ "0|1|2|3|a|as|b|p|bp": {action_: "o=", nextState: "o"},
1218
+ "o|d|D|q|qd|qD|dq": {action_: ["output", "o="], nextState: "o"},
1219
+ },
1220
+ "$...$": {
1221
+ a: {action_: "a="}, // 2$n$
1222
+ "0|1|2|3|as|b|p|bp|o": {action_: "o=", nextState: "o"}, // not 'amount'
1223
+ "as|o": {action_: "o="},
1224
+ "q|d|D|qd|qD|dq": {action_: ["output", "o="], nextState: "o"},
1225
+ },
1226
+ "\\bond{(...)}": {
1227
+ "*": {
1228
+ action_: [{type_: "output", option: 2}, "bond"],
1229
+ nextState: "3",
1230
+ },
1231
+ },
1232
+ "\\frac{(...)}": {
1233
+ "*": {
1234
+ action_: [{type_: "output", option: 1}, "frac-output"],
1235
+ nextState: "3",
1236
+ },
1237
+ },
1238
+ "\\overset{(...)}": {
1239
+ "*": {
1240
+ action_: [{type_: "output", option: 2}, "overset-output"],
1241
+ nextState: "3",
1242
+ },
1243
+ },
1244
+ "\\underset{(...)}": {
1245
+ "*": {
1246
+ action_: [{type_: "output", option: 2}, "underset-output"],
1247
+ nextState: "3",
1248
+ },
1249
+ },
1250
+ "\\underbrace{(...)}": {
1251
+ "*": {
1252
+ action_: [
1253
+ {type_: "output", option: 2},
1254
+ "underbrace-output",
1255
+ ],
1256
+ nextState: "3",
1257
+ },
1258
+ },
1259
+ "\\color{(...)}{(...)}1|\\color(...){(...)}2": {
1260
+ "*": {
1261
+ action_: [{type_: "output", option: 2}, "color-output"],
1262
+ nextState: "3",
1263
+ },
1264
+ },
1265
+ "\\color{(...)}0": {
1266
+ "*": {action_: [{type_: "output", option: 2}, "color0-output"]},
1267
+ },
1268
+ "\\ce{(...)}": {
1269
+ "*": {
1270
+ action_: [{type_: "output", option: 2}, "ce"],
1271
+ nextState: "3",
1272
+ },
1273
+ },
1274
+ "\\,": {
1275
+ "*": {
1276
+ action_: [{type_: "output", option: 1}, "copy"],
1277
+ nextState: "1",
1278
+ },
1279
+ },
1280
+ "\\x{}{}|\\x{}|\\x": {
1281
+ "0|1|2|3|a|as|b|p|bp|o|c0": {
1282
+ action_: ["o=", "output"],
1283
+ nextState: "3",
1284
+ },
1285
+ "*": {action_: ["output", "o=", "output"], nextState: "3"},
1286
+ },
1287
+ others: {
1288
+ "*": {
1289
+ action_: [{type_: "output", option: 1}, "copy"],
1290
+ nextState: "3",
1291
+ },
1292
+ },
1293
+ else2: {
1294
+ a: {action_: "a to o", nextState: "o", revisit: true},
1295
+ as: {
1296
+ action_: ["output", "sb=true"],
1297
+ nextState: "1",
1298
+ revisit: true,
1299
+ },
1300
+ "r|rt|rd|rdt|rdq": {
1301
+ action_: ["output"],
1302
+ nextState: "0",
1303
+ revisit: true,
1304
+ },
1305
+ "*": {action_: ["output", "copy"], nextState: "3"},
1306
+ },
1307
+ }),
1308
+ actions: {
1309
+ "o after d": function (buffer, m) {
1310
+ let ret;
1311
+ if ((buffer.d || "").match(/^[0-9]+$/)) {
1312
+ const tmp = buffer.d;
1313
+ buffer.d = undefined;
1314
+ ret = this["output"](buffer);
1315
+ buffer.b = tmp;
1316
+ } else {
1317
+ ret = this["output"](buffer);
1318
+ }
1319
+ mhchemParser.actions["o="](buffer, m);
1320
+ return ret;
1321
+ },
1322
+ "d= kv": function (buffer, m) {
1323
+ buffer.d = m;
1324
+ buffer.dType = "kv";
1325
+ },
1326
+ "charge or bond": function (buffer, m) {
1327
+ if (buffer["beginsWithBond"]) {
1328
+ /** @type {ParserOutput[]} */
1329
+ const ret = [];
1330
+ mhchemParser.concatArray(ret, this["output"](buffer));
1331
+ mhchemParser.concatArray(
1332
+ ret,
1333
+ mhchemParser.actions["bond"](buffer, m, "-"),
1334
+ );
1335
+ return ret;
1336
+ }
1337
+ buffer.d = m;
1338
+ },
1339
+ "- after o/d": function (buffer, m, isAfterD) {
1340
+ let c1 = mhchemParser.patterns.match_(
1341
+ "orbital",
1342
+ buffer.o || "",
1343
+ );
1344
+ const c2 = mhchemParser.patterns.match_(
1345
+ "one lowercase greek letter $",
1346
+ buffer.o || "",
1347
+ );
1348
+ const c3 = mhchemParser.patterns.match_(
1349
+ "one lowercase latin letter $",
1350
+ buffer.o || "",
1351
+ );
1352
+ const c4 = mhchemParser.patterns.match_(
1353
+ "$one lowercase latin letter$ $",
1354
+ buffer.o || "",
1355
+ );
1356
+ const hyphenFollows =
1357
+ m === "-" &&
1358
+ ((c1 && c1.remainder === "") || c2 || c3 || c4);
1359
+ if (
1360
+ hyphenFollows &&
1361
+ !buffer.a &&
1362
+ !buffer.b &&
1363
+ !buffer.p &&
1364
+ !buffer.d &&
1365
+ !buffer.q &&
1366
+ !c1 &&
1367
+ c3
1368
+ ) {
1369
+ buffer.o = "$" + buffer.o + "$";
1370
+ }
1371
+ /** @type {ParserOutput[]} */
1372
+ const ret = [];
1373
+ if (hyphenFollows) {
1374
+ mhchemParser.concatArray(ret, this["output"](buffer));
1375
+ ret.push({type_: "hyphen"});
1376
+ } else {
1377
+ c1 = mhchemParser.patterns.match_("digits", buffer.d || "");
1378
+ if (isAfterD && c1 && c1.remainder === "") {
1379
+ mhchemParser.concatArray(
1380
+ ret,
1381
+ mhchemParser.actions["d="](buffer, m),
1382
+ );
1383
+ mhchemParser.concatArray(ret, this["output"](buffer));
1384
+ } else {
1385
+ mhchemParser.concatArray(ret, this["output"](buffer));
1386
+ mhchemParser.concatArray(
1387
+ ret,
1388
+ mhchemParser.actions["bond"](buffer, m, "-"),
1389
+ );
1390
+ }
1391
+ }
1392
+ return ret;
1393
+ },
1394
+ "a to o": function (buffer) {
1395
+ buffer.o = buffer.a;
1396
+ buffer.a = undefined;
1397
+ },
1398
+ "sb=true": function (buffer) {
1399
+ buffer.sb = true;
1400
+ },
1401
+ "sb=false": function (buffer) {
1402
+ buffer.sb = false;
1403
+ },
1404
+ "beginsWithBond=true": function (buffer) {
1405
+ buffer["beginsWithBond"] = true;
1406
+ },
1407
+ "beginsWithBond=false": function (buffer) {
1408
+ buffer["beginsWithBond"] = false;
1409
+ },
1410
+ "parenthesisLevel++": function (buffer) {
1411
+ buffer["parenthesisLevel"]++;
1412
+ },
1413
+ "parenthesisLevel--": function (buffer) {
1414
+ buffer["parenthesisLevel"]--;
1415
+ },
1416
+ "state of aggregation": function (buffer, m) {
1417
+ return {
1418
+ type_: "state of aggregation",
1419
+ p1: mhchemParser.go(m, "o"),
1420
+ };
1421
+ },
1422
+ comma: function (buffer, m) {
1423
+ const a = m.replace(/\s*$/, "");
1424
+ const withSpace = a !== m;
1425
+ if (withSpace && buffer["parenthesisLevel"] === 0) {
1426
+ return {type_: "comma enumeration L", p1: a};
1427
+ }
1428
+ return {type_: "comma enumeration M", p1: a};
1429
+ },
1430
+ output: function (buffer, m, entityFollows) {
1431
+ // entityFollows:
1432
+ // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb)
1433
+ // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1)
1434
+ // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as)
1435
+ /** @type {ParserOutput | ParserOutput[]} */
1436
+ let ret;
1437
+ if (!buffer.r) {
1438
+ ret = [];
1439
+ if (
1440
+ !buffer.a &&
1441
+ !buffer.b &&
1442
+ !buffer.p &&
1443
+ !buffer.o &&
1444
+ !buffer.q &&
1445
+ !buffer.d &&
1446
+ !entityFollows
1447
+ ) {
1448
+ //ret = [];
1449
+ } else {
1450
+ if (buffer.sb) {
1451
+ ret.push({type_: "entitySkip"});
1452
+ }
1453
+ if (
1454
+ !buffer.o &&
1455
+ !buffer.q &&
1456
+ !buffer.d &&
1457
+ !buffer.b &&
1458
+ !buffer.p &&
1459
+ entityFollows !== 2
1460
+ ) {
1461
+ buffer.o = buffer.a;
1462
+ buffer.a = undefined;
1463
+ } else if (
1464
+ !buffer.o &&
1465
+ !buffer.q &&
1466
+ !buffer.d &&
1467
+ (buffer.b || buffer.p)
1468
+ ) {
1469
+ buffer.o = buffer.a;
1470
+ buffer.d = buffer.b;
1471
+ buffer.q = buffer.p;
1472
+ buffer.a = buffer.b = buffer.p = undefined;
1473
+ } else {
1474
+ if (
1475
+ buffer.o &&
1476
+ buffer.dType === "kv" &&
1477
+ mhchemParser.patterns.match_(
1478
+ "d-oxidation$",
1479
+ buffer.d || "",
1480
+ )
1481
+ ) {
1482
+ buffer.dType = "oxidation";
1483
+ } else if (
1484
+ buffer.o &&
1485
+ buffer.dType === "kv" &&
1486
+ !buffer.q
1487
+ ) {
1488
+ buffer.dType = undefined;
1489
+ }
1490
+ }
1491
+ ret.push({
1492
+ type_: "chemfive",
1493
+ a: mhchemParser.go(buffer.a, "a"),
1494
+ b: mhchemParser.go(buffer.b, "bd"),
1495
+ p: mhchemParser.go(buffer.p, "pq"),
1496
+ o: mhchemParser.go(buffer.o, "o"),
1497
+ q: mhchemParser.go(buffer.q, "pq"),
1498
+ d: mhchemParser.go(
1499
+ buffer.d,
1500
+ buffer.dType === "oxidation"
1501
+ ? "oxidation"
1502
+ : "bd",
1503
+ ),
1504
+ dType: buffer.dType,
1505
+ });
1506
+ }
1507
+ } else {
1508
+ // r
1509
+ /** @type {ParserOutput[]} */
1510
+ let rd;
1511
+ if (buffer.rdt === "M") {
1512
+ rd = mhchemParser.go(buffer.rd, "tex-math");
1513
+ } else if (buffer.rdt === "T") {
1514
+ rd = [{type_: "text", p1: buffer.rd || ""}];
1515
+ } else {
1516
+ rd = mhchemParser.go(buffer.rd);
1517
+ }
1518
+ /** @type {ParserOutput[]} */
1519
+ let rq;
1520
+ if (buffer.rqt === "M") {
1521
+ rq = mhchemParser.go(buffer.rq, "tex-math");
1522
+ } else if (buffer.rqt === "T") {
1523
+ rq = [{type_: "text", p1: buffer.rq || ""}];
1524
+ } else {
1525
+ rq = mhchemParser.go(buffer.rq);
1526
+ }
1527
+ ret = {
1528
+ type_: "arrow",
1529
+ r: buffer.r,
1530
+ rd: rd,
1531
+ rq: rq,
1532
+ };
1533
+ }
1534
+ for (const p in buffer) {
1535
+ if (p !== "parenthesisLevel" && p !== "beginsWithBond") {
1536
+ delete buffer[p];
1537
+ }
1538
+ }
1539
+ return ret;
1540
+ },
1541
+ "oxidation-output": function (buffer, m) {
1542
+ const ret = ["{"];
1543
+ mhchemParser.concatArray(ret, mhchemParser.go(m, "oxidation"));
1544
+ ret.push("}");
1545
+ return ret;
1546
+ },
1547
+ "frac-output": function (buffer, m) {
1548
+ return {
1549
+ type_: "frac-ce",
1550
+ p1: mhchemParser.go(m[0]),
1551
+ p2: mhchemParser.go(m[1]),
1552
+ };
1553
+ },
1554
+ "overset-output": function (buffer, m) {
1555
+ return {
1556
+ type_: "overset",
1557
+ p1: mhchemParser.go(m[0]),
1558
+ p2: mhchemParser.go(m[1]),
1559
+ };
1560
+ },
1561
+ "underset-output": function (buffer, m) {
1562
+ return {
1563
+ type_: "underset",
1564
+ p1: mhchemParser.go(m[0]),
1565
+ p2: mhchemParser.go(m[1]),
1566
+ };
1567
+ },
1568
+ "underbrace-output": function (buffer, m) {
1569
+ return {
1570
+ type_: "underbrace",
1571
+ p1: mhchemParser.go(m[0]),
1572
+ p2: mhchemParser.go(m[1]),
1573
+ };
1574
+ },
1575
+ "color-output": function (buffer, m) {
1576
+ return {
1577
+ type_: "color",
1578
+ color1: m[0],
1579
+ color2: mhchemParser.go(m[1]),
1580
+ };
1581
+ },
1582
+ "r=": function (buffer, m) {
1583
+ buffer.r = m;
1584
+ },
1585
+ "rdt=": function (buffer, m) {
1586
+ buffer.rdt = m;
1587
+ },
1588
+ "rd=": function (buffer, m) {
1589
+ buffer.rd = m;
1590
+ },
1591
+ "rqt=": function (buffer, m) {
1592
+ buffer.rqt = m;
1593
+ },
1594
+ "rq=": function (buffer, m) {
1595
+ buffer.rq = m;
1596
+ },
1597
+ operator: function (buffer, m, p1) {
1598
+ return {type_: "operator", kind_: p1 || m};
1599
+ },
1600
+ },
1601
+ },
1602
+ a: {
1603
+ transitions: mhchemParser.createTransitions({
1604
+ empty: {
1605
+ "*": {},
1606
+ },
1607
+ "1/2$": {
1608
+ "0": {action_: "1/2"},
1609
+ },
1610
+ else: {
1611
+ "0": {nextState: "1", revisit: true},
1612
+ },
1613
+ "$(...)$": {
1614
+ "*": {action_: "tex-math tight", nextState: "1"},
1615
+ },
1616
+ ",": {
1617
+ "*": {action_: {type_: "insert", option: "commaDecimal"}},
1618
+ },
1619
+ else2: {
1620
+ "*": {action_: "copy"},
1621
+ },
1622
+ }),
1623
+ actions: {},
1624
+ },
1625
+ o: {
1626
+ transitions: mhchemParser.createTransitions({
1627
+ empty: {
1628
+ "*": {},
1629
+ },
1630
+ "1/2$": {
1631
+ "0": {action_: "1/2"},
1632
+ },
1633
+ else: {
1634
+ "0": {nextState: "1", revisit: true},
1635
+ },
1636
+ letters: {
1637
+ "*": {action_: "rm"},
1638
+ },
1639
+ "\\ca": {
1640
+ "*": {action_: {type_: "insert", option: "circa"}},
1641
+ },
1642
+ "\\x{}{}|\\x{}|\\x": {
1643
+ "*": {action_: "copy"},
1644
+ },
1645
+ "${(...)}$|$(...)$": {
1646
+ "*": {action_: "tex-math"},
1647
+ },
1648
+ "{(...)}": {
1649
+ "*": {action_: "{text}"},
1650
+ },
1651
+ else2: {
1652
+ "*": {action_: "copy"},
1653
+ },
1654
+ }),
1655
+ actions: {},
1656
+ },
1657
+ text: {
1658
+ transitions: mhchemParser.createTransitions({
1659
+ empty: {
1660
+ "*": {action_: "output"},
1661
+ },
1662
+ "{...}": {
1663
+ "*": {action_: "text="},
1664
+ },
1665
+ "${(...)}$|$(...)$": {
1666
+ "*": {action_: "tex-math"},
1667
+ },
1668
+ "\\greek": {
1669
+ "*": {action_: ["output", "rm"]},
1670
+ },
1671
+ "\\,|\\x{}{}|\\x{}|\\x": {
1672
+ "*": {action_: ["output", "copy"]},
1673
+ },
1674
+ else: {
1675
+ "*": {action_: "text="},
1676
+ },
1677
+ }),
1678
+ actions: {
1679
+ output: function (buffer) {
1680
+ if (buffer.text_) {
1681
+ /** @type {ParserOutput} */
1682
+ const ret = {type_: "text", p1: buffer.text_};
1683
+ for (const p in buffer) {
1684
+ delete buffer[p];
1685
+ }
1686
+ return ret;
1687
+ }
1688
+ },
1689
+ },
1690
+ },
1691
+ pq: {
1692
+ transitions: mhchemParser.createTransitions({
1693
+ empty: {
1694
+ "*": {},
1695
+ },
1696
+ "state of aggregation $": {
1697
+ "*": {action_: "state of aggregation"},
1698
+ },
1699
+ i$: {
1700
+ "0": {nextState: "!f", revisit: true},
1701
+ },
1702
+ "(KV letters),": {
1703
+ "0": {action_: "rm", nextState: "0"},
1704
+ },
1705
+ formula$: {
1706
+ "0": {nextState: "f", revisit: true},
1707
+ },
1708
+ "1/2$": {
1709
+ "0": {action_: "1/2"},
1710
+ },
1711
+ else: {
1712
+ "0": {nextState: "!f", revisit: true},
1713
+ },
1714
+ "${(...)}$|$(...)$": {
1715
+ "*": {action_: "tex-math"},
1716
+ },
1717
+ "{(...)}": {
1718
+ "*": {action_: "text"},
1719
+ },
1720
+ "a-z": {
1721
+ f: {action_: "tex-math"},
1722
+ },
1723
+ letters: {
1724
+ "*": {action_: "rm"},
1725
+ },
1726
+ "-9.,9": {
1727
+ "*": {action_: "9,9"},
1728
+ },
1729
+ ",": {
1730
+ "*": {
1731
+ action_: {
1732
+ type_: "insert+p1",
1733
+ option: "comma enumeration S",
1734
+ },
1735
+ },
1736
+ },
1737
+ "\\color{(...)}{(...)}1|\\color(...){(...)}2": {
1738
+ "*": {action_: "color-output"},
1739
+ },
1740
+ "\\color{(...)}0": {
1741
+ "*": {action_: "color0-output"},
1742
+ },
1743
+ "\\ce{(...)}": {
1744
+ "*": {action_: "ce"},
1745
+ },
1746
+ "\\,|\\x{}{}|\\x{}|\\x": {
1747
+ "*": {action_: "copy"},
1748
+ },
1749
+ else2: {
1750
+ "*": {action_: "copy"},
1751
+ },
1752
+ }),
1753
+ actions: {
1754
+ "state of aggregation": function (buffer, m) {
1755
+ return {
1756
+ type_: "state of aggregation subscript",
1757
+ p1: mhchemParser.go(m, "o"),
1758
+ };
1759
+ },
1760
+ "color-output": function (buffer, m) {
1761
+ return {
1762
+ type_: "color",
1763
+ color1: m[0],
1764
+ color2: mhchemParser.go(m[1], "pq"),
1765
+ };
1766
+ },
1767
+ },
1768
+ },
1769
+ bd: {
1770
+ transitions: mhchemParser.createTransitions({
1771
+ empty: {
1772
+ "*": {},
1773
+ },
1774
+ x$: {
1775
+ "0": {nextState: "!f", revisit: true},
1776
+ },
1777
+ formula$: {
1778
+ "0": {nextState: "f", revisit: true},
1779
+ },
1780
+ else: {
1781
+ "0": {nextState: "!f", revisit: true},
1782
+ },
1783
+ "-9.,9 no missing 0": {
1784
+ "*": {action_: "9,9"},
1785
+ },
1786
+ ".": {
1787
+ "*": {action_: {type_: "insert", option: "electron dot"}},
1788
+ },
1789
+ "a-z": {
1790
+ f: {action_: "tex-math"},
1791
+ },
1792
+ x: {
1793
+ "*": {action_: {type_: "insert", option: "KV x"}},
1794
+ },
1795
+ letters: {
1796
+ "*": {action_: "rm"},
1797
+ },
1798
+ "'": {
1799
+ "*": {action_: {type_: "insert", option: "prime"}},
1800
+ },
1801
+ "${(...)}$|$(...)$": {
1802
+ "*": {action_: "tex-math"},
1803
+ },
1804
+ "{(...)}": {
1805
+ "*": {action_: "text"},
1806
+ },
1807
+ "\\color{(...)}{(...)}1|\\color(...){(...)}2": {
1808
+ "*": {action_: "color-output"},
1809
+ },
1810
+ "\\color{(...)}0": {
1811
+ "*": {action_: "color0-output"},
1812
+ },
1813
+ "\\ce{(...)}": {
1814
+ "*": {action_: "ce"},
1815
+ },
1816
+ "\\,|\\x{}{}|\\x{}|\\x": {
1817
+ "*": {action_: "copy"},
1818
+ },
1819
+ else2: {
1820
+ "*": {action_: "copy"},
1821
+ },
1822
+ }),
1823
+ actions: {
1824
+ "color-output": function (buffer, m) {
1825
+ return {
1826
+ type_: "color",
1827
+ color1: m[0],
1828
+ color2: mhchemParser.go(m[1], "bd"),
1829
+ };
1830
+ },
1831
+ },
1832
+ },
1833
+ oxidation: {
1834
+ transitions: mhchemParser.createTransitions({
1835
+ empty: {
1836
+ "*": {},
1837
+ },
1838
+ "roman numeral": {
1839
+ "*": {action_: "roman-numeral"},
1840
+ },
1841
+ "${(...)}$|$(...)$": {
1842
+ "*": {action_: "tex-math"},
1843
+ },
1844
+ else: {
1845
+ "*": {action_: "copy"},
1846
+ },
1847
+ }),
1848
+ actions: {
1849
+ "roman-numeral": function (buffer, m) {
1850
+ return {type_: "roman numeral", p1: m || ""};
1851
+ },
1852
+ },
1853
+ },
1854
+ "tex-math": {
1855
+ transitions: mhchemParser.createTransitions({
1856
+ empty: {
1857
+ "*": {action_: "output"},
1858
+ },
1859
+ "\\ce{(...)}": {
1860
+ "*": {action_: ["output", "ce"]},
1861
+ },
1862
+ "{...}|\\,|\\x{}{}|\\x{}|\\x": {
1863
+ "*": {action_: "o="},
1864
+ },
1865
+ else: {
1866
+ "*": {action_: "o="},
1867
+ },
1868
+ }),
1869
+ actions: {
1870
+ output: function (buffer) {
1871
+ if (buffer.o) {
1872
+ /** @type {ParserOutput} */
1873
+ const ret = {type_: "tex-math", p1: buffer.o};
1874
+ for (const p in buffer) {
1875
+ delete buffer[p];
1876
+ }
1877
+ return ret;
1878
+ }
1879
+ },
1880
+ },
1881
+ },
1882
+ "tex-math tight": {
1883
+ transitions: mhchemParser.createTransitions({
1884
+ empty: {
1885
+ "*": {action_: "output"},
1886
+ },
1887
+ "\\ce{(...)}": {
1888
+ "*": {action_: ["output", "ce"]},
1889
+ },
1890
+ "{...}|\\,|\\x{}{}|\\x{}|\\x": {
1891
+ "*": {action_: "o="},
1892
+ },
1893
+ "-|+": {
1894
+ "*": {action_: "tight operator"},
1895
+ },
1896
+ else: {
1897
+ "*": {action_: "o="},
1898
+ },
1899
+ }),
1900
+ actions: {
1901
+ "tight operator": function (buffer, m) {
1902
+ buffer.o = (buffer.o || "") + "{" + m + "}";
1903
+ },
1904
+ output: function (buffer) {
1905
+ if (buffer.o) {
1906
+ /** @type {ParserOutput} */
1907
+ const ret = {type_: "tex-math", p1: buffer.o};
1908
+ for (const p in buffer) {
1909
+ delete buffer[p];
1910
+ }
1911
+ return ret;
1912
+ }
1913
+ },
1914
+ },
1915
+ },
1916
+ "9,9": {
1917
+ transitions: mhchemParser.createTransitions({
1918
+ empty: {
1919
+ "*": {},
1920
+ },
1921
+ ",": {
1922
+ "*": {action_: "comma"},
1923
+ },
1924
+ else: {
1925
+ "*": {action_: "copy"},
1926
+ },
1927
+ }),
1928
+ actions: {
1929
+ comma: function () {
1930
+ return {type_: "commaDecimal"};
1931
+ },
1932
+ },
1933
+ },
1934
+ //#endregion
1935
+ //
1936
+ // \pu state machines
1937
+ //
1938
+ //#region pu
1939
+ pu: {
1940
+ transitions: mhchemParser.createTransitions({
1941
+ empty: {
1942
+ "*": {action_: "output"},
1943
+ },
1944
+ space$: {
1945
+ "*": {action_: ["output", "space"]},
1946
+ },
1947
+ "{[(|)]}": {
1948
+ "0|a": {action_: "copy"},
1949
+ },
1950
+ "(-)(9)^(-9)": {
1951
+ "0": {action_: "number^", nextState: "a"},
1952
+ },
1953
+ "(-)(9.,9)(e)(99)": {
1954
+ "0": {action_: "enumber", nextState: "a"},
1955
+ },
1956
+ space: {
1957
+ "0|a": {},
1958
+ },
1959
+ "pm-operator": {
1960
+ "0|a": {
1961
+ action_: {type_: "operator", option: "\\pm"},
1962
+ nextState: "0",
1963
+ },
1964
+ },
1965
+ operator: {
1966
+ "0|a": {action_: "copy", nextState: "0"},
1967
+ },
1968
+ "//": {
1969
+ d: {action_: "o=", nextState: "/"},
1970
+ },
1971
+ "/": {
1972
+ d: {action_: "o=", nextState: "/"},
1973
+ },
1974
+ "{...}|else": {
1975
+ "0|d": {action_: "d=", nextState: "d"},
1976
+ a: {action_: ["space", "d="], nextState: "d"},
1977
+ "/|q": {action_: "q=", nextState: "q"},
1978
+ },
1979
+ }),
1980
+ actions: {
1981
+ enumber: function (buffer, m) {
1982
+ /** @type {ParserOutput[]} */
1983
+ const ret = [];
1984
+ if (m[0] === "+-" || m[0] === "+/-") {
1985
+ ret.push("\\pm ");
1986
+ } else if (m[0]) {
1987
+ ret.push(m[0]);
1988
+ }
1989
+ if (m[1]) {
1990
+ mhchemParser.concatArray(
1991
+ ret,
1992
+ mhchemParser.go(m[1], "pu-9,9"),
1993
+ );
1994
+ if (m[2]) {
1995
+ if (m[2].match(/[,.]/)) {
1996
+ mhchemParser.concatArray(
1997
+ ret,
1998
+ mhchemParser.go(m[2], "pu-9,9"),
1999
+ );
2000
+ } else {
2001
+ ret.push(m[2]);
2002
+ }
2003
+ }
2004
+ m[3] = m[4] || m[3];
2005
+ if (m[3]) {
2006
+ m[3] = m[3].trim();
2007
+ if (m[3] === "e" || m[3].substr(0, 1) === "*") {
2008
+ ret.push({type_: "cdot"});
2009
+ } else {
2010
+ ret.push({type_: "times"});
2011
+ }
2012
+ }
2013
+ }
2014
+ if (m[3]) {
2015
+ ret.push("10^{" + m[5] + "}");
2016
+ }
2017
+ return ret;
2018
+ },
2019
+ "number^": function (buffer, m) {
2020
+ /** @type {ParserOutput[]} */
2021
+ const ret = [];
2022
+ if (m[0] === "+-" || m[0] === "+/-") {
2023
+ ret.push("\\pm ");
2024
+ } else if (m[0]) {
2025
+ ret.push(m[0]);
2026
+ }
2027
+ mhchemParser.concatArray(ret, mhchemParser.go(m[1], "pu-9,9"));
2028
+ ret.push("^{" + m[2] + "}");
2029
+ return ret;
2030
+ },
2031
+ operator: function (buffer, m, p1) {
2032
+ return {type_: "operator", kind_: p1 || m};
2033
+ },
2034
+ space: function () {
2035
+ return {type_: "pu-space-1"};
2036
+ },
2037
+ output: function (buffer) {
2038
+ /** @type {ParserOutput | ParserOutput[]} */
2039
+ let ret;
2040
+ const md = mhchemParser.patterns.match_(
2041
+ "{(...)}",
2042
+ buffer.d || "",
2043
+ );
2044
+ if (md && md.remainder === "") {
2045
+ buffer.d = md.match_;
2046
+ }
2047
+ const mq = mhchemParser.patterns.match_(
2048
+ "{(...)}",
2049
+ buffer.q || "",
2050
+ );
2051
+ if (mq && mq.remainder === "") {
2052
+ buffer.q = mq.match_;
2053
+ }
2054
+ if (buffer.d) {
2055
+ buffer.d = buffer.d.replace(
2056
+ /\u00B0C|\^oC|\^{o}C/g,
2057
+ "{}^{\\circ}C",
2058
+ );
2059
+ buffer.d = buffer.d.replace(
2060
+ /\u00B0F|\^oF|\^{o}F/g,
2061
+ "{}^{\\circ}F",
2062
+ );
2063
+ }
2064
+ if (buffer.q) {
2065
+ // fraction
2066
+ buffer.q = buffer.q.replace(
2067
+ /\u00B0C|\^oC|\^{o}C/g,
2068
+ "{}^{\\circ}C",
2069
+ );
2070
+ buffer.q = buffer.q.replace(
2071
+ /\u00B0F|\^oF|\^{o}F/g,
2072
+ "{}^{\\circ}F",
2073
+ );
2074
+ const b5 = {
2075
+ d: mhchemParser.go(buffer.d, "pu"),
2076
+ q: mhchemParser.go(buffer.q, "pu"),
2077
+ };
2078
+ if (buffer.o === "//") {
2079
+ ret = {type_: "pu-frac", p1: b5.d, p2: b5.q};
2080
+ } else {
2081
+ ret = b5.d;
2082
+ if (b5.d.length > 1 || b5.q.length > 1) {
2083
+ ret.push({type_: " / "});
2084
+ } else {
2085
+ ret.push({type_: "/"});
2086
+ }
2087
+ mhchemParser.concatArray(ret, b5.q);
2088
+ }
2089
+ } else {
2090
+ // no fraction
2091
+ ret = mhchemParser.go(buffer.d, "pu-2");
2092
+ }
2093
+ for (const p in buffer) {
2094
+ delete buffer[p];
2095
+ }
2096
+ return ret;
2097
+ },
2098
+ },
2099
+ },
2100
+ "pu-2": {
2101
+ transitions: mhchemParser.createTransitions({
2102
+ empty: {
2103
+ "*": {action_: "output"},
2104
+ },
2105
+ "*": {
2106
+ "*": {action_: ["output", "cdot"], nextState: "0"},
2107
+ },
2108
+ "\\x": {
2109
+ "*": {action_: "rm="},
2110
+ },
2111
+ space: {
2112
+ "*": {action_: ["output", "space"], nextState: "0"},
2113
+ },
2114
+ "^{(...)}|^(-1)": {
2115
+ "1": {action_: "^(-1)"},
2116
+ },
2117
+ "-9.,9": {
2118
+ "0": {action_: "rm=", nextState: "0"},
2119
+ "1": {action_: "^(-1)", nextState: "0"},
2120
+ },
2121
+ "{...}|else": {
2122
+ "*": {action_: "rm=", nextState: "1"},
2123
+ },
2124
+ }),
2125
+ actions: {
2126
+ cdot: function () {
2127
+ return {type_: "tight cdot"};
2128
+ },
2129
+ "^(-1)": function (buffer, m) {
2130
+ buffer.rm += "^{" + m + "}";
2131
+ },
2132
+ space: function () {
2133
+ return {type_: "pu-space-2"};
2134
+ },
2135
+ output: function (buffer) {
2136
+ /** @type {ParserOutput | ParserOutput[]} */
2137
+ let ret = [];
2138
+ if (buffer.rm) {
2139
+ const mrm = mhchemParser.patterns.match_(
2140
+ "{(...)}",
2141
+ buffer.rm || "",
2142
+ );
2143
+ if (mrm && mrm.remainder === "") {
2144
+ ret = mhchemParser.go(mrm.match_, "pu");
2145
+ } else {
2146
+ ret = {type_: "rm", p1: buffer.rm};
2147
+ }
2148
+ }
2149
+ for (const p in buffer) {
2150
+ delete buffer[p];
2151
+ }
2152
+ return ret;
2153
+ },
2154
+ },
2155
+ },
2156
+ "pu-9,9": {
2157
+ transitions: mhchemParser.createTransitions({
2158
+ empty: {
2159
+ "0": {action_: "output-0"},
2160
+ o: {action_: "output-o"},
2161
+ },
2162
+ ",": {
2163
+ "0": {action_: ["output-0", "comma"], nextState: "o"},
2164
+ },
2165
+ ".": {
2166
+ "0": {action_: ["output-0", "copy"], nextState: "o"},
2167
+ },
2168
+ else: {
2169
+ "*": {action_: "text="},
2170
+ },
2171
+ }),
2172
+ actions: {
2173
+ comma: function () {
2174
+ return {type_: "commaDecimal"};
2175
+ },
2176
+ "output-0": function (buffer) {
2177
+ /** @type {ParserOutput[]} */
2178
+ const ret = [];
2179
+ buffer.text_ = buffer.text_ || "";
2180
+ if (buffer.text_.length > 4) {
2181
+ let a = buffer.text_.length % 3;
2182
+ if (a === 0) {
2183
+ a = 3;
2184
+ }
2185
+ for (let i = buffer.text_.length - 3; i > 0; i -= 3) {
2186
+ ret.push(buffer.text_.substr(i, 3));
2187
+ ret.push({type_: "1000 separator"});
2188
+ }
2189
+ ret.push(buffer.text_.substr(0, a));
2190
+ ret.reverse();
2191
+ } else {
2192
+ ret.push(buffer.text_);
2193
+ }
2194
+ for (const p in buffer) {
2195
+ delete buffer[p];
2196
+ }
2197
+ return ret;
2198
+ },
2199
+ "output-o": function (buffer) {
2200
+ /** @type {ParserOutput[]} */
2201
+ const ret = [];
2202
+ buffer.text_ = buffer.text_ || "";
2203
+ if (buffer.text_.length > 4) {
2204
+ const a = buffer.text_.length - 3;
2205
+ for (var i = 0; i < a; i += 3) {
2206
+ ret.push(buffer.text_.substr(i, 3));
2207
+ ret.push({type_: "1000 separator"});
2208
+ }
2209
+ ret.push(buffer.text_.substr(i));
2210
+ } else {
2211
+ ret.push(buffer.text_);
2212
+ }
2213
+ for (const p in buffer) {
2214
+ delete buffer[p];
2215
+ }
2216
+ return ret;
2217
+ },
2218
+ },
2219
+ },
2220
+ //#endregion
2221
+ };
2222
+
2223
+ //
2224
+ // texify: Take MhchemParser output and convert it to TeX
2225
+ //
2226
+ /** @type {Texify} */
2227
+ var texify = {
2228
+ go: function (input, isInner) {
2229
+ // (recursive, max 4 levels)
2230
+ if (!input) {
2231
+ return "";
2232
+ }
2233
+ let res = "";
2234
+ let cee = false;
2235
+ for (let i = 0; i < input.length; i++) {
2236
+ const inputi = input[i];
2237
+ if (typeof inputi === "string") {
2238
+ res += inputi;
2239
+ } else {
2240
+ res += texify._go2(inputi);
2241
+ if (inputi.type_ === "1st-level escape") {
2242
+ cee = true;
2243
+ }
2244
+ }
2245
+ }
2246
+ if (!isInner && !cee && res) {
2247
+ res = "{" + res + "}";
2248
+ }
2249
+ return res;
2250
+ },
2251
+ _goInner: function (input) {
2252
+ if (!input) {
2253
+ return input;
2254
+ }
2255
+ return texify.go(input, true);
2256
+ },
2257
+ _go2: function (buf) {
2258
+ /** @type {undefined | string} */
2259
+ let res;
2260
+ switch (buf.type_) {
2261
+ case "chemfive":
2262
+ res = "";
2263
+ var b5 = {
2264
+ a: texify._goInner(buf.a),
2265
+ b: texify._goInner(buf.b),
2266
+ p: texify._goInner(buf.p),
2267
+ o: texify._goInner(buf.o),
2268
+ q: texify._goInner(buf.q),
2269
+ d: texify._goInner(buf.d),
2270
+ };
2271
+ //
2272
+ // a
2273
+ //
2274
+ if (b5.a) {
2275
+ if (b5.a.match(/^[+\-]/)) {
2276
+ b5.a = "{" + b5.a + "}";
2277
+ }
2278
+ res += b5.a + "\\,";
2279
+ }
2280
+ //
2281
+ // b and p
2282
+ //
2283
+ if (b5.b || b5.p) {
2284
+ res += "{\\vphantom{X}}";
2285
+ res +=
2286
+ "^{\\hphantom{" +
2287
+ (b5.b || "") +
2288
+ "}}_{\\hphantom{" +
2289
+ (b5.p || "") +
2290
+ "}}";
2291
+ res += "{\\vphantom{X}}";
2292
+ res +=
2293
+ "^{\\smash[t]{\\vphantom{2}}\\mathllap{" +
2294
+ (b5.b || "") +
2295
+ "}}";
2296
+ res +=
2297
+ "_{\\vphantom{2}\\mathllap{\\smash[t]{" +
2298
+ (b5.p || "") +
2299
+ "}}}";
2300
+ }
2301
+ //
2302
+ // o
2303
+ //
2304
+ if (b5.o) {
2305
+ if (b5.o.match(/^[+\-]/)) {
2306
+ b5.o = "{" + b5.o + "}";
2307
+ }
2308
+ res += b5.o;
2309
+ }
2310
+ //
2311
+ // q and d
2312
+ //
2313
+ if (buf.dType === "kv") {
2314
+ if (b5.d || b5.q) {
2315
+ res += "{\\vphantom{X}}";
2316
+ }
2317
+ if (b5.d) {
2318
+ res += "^{" + b5.d + "}";
2319
+ }
2320
+ if (b5.q) {
2321
+ res += "_{\\smash[t]{" + b5.q + "}}";
2322
+ }
2323
+ } else if (buf.dType === "oxidation") {
2324
+ if (b5.d) {
2325
+ res += "{\\vphantom{X}}";
2326
+ res += "^{" + b5.d + "}";
2327
+ }
2328
+ if (b5.q) {
2329
+ res += "{\\vphantom{X}}";
2330
+ res += "_{\\smash[t]{" + b5.q + "}}";
2331
+ }
2332
+ } else {
2333
+ if (b5.q) {
2334
+ res += "{\\vphantom{X}}";
2335
+ res += "_{\\smash[t]{" + b5.q + "}}";
2336
+ }
2337
+ if (b5.d) {
2338
+ res += "{\\vphantom{X}}";
2339
+ res += "^{" + b5.d + "}";
2340
+ }
2341
+ }
2342
+ break;
2343
+ case "rm":
2344
+ res = "\\mathrm{" + buf.p1 + "}";
2345
+ break;
2346
+ case "text":
2347
+ if (buf.p1.match(/[\^_]/)) {
2348
+ buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}");
2349
+ res = "\\mathrm{" + buf.p1 + "}";
2350
+ } else {
2351
+ res = "\\text{" + buf.p1 + "}";
2352
+ }
2353
+ break;
2354
+ case "roman numeral":
2355
+ res = "\\mathrm{" + buf.p1 + "}";
2356
+ break;
2357
+ case "state of aggregation":
2358
+ res = "\\mskip2mu " + texify._goInner(buf.p1);
2359
+ break;
2360
+ case "state of aggregation subscript":
2361
+ res = "\\mskip1mu " + texify._goInner(buf.p1);
2362
+ break;
2363
+ case "bond":
2364
+ res = texify._getBond(buf.kind_);
2365
+ if (!res) {
2366
+ throw [
2367
+ "MhchemErrorBond",
2368
+ "mhchem Error. Unknown bond type (" + buf.kind_ + ")",
2369
+ ];
2370
+ }
2371
+ break;
2372
+ case "frac":
2373
+ var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}";
2374
+ res =
2375
+ "\\mathchoice{\\textstyle" +
2376
+ c +
2377
+ "}{" +
2378
+ c +
2379
+ "}{" +
2380
+ c +
2381
+ "}{" +
2382
+ c +
2383
+ "}";
2384
+ break;
2385
+ case "pu-frac":
2386
+ var d =
2387
+ "\\frac{" +
2388
+ texify._goInner(buf.p1) +
2389
+ "}{" +
2390
+ texify._goInner(buf.p2) +
2391
+ "}";
2392
+ res =
2393
+ "\\mathchoice{\\textstyle" +
2394
+ d +
2395
+ "}{" +
2396
+ d +
2397
+ "}{" +
2398
+ d +
2399
+ "}{" +
2400
+ d +
2401
+ "}";
2402
+ break;
2403
+ case "tex-math":
2404
+ res = buf.p1 + " ";
2405
+ break;
2406
+ case "frac-ce":
2407
+ res =
2408
+ "\\frac{" +
2409
+ texify._goInner(buf.p1) +
2410
+ "}{" +
2411
+ texify._goInner(buf.p2) +
2412
+ "}";
2413
+ break;
2414
+ case "overset":
2415
+ res =
2416
+ "\\overset{" +
2417
+ texify._goInner(buf.p1) +
2418
+ "}{" +
2419
+ texify._goInner(buf.p2) +
2420
+ "}";
2421
+ break;
2422
+ case "underset":
2423
+ res =
2424
+ "\\underset{" +
2425
+ texify._goInner(buf.p1) +
2426
+ "}{" +
2427
+ texify._goInner(buf.p2) +
2428
+ "}";
2429
+ break;
2430
+ case "underbrace":
2431
+ res =
2432
+ "\\underbrace{" +
2433
+ texify._goInner(buf.p1) +
2434
+ "}_{" +
2435
+ texify._goInner(buf.p2) +
2436
+ "}";
2437
+ break;
2438
+ case "color":
2439
+ res =
2440
+ "{\\color{" +
2441
+ buf.color1 +
2442
+ "}{" +
2443
+ texify._goInner(buf.color2) +
2444
+ "}}";
2445
+ break;
2446
+ case "color0":
2447
+ res = "\\color{" + buf.color + "}";
2448
+ break;
2449
+ case "arrow":
2450
+ var b6 = {
2451
+ rd: texify._goInner(buf.rd),
2452
+ rq: texify._goInner(buf.rq),
2453
+ };
2454
+ var arrow = "\\x" + texify._getArrow(buf.r);
2455
+ if (b6.rq) {
2456
+ arrow += "[{" + b6.rq + "}]";
2457
+ }
2458
+ if (b6.rd) {
2459
+ arrow += "{" + b6.rd + "}";
2460
+ } else {
2461
+ arrow += "{}";
2462
+ }
2463
+ res = arrow;
2464
+ break;
2465
+ case "operator":
2466
+ res = texify._getOperator(buf.kind_);
2467
+ break;
2468
+ case "1st-level escape":
2469
+ res = buf.p1 + " "; // &, \\\\, \\hlin
2470
+ break;
2471
+ case "space":
2472
+ res = " ";
2473
+ break;
2474
+ case "entitySkip":
2475
+ res = "~";
2476
+ break;
2477
+ case "pu-space-1":
2478
+ res = "~";
2479
+ break;
2480
+ case "pu-space-2":
2481
+ res = "\\mkern3mu ";
2482
+ break;
2483
+ case "1000 separator":
2484
+ res = "\\mkern2mu ";
2485
+ break;
2486
+ case "commaDecimal":
2487
+ res = "{,}";
2488
+ break;
2489
+ case "comma enumeration L":
2490
+ res = "{" + buf.p1 + "}\\mkern6mu ";
2491
+ break;
2492
+ case "comma enumeration M":
2493
+ res = "{" + buf.p1 + "}\\mkern3mu ";
2494
+ break;
2495
+ case "comma enumeration S":
2496
+ res = "{" + buf.p1 + "}\\mkern1mu ";
2497
+ break;
2498
+ case "hyphen":
2499
+ res = "\\text{-}";
2500
+ break;
2501
+ case "addition compound":
2502
+ res = "\\,{\\cdot}\\,";
2503
+ break;
2504
+ case "electron dot":
2505
+ res = "\\mkern1mu \\bullet\\mkern1mu ";
2506
+ break;
2507
+ case "KV x":
2508
+ res = "{\\times}";
2509
+ break;
2510
+ case "prime":
2511
+ res = "\\prime ";
2512
+ break;
2513
+ case "cdot":
2514
+ res = "\\cdot ";
2515
+ break;
2516
+ case "tight cdot":
2517
+ res = "\\mkern1mu{\\cdot}\\mkern1mu ";
2518
+ break;
2519
+ case "times":
2520
+ res = "\\times ";
2521
+ break;
2522
+ case "circa":
2523
+ res = "{\\sim}";
2524
+ break;
2525
+ case "^":
2526
+ res = "uparrow";
2527
+ break;
2528
+ case "v":
2529
+ res = "downarrow";
2530
+ break;
2531
+ case "ellipsis":
2532
+ res = "\\ldots ";
2533
+ break;
2534
+ case "/":
2535
+ res = "/";
2536
+ break;
2537
+ case " / ":
2538
+ res = "\\,/\\,";
2539
+ break;
2540
+ default:
2541
+ assertNever(buf);
2542
+ throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output
2543
+ }
2544
+ assertString(res);
2545
+ return res;
2546
+ },
2547
+ _getArrow: function (a) {
2548
+ switch (a) {
2549
+ case "->":
2550
+ return "rightarrow";
2551
+ case "\u2192":
2552
+ return "rightarrow";
2553
+ case "\u27F6":
2554
+ return "rightarrow";
2555
+ case "<-":
2556
+ return "leftarrow";
2557
+ case "<->":
2558
+ return "leftrightarrow";
2559
+ case "<-->":
2560
+ return "rightleftarrows";
2561
+ case "<=>":
2562
+ return "rightleftharpoons";
2563
+ case "\u21CC":
2564
+ return "rightleftharpoons";
2565
+ case "<=>>":
2566
+ return "rightequilibrium";
2567
+ case "<<=>":
2568
+ return "leftequilibrium";
2569
+ default:
2570
+ assertNever(a);
2571
+ throw ["MhchemBugT", "mhchem bug T. Please report."];
2572
+ }
2573
+ },
2574
+ _getBond: function (a) {
2575
+ switch (a) {
2576
+ case "-":
2577
+ return "{-}";
2578
+ case "1":
2579
+ return "{-}";
2580
+ case "=":
2581
+ return "{=}";
2582
+ case "2":
2583
+ return "{=}";
2584
+ case "#":
2585
+ return "{\\equiv}";
2586
+ case "3":
2587
+ return "{\\equiv}";
2588
+ case "~":
2589
+ return "{\\tripledash}";
2590
+ case "~-":
2591
+ return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";
2592
+ case "~=":
2593
+ return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";
2594
+ case "~--":
2595
+ return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";
2596
+ case "-~-":
2597
+ return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";
2598
+ case "...":
2599
+ return "{{\\cdot}{\\cdot}{\\cdot}}";
2600
+ case "....":
2601
+ return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";
2602
+ case "->":
2603
+ return "{\\rightarrow}";
2604
+ case "<-":
2605
+ return "{\\leftarrow}";
2606
+ case "<":
2607
+ return "{<}";
2608
+ case ">":
2609
+ return "{>}";
2610
+ default:
2611
+ assertNever(a);
2612
+ throw ["MhchemBugT", "mhchem bug T. Please report."];
2613
+ }
2614
+ },
2615
+ _getOperator: function (a) {
2616
+ switch (a) {
2617
+ case "+":
2618
+ return " {}+{} ";
2619
+ case "-":
2620
+ return " {}-{} ";
2621
+ case "=":
2622
+ return " {}={} ";
2623
+ case "<":
2624
+ return " {}<{} ";
2625
+ case ">":
2626
+ return " {}>{} ";
2627
+ case "<<":
2628
+ return " {}\\ll{} ";
2629
+ case ">>":
2630
+ return " {}\\gg{} ";
2631
+ case "\\pm":
2632
+ return " {}\\pm{} ";
2633
+ case "\\approx":
2634
+ return " {}\\approx{} ";
2635
+ case "$\\approx$":
2636
+ return " {}\\approx{} ";
2637
+ case "v":
2638
+ return " \\downarrow{} ";
2639
+ case "(v)":
2640
+ return " \\downarrow{} ";
2641
+ case "^":
2642
+ return " \\uparrow{} ";
2643
+ case "(^)":
2644
+ return " \\uparrow{} ";
2645
+ default:
2646
+ assertNever(a);
2647
+ throw ["MhchemBugT", "mhchem bug T. Please report."];
2648
+ }
2649
+ },
2650
+ };
2651
+
2652
+ //
2653
+ // Helpers for code anaylsis
2654
+ // Will show type error at calling position
2655
+ //
2656
+ /** @param {number} a */
2657
+ function assertNever(a) {}
2658
+ /** @param {string} a */
2659
+ function assertString(a) {}