desmost 0.9.0 → 0.10.0

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.
Files changed (104) hide show
  1. package/README.md +87 -11
  2. package/dist/compiler/compile.d.ts +1 -7
  3. package/dist/compiler/compile.d.ts.map +1 -1
  4. package/dist/compiler/compile.js +3 -94
  5. package/dist/compiler/compile.js.map +1 -1
  6. package/dist/compiler/compiler.d.ts +56 -0
  7. package/dist/compiler/compiler.d.ts.map +1 -0
  8. package/dist/compiler/compiler.js +209 -0
  9. package/dist/compiler/compiler.js.map +1 -0
  10. package/dist/compiler/format.d.ts +2 -2
  11. package/dist/compiler/format.d.ts.map +1 -1
  12. package/dist/compiler/format.js +18 -9
  13. package/dist/compiler/format.js.map +1 -1
  14. package/dist/decompiler/decompile.d.ts +1 -1
  15. package/dist/decompiler/decompile.d.ts.map +1 -1
  16. package/dist/decompiler/decompile.js +1 -3
  17. package/dist/decompiler/decompile.js.map +1 -1
  18. package/dist/decompiler/extract.d.ts.map +1 -1
  19. package/dist/decompiler/extract.js +7 -3
  20. package/dist/decompiler/extract.js.map +1 -1
  21. package/dist/decompiler/format.d.ts.map +1 -1
  22. package/dist/decompiler/format.js +0 -1
  23. package/dist/decompiler/format.js.map +1 -1
  24. package/dist/errors.d.ts +35 -27
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +46 -48
  27. package/dist/errors.js.map +1 -1
  28. package/dist/index.internal.d.ts +1 -1
  29. package/dist/index.internal.d.ts.map +1 -1
  30. package/dist/magic/global/desmos.d.ts +2 -2
  31. package/dist/magic/global/desmos.d.ts.map +1 -1
  32. package/dist/magic/global/desmos.js +3 -2
  33. package/dist/magic/global/desmos.js.map +1 -1
  34. package/dist/magic/global/viewport.d.ts +2 -2
  35. package/dist/magic/global/viewport.d.ts.map +1 -1
  36. package/dist/magic/global/viewport.js +5 -5
  37. package/dist/magic/global/viewport.js.map +1 -1
  38. package/dist/magic/incantation.d.ts +4 -4
  39. package/dist/magic/incantation.d.ts.map +1 -1
  40. package/dist/magic/incantation.js +15 -8
  41. package/dist/magic/incantation.js.map +1 -1
  42. package/dist/magic/local/colour.d.ts +3 -1
  43. package/dist/magic/local/colour.d.ts.map +1 -1
  44. package/dist/magic/local/colour.js +15 -11
  45. package/dist/magic/local/colour.js.map +1 -1
  46. package/dist/magic/local/label.d.ts +2 -2
  47. package/dist/magic/local/label.d.ts.map +1 -1
  48. package/dist/magic/local/label.js +8 -7
  49. package/dist/magic/local/label.js.map +1 -1
  50. package/dist/magic/local/line.d.ts +2 -2
  51. package/dist/magic/local/line.d.ts.map +1 -1
  52. package/dist/magic/local/line.js +0 -1
  53. package/dist/magic/local/line.js.map +1 -1
  54. package/dist/options.d.ts +59 -27
  55. package/dist/options.d.ts.map +1 -1
  56. package/dist/options.js +2 -1
  57. package/dist/options.js.map +1 -1
  58. package/dist/parser/ast.d.ts +3 -17
  59. package/dist/parser/ast.d.ts.map +1 -1
  60. package/dist/parser/ast.js +0 -2
  61. package/dist/parser/ast.js.map +1 -1
  62. package/dist/parser/desmost-parser.d.ts +33 -22
  63. package/dist/parser/desmost-parser.d.ts.map +1 -1
  64. package/dist/parser/desmost-parser.js +106 -92
  65. package/dist/parser/desmost-parser.js.map +1 -1
  66. package/dist/parser/generic-parser.d.ts +19 -10
  67. package/dist/parser/generic-parser.d.ts.map +1 -1
  68. package/dist/parser/generic-parser.js +56 -16
  69. package/dist/parser/generic-parser.js.map +1 -1
  70. package/dist/utils.d.ts +9 -2
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +13 -2
  73. package/dist/utils.js.map +1 -1
  74. package/package.json +4 -3
  75. package/src/compiler/compile.ts +7 -120
  76. package/src/compiler/compiler.ts +275 -0
  77. package/src/compiler/format.ts +19 -7
  78. package/src/decompiler/decompile.ts +1 -7
  79. package/src/decompiler/extract.ts +3 -1
  80. package/src/decompiler/format.ts +0 -1
  81. package/src/errors.ts +40 -24
  82. package/src/index.internal.ts +1 -1
  83. package/src/magic/.template.ts +2 -2
  84. package/src/magic/global/desmos.ts +7 -9
  85. package/src/magic/global/viewport.ts +11 -17
  86. package/src/magic/incantation.ts +21 -22
  87. package/src/magic/local/colour.ts +23 -13
  88. package/src/magic/local/label.ts +14 -19
  89. package/src/magic/local/line.ts +2 -2
  90. package/src/options.ts +83 -51
  91. package/src/parser/ast.ts +1 -21
  92. package/src/parser/desmost-parser.ts +131 -135
  93. package/src/parser/generic-parser.ts +71 -29
  94. package/src/utils.ts +25 -3
  95. package/dist/compiler/evaluate.d.ts +0 -18
  96. package/dist/compiler/evaluate.d.ts.map +0 -1
  97. package/dist/compiler/evaluate.js +0 -93
  98. package/dist/compiler/evaluate.js.map +0 -1
  99. package/dist/desmos.d.ts +0 -16
  100. package/dist/desmos.d.ts.map +0 -1
  101. package/dist/desmos.js +0 -19
  102. package/dist/desmos.js.map +0 -1
  103. package/src/compiler/evaluate.ts +0 -128
  104. package/src/desmos.ts +0 -22
