|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import utils from "./utils"; |
|
import ParseError from "./ParseError"; |
|
import {Token} from "./Token"; |
|
|
|
import type {AnyParseNode} from "./parseNode"; |
|
import type {MacroMap} from "./defineMacro"; |
|
|
|
export type StrictFunction = |
|
(errorCode: string, errorMsg: string, token?: Token | AnyParseNode) => |
|
?(boolean | string); |
|
|
|
export type TrustContextTypes = { |
|
"\\href": {| |
|
command: "\\href", |
|
url: string, |
|
protocol?: string, |
|
|}, |
|
"\\includegraphics": {| |
|
command: "\\includegraphics", |
|
url: string, |
|
protocol?: string, |
|
|}, |
|
"\\url": {| |
|
command: "\\url", |
|
url: string, |
|
protocol?: string, |
|
|}, |
|
"\\htmlClass": {| |
|
command: "\\htmlClass", |
|
class: string, |
|
|}, |
|
"\\htmlId": {| |
|
command: "\\htmlId", |
|
id: string, |
|
|}, |
|
"\\htmlStyle": {| |
|
command: "\\htmlStyle", |
|
style: string, |
|
|}, |
|
"\\htmlData": {| |
|
command: "\\htmlData", |
|
attributes: {[string]: string}, |
|
|}, |
|
}; |
|
export type AnyTrustContext = $Values<TrustContextTypes>; |
|
export type TrustFunction = (context: AnyTrustContext) => ?boolean; |
|
|
|
export type SettingsOptions = $Shape<Settings>; |
|
|
|
type EnumType = {| enum: string[] |}; |
|
type Type = "boolean" | "string" | "number" | "object" | "function" | EnumType; |
|
type Schema = { |
|
[$Keys<SettingsOptions>]: { |
|
|
|
|
|
|
|
type: Type | Type[]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
default?: any; |
|
|
|
|
|
|
|
description?: string; |
|
|
|
|
|
|
|
processor?: (any) => any, |
|
|
|
|
|
|
|
|
|
|
|
cli?: string | false; |
|
|
|
|
|
|
|
cliDefault?: any; |
|
|
|
|
|
|
|
|
|
cliDescription?: string; |
|
|
|
|
|
|
|
|
|
cliProcessor?: (any, any) => any; |
|
}; |
|
}; |
|
|
|
|
|
|
|
|
|
export const SETTINGS_SCHEMA: Schema = { |
|
displayMode: { |
|
type: "boolean", |
|
description: "Render math in display mode, which puts the math in " + |
|
"display style (so \\int and \\sum are large, for example), and " + |
|
"centers the math on the page on its own line.", |
|
cli: "-d, --display-mode", |
|
}, |
|
output: { |
|
type: {enum: ["htmlAndMathml", "html", "mathml"]}, |
|
description: "Determines the markup language of the output.", |
|
cli: "-F, --format <type>", |
|
}, |
|
leqno: { |
|
type: "boolean", |
|
description: "Render display math in leqno style (left-justified tags).", |
|
}, |
|
fleqn: { |
|
type: "boolean", |
|
description: "Render display math flush left.", |
|
}, |
|
throwOnError: { |
|
type: "boolean", |
|
default: true, |
|
cli: "-t, --no-throw-on-error", |
|
cliDescription: "Render errors (in the color given by --error-color) ins" + |
|
"tead of throwing a ParseError exception when encountering an error.", |
|
}, |
|
errorColor: { |
|
type: "string", |
|
default: "#cc0000", |
|
cli: "-c, --error-color <color>", |
|
cliDescription: "A color string given in the format 'rgb' or 'rrggbb' " + |
|
"(no #). This option determines the color of errors rendered by the " + |
|
"-t option.", |
|
cliProcessor: (color) => "#" + color, |
|
}, |
|
macros: { |
|
type: "object", |
|
cli: "-m, --macro <def>", |
|
cliDescription: "Define custom macro of the form '\\foo:expansion' (use " + |
|
"multiple -m arguments for multiple macros).", |
|
cliDefault: [], |
|
cliProcessor: (def, defs) => { |
|
defs.push(def); |
|
return defs; |
|
}, |
|
}, |
|
minRuleThickness: { |
|
type: "number", |
|
description: "Specifies a minimum thickness, in ems, for fraction lines," + |
|
" `\\sqrt` top lines, `{array}` vertical lines, `\\hline`, " + |
|
"`\\hdashline`, `\\underline`, `\\overline`, and the borders of " + |
|
"`\\fbox`, `\\boxed`, and `\\fcolorbox`.", |
|
processor: (t) => Math.max(0, t), |
|
cli: "--min-rule-thickness <size>", |
|
cliProcessor: parseFloat, |
|
}, |
|
colorIsTextColor: { |
|
type: "boolean", |
|
description: "Makes \\color behave like LaTeX's 2-argument \\textcolor, " + |
|
"instead of LaTeX's one-argument \\color mode change.", |
|
cli: "-b, --color-is-text-color", |
|
}, |
|
strict: { |
|
type: [{enum: ["warn", "ignore", "error"]}, "boolean", "function"], |
|
description: "Turn on strict / LaTeX faithfulness mode, which throws an " + |
|
"error if the input uses features that are not supported by LaTeX.", |
|
cli: "-S, --strict", |
|
cliDefault: false, |
|
}, |
|
trust: { |
|
type: ["boolean", "function"], |
|
description: "Trust the input, enabling all HTML features such as \\url.", |
|
cli: "-T, --trust", |
|
}, |
|
maxSize: { |
|
type: "number", |
|
default: Infinity, |
|
description: "If non-zero, all user-specified sizes, e.g. in " + |
|
"\\rule{500em}{500em}, will be capped to maxSize ems. Otherwise, " + |
|
"elements and spaces can be arbitrarily large", |
|
processor: (s) => Math.max(0, s), |
|
cli: "-s, --max-size <n>", |
|
cliProcessor: parseInt, |
|
}, |
|
maxExpand: { |
|
type: "number", |
|
default: 1000, |
|
description: "Limit the number of macro expansions to the specified " + |
|
"number, to prevent e.g. infinite macro loops. If set to Infinity, " + |
|
"the macro expander will try to fully expand as in LaTeX.", |
|
processor: (n) => Math.max(0, n), |
|
cli: "-e, --max-expand <n>", |
|
cliProcessor: (n) => (n === "Infinity" ? Infinity : parseInt(n)), |
|
}, |
|
globalGroup: { |
|
type: "boolean", |
|
cli: false, |
|
}, |
|
}; |
|
|
|
function getDefaultValue(schema): any { |
|
if (schema.default) { |
|
return schema.default; |
|
} |
|
const type = schema.type; |
|
const defaultType = Array.isArray(type) ? type[0] : type; |
|
if (typeof defaultType !== 'string') { |
|
return defaultType.enum[0]; |
|
} |
|
switch (defaultType) { |
|
case 'boolean': |
|
return false; |
|
case 'string': |
|
return ''; |
|
case 'number': |
|
return 0; |
|
case 'object': |
|
return {}; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default class Settings { |
|
displayMode: boolean; |
|
output: "html" | "mathml" | "htmlAndMathml"; |
|
leqno: boolean; |
|
fleqn: boolean; |
|
throwOnError: boolean; |
|
errorColor: string; |
|
macros: MacroMap; |
|
minRuleThickness: number; |
|
colorIsTextColor: boolean; |
|
strict: boolean | "ignore" | "warn" | "error" | StrictFunction; |
|
trust: boolean | TrustFunction; |
|
maxSize: number; |
|
maxExpand: number; |
|
globalGroup: boolean; |
|
|
|
constructor(options: SettingsOptions) { |
|
|
|
options = options || {}; |
|
for (const prop in SETTINGS_SCHEMA) { |
|
if (SETTINGS_SCHEMA.hasOwnProperty(prop)) { |
|
|
|
const schema = SETTINGS_SCHEMA[prop]; |
|
|
|
|
|
this[prop] = options[prop] !== undefined ? (schema.processor |
|
? schema.processor(options[prop]) : options[prop]) |
|
: getDefaultValue(schema); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
reportNonstrict(errorCode: string, errorMsg: string, |
|
token?: Token | AnyParseNode) { |
|
let strict = this.strict; |
|
if (typeof strict === "function") { |
|
|
|
|
|
strict = strict(errorCode, errorMsg, token); |
|
} |
|
if (!strict || strict === "ignore") { |
|
return; |
|
} else if (strict === true || strict === "error") { |
|
throw new ParseError( |
|
"LaTeX-incompatible input and strict mode is set to 'error': " + |
|
`${errorMsg} [${errorCode}]`, token); |
|
} else if (strict === "warn") { |
|
typeof console !== "undefined" && console.warn( |
|
"LaTeX-incompatible input and strict mode is set to 'warn': " + |
|
`${errorMsg} [${errorCode}]`); |
|
} else { |
|
typeof console !== "undefined" && console.warn( |
|
"LaTeX-incompatible input and strict mode is set to " + |
|
`unrecognized '${strict}': ${errorMsg} [${errorCode}]`); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useStrictBehavior(errorCode: string, errorMsg: string, |
|
token?: Token | AnyParseNode): boolean { |
|
let strict = this.strict; |
|
if (typeof strict === "function") { |
|
|
|
|
|
|
|
|
|
try { |
|
strict = strict(errorCode, errorMsg, token); |
|
} catch (error) { |
|
strict = "error"; |
|
} |
|
} |
|
if (!strict || strict === "ignore") { |
|
return false; |
|
} else if (strict === true || strict === "error") { |
|
return true; |
|
} else if (strict === "warn") { |
|
typeof console !== "undefined" && console.warn( |
|
"LaTeX-incompatible input and strict mode is set to 'warn': " + |
|
`${errorMsg} [${errorCode}]`); |
|
return false; |
|
} else { |
|
typeof console !== "undefined" && console.warn( |
|
"LaTeX-incompatible input and strict mode is set to " + |
|
`unrecognized '${strict}': ${errorMsg} [${errorCode}]`); |
|
return false; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isTrusted(context: AnyTrustContext): boolean { |
|
if (context.url && !context.protocol) { |
|
const protocol = utils.protocolFromUrl(context.url); |
|
if (protocol == null) { |
|
return false; |
|
} |
|
context.protocol = protocol; |
|
} |
|
const trust = typeof this.trust === "function" |
|
? this.trust(context) |
|
: this.trust; |
|
return Boolean(trust); |
|
} |
|
} |
|
|