@khanacademy/perseus 46.0.1 → 47.0.1

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.
@@ -1,8 +1,37 @@
1
- import type { Coord } from "./interactive2/types";
2
- import type { Interval, vec } from "mafs";
1
+ /**
2
+ * The Perseus "data schema" file.
3
+ *
4
+ * This file, and the types in it, represents the "data schema" that Perseus
5
+ * uses. The @khanacademy/perseus-editor package edits and produces objects
6
+ * that conform to the types in this file. Similarly, the top-level renderers
7
+ * in @khanacademy/perseus, consume objects that conform to these types.
8
+ *
9
+ * WARNING: This file should not import any types from elsewhere so that it is
10
+ * easy to reason about changes that alter the Perseus schema. This helps
11
+ * ensure that it is not changed accidentally when upgrading a dependant
12
+ * package or other part of Perseus code. Note that TypeScript does type
13
+ * checking via something called "structural typing". This means that as long
14
+ * as the shape of a type matches, the name it goes by doesn't matter. As a
15
+ * result, a `Coord` type that looks like this `[x: number, y: number]` is
16
+ * _identical_, in TypeScript's eyes, to this `Vector2` type `[x: number, y:
17
+ * number]`. Also, with tuples, the labels for each entry is ignored, so `[x:
18
+ * number, y: number]` is compatible with `[min: number, max: number]`. The
19
+ * labels are for humans, not TypeScript. :)
20
+ *
21
+ * If you make changes to types in this file, be very sure that:
22
+ *
23
+ * a) the changes are backwards compatible. If they are not, old data from
24
+ * previous versions of the "schema" could become unrenderable, or worse,
25
+ * introduce hard-to-diagnose bugs.
26
+ * b) the parsing code (`util/parse-perseus-json/`) is updated to handle
27
+ * the new format _as well as_ the old format.
28
+ */
29
+ export type Coord = [x: number, y: number];
30
+ export type Interval = [min: number, max: number];
31
+ export type Vector2 = Coord;
3
32
  export type Range = Interval;
4
- export type Size = [number, number];
5
- export type CollinearTuple = [vec.Vector2, vec.Vector2];
33
+ export type Size = [width: number, height: number];
34
+ export type CollinearTuple = [Vector2, Vector2];
6
35
  export type ShowSolutions = "all" | "selected" | "none";
7
36
  /**
8
37
  * Our core set of Perseus widgets.
@@ -124,17 +153,6 @@ export type PerseusItem = {
124
153
  * This item is never scored and is rendered by the `ArticleRenderer`.
125
154
  */
126
155
  export type PerseusArticle = PerseusRenderer | ReadonlyArray<PerseusRenderer>;