@@ -1,5 +1,5 @@
1
1
  export { DEFAULT_OPTIONS } from "./options";
2
- export type { DesmostDebug } from "./compiler/compile";
2
+ export type { DesmostDebug } from "./compiler/compiler";
3
3
 
4
4
  export { Ast } from "./parser";
5
5
 
@@ -1,7 +1,7 @@
1
1
  // import { Incantation, ArgIncantation, type GLOBAL, type LOCAL, type EXPR } from "../incantation";
2
2
 
3
3
  // import type { DesmostOptions } from "../../options";
4
- // import { UnrecoverableError, type Unrecoverable } from "../../errors";
4
+ // import { DesmostError, type Fallible } from "../../errors";
5
5
 
6
6
 
7
7
  // export class ?Incantation extends ArgIncantation<?>
@@ -18,7 +18,7 @@
18
18
  // // TODO
19
19
  // }
20
20
 
21
- // override evaluate_arg(raw: ?, options: DesmostOptions): Unrecoverable<?>
21
+ // override evaluate_arg(raw: ?, options: DesmostOptions): Fallible<?>
22
22
  // {
23
23
  // let out = super.evaluate_arg(raw, options) as ?;
24
24
 
@@ -1,6 +1,6 @@
1
1
  import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
2
2
 
3
- import { UnrecoverableError, type Unrecoverable } from "../../errors";
3
+ import { DesmostError, type Fallible } from "../../errors";
4
4
  import type { DesmostOptions } from "../../options";
5
5
 
6
6
 
@@ -26,19 +26,17 @@ export class DesmosIncantation extends ArgIncantation<GLOBAL>
26
26
  }
27
27
  }
28
28
 
