You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.0 KiB
JavaScript
112 lines
3.0 KiB
JavaScript
// @flow
|
|
/**
|
|
* This file contains a list of utility functions which are useful in other
|
|
* files.
|
|
*/
|
|
|
|
import type {AnyParseNode} from "./parseNode";
|
|
|
|
/**
|
|
* Return whether an element is contained in a list
|
|
*/
|
|
const contains = function<T>(list: Array<T>, elem: T): boolean {
|
|
return list.indexOf(elem) !== -1;
|
|
};
|
|
|
|
/**
|
|
* Provide a default value if a setting is undefined
|
|
* NOTE: Couldn't use `T` as the output type due to facebook/flow#5022.
|
|
*/
|
|
const deflt = function<T>(setting: T | void, defaultIfUndefined: T): * {
|
|
return setting === undefined ? defaultIfUndefined : setting;
|
|
};
|
|
|
|
// hyphenate and escape adapted from Facebook's React under Apache 2 license
|
|
|
|
const uppercase = /([A-Z])/g;
|
|
const hyphenate = function(str: string): string {
|
|
return str.replace(uppercase, "-$1").toLowerCase();
|
|
};
|
|
|
|
const ESCAPE_LOOKUP = {
|
|
"&": "&",
|
|
">": ">",
|
|
"<": "<",
|
|
"\"": """,
|
|
"'": "'",
|
|
};
|
|
|
|
const ESCAPE_REGEX = /[&><"']/g;
|
|
|
|
/**
|
|
* Escapes text to prevent scripting attacks.
|
|
*/
|
|
function escape(text: mixed): string {
|
|
return String(text).replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]);
|
|
}
|
|
|
|
/**
|
|
* Sometimes we want to pull out the innermost element of a group. In most
|
|
* cases, this will just be the group itself, but when ordgroups and colors have
|
|
* a single element, we want to pull that out.
|
|
*/
|
|
const getBaseElem = function(group: AnyParseNode): AnyParseNode {
|
|
if (group.type === "ordgroup") {
|
|
if (group.body.length === 1) {
|
|
return getBaseElem(group.body[0]);
|
|
} else {
|
|
return group;
|
|
}
|
|
} else if (group.type === "color") {
|
|
if (group.body.length === 1) {
|
|
return getBaseElem(group.body[0]);
|
|
} else {
|
|
return group;
|
|
}
|
|
} else if (group.type === "font") {
|
|
return getBaseElem(group.body);
|
|
} else {
|
|
return group;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* TeXbook algorithms often reference "character boxes", which are simply groups
|
|
* with a single character in them. To decide if something is a character box,
|
|
* we find its innermost group, and see if it is a single character.
|
|
*/
|
|
const isCharacterBox = function(group: AnyParseNode): boolean {
|
|
const baseElem = getBaseElem(group);
|
|
|
|
// These are all they types of groups which hold single characters
|
|
return baseElem.type === "mathord" ||
|
|
baseElem.type === "textord" ||
|
|
baseElem.type === "atom";
|
|
};
|
|
|
|
export const assert = function<T>(value: ?T): T {
|
|
if (!value) {
|
|
throw new Error('Expected non-null, but got ' + String(value));
|
|
}
|
|
return value;
|
|
};
|
|
|
|
/**
|
|
* Return the protocol of a URL, or "_relative" if the URL does not specify a
|
|
* protocol (and thus is relative).
|
|
*/
|
|
export const protocolFromUrl = function(url: string): string {
|
|
const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url);
|
|
return (protocol != null ? protocol[1] : "_relative");
|
|
};
|
|
|
|
export default {
|
|
contains,
|
|
deflt,
|
|
escape,
|
|
hyphenate,
|
|
getBaseElem,
|
|
isCharacterBox,
|
|
protocolFromUrl,
|
|
};
|