127
- /**
128
- * A "MultiItem" is an advanced Perseus item. It is rendered by the
129
- * `MultiRenderer` and you can control the layout of individual parts of the
130
- * item.
131
- *
132
- * @deprecated MultiItem support is slated for removal in a future Perseus
133
- * release.
134
- */
135
- export type MultiItem = {
136
- _multi: any;
137
- };
138
156
  export type Version = {
139
157
  major: number;
140
158
  minor: number;
package/dist/types.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { ILogger } from "./logging/log";
2
- import type { Item } from "./multi-items/item-types";
3
2
  import type { Hint, PerseusAnswerArea, PerseusGraphType, PerseusWidget, PerseusWidgetsMap } from "./perseus-types";
4
3
  import type { PerseusStrings } from "./strings";
5
4
  import type { SizeClass } from "./util/sizing-utils";
@@ -99,7 +98,6 @@ export type ChangeHandler = (arg1: {
99
98
  question?: any;
100
99
  answerArea?: PerseusAnswerArea | null;
101
100
  itemDataVersion?: Version;
102
- item?: Item;
103
101
  editorMode?: EditorMode;
104
102
  jsonMode?: boolean;
105
103
  value?: any;
@@ -54,8 +54,6 @@ export declare function getWidgetsMapFromItemData(itemData: PerseusItem): Perseu
54
54
  export declare function getWidgetFromWidgetMap(widgetId: string, widgetMap: PerseusWidgetsMap): PerseusWidget | null;
55
55
  /**
56
56
  * Get select widgets from a widget map.
57
- * Useful for multi-items that needs to split
58
- * one PerseusItem into several
59
57
  *
60
58
  * @param {ReadonlyArray<string>} widgetIds to extract
61
59
  * @param {PerseusWidgetsMap} widgetMap to extract from
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core Perseus API (includes renderers and widgets)",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "46.0.1",
6
+ "version": "47.0.1",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -1,33 +0,0 @@
1
- /**
2
- * Type definitions for multi-item types, including:
3
- *
4
- * - Item: A multi-item tree wrapped in a `_multi` key, to help us recognize it
5
- * as a multi-item in other contexts and avoid misinterpreting its
6
- * other properties.
7
- * - ItemTree: A multi-item without the `_multi` key. Conforms to the Tree
8
- * interface, so it's compatible with our tree traversal functions.
9
- * - And the various types of nodes that compose a tree.
10
- */
11
- import type { Tree, ArrayNode, ObjectNode } from "./tree-types";
12
- import type { PerseusWidgetsMap } from "../perseus-types";
13
- import type { ImageDict } from "../types";
14
- export type ContentNode = {
15
- __type: "content" | "item";
16
- content?: string | null | undefined;
17
- images?: ImageDict | null | undefined;
18
- widgets?: PerseusWidgetsMap | null | undefined;
19
- };
20
- export type HintNode = {
21
- __type: "hint";
22
- content?: string | null | undefined;
23
- images?: ImageDict | null | undefined;
24
- widgets?: PerseusWidgetsMap | null | undefined;
25
- replace?: boolean | null | undefined;
26
- };
27
- export type TagsNode = ReadonlyArray<string>;
28
- export type ItemArrayNode = ArrayNode<ContentNode, HintNode, TagsNode>;
29
- export type ItemObjectNode = ObjectNode<ContentNode, HintNode, TagsNode>;
30
- export type ItemTree = Tree<ContentNode, HintNode, TagsNode>;
31
- export type Item = {
32
- _multi: ItemTree;
33
- };
@@ -1,53 +0,0 @@
1
- /**
2
- * Utility functions for constructing and manipulating multi-items.
3
- *
4
- * These functions apply *specifically* to Items and ItemTrees - things that
5
- * actually semantically *are* multi-items. For more general functions for
6
- * traversing and manipulating *anything* shaped like a multi-item (like a
7
- * renderer tree or a score tree or, well, a multi-item), see trees.js.
8
- */
9
- import type { Item, ItemTree, ContentNode, HintNode } from "./item-types";
10
- import type { Shape } from "./shape-types";
11
- /**
12
- * Return a semantically empty ItemTree that conforms to the given shape.
13
- *
14
- * - An empty content node has an empty content string and no widgets/images.
15
- * - An empty hint node has an empty content string and no widgets/images.
16
- * - An empty array node has no elements.
17
- * - An empty object node has a semantically empty node for each of its keys.
18
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
19
- */
20
- export declare function buildEmptyItemTreeForShape(shape: Shape): ItemTree;
21
- /**
22
- * Return a semantically empty Item that conforms to the given shape.
23
- *
24
- * - An empty content node has an empty content string and no widgets/images.
25
- * - An empty hint node has an empty content string and no widgets/images.
26
- * - An empty array node has no elements.
27
- * - An empty object node has a semantically empty node for each of its keys.
28
- * (That is, we recursively call buildEmptyItemTreeForShape for each key.)
29
- */
30
- export declare function buildEmptyItemForShape(shape: Shape): Item;
31
- /**
32
- * Given an Item and its Shape, yield all of its content nodes to the callback.
33
- */
34
- export declare function findContentNodesInItem(item: Item, shape: Shape, callback: (c: ContentNode) => any): void;
35
- /**
36
- * Given an Item and its Shape, yield all of its hint nodes to the callback.
37
- */
38
- export declare function findHintNodesInItem(item: Item, shape: Shape, callback: (h: HintNode) => any): void;
39
- /**
40
- * Given an ItemTree, return a Shape that it conforms to.
41
- *
42
- * The Shape might not be complete or correct Shape that this Item was designed
43
- * for. If you have access to the intended Shape, use that instead.
44
- */
45
- export declare function inferItemShape(item: Item): Shape;
46
- /**
47
- * Convert the given Item to an ItemTree, by unwrapping the `_multi` key.
48
- */
49
- export declare function itemToTree(item: Item): ItemTree;
50
- /**
51
- * Convert the given ItemTree to an Item, by wrapping it in the `_multi` key.
52
- */
53
- export declare function treeToItem(node: ItemTree): Item;
@@ -1,159 +0,0 @@
1
- import * as React from "react";
2
- import { PerseusI18nContext } from "../components/i18n-context";
3
- import Renderer from "../renderer";
4
- import type { Item, ContentNode, HintNode, TagsNode } from "./item-types";
5
- import type { Shape, ArrayShape } from "./shape-types";
6
- import type { Tree } from "./tree-types";
7
- import type { TreeMapper, ContentMapper, HintMapper, Path } from "./trees";
8
- import type { APIOptions, FilterCriterion, PerseusDependenciesV2, Widget } from "../types";
9
- import type { PropsFor } from "@khanacademy/wonder-blocks-core";
10
- type Hint = any;
11
- type Score = any;
12
- type SerializedState = any;
13
- type RendererProps = PropsFor<typeof Renderer>;
14
- type ContentRendererElement = React.ReactElement<any>;
15
- type HintRendererElement = React.ReactElement<any>;
16
- type ContentRendererData = {
17
- makeRenderer: () => ContentRendererElement;
18
- ref: Renderer | null | undefined;
19
- };
20
- type FindWidgetsFunc = (criterion: FilterCriterion) => ReadonlyArray<Widget | null | undefined>;
21
- type HintRendererData = {
22
- makeRenderer: () => HintRendererElement;
23
- findExternalWidgets: FindWidgetsFunc | null | undefined;
24
- ref: null;
25
- hint: Hint;
26
- };
27
- type RendererData = ContentRendererData | HintRendererData;
28
- type RendererDataTree = Tree<ContentRendererData, HintRendererData, null>;
29
- /**
30
- * TODO(somewhatabstract, JIRA-XXXX):
31
- * Some usage of this type somewhere is causing TypeScript to believe that these
32
- * elements should be components. Don't know where that is, to fix it up
33
- * properly. In reality, these types are just too hard to use and aren't
34
- * really helping us out as I now have to suppress this rather than
35
- * get value from the type. :(
36
- */
37
- type RendererTree = Tree<ContentRendererElement, HintRendererElement, null>;
38
- type ScoreTree = Tree<Score, null, null>;
39
- type SerializedStateTree = Tree<SerializedState, null, null>;
40
- type Props = {
41
- item: Item;
42
- shape: Shape;
43
- children: (tree: {
44
- renderers: RendererTree;
45
- }) => React.ReactElement<any>;
46
- serializedState?: SerializedStateTree | null | undefined;
47
- onSerializedStateUpdated?: (state: SerializedStateTree) => void;
48
- onInteractWithWidget?: (id: string) => void;
49
- apiOptions?: APIOptions;
50
- reviewMode?: boolean | null | undefined;
51
- dependencies: PerseusDependenciesV2;
52
- };
53
- type State = {
54
- rendererDataTree: RendererDataTree | null | undefined;
55
- renderError: Error | null | undefined;
56
- };
57
- declare class MultiRenderer extends React.Component<Props, State> {
58
- static contextType: React.Context<{
59
- strings: import("../strings").PerseusStrings;
60
- locale: string;
61
- }>;
62
- context: React.ContextType<typeof PerseusI18nContext>;
63
- rendererDataTreeMapper: TreeMapper<ContentNode, ContentRendererData, HintNode, HintRendererData, TagsNode, null>;
64
- getRenderersMapper: TreeMapper<ContentRendererData, ContentRendererElement, HintRendererData, HintRendererElement, null, null>;
65
- constructor(props: Props);
66
- UNSAFE_componentWillReceiveProps(nextProps: Props): void;
67
- /**
68
- * Attempt to build a State that includes a renderer tree corresponding to
69
- * the item provided in props. On error, return a state with `renderError`
70
- * set instead.
71
- */
72
- _tryMakeRendererState(props: Props): State;
73
- _handleSerializedStateUpdated: (path: Path, newState?: any) => void;
74
- /**
75
- * Props that aren't directly used by the MultiRenderer are delegated to
76
- * the underlying Renderers.
77
- */
78
- _getRendererProps(): RendererProps;
79
- /**
80
- * Construct a Renderer and a ref placeholder for the given ContentNode.
81
- */
82
- _makeContentRendererData(content: ContentNode, path: Path): ContentRendererData;
83
- /**
84
- * Construct a Renderer for the given HintNode, and keep track of the hint
85
- * itself for future use, too.
86
- */
87
- _makeHintRendererData(hint: HintNode): HintRendererData;
88
- /**
89
- * Construct a tree of interconnected RendererDatas, corresponding to the
90
- * given item. Called in `_tryMakeRendererState`, in order to store this
91
- * tree in the component state.
92
- */
93
- _makeRendererDataTree(item: Item, shape: Shape): RendererDataTree;
94
- /**
95
- * Return all widgets that meet the given criterion, from all Renderers
96
- * except the Renderer that triggered this call.
97
- *
98
- * This function is provided to each Renderer's `findExternalWidgets` prop,
99
- * which enables widgets in different Renderers to discover each other and
100
- * communicate.
101
- */
102
- _findWidgets(callingData: RendererData, filterCriterion: FilterCriterion): ReadonlyArray<Widget | null | undefined>;
103
- /**
104
- * Copy the renderer tree, apply the given transformation to the leaf nodes
105
- * and the optional given transformation to the array nodes, and return the
106
- * result.
107
- *
108
- * Used to provide structured data to the call site (the Renderer tree on
109
- * `render`, the Score tree on `getScores`, etc.), and to traverse the
110
- * renderer tree even when we disregard the output (like in
111
- * `_findWidgets`).
112
- */
113
- _mapRenderers<O>(leafMapper: ContentMapper<RendererData, O> & HintMapper<RendererData, O>): Tree<O, O, null> | null | undefined;
114
- _scoreFromRef(ref?: Renderer | null): Score;
115
- /**
116
- * Return a tree in the shape of the multi-item, with scores at each of
117
- * the content nodes and `null` at the other leaf nodes.
118
- */
119
- getScores(): ScoreTree;
120
- /**
121
- * Return a single composite score for all rendered content nodes.
122
- * The `guess` is a tree in the shape of the multi-item, with an individual
123
- * guess at each content node and `null` at the other leaf nodes.
124
- */
125
- score(): Score;
126
- /**
127
- * Return a tree in the shape of the multi-item, with serialized state at
128
- * each of the content nodes and `null` at the other leaf nodes.
129
- *
130
- * If the lastSerializedState argument is supplied, this function will fill
131
- * in the state of not-currently-rendered content and hint nodes with the
132
- * values from the previous serialized state. If no lastSerializedState is
133
- * supplied, `null` will be returned for not-currently-rendered content and
134
- * hint nodes.
135
- */
136
- _getSerializedState(lastSerializedState?: SerializedStateTree): SerializedStateTree;
137
- /**
138
- * Given a tree in the shape of the multi-item, with serialized state at
139
- * each of the content nodes, restore each state to the corresponding
140
- * renderer if currently mounted.
141
- */
142
- restoreSerializedState(serializedState: SerializedState, callback?: () => any): void;
143
- /**
144
- * Given an array of renderers, if it happens to be an array of *hint*
145
- * renderers, then attach a `firstN` method to the array, which allows the
146
- * layout to render the hints together in one HintsRenderer.
147
- */
148
- _annotateRendererArray(renderers: ReadonlyArray<Renderer>, rendererDatas: ReadonlyArray<RendererData>, shape: ArrayShape): ReadonlyArray<Renderer>;
149
- /**
150
- * Return a tree in the shape of the multi-item, with a Renderer at each
151
- * content node and a HintRenderer at each hint node.
152
- *
153
- * This is generated by running each of the `makeRenderer` functions at the
154
- * leaf nodes.
155
- */
156
- _getRenderers(): RendererTree;
157
- render(): React.ReactNode;
158
- }
159
- export default MultiRenderer;
@@ -1,14 +0,0 @@
1
- /**
2
- * Utility functions to build React PropTypes for multi-items and shapes.
3
- *
4
- * If you're writing new components, though, consider using the Item and Shape
5
- * types instead.
6
- */
7
- import type { Shape } from "./shape-types";
8
- /**
9
- * Return a PropType that accepts Items of the given shape, and rejects other
10
- * objects.
11
- *
12
- * Usage: `propTypes: {item: buildPropTypeForShape(myShape)}`
13
- */
14
- export declare function buildPropTypeForShape(shape: Shape): any;
@@ -1,47 +0,0 @@
1
- /**
2
- * Type definitions for multi-item shapes.
3
- *
4
- * A shape is an object that serves as a runtime type declaration: it specifies
5
- * a tree structure for a particular class of multi-item.
6
- *
7
- * We use shapes instead static compile-time typing because the CMS needs to
8
- * understand the shape of our content library's multi-items at runtime, and
9
- * it's not always possible to infer the full shape from an example multi-item.
10
- *
11
- * Shapes also enable us to traverse a multi-item-shaped tree with confidence,
12
- * even when we can't infer the shape from the tree alone.
13
- *
14
- * We *could* go all-in on a more general library to make certain types
15
- * runtime-inspectable, in order to DRY some things up, but that's probably a
16
- * big ol' infrastructural magic mess, and the narrower scope of Shapes makes
17
- * it easier to be confident that we've covered all cases rather than having to
18
- * deal with all possible Javascript types.
19
- */
20
- export type ContentShape = {
21
- type: "content";
22
- };
23
- export type HintShape = {
24
- type: "hint";
25
- };
26
- export type TagsShape = {
27
- type: "tags";
28
- };
29
- export type ArrayShape = {
30
- type: "array";
31
- /**
32
- * Each element of an ArrayNode has the same shape, which is specified by
33
- * the `elementShape` property.
34
- */
35
- elementShape: Shape;
36
- };
37
- export type ObjectShape = {
38
- type: "object";
39
- /**
40
- * Each property of an ObjectNode has its own shape, which is specified
41
- * under the corresponding key in the `shape` property.
42
- */
43
- shape: {
44
- [k: string]: Shape;
45
- };
46
- };
47
- export type Shape = ContentShape | HintShape | TagsShape | ArrayShape | ObjectShape;
@@ -1,23 +0,0 @@
1
- /**
2
- * Utility functions for constructing and inferring multi-item shapes.
3
- *
4
- * A shape is an object that serves as a runtime type declaration: it specifies
5
- * a tree structure for a particular class of multi-item. See shape-types.js
6
- * for further discussion.
7
- *
8
- * This module allows you to construct arbitrary Shape trees, by combining
9
- * leaf node shapes like `content` and `hint` into composite shapes like
10
- * `arrayOf(shape({foo: content, bar: hint}))`.
11
- */
12
- import type { Shape, ContentShape, HintShape, TagsShape, ArrayShape, ObjectShape } from "./shape-types";
13
- declare const _default: {
14
- content: ContentShape;
15
- hint: HintShape;
16
- hints: ArrayShape;
17
- tags: TagsShape;
18
- arrayOf: (elementShape: Shape) => ArrayShape;
19
- shape: (shape: {
20
- [k: string]: Shape;
21
- }) => ObjectShape;
22
- };
23
- export default _default;
@@ -1,34 +0,0 @@
1
- /**
2
- * Type definitions for generic trees that are shaped like multi-items.
3
- *
4
- * Multi-items are trees! But we also often have other trees that are shaped
5
- * like multi-items - for example, if we map a multi-item tree into a tree of
6
- * renderer info and state, and then map that again into a tree of just the
7
- * renderer nodes, like we do in MultiRenderer.
8
- *
9
- * Therefore, we provide the type Tree<C, H>, which represents a tree that's
10
- * shaped like a multi-item, but the data that lives at each type of leaf could
11
- * be anything.
12
- *
13
- * So, in a Tree<C, H>, content leaf nodes have type C, and hint leaf nodes
14
- * have type H. An ItemTree is a Tree<ContentNode, HintNode>.
15
- *
16
- * That is, we still preserve the distinction between node types, and thereby
17
- * enforce the Tree's adherence to some multi-item Shape, but we're flexible
18
- * about exactly what type of data the tree contains at its leaves.
19
- *
20
- * This enables us to write generic tree-traversal and tree-mapping functions,
21
- * as you'll see in trees.js.
22
- */
23
- export type ArrayNode<C, H, T> = Tree<C, H, T>;
24
- export type ObjectNode<C, H, T> = {
25
- [k: string]: Tree<C, H, T>;
26
- };
27
- /**
28
- * TODO(somewhatabstract, JIRA-XXXX):
29
- * We should ditch this type or create some helpers for working with it.
30
- * As it stands, consumers have to check each node's type before using it
31
- * in order to ensure that TypeScript can track its refinement and appropriate use.
32
- * It's messy.
33
- */
34
- export type Tree<C, H, T> = C | H | T | ArrayNode<C, H, T> | ObjectNode<C, H, T>;
@@ -1,146 +0,0 @@
1
- /**
2
- * Utility functions for manipulating multi-item-shaped trees.
3
- *
4
- * Multi-items are trees! But we also often have other trees that are shaped
5
- * like multi-items - for example, if we map a multi-item tree into a tree of
6
- * renderer info and state, and then map that again into a tree of just the
7
- * renderer nodes, like we do in MultiRenderer. See tree-types.js for further
8
- * discussion.
9
- *
10
- * These functions enable us to manipulate generic multi-item-shaped trees,
11
- * regardless of what type of data they contain at their leaves. You can use
12
- * the mapper functions to transform a tree into another tree of the same
13
- * shape, or to discover all the nodes of a particular type.
14
- *
15
- * We expose two simple mapper functions (mapContentNodes and mapHintNodes),
16
- * and also a more complex interface for creating a mapping over all of a
17
- * tree's node types simultaneously:
18
- *
19
- * `buildMapper()` returns a TreeMapper object that allows you to build your
20
- * mapper object one node type at a time. Then, you can execute your mapping by
21
- * calling the `mapTree` method.
22
- *
23
- * For example:
24
- * const renderers = buildMapper()
25
- * .setContentMapper(this.renderContentNode)
26
- * .setHintMapper(this.renderHintNode)
27
- * .setTagsMapper(this.renderTagsNode)
28
- * .setArrayMapper(this.hideSkippedQuestions)
29
- * .mapTree(tree, shape);
30
- *
31
- * This will copy the given tree, apply the given transformations to the
32
- * content, hint, and array nodes respectively, and return the resulting tree.
33
- *
34
- * For node types whose mappers aren't specified, we default to the identity
35
- * function. (This builder interface enables us to implement that default
36
- * behavior in a provably type-safe way, while not requiring the call site to
37
- * be aware of all the node types. Hooray!)
38
- *
39
- * The call to `setArrayMapper` must come last, because the array mapper's
40
- * argument types depend on the other mappers' types. See ArrayMapper for more
41
- * details.
42
- *
43
- * WARNING: These functions trust that the provided tree conforms to the
44
- * provided shape. If not, behavior is undefined and may not respect the type
45
- * signatures specified here.
46
- */
47
- import type { Shape, ContentShape, HintShape, TagsShape, ArrayShape } from "./shape-types";
48
- import type { Tree, ArrayNode } from "./tree-types";
49
- /**
50
- * The sequence of edges that lead to a particular node in a Tree.
51
- * Elements can be `string` to correspond to an ObjectNode key, or `number` to
52
- * correspond to an ArrayNode index.
53
- */
54
- export type Path = ReadonlyArray<string | number>;
55
- /**
56
- * These are function interfaces for mapping over various types of tree nodes.
57
- *
58
- * ArrayMapper is a bit more complicated than the leaf node mappers. It's
59
- * executed in the context of a `mapTree` call, after we've finished mapping
60
- * its child nodes, so the function has access to both the resulting array
61
- * (with mapped elements) and the original array (with the original untouched
62
- * elements).
63
- *
64
- * The ArrayMapper then has the opportunity to apply a final transformation to
65
- * the resulting array, like filtering certain elements or (in the hacky
66
- * MultiRenderer case) attaching a `renderHints` method to arrays of hint
67
- * renderers :)
68
- *
69
- * This is why `TreeMapper#setArrayMapper` must be called last: ArrayMapper's
70
- * types depend on the ContentMapper and HintMapper's types. And, since you can
71
- * only specify one mapper at a time in this builder interface (which is
72
- * necessary to provide default mappers in a type-safe way), you need your
73
- * dependencies to already be in place by the time you call `setArrayMapper`.
74
- * Otherwise, we'd have to set the ArrayMapper and *hope* that you *eventually*
75
- * provide a compatible ContentMapper and HintMapper, which is difficult to
76
- * prove at compile time.
77
- *
78
- * There's no ObjectMapper here, but not for any particular reason. We just
79
- * don't have a use case for it yet, so we haven't built it yet.
80
- */
81
- export type ContentMapper<CI, CO> = (content: CI, shape: ContentShape, path: Path) => CO;
82
- export type HintMapper<HI, HO> = (hint: HI, shape: HintShape, path: Path) => HO;
83
- export type TagsMapper<TI, TO> = (tag: TI, shape: TagsShape, path: Path) => TO;
84
- export type ArrayMapper<CI, CO, HI, HO, TI, TO> = (mappedArray: ArrayNode<CO, HO, TO>, originalArray: ArrayNode<CI, HI, TI>, shape: ArrayShape, path: Path) => ArrayNode<CO, HO, TO>;
85
- /**
86
- * A TreeMapper is a collection of node mappers, which, together, compose the
87
- * behavior for mapping over an entire tree.
88
- *
89
- * This serves as the interface for the two TreeMapper classes, including both
90
- * the internal mapper properties that we care about, and the `mapTree`
91
- * function that the call site will use.
92
- */
93
- export interface TreeMapper<CI, CO, HI, HO, TI, TO> {
94
- content: ContentMapper<CI, CO>;
95
- hint: HintMapper<HI, HO>;
96
- tags: TagsMapper<TI, TO>;
97
- array: ArrayMapper<CI, CO, HI, HO, TI, TO>;
98
- mapTree(tree: Tree<CI, HI, TI>, shape: Shape): Tree<CO, HO, TO>;
99
- }
100
- /**
101
- * This is a TreeMapper that only has mappers specified for its leaf nodes; its
102
- * array mapper is the identity function.
103
- *
104
- * This is the TreeMapper initially returned by `buildMapper`. It allows you to
105
- * change the types of your ContentMapper and HintMapper, which is safe because
106
- * none of the other mappers that depend on those types (aka ArrayMapper) have
107
- * been specified yet. (Or, more specifically, the ArrayMapper is currently
108
- * `identity`, which can trivially vary with the ContentMapper and HintMapper's
109
- * types.)
110
- *
111
- * Once you call `setArrayMapper`, however, we move to the other class:
112
- * TreeMapperForLeavesAndCollections.
113
- */
114
- declare class TreeMapperJustForLeaves<CI, CO, HI, HO, TI, TO> {
115
- content: ContentMapper<CI, CO>;
116
- hint: HintMapper<HI, HO>;
117
- tags: TagsMapper<TI, TO>;
118
- array: ArrayMapper<CI, CO, HI, HO, TI, TO>;
119
- constructor(content: ContentMapper<CI, CO>, hint: HintMapper<HI, HO>, tags: TagsMapper<TI, TO>);
120
- setContentMapper<CI2, CO2>(newContentMapper: ContentMapper<CI2, CO2>): TreeMapperJustForLeaves<CI2, CO2, HI, HO, TI, TO>;
121
- setHintMapper<HI2, HO2>(newHintMapper: HintMapper<HI2, HO2>): TreeMapperJustForLeaves<CI, CO, HI2, HO2, TI, TO>;
122
- setTagsMapper<TI2, TO2>(newTagsMapper: TagsMapper<TI2, TO2>): TreeMapperJustForLeaves<CI, CO, HI, HO, TI2, TO2>;
123
- setArrayMapper(newArrayMapper: ArrayMapper<CI, CO, HI, HO, TI, TO>): TreeMapperForLeavesAndCollections<CI, CO, HI, HO, TI, TO>;
124
- mapTree(tree: Tree<CI, HI, TI>, shape: Shape): Tree<CO, HO, TO>;
125
- }
126
- /**
127
- * This is a TreeMapper that already has an ArrayMapper specified, so its
128
- * ContentMapper and HintMapper are now locked in.
129
- */
130
- declare class TreeMapperForLeavesAndCollections<CI, CO, HI, HO, TI, TO> {
131
- content: ContentMapper<CI, CO>;
132
- hint: HintMapper<HI, HO>;
133
- tags: TagsMapper<TI, TO>;
134
- array: ArrayMapper<CI, CO, HI, HO, TI, TO>;
135
- constructor(content: ContentMapper<CI, CO>, hint: HintMapper<HI, HO>, tags: TagsMapper<TI, TO>, array: ArrayMapper<CI, CO, HI, HO, TI, TO>);
136
- setArrayMapper(newArrayMapper: ArrayMapper<CI, CO, HI, HO, TI, TO>): TreeMapperForLeavesAndCollections<CI, CO, HI, HO, TI, TO>;
137
- mapTree(tree: Tree<CI, HI, TI>, shape: Shape): Tree<CO, HO, TO>;
138
- }
139
- /**
140
- * Return a new TreeMapper that will perform a no-op transformation on an input
141
- * tree. To make it useful, chain any combination of `setContentMapper`,
142
- * `setHintMapper`, `setTagMapper`, and `setArrayMapper` to specify
143
- * transformations for the individual node types.
144
- */
145
- export declare function buildMapper<C, C, H, H, T, T>(): TreeMapperJustForLeaves<C, C, H, H, T, T>;
146
- export {};