29
- override evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<DesmosSettings>
29
+ override evaluate_arg(raw: string, options: DesmostOptions): Fallible<DesmosSettings>
30
30
  {
31
31
  let out = super.evaluate_arg(raw, options) as DesmosSettings;
32
32
 
33
33
  if (options.check_args) {
34
34
  if (Object.keys(out).length === 0) {
35
- throw new UnrecoverableError.MissingInput(
36
- `/${this.identifier} received empty settings`,
37
- {
38
- hint: `Provide settings like \`/desmos{expressionsCollapsed: true}\``,
39
- note: `Use just /desmos (without \`{}\`) if you want it as an indicator`,
40
- }
41
- );
35
+ throw new DesmostError.MissingInput({
36
+ msg: `/desmos received empty settings`,
37
+ hint: `Provide settings like \`/desmos{expressionsCollapsed: true}\``,
38
+ note: `Use just /desmos (without \`{}\`) if you want it as an indicator`,
39
+ });
42
40
  }
43
41
  }
44
42
 
@@ -1,6 +1,6 @@
1
1
  import { Incantation, ArgIncantation, type GLOBAL } from "../incantation";
2
2
 
3
- import { UnrecoverableError, type Unrecoverable } from "../../errors";
3
+ import { DesmostError, type Fallible } from "../../errors";
4
4
  import type { DesmostOptions } from "../../options";
5
5
 
6
6
 
@@ -36,20 +36,17 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
36
36
  target.setMathBounds({ left, right, bottom, top });
37
37
  }
38
38
 
39
- override evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<ViewportBounds>
39
+ override evaluate_arg(raw: string, options: DesmostOptions): Fallible<ViewportBounds>
40
40
  {
41
41
  let out = super.evaluate_arg(raw, options) as ViewportBounds;
42
42
 
43
43
  if (options.check_args) {
44
44
  if (Object.keys(out).length === 0) {
45
- throw new UnrecoverableError.InvalidArgument(
46
- `/${this.identifier} received empty viewport bounds`,
47
- {
48
- hint: `Provide bounds like \`/viewport{left: -8, right: 8}\``,
49
- note: `Missing bounds are kept as their defaults`,
50
- flagged_by: "check_args",
51
- }
52
- );
45
+ throw new DesmostError.InvalidArgument({
46
+ msg: `/${this.identifier} received empty viewport bounds`,
47
+ hint: `Provide bounds like \`/viewport{left: -8, right: 8}\``,
48
+ note: `Missing bounds are kept as their defaults`,
49
+ });
53
50
  }
54
51
 
55
52
  let invalid_keys = Object.keys(out).filter(key => !VALID_KEYS.includes(key));
@@ -57,13 +54,10 @@ export class ViewportIncantation extends ArgIncantation<GLOBAL>
57
54
  if (invalid_keys.length > 0) {
58
55
  let plural = invalid_keys.length > 1 ? "fields" : "field";
59
56
 
60
- throw new UnrecoverableError.InvalidArgument(
61
- `/${this.identifier} received invalid ${plural}: [${invalid_keys.join(", ")}]`,
62
- {
63
- hint: `Valid fields are: [${VALID_KEYS.join(", ")}]`,
64
- flagged_by: "check_args",
65
- }
66
- );
57
+ throw new DesmostError.InvalidArgument({
58
+ msg: `/${this.identifier} received invalid ${plural}: [${invalid_keys.join(", ")}]`,
59
+ hint: `Valid fields are: [${VALID_KEYS.join(", ")}]`,
60
+ });
67
61
  }
68
62
  }
69
63
 
@@ -2,7 +2,7 @@ import Json5 from "json5";
2
2
  import dedent from "dedent";
3
3
 
4
4
  import type { DesmostOptions } from "../options";
5
- import { UnrecoverableError, type Unrecoverable } from "../errors";
5
+ import { DesmostError, type Fallible } from "../errors";
6
6
 
7
7
 
8
8
  /**
@@ -46,9 +46,11 @@ export abstract class Incantation<
46
46
  {
47
47
  if ((actual ?? "expression") !== required)
48
48
  {
49
- throw new UnrecoverableError.IllegalIncantation(
50
- `/${this.identifier} can only applied to ${required === "expression" ? "latex" : required} blocks, but target block has type: ${actual}`
51
- );
49
+ let req = required === "expression" ? "latex" : required;
50
+
51
+ throw new DesmostError.IllegalIncantation({
52
+ msg: `/${this.identifier} can only applied to ${req} blocks, but target block has type: ${actual}`,
53
+ });
52
54
  }
53
55
  }
54
56
  }
@@ -80,7 +82,7 @@ export abstract class ArgIncantation<
80
82
  *
81
83
  * Validity checks for missing or invalid values, incorrect types, and unknown fields should be performed here, so that `.apply()` can assume the data it receives is guaranteed to be valid.
82
84
  */
83
- evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<unknown>
85
+ evaluate_arg(raw: string, options: DesmostOptions): Fallible<unknown>
84
86
  {
85
87
  switch (this.arg_type) {
86
88
  case Incantation.ArgType.LATEX: return raw;
@@ -95,7 +97,7 @@ export abstract class ArgIncantation<
95
97
  }
96
98
  catch (e) {
97
99
  // @ts-expect-error: fine
98
- throw new UnrecoverableError.InvalidArgument(e.message);
100
+ throw new DesmostError.InvalidArgument({ msg: e.message });
99
101
  }
100
102
  }
101
103
  }
