katex 0.16.44 → 0.16.46
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.
- package/README.md +3 -3
- package/contrib/copy-tex/README.md +2 -2
- package/contrib/mathtex-script-type/README.md +5 -5
- package/contrib/mathtex-script-type/mathtex-script-type.js +2 -1
- package/contrib/mhchem/README.md +1 -1
- package/contrib/render-a11y-string/render-a11y-string.ts +7 -5
- package/contrib/render-a11y-string/test/render-a11y-string-spec.ts +0 -1
- package/dist/README.md +3 -3
- package/dist/contrib/mathtex-script-type.js +2 -1
- package/dist/contrib/mathtex-script-type.min.js +1 -1
- package/dist/contrib/mathtex-script-type.mjs +2 -1
- package/dist/contrib/render-a11y-string.js +47 -8
- package/dist/contrib/render-a11y-string.min.js +1 -1
- package/dist/contrib/render-a11y-string.mjs +27 -2
- package/dist/katex-swap.css +5 -2
- package/dist/katex-swap.min.css +1 -1
- package/dist/katex.css +5 -2
- package/dist/katex.js +551 -345
- package/dist/katex.min.css +1 -1
- package/dist/katex.min.js +1 -1
- package/dist/katex.mjs +522 -348
- package/package.json +15 -15
- package/src/Options.ts +29 -28
- package/src/Parser.ts +12 -15
- package/src/Settings.ts +177 -60
- package/src/atoms.ts +33 -0
- package/src/buildCommon.ts +54 -46
- package/src/buildHTML.ts +4 -3
- package/src/buildMathML.ts +54 -47
- package/src/defineEnvironment.ts +1 -1
- package/src/defineFunction.ts +10 -3
- package/src/delimiter.ts +17 -13
- package/src/domTree.ts +28 -23
- package/src/environments/array.ts +12 -6
- package/src/environments/cd.ts +9 -2
- package/src/fontMetrics.ts +10 -23
- package/src/fontMetricsData.d.ts +6 -1
- package/src/functions/arrow.ts +4 -5
- package/src/functions/delimsizing.ts +22 -16
- package/src/functions/enclose.ts +6 -6
- package/src/functions/environment.ts +7 -2
- package/src/functions/font.ts +13 -8
- package/src/functions/hbox.ts +2 -2
- package/src/functions/horizBrace.ts +4 -6
- package/src/functions/math.ts +1 -0
- package/src/functions/op.ts +10 -5
- package/src/functions/smash.ts +1 -1
- package/src/functions/styling.ts +17 -5
- package/src/functions/supsub.ts +6 -3
- package/src/functions/text.ts +7 -3
- package/src/functions/vcenter.ts +3 -1
- package/src/parseNode.ts +7 -5
- package/src/stretchy.ts +14 -26
- package/src/styles/katex.scss +3 -1
- package/src/svgGeometry.ts +32 -27
- package/src/symbols.ts +11 -26
- package/src/tree.ts +11 -5
- package/src/types/fonts.ts +73 -0
- package/src/{types.ts → types/index.ts} +4 -10
- package/src/utils.ts +0 -1
- package/src/wide-character.ts +101 -55
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "katex",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.46",
|
|
4
4
|
"description": "Fast math typesetting for the web.",
|
|
5
5
|
"main": "dist/katex.js",
|
|
6
6
|
"types": "types/katex.d.ts",
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"packageManager": "yarn@4.1.1",
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@babel/core": "^7.29.0",
|
|
61
|
-
"@babel/eslint-parser": "^7.28.6",
|
|
62
61
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
63
62
|
"@babel/plugin-transform-react-jsx": "^7.28.6",
|
|
64
63
|
"@babel/plugin-transform-runtime": "^7.29.0",
|
|
@@ -67,13 +66,16 @@
|
|
|
67
66
|
"@babel/preset-typescript": "^7.28.5",
|
|
68
67
|
"@babel/register": "^7.28.6",
|
|
69
68
|
"@babel/runtime": "^7.28.6",
|
|
69
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
70
|
+
"@eslint/js": "^10.0.1",
|
|
70
71
|
"@rollup/plugin-babel": "^5.3.1",
|
|
71
72
|
"@rollup/plugin-commonjs": "^28.0.9",
|
|
72
73
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
73
74
|
"@semantic-release/changelog": "^6.0.1",
|
|
74
75
|
"@semantic-release/git": "^10.0.1",
|
|
75
|
-
"@
|
|
76
|
-
"@typescript-eslint/
|
|
76
|
+
"@stylistic/stylelint-plugin": "^5.1.0",
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
|
78
|
+
"@typescript-eslint/parser": "^8.59.1",
|
|
77
79
|
"babel-jest": "^30.2.0",
|
|
78
80
|
"babel-loader": "^8.2.5",
|
|
79
81
|
"babel-plugin-istanbul": "^6.1.1",
|
|
@@ -85,12 +87,11 @@
|
|
|
85
87
|
"caniuse-lite": "^1.0.30001384",
|
|
86
88
|
"css-loader": "^6.7.1",
|
|
87
89
|
"cssnano": "^5.1.13",
|
|
88
|
-
"eslint": "^
|
|
89
|
-
"eslint-import-resolver-webpack": "^0.13.10",
|
|
90
|
+
"eslint": "^10.0.3",
|
|
90
91
|
"eslint-plugin-actions": "^2.0.0",
|
|
91
|
-
"eslint-plugin-
|
|
92
|
-
"eslint-plugin-react": "^7.31.1",
|
|
92
|
+
"eslint-plugin-react": "^7.37.5",
|
|
93
93
|
"fs-extra": "^10.1.0",
|
|
94
|
+
"globals": "^17.6.0",
|
|
94
95
|
"got": "^11.8.5",
|
|
95
96
|
"husky": "^4.3.8",
|
|
96
97
|
"istanbul-lib-coverage": "^3.2.0",
|
|
@@ -113,7 +114,6 @@
|
|
|
113
114
|
"postcss-loader": "^7.0.1",
|
|
114
115
|
"postcss-preset-env": "^7.8.0",
|
|
115
116
|
"postcss-scss": "^4.0.9",
|
|
116
|
-
"prettier": "^2.7.1",
|
|
117
117
|
"rimraf": "^3.0.2",
|
|
118
118
|
"rollup": "^2.79.2",
|
|
119
119
|
"sass": "^1.94.2",
|
|
@@ -122,16 +122,16 @@
|
|
|
122
122
|
"semantic-release": "^19.0.5",
|
|
123
123
|
"sri-toolbox": "^0.2.0",
|
|
124
124
|
"style-loader": "^3.3.1",
|
|
125
|
-
"stylelint": "^
|
|
126
|
-
"stylelint-config-standard": "^
|
|
127
|
-
"stylelint-scss": "^
|
|
125
|
+
"stylelint": "^17.9.1",
|
|
126
|
+
"stylelint-config-standard": "^40.0.0",
|
|
127
|
+
"stylelint-scss": "^7.0.0",
|
|
128
128
|
"terser-webpack-plugin": "^5.3.6",
|
|
129
129
|
"tslib": "^2.8.1",
|
|
130
130
|
"typescript": "^5.9.3",
|
|
131
131
|
"webpack": "^5.74.0",
|
|
132
|
-
"webpack-bundle-analyzer": "^
|
|
133
|
-
"webpack-cli": "^
|
|
134
|
-
"webpack-dev-server": "^
|
|
132
|
+
"webpack-bundle-analyzer": "^5.0.0",
|
|
133
|
+
"webpack-cli": "^5.0.0",
|
|
134
|
+
"webpack-dev-server": "^5.0.0",
|
|
135
135
|
"webpack-remove-empty-scripts": "^1.0.4"
|
|
136
136
|
},
|
|
137
137
|
"bin": "cli.js",
|
package/src/Options.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {getGlobalMetrics} from "./fontMetrics";
|
|
9
|
-
import type {FontMetrics} from "./fontMetrics";
|
|
10
9
|
import type {StyleInterface} from "./Style";
|
|
10
|
+
import type {FontMetrics, MathFont, TextFont, FontWeight, FontShape} from "./types/fonts";
|
|
11
11
|
|
|
12
12
|
const sizeStyleMap = [
|
|
13
13
|
// Each element contains [textsize, scriptsize, scriptscriptsize].
|
|
@@ -35,18 +35,14 @@ const sizeAtStyle = function(size: number, style: StyleInterface): number {
|
|
|
35
35
|
return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1];
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
// In these types, "" (empty string) means "no change".
|
|
39
|
-
export type FontWeight = "textbf" | "textmd" | "";
|
|
40
|
-
export type FontShape = "textit" | "textup" | "";
|
|
41
|
-
|
|
42
38
|
export type OptionsData = {
|
|
43
39
|
style: StyleInterface;
|
|
44
40
|
color?: string | undefined;
|
|
45
41
|
size?: number;
|
|
46
42
|
textSize?: number;
|
|
47
43
|
phantom?: boolean;
|
|
48
|
-
font?:
|
|
49
|
-
fontFamily?:
|
|
44
|
+
font?: MathFont;
|
|
45
|
+
fontFamily?: TextFont;
|
|
50
46
|
fontWeight?: FontWeight;
|
|
51
47
|
fontShape?: FontShape;
|
|
52
48
|
sizeMultiplier?: number;
|
|
@@ -70,8 +66,8 @@ class Options {
|
|
|
70
66
|
// A font family applies to a group of fonts (i.e. SansSerif), while a font
|
|
71
67
|
// represents a specific font (i.e. SansSerif Bold).
|
|
72
68
|
// See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
|
|
73
|
-
font:
|
|
74
|
-
fontFamily:
|
|
69
|
+
font: MathFont;
|
|
70
|
+
fontFamily: TextFont;
|
|
75
71
|
fontWeight: FontWeight;
|
|
76
72
|
fontShape: FontShape;
|
|
77
73
|
sizeMultiplier: number;
|
|
@@ -92,8 +88,8 @@ class Options {
|
|
|
92
88
|
this.phantom = !!data.phantom;
|
|
93
89
|
this.font = data.font || "";
|
|
94
90
|
this.fontFamily = data.fontFamily || "";
|
|
95
|
-
this.fontWeight = data.fontWeight ||
|
|
96
|
-
this.fontShape = data.fontShape ||
|
|
91
|
+
this.fontWeight = data.fontWeight || "";
|
|
92
|
+
this.fontShape = data.fontShape || "";
|
|
97
93
|
this.sizeMultiplier = sizeMultipliers[this.size - 1];
|
|
98
94
|
this.maxSize = data.maxSize;
|
|
99
95
|
this.minRuleThickness = data.minRuleThickness;
|
|
@@ -171,8 +167,11 @@ class Options {
|
|
|
171
167
|
havingBaseStyle(style: StyleInterface): Options {
|
|
172
168
|
style = style || this.style.text();
|
|
173
169
|
const wantSize = sizeAtStyle(Options.BASESIZE, style);
|
|
174
|
-
if (
|
|
175
|
-
|
|
170
|
+
if (
|
|
171
|
+
this.size === wantSize &&
|
|
172
|
+
this.textSize === Options.BASESIZE &&
|
|
173
|
+
this.style === style
|
|
174
|
+
) {
|
|
176
175
|
return this;
|
|
177
176
|
} else {
|
|
178
177
|
return this.extend({
|
|
@@ -191,14 +190,14 @@ class Options {
|
|
|
191
190
|
switch (this.style.id) {
|
|
192
191
|
case 4:
|
|
193
192
|
case 5:
|
|
194
|
-
size = 3;
|
|
193
|
+
size = 3; // normalsize in scriptstyle
|
|
195
194
|
break;
|
|
196
195
|
case 6:
|
|
197
196
|
case 7:
|
|
198
|
-
size = 1;
|
|
197
|
+
size = 1; // normalsize in scriptscriptstyle
|
|
199
198
|
break;
|
|
200
199
|
default:
|
|
201
|
-
size = 6;
|
|
200
|
+
size = 6; // normalsize in textstyle or displaystyle
|
|
202
201
|
}
|
|
203
202
|
return this.extend({
|
|
204
203
|
style: this.style.text(),
|
|
@@ -228,20 +227,15 @@ class Options {
|
|
|
228
227
|
* Creates a new options object with the given math font or old text font.
|
|
229
228
|
* @type {[type]}
|
|
230
229
|
*/
|
|
231
|
-
withFont(font:
|
|
232
|
-
return this.extend({
|
|
233
|
-
font,
|
|
234
|
-
});
|
|
230
|
+
withFont(font: MathFont): Options {
|
|
231
|
+
return this.extend({font});
|
|
235
232
|
}
|
|
236
233
|
|
|
237
234
|
/**
|
|
238
235
|
* Create a new options objects with the given fontFamily.
|
|
239
236
|
*/
|
|
240
|
-
withTextFontFamily(fontFamily:
|
|
241
|
-
return this.extend({
|
|
242
|
-
fontFamily,
|
|
243
|
-
font: "",
|
|
244
|
-
});
|
|
237
|
+
withTextFontFamily(fontFamily: TextFont): Options {
|
|
238
|
+
return this.extend({fontFamily, font: ""});
|
|
245
239
|
}
|
|
246
240
|
|
|
247
241
|
/**
|
|
@@ -270,7 +264,11 @@ class Options {
|
|
|
270
264
|
*/
|
|
271
265
|
sizingClasses(oldOptions: Options): Array<string> {
|
|
272
266
|
if (oldOptions.size !== this.size) {
|
|
273
|
-
return [
|
|
267
|
+
return [
|
|
268
|
+
"sizing",
|
|
269
|
+
"reset-size" + oldOptions.size,
|
|
270
|
+
"size" + this.size,
|
|
271
|
+
];
|
|
274
272
|
} else {
|
|
275
273
|
return [];
|
|
276
274
|
}
|
|
@@ -282,7 +280,11 @@ class Options {
|
|
|
282
280
|
*/
|
|
283
281
|
baseSizingClasses(): Array<string> {
|
|
284
282
|
if (this.size !== Options.BASESIZE) {
|
|
285
|
-
return [
|
|
283
|
+
return [
|
|
284
|
+
"sizing",
|
|
285
|
+
"reset-size" + this.size,
|
|
286
|
+
"size" + Options.BASESIZE,
|
|
287
|
+
];
|
|
286
288
|
} else {
|
|
287
289
|
return [];
|
|
288
290
|
}
|
|
@@ -298,7 +300,6 @@ class Options {
|
|
|
298
300
|
return this._fontMetrics;
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
|
|
302
303
|
/**
|
|
303
304
|
* Gets the CSS color of the current options object
|
|
304
305
|
*/
|
package/src/Parser.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint no-constant-condition:0 */
|
|
2
2
|
import functions from "./functions";
|
|
3
3
|
import MacroExpander, {implicitCommands} from "./MacroExpander";
|
|
4
|
-
import symbols, {
|
|
4
|
+
import symbols, {extraLatin} from "./symbols";
|
|
5
|
+
import {isAtom} from "./atoms";
|
|
5
6
|
import {validUnit} from "./units";
|
|
6
7
|
import {supportedCodepoint} from "./unicodeScripts";
|
|
7
8
|
import ParseError from "./ParseError";
|
|
@@ -15,9 +16,9 @@ import {Token} from "./Token";
|
|
|
15
16
|
import unicodeAccents from /*preval*/ "./unicodeAccents";
|
|
16
17
|
import unicodeSymbols from /*preval*/ "./unicodeSymbols";
|
|
17
18
|
|
|
18
|
-
import type {ParseNode, AnyParseNode, SymbolParseNode,
|
|
19
|
-
from "./parseNode";
|
|
20
|
-
import type {
|
|
19
|
+
import type {NodeType, ParseNode, AnyParseNode, SymbolParseNode,
|
|
20
|
+
UnsupportedCmdParseNode} from "./parseNode";
|
|
21
|
+
import type {Group} from "./atoms";
|
|
21
22
|
import type {Mode, ArgType, BreakToken} from "./types";
|
|
22
23
|
import type {FunctionContext, FunctionSpec} from "./defineFunction";
|
|
23
24
|
import type {EnvSpec} from "./defineEnvironment";
|
|
@@ -521,7 +522,7 @@ export default class Parser {
|
|
|
521
522
|
*/
|
|
522
523
|
parseArguments(
|
|
523
524
|
func: string, // Should look like "\name" or "\begin{name}".
|
|
524
|
-
funcData: FunctionSpec<
|
|
525
|
+
funcData: FunctionSpec<NodeType> | EnvSpec<NodeType>,
|
|
525
526
|
): {
|
|
526
527
|
args: AnyParseNode[];
|
|
527
528
|
optArgs: (AnyParseNode | null | undefined)[];
|
|
@@ -579,13 +580,15 @@ export default class Parser {
|
|
|
579
580
|
return this.parseArgumentGroup(optional, type);
|
|
580
581
|
case "hbox": {
|
|
581
582
|
// hbox argument type wraps the argument in the equivalent of
|
|
582
|
-
// \hbox, which is like \text but switching to \textstyle size
|
|
583
|
+
// \hbox, which is like \text but switching to \textstyle size
|
|
584
|
+
// and resetting math font.
|
|
583
585
|
const group = this.parseArgumentGroup(optional, "text");
|
|
584
586
|
return group != null ? {
|
|
585
587
|
type: "styling",
|
|
586
588
|
mode: group.mode,
|
|
587
589
|
body: [group],
|
|
588
590
|
style: "text", // simulate \textstyle
|
|
591
|
+
resetFont: true,
|
|
589
592
|
} : null;
|
|
590
593
|
}
|
|
591
594
|
case "raw": {
|
|
@@ -974,26 +977,22 @@ export default class Parser {
|
|
|
974
977
|
const group: Group = symbols[this.mode][text].group;
|
|
975
978
|
const loc = SourceLocation.range(nucleus);
|
|
976
979
|
let s: SymbolParseNode;
|
|
977
|
-
if (
|
|
978
|
-
// TODO(ts)
|
|
979
|
-
const family = group as Atom;
|
|
980
|
+
if (isAtom(group)) {
|
|
980
981
|
s = {
|
|
981
982
|
type: "atom",
|
|
982
983
|
mode: this.mode,
|
|
983
|
-
family,
|
|
984
|
+
family: group,
|
|
984
985
|
loc,
|
|
985
986
|
text,
|
|
986
987
|
};
|
|
987
988
|
} else {
|
|
988
|
-
// TODO(ts)
|
|
989
989
|
s = {
|
|
990
|
-
type: group
|
|
990
|
+
type: group,
|
|
991
991
|
mode: this.mode,
|
|
992
992
|
loc,
|
|
993
993
|
text,
|
|
994
994
|
};
|
|
995
995
|
}
|
|
996
|
-
// TODO(ts)
|
|
997
996
|
symbol = s;
|
|
998
997
|
} else if (text.charCodeAt(0) >= 0x80) { // no symbol for e.g. ^
|
|
999
998
|
if (this.settings.strict) {
|
|
@@ -1045,12 +1044,10 @@ export default class Parser {
|
|
|
1045
1044
|
label: command,
|
|
1046
1045
|
isStretchy: false,
|
|
1047
1046
|
isShifty: true,
|
|
1048
|
-
// TODO(ts)
|
|
1049
1047
|
base: symbol,
|
|
1050
1048
|
};
|
|
1051
1049
|
}
|
|
1052
1050
|
}
|
|
1053
|
-
// TODO(ts)
|
|
1054
1051
|
return symbol;
|
|
1055
1052
|
}
|
|
1056
1053
|
}
|
package/src/Settings.ts
CHANGED
|
@@ -52,56 +52,144 @@ export type AnyTrustContext = TrustContextTypes[keyof TrustContextTypes];
|
|
|
52
52
|
export type TrustFunction = (context: AnyTrustContext) => boolean | null | undefined;
|
|
53
53
|
export type SettingsOptions = Partial<Settings>;
|
|
54
54
|
|
|
55
|
-
type EnumType = {
|
|
56
|
-
enum:
|
|
55
|
+
type EnumType<T extends string = string> = {
|
|
56
|
+
enum: T[];
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
type Type = "boolean" | "string" | "number" | "object" | "function" | EnumType;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Union of all values that appear as schema defaults, cliDefaults, or
|
|
62
|
+
* cliProcessor return values. StrictFunction / TrustFunction are
|
|
63
|
+
* option-value types, not default/schema values, so they are excluded.
|
|
64
|
+
*/
|
|
65
|
+
type SettingsValue = boolean | string | number | MacroMap | string[];
|
|
66
|
+
type DefaultValue = Exclude<SettingsValue, string[]>;
|
|
67
|
+
|
|
68
|
+
type SchemaMetadata<K extends keyof SettingsOptions> = {
|
|
69
|
+
/**
|
|
70
|
+
* The description.
|
|
71
|
+
*/
|
|
72
|
+
description?: string;
|
|
73
|
+
/**
|
|
74
|
+
* The function to process the option.
|
|
75
|
+
*/
|
|
76
|
+
processor?: (value: Settings[K]) => Settings[K];
|
|
77
|
+
/**
|
|
78
|
+
* The command line argument. See Commander.js docs for more information.
|
|
79
|
+
* If not specified, the name prefixed with -- will be used. Set false not
|
|
80
|
+
* to add to the CLI.
|
|
81
|
+
*/
|
|
82
|
+
cli?: string | false;
|
|
83
|
+
/**
|
|
84
|
+
* The default value for the CLI.
|
|
85
|
+
*/
|
|
86
|
+
cliDefault?: SettingsValue;
|
|
87
|
+
/**
|
|
88
|
+
* The description for the CLI. If not specified, the description for the
|
|
89
|
+
* option will be used.
|
|
90
|
+
*/
|
|
91
|
+
cliDescription?: string;
|
|
92
|
+
/**
|
|
93
|
+
* The custom argument processor for the CLI. See Commander.js docs for
|
|
94
|
+
* more information. Signature varies per setting (e.g. parseFloat,
|
|
95
|
+
* or (def, defs) => defs.push(def) for macros).
|
|
96
|
+
*/
|
|
97
|
+
cliProcessor?: (...args: any[]) => SettingsValue;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
type BooleanSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
101
|
+
/**
|
|
102
|
+
* Allowed type(s) of the value.
|
|
103
|
+
*/
|
|
104
|
+
type: "boolean";
|
|
105
|
+
/**
|
|
106
|
+
* The default value. If not specified, false will be used.
|
|
107
|
+
*/
|
|
108
|
+
default?: Extract<Settings[K], boolean>;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
type StringSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
112
|
+
/**
|
|
113
|
+
* Allowed type(s) of the value.
|
|
114
|
+
*/
|
|
115
|
+
type: "string";
|
|
116
|
+
/**
|
|
117
|
+
* The default value. If not specified, an empty string will be used.
|
|
118
|
+
*/
|
|
119
|
+
default?: Extract<Settings[K], string>;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type NumberSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
123
|
+
/**
|
|
124
|
+
* Allowed type(s) of the value.
|
|
125
|
+
*/
|
|
126
|
+
type: "number";
|
|
127
|
+
/**
|
|
128
|
+
* The default value. If not specified, 0 will be used.
|
|
129
|
+
*/
|
|
130
|
+
default?: Extract<Settings[K], number>;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
type ObjectSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
134
|
+
/**
|
|
135
|
+
* Allowed type(s) of the value.
|
|
136
|
+
*/
|
|
137
|
+
type: "object";
|
|
138
|
+
/**
|
|
139
|
+
* The default value. If not specified, an empty object will be used.
|
|
140
|
+
*/
|
|
141
|
+
default?: Extract<Settings[K], MacroMap>;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
type FunctionSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
145
|
+
/**
|
|
146
|
+
* Allowed type(s) of the value.
|
|
147
|
+
*/
|
|
148
|
+
type: "function";
|
|
149
|
+
/**
|
|
150
|
+
* Settings do not currently use function-valued defaults.
|
|
151
|
+
*/
|
|
152
|
+
default?: never;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
type EnumSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
156
|
+
/**
|
|
157
|
+
* Allowed type(s) of the value.
|
|
158
|
+
*/
|
|
159
|
+
type: EnumType<Extract<Settings[K], string>>;
|
|
160
|
+
/**
|
|
161
|
+
* The default value. If not specified, the first enum value will be used.
|
|
162
|
+
*/
|
|
163
|
+
default?: Extract<Settings[K], string>;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
type SingleTypeSchema<K extends keyof SettingsOptions> =
|
|
167
|
+
| BooleanSchema<K>
|
|
168
|
+
| StringSchema<K>
|
|
169
|
+
| NumberSchema<K>
|
|
170
|
+
| ObjectSchema<K>
|
|
171
|
+
| FunctionSchema<K>
|
|
172
|
+
| EnumSchema<K>;
|
|
173
|
+
|
|
174
|
+
type MultiTypeSchema<K extends keyof SettingsOptions> = SchemaMetadata<K> & {
|
|
175
|
+
/**
|
|
176
|
+
* Allowed type(s) of the value.
|
|
177
|
+
*/
|
|
178
|
+
type: [SingleTypeSchema<K>["type"], ...Array<SingleTypeSchema<K>["type"]>];
|
|
179
|
+
/**
|
|
180
|
+
* The default value. If not specified, the first allowed type determines
|
|
181
|
+
* the default value.
|
|
182
|
+
*/
|
|
183
|
+
default?: Extract<Settings[K], DefaultValue>;
|
|
102
184
|
};
|
|
103
185
|
|
|
104
|
-
type SchemaEntry
|
|
186
|
+
type SchemaEntry<K extends keyof SettingsOptions> =
|
|
187
|
+
| SingleTypeSchema<K>
|
|
188
|
+
| MultiTypeSchema<K>;
|
|
189
|
+
|
|
190
|
+
type Schema = {
|
|
191
|
+
[key in keyof SettingsOptions]?: SchemaEntry<key>;
|
|
192
|
+
};
|
|
105
193
|
|
|
106
194
|
// TODO: automatically generate documentation
|
|
107
195
|
// TODO: check all properties on Settings exist
|
|
@@ -208,16 +296,18 @@ export const SETTINGS_SCHEMA: Schema = {
|
|
|
208
296
|
},
|
|
209
297
|
};
|
|
210
298
|
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
299
|
+
function getImplicitDefault(type: "boolean"): boolean;
|
|
300
|
+
function getImplicitDefault(type: "string"): string;
|
|
301
|
+
function getImplicitDefault(type: "number"): number;
|
|
302
|
+
function getImplicitDefault(type: "object"): MacroMap;
|
|
303
|
+
function getImplicitDefault(type: "function"): never;
|
|
304
|
+
function getImplicitDefault<T extends string>(type: EnumType<T>): T;
|
|
305
|
+
function getImplicitDefault(type: Type): DefaultValue;
|
|
306
|
+
function getImplicitDefault(type: Type): DefaultValue {
|
|
307
|
+
if (typeof type !== 'string') {
|
|
308
|
+
return type.enum[0];
|
|
219
309
|
}
|
|
220
|
-
switch (
|
|
310
|
+
switch (type) {
|
|
221
311
|
case 'boolean':
|
|
222
312
|
return false;
|
|
223
313
|
case 'string':
|
|
@@ -226,9 +316,37 @@ function getDefaultValue(schema: SchemaEntry): any {
|
|
|
226
316
|
return 0;
|
|
227
317
|
case 'object':
|
|
228
318
|
return {};
|
|
319
|
+
default:
|
|
320
|
+
throw new Error(
|
|
321
|
+
"Unexpected schema type; settings must declare an explicit default.");
|
|
229
322
|
}
|
|
230
323
|
}
|
|
231
324
|
|
|
325
|
+
function getDefaultValue<K extends keyof SettingsOptions>(
|
|
326
|
+
schema: SchemaEntry<K>,
|
|
327
|
+
): Settings[K];
|
|
328
|
+
function getDefaultValue(schema: SchemaEntry<keyof SettingsOptions>): DefaultValue {
|
|
329
|
+
if (schema.default !== undefined) {
|
|
330
|
+
return schema.default;
|
|
331
|
+
}
|
|
332
|
+
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
333
|
+
return getImplicitDefault(type);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function applySetting<K extends keyof SettingsOptions>(
|
|
337
|
+
target: Settings,
|
|
338
|
+
prop: K,
|
|
339
|
+
options: SettingsOptions,
|
|
340
|
+
schema: SchemaEntry<K>,
|
|
341
|
+
) {
|
|
342
|
+
const optionValue = options[prop];
|
|
343
|
+
target[prop] = optionValue !== undefined
|
|
344
|
+
? (schema.processor
|
|
345
|
+
? schema.processor(optionValue)
|
|
346
|
+
: optionValue)
|
|
347
|
+
: getDefaultValue(schema);
|
|
348
|
+
}
|
|
349
|
+
|
|
232
350
|
/**
|
|
233
351
|
* The main Settings object
|
|
234
352
|
*
|
|
@@ -259,12 +377,11 @@ export default class Settings {
|
|
|
259
377
|
// allow null options
|
|
260
378
|
options = options || {};
|
|
261
379
|
for (const prop of Object.keys(SETTINGS_SCHEMA) as Array<keyof SettingsOptions>) {
|
|
262
|
-
const schema = SETTINGS_SCHEMA[prop] as SchemaEntry;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
: getDefaultValue(schema);
|
|
380
|
+
const schema = SETTINGS_SCHEMA[prop] as SchemaEntry<typeof prop> | undefined;
|
|
381
|
+
if (schema) {
|
|
382
|
+
// TODO: validate options
|
|
383
|
+
applySetting(this, prop, options, schema);
|
|
384
|
+
}
|
|
268
385
|
}
|
|
269
386
|
}
|
|
270
387
|
|
package/src/atoms.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small module for atom-group constants and type guard. Kept separate from
|
|
3
|
+
* `symbols.ts` so that consumers (notably `contrib/render-a11y-string`) can
|
|
4
|
+
* pull in `isAtom` without dragging in the ~870-line symbol tables.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Some of these have a "-token" suffix since these are also used as `ParseNode`
|
|
8
|
+
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
|
9
|
+
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
|
10
|
+
// looking up the `symbols` map.
|
|
11
|
+
export const ATOMS = {
|
|
12
|
+
"bin": 1,
|
|
13
|
+
"close": 1,
|
|
14
|
+
"inner": 1,
|
|
15
|
+
"open": 1,
|
|
16
|
+
"punct": 1,
|
|
17
|
+
"rel": 1,
|
|
18
|
+
};
|
|
19
|
+
export const NON_ATOMS = {
|
|
20
|
+
"accent-token": 1,
|
|
21
|
+
"mathord": 1,
|
|
22
|
+
"op-token": 1,
|
|
23
|
+
"spacing": 1,
|
|
24
|
+
"textord": 1,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type Atom = keyof typeof ATOMS;
|
|
28
|
+
export type NonAtom = keyof typeof NON_ATOMS;
|
|
29
|
+
export type Group = Atom | NonAtom;
|
|
30
|
+
|
|
31
|
+
export function isAtom(value: string): value is Atom {
|
|
32
|
+
return value in ATOMS;
|
|
33
|
+
}
|