UNPKG

2.71 kBJavaScriptView Raw
1// @flow
2/**
3 * This file contains a list of utility functions which are useful in other
4 * files.
5 */
6
7import type {AnyParseNode} from "./parseNode";
8
9/**
10 * Return whether an element is contained in a list
11 */
12const contains = function<T>(list: Array<T>, elem: T): boolean {
13 return list.indexOf(elem) !== -1;
14};
15
16/**
17 * Provide a default value if a setting is undefined
18 * NOTE: Couldn't use `T` as the output type due to facebook/flow#5022.
19 */
20const deflt = function<T>(setting: T | void, defaultIfUndefined: T): * {
21 return setting === undefined ? defaultIfUndefined : setting;
22};
23
24// hyphenate and escape adapted from Facebook's React under Apache 2 license
25
26const uppercase = /([A-Z])/g;
27const hyphenate = function(str: string): string {
28 return str.replace(uppercase, "-$1").toLowerCase();
29};
30
31const ESCAPE_LOOKUP = {
32 "&": "&amp;",
33 ">": "&gt;",
34 "<": "&lt;",
35 "\"": "&quot;",
36 "'": "&#x27;",
37};
38
39const ESCAPE_REGEX = /[&><"']/g;
40
41/**
42 * Escapes text to prevent scripting attacks.
43 */
44function escape(text: mixed): string {
45 return String(text).replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]);
46}
47
48/**
49 * Sometimes we want to pull out the innermost element of a group. In most
50 * cases, this will just be the group itself, but when ordgroups and colors have
51 * a single element, we want to pull that out.
52 */
53const getBaseElem = function(group: AnyParseNode): AnyParseNode {
54 if (group.type === "ordgroup") {
55 if (group.body.length === 1) {
56 return getBaseElem(group.body[0]);
57 } else {
58 return group;
59 }
60 } else if (group.type === "color") {
61 if (group.body.length === 1) {
62 return getBaseElem(group.body[0]);
63 } else {
64 return group;
65 }
66 } else if (group.type === "font") {
67 return getBaseElem(group.body);
68 } else {
69 return group;
70 }
71};
72
73/**
74 * TeXbook algorithms often reference "character boxes", which are simply groups
75 * with a single character in them. To decide if something is a character box,
76 * we find its innermost group, and see if it is a single character.
77 */
78const isCharacterBox = function(group: AnyParseNode): boolean {
79 const baseElem = getBaseElem(group);
80
81 // These are all they types of groups which hold single characters
82 return baseElem.type === "mathord" ||
83 baseElem.type === "textord" ||
84 baseElem.type === "atom";
85};
86
87export const assert = function<T>(value: ?T): T {
88 if (!value) {
89 throw new Error('Expected non-null, but got ' + String(value));
90 }
91 return value;
92};
93
94export default {
95 contains,
96 deflt,
97 escape,
98 hyphenate,
99 getBaseElem,
100 isCharacterBox,
101};