@@ -103,34 +105,31 @@ export abstract class ArgIncantation<
103
105
 
104
106
  protected require_nonempty(
105
107
  arg: object,
106
- msg?: string,
107
- info?: UnrecoverableError.Info,
108
- ): Unrecoverable<void>
108
+ error_data?: DesmostError.Data,
109
+ ): Fallible<void>
109
110
  {
110
111
  if (Object.entries(arg).length === 0) {
111
- throw new UnrecoverableError.MissingInput(
112
- msg ?? `/${this.identifier} received an empty argument {}`,
113
- info,
114
- );
112
+ throw new DesmostError.MissingInput({
113
+ msg: `/${this.identifier} received an empty argument {}`,
114
+ ...error_data
115
+ });
115
116
  }
116
117
  }
117
118
 
118
119
  protected require_known(
119
120
  arg: object,
120
121
  valid_fields: string[],
121
- info?: UnrecoverableError.Info,
122
- ): Unrecoverable<void>
122
+ error_data?: DesmostError.Data,
123
+ ): Fallible<void>
123
124
  {
124
125
  // TODO accumulate
125
126
  for (let field of Object.keys(arg)) {
126
127
  if (!valid_fields.includes(field)) {
127
- throw new UnrecoverableError.InvalidArgument(
128
- `/${this.identifier} received invalid field: ${field}`,
129
- {
130
- hint: `Valid fields are [${valid_fields.join(", ")}]`,
131
- ...info,
132
- }
133
- );
128
+ throw new DesmostError.InvalidArgument({
129
+ msg: `/${this.identifier} received invalid field: ${field}`,
130
+ hint: `Valid fields are [${valid_fields.join(", ")}]`,
131
+ ...error_data,
132
+ });
134
133
  }
135
134
  }
136
135
  }
@@ -1,10 +1,15 @@
1
1
  import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
2
2
 
3
- import { DesmosColour } from "../../desmos";
4
- import { UnrecoverableError } from "../../errors";
3
+ import { DesmostError } from "../../errors";
5
4
  import type { DesmostOptions } from "../../options";
6
5
 
7
6
 
7
+ type DesmosColourName = keyof typeof Desmos.Colors;
8
+ type DesmosColour = (typeof Desmos.Colors)[DesmosColourName];
9
+
10
+ const VALID_COLOURS = ["RED", "BLUE", "GREEN", "PURPLE", "ORANGE", "BLACK"];
11
+
12
+
8
13
  export class ColourIncantation extends ArgIncantation<LOCAL>
9
14
  {
10
15
  override readonly description
@@ -23,17 +28,22 @@ export class ColourIncantation extends ArgIncantation<LOCAL>
23
28
 
24
29
  override evaluate_arg(data: string, options: DesmostOptions): DesmosColour
25
30
  {
26
- switch (data.trim().toUpperCase()) {
27
- case "RED": return DesmosColour.RED;
28
- case "BLUE": return DesmosColour.BLUE;
29
- case "GREEN": return DesmosColour.GREEN;
30
- case "PURPLE": return DesmosColour.PURPLE;
31
- case "ORANGE": return DesmosColour.ORANGE;
32
- case "BLACK": return DesmosColour.BLACK;
33
- default:
34
- throw new UnrecoverableError(
35
- `Invalid colour: \`${data}\``
36
- );
31
+ let colour = data.trim().toUpperCase();
32
+
33
+ if (VALID_COLOURS.includes(colour)) {
34
+ return Desmos.Colors[colour as DesmosColourName];
35
+ }
36
+ else {
37
+ let internal = Desmos.Colors[colour as DesmosColourName];
38
+
39
+ if (options.check_args && internal == undefined) {
40
+ throw new DesmostError.InvalidArgument({
41
+ msg: `/colour received invalid colour: \`${data}\``,
42
+ hint: `Valid colours are ${VALID_COLOURS.join(", ")}`,
43
+ });
44
+ }
45
+
46
+ return internal;
37
47
  }
38
48
  }
39
49
  }
@@ -1,6 +1,6 @@
1
1
  import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
2
2
 
3
- import { UnrecoverableError } from "../../errors";
3
+ import { DesmostError } from "../../errors";
4
4
  import type { DesmostOptions } from "../../options";
5
5
 
6
6
 
@@ -8,8 +8,8 @@ interface LabelOptions
8
8
  {
9
9
  text: string;
10
10
  show?: boolean;
11
- size?: number | keyof typeof Desmos.LabelSizes;
12
- pos?: keyof typeof Desmos.LabelOrientations;
11
+ size?: number;
12
+ pos?: "ABOVE" | "BELOW" | "LEFT" | "RIGHT" | "ABOVE_LEFT" | "ABOVE_RIGHT" | "BELOW_LEFT" | "BELOW_RIGHT";
13
13
  }
14
14
 
15
15
  const VALID_FIELDS = ["text", "show", "size", "pos"];
@@ -36,6 +36,7 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
36
36
  target.showLabel = data.show ?? true;
37
37
  // @ts-expect-error: outdated types
38
38
  if (data.size != undefined) target.labelSize = data.size;
39
+ // @ts-expect-error: outdated types
39
40
  if (data.pos != undefined) target.labelOrientation = data.pos;
40
41
  }
41
42
 
@@ -44,19 +45,16 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
44
45
  let out = super.evaluate_arg(raw, options) as LabelOptions;
45
46
 
46
47
  if (options.check_args) {
47
- super.require_nonempty(out, `/label received empty argument`, {
48
+ super.require_nonempty(out, {
49
+ msg: `/label received empty argument`,
48
50
  hint: `You can provide [${VALID_FIELDS.join(", ")}]`,
49
- flagged_by: "check_args",
50
51
  });
51
52
 
52
53
  if (!("text" in out)) {
53
- throw new UnrecoverableError.MissingInput(
54
- `/label is missing label text`,
55
- {
56
- hint: `Provide text for the label: \`/label{text: "sup world!"}\``,
57
- flagged_by: "check_args",
58
- }
59
- );
54
+ throw new DesmostError.MissingInput({
55
+ msg: `/label is missing label text`,
56
+ hint: `Provide text for the label: \`/label{text: "sup world!"}\``,
57
+ });
60
58
  }
61
59
 
62
60
  super.require_known(out, VALID_FIELDS);
@@ -74,13 +72,10 @@ export class LabelIncantation extends ArgIncantation<LOCAL>
74
72
  let orientation = Desmos.LabelOrientations[pos];
75
73
 
76
74
  if (options.check_args && orientation == undefined) {
77
- throw new UnrecoverableError.InvalidArgument(
78
- `/label received invalid label position: ${pos}`,
79
- {
80
- hint: `Valid label positions are ${VALID_POSITIONS.join(", ")}`,
81
- flagged_by: "check_args"
82
- }
83
- );
75
+ throw new DesmostError.InvalidArgument({
76
+ msg: `/label received invalid label position: ${pos}`,
77
+ hint: `Valid label positions are ${VALID_POSITIONS.join(", ")}`,
78
+ });
84
79
  }
85
80
 
86
81
  out.pos = orientation;
@@ -1,7 +1,7 @@
1
1
  import { Incantation, ArgIncantation, type LOCAL } from "../incantation";
2
2
 
3
3
  import type { DesmostOptions } from "../../options";
4
- import { type Unrecoverable } from "../../errors";
4
+ import type { Fallible } from "../../errors";
5
5
 
6
6
 
7
7
  interface LineOptions
@@ -32,7 +32,7 @@ export class LineIncantation extends ArgIncantation<LOCAL>
32
32
  if (data.opacity != undefined) target.lineOpacity = data.opacity;
33
33
  }
34
34
 
35
- override evaluate_arg(raw: string, options: DesmostOptions): Unrecoverable<LineOptions>
35
+ override evaluate_arg(raw: string, options: DesmostOptions): Fallible<LineOptions>
36
36
  {
37
37
  let out = super.evaluate_arg(raw, options) as LineOptions;
38
38
 
package/src/options.ts CHANGED
@@ -2,6 +2,36 @@ import { LINE } from "./utils";
2
2
  import { compile } from "./compiler/compile";
3
3
 
4
4
 
5
+ /** Default options that Desmost uses for `compile()` and `decompile()`. */
6
+ export const DEFAULT_OPTIONS: DesmostOptions =
7
+ {
8
+ errors: "surface",
9
+ place_errors: "inline",
10
+ error_prefix: `[DESMOST ERROR]\n${LINE}\n`,
11
+ expand_errors: true,
12
+ check_args: true,
13
+ prettify: true,
14
+ dedent_text: true,
15
+ ignore_comments: false,
16
+ ignore_all_blanks: false,
17
+ keep_leading_blanks: false,
18
+ keep_trailing_blanks: false,
19
+ debug: false,
20
+ };
21
+
22
+
23
+ /**
24
+ * Fill in `options` with Desmost's defaults to produce a complete `DesmostOptions` config.
25
+ */
26
+ export function fill_defaults(options: Partial<DesmostOptions> | undefined): DesmostOptions
27
+ {
28
+ return {
29
+ ...DEFAULT_OPTIONS,
30
+ ...options,
31
+ };
32
+ }
33
+
34
+
5
35
  /**
6
36
  * Options to customise Desmost compilation.
7
37
  *
@@ -29,14 +59,15 @@ import { compile } from "./compiler/compile";
29
59
  export interface DesmostOptions
30
60
  {
31
61
  /**
32
- * How should errors be *surfaced* to the end user?
62
+ * How should errors be displayed?
33
63
  *
34
- * - `surface` (default): Blocks that result in errors will become Desmos text expressions containing the error message, leaving other expressions unaffected.
64
+ * - `surface` (default): Blocks that result in errors will become Desmos text blocks containing the error message, leaving other expressions unaffected.
35
65
  *
36
- * - `crash`: The entire compilation to Desmos will terminate with a single error message. This means you don't get any output at all, but errors are also immediately obvious.
37
- * - Note that this will *clear all expressions* in the calculator instance.
66
+ * - `crash`: The entire compilation to Desmos will terminate with a single error message in a text block.
67
+ * - This means you don't get any Desmos rendering at all, but errors are also immediately obvious.
68
+ * - Note that this will *clear all expressions* in the calculator instance. If you pass in a non-blank `Desmos.Calculator` to `compile()`, it could get cleared.
38
69
  *
39
- * - `suppress`: Silently fail on the frontend (if you wish to give the illusion that everything is fine).
70
+ * - `suppress`: Silently fail on the frontend (if you wish to give the illusion that everything is fine!).
40
71
  */
41
72
  errors: "surface" | "crash" | "suppress"
42
73
 
@@ -52,7 +83,7 @@ export interface DesmostOptions
52
83
  /**
53
84
  * The prefix to prepend to error blocks.
54
85
  *
55
- * Defaults to `[DESMOST ERROR]\n`.
86
+ * Defaults to `"[DESMOST ERROR]"`.
56
87
  *
57
88
  * Provide a `""` blank string if you wish for no prefix to be added.
58
89
  */
@@ -61,100 +92,101 @@ export interface DesmostOptions
61
92
  /**
62
93
  * Show all the available diagnostics for errors, including hints and debug information?
63
94
  *
64
- * Defaults to `true`, meaning all output is shown.
95
+ * Defaults to `true` all output is shown.
65
96
  */
66
97
  expand_errors: boolean
67
98
 
68
99
  /**
69
- * Error if an incantation receives a `{}` object argument with unknown fields?
100
+ * Error if an incantation receives a `{}` object argument with unknown fields, or no fields at all?
70
101
  *
71
- * This also errors if an incantation receives an empty `{}` object.
72
- *
73
- * For instance, `/label{position: LEFT}` is invalid; it should be `/label{pos: LEFT}`. With `check_args: false`, this silently no-ops; with `check_args: true`, it flags an error.
102
+ * For instance, `/label{position: LEFT}` is invalid; it should be `/label{pos: LEFT}`. With `check_args: false`, this silently no-ops.
74
103
  *
75
104
  * Desmost doesn’t remove unknown fields, it just passes them directly to the Desmos API. If you know what you’re doing and a field you know exists isn’t supported by Desmos, you can disable this to avoid erroring.
76
105
  *
77
- * Defaults to `true`, meaning arguments are checked.
106
+ * Defaults to `true` arguments are checked. The Desmos API happily accepts and ignores invalid fields, so Desmost provides a safety net for you ;)
78
107
  */
79
108
  check_args: boolean
80
109
 
81
110
  /**
82
111
  * Prettify LaTeX output so it renders nicely in the Desmos editor?
83
112
  *
84
- * Defaults to `true`, meaning LaTeX is prettified.
113
+ * This means you can keep your source code much neater. It handles stuff like converting `()` –> `\left(\right)`, `x, y` –> `x,\ y`, `min(x, y)` –> `\operatorname{min}\left(x,\ y\right)`, and more!
114
+ *
115
+ * Defaults to `true` – LaTeX is prettified.
85
116
  */
86
117
  prettify: boolean
87
118
 
88
119
  /**
89
120
  * Strip common indentation from `/text{}` blocks?
90
121
  *
91
- * Defaults to `true`, meaning text is dedented.
122
+ * This allows you to indent content for readability:
123
+ *
124
+ * ```hs
125
+ * /text{
126
+ * Now I have
127
+ * a lovely indent
128
+ * }
129
+ * ```
130
+ *
131
+ * Defaults to `true` – text is dedented.
92
132
  */
93
133
  dedent_text: boolean
94
134
 
95
135
  /**
96
- * Should `%` LaTeX comments be ignored, instead of turned into text expressions (notes)?
136
+ * Should `%` LaTeX comments be ignored, instead of turned into text blocks (notes)?
97
137
  *
98
- * Defaults to `false`, meaning comments are kept.
138
+ * ```hs
139
+ * % Do I become a text expression?
140
+ * y = x
141
+ * ```
142
+ *
143
+ * Defaults to `false` – comments are kept.
99
144
  */
100
145
  ignore_comments: boolean
101
146
 
102
147
  /**
103
148
  * Should all line breaks be ignored, instead of kept as blank expressions?
104
149
  *
105
- * Defaults to `false`, meaning all blank lines are kept.
150
+ * ```hs
151
+ * % Should there be a blank block after this?
152
+ *
153
+ * % Should there be a blank block before this?
154
+ * ```
155
+ *
156
+ * This takes precedence over `keep_leading_blanks` and `keep_trailing_blanks`.
157
+ *
158
+ * Defaults to `false` – blank lines are recognised.
106
159
  */
107
160
  ignore_all_blanks: boolean
108
161
 
109
162
  /**
110
163
  * Should trailing blank lines at the start of the source be kept as blank expressions?
111
164
  *
112
- * Defaults to `false`, meaning leading blank lines are ignored.
165
+ * This is disabled by default so line breaks after global incantations don’t mess things up:
166
+ *
167
+ * ```hs
168
+ * /viewport{left: -8, right: 8}
169
+ *
170
+ * % I don’t have a blank block above me, yay
171
+ * ```
172
+ *
173
+ * Defaults to `false` – leading blank lines are ignored.
113
174
  */
114
175
  keep_leading_blanks: boolean
115
176
 
116
177
  /**
117
178
  * Should trailing blank lines at the end of the source be kept as blank expressions?
118
179
  *
119
- * Defaults to `false`, meaning trailing blank lines are ignored.
180
+ * Defaults to `false` trailing blank lines are ignored.
120
181
  */
121
182
  keep_trailing_blanks: boolean
122
183
 
123
184
  /**
124
- * Return debug diagnostics?
185
+ * Return debug diagnostics from `compile()`?
125
186
  *
126
- * This includes the unevaluated AST and performance diagnostics.
187
+ * This includes the unevaluated AST and performance diagnostics. Relevant types are exposed from `desmost/internal`, but beware that these are implementation details and unstable.
127
188
  *
128
- * Defaults to `false`, meaning `compile()` returns `void`.
189
+ * Defaults to `false` `compile()` returns `void`.
129
190
  */
130
191
  debug: boolean
131
192
  }
132
-
133
-
134
- export const DEFAULT_OPTIONS: DesmostOptions =
135
- {
136
- errors: "surface",
137
- place_errors: "inline",
138
- error_prefix: `[DESMOST ERROR]\n${LINE}\n`,
139
- expand_errors: true,
140
- prettify: true,
141
- dedent_text: true,
142
- check_args: false,
143
- ignore_comments: false,
144
- ignore_all_blanks: false,
145
- keep_leading_blanks: false,
146
- keep_trailing_blanks: false,
147
- debug: false,
148
- };
149
-
150
-
151
- /**
152
- * Fill in `options` with Desmost's defaults to produce a complete `DesmostOptions` config.
153
- */
154
- export function fill_defaults(options: Partial<DesmostOptions> | undefined): DesmostOptions
155
- {
156
- return {
157
- ...DEFAULT_OPTIONS,
158
- ...options,
159
- };
160
- }
package/src/parser/ast.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { UnrecoverableError } from "../errors";
2
1
  import { Incantation, ArgIncantation } from "../magic";
3
2
 
4
3
 
@@ -9,7 +8,6 @@ export namespace Ast
9
8
  {
10
9
  EXPRESSION = "Expression",
11
10
  INCANTATION_INVOCATION = "Incantation-Invocation",
12
- INVALID_INCANTATION = "Invalid-Incantation",
13
11
  }
14
12
 
15
13
 
@@ -18,10 +16,7 @@ export namespace Ast
18
16
  {
19
17
  kind: Kind.EXPRESSION
20
18
  data: Desmos.ExpressionState
21
- incantations: Array<
22
- | IncantationInvocation<Incantation.Effect.LOCAL>
23
- | InvalidInvocation
24
- >
19
+ incantations: IncantationInvocation<Incantation.Effect.LOCAL>[]
25
20
  }
26
21
 
27
22
 
@@ -30,31 +25,16 @@ export namespace Ast
30
25
  | {
31
26
  kind: Kind.INCANTATION_INVOCATION
32
27
  incantation: Incantation<Effect>
33
- arg_raw: undefined
34
28
  }
35
29
  | {
36
30
  kind: Kind.INCANTATION_INVOCATION
37
31
  incantation: ArgIncantation<Effect>
38
32
  arg_raw: string | undefined
39
33
  };
40
-
41
- /**
42
- * An invalid invantation invocation that raised an error when parsed.
43
- *
44
- * This will be propogated to the user as an extra Desmos text expression (unless they have `errors: "suppress"` configured).
45
- */
46
- export interface InvalidInvocation
47
- {
48
- kind: Kind.INVALID_INCANTATION
49
- incantation: Incantation
50
- arg_raw?: string
51
- error: UnrecoverableError
52
- }
53
34
  }
54
35
 
55
36
  /** An abstract object produced by the parser. */
56
37
  export type Ast =
57
38
  | Ast.Expression
58
39
  | Ast.IncantationInvocation
59
- | Ast.InvalidInvocation
60
40
  ;