We collect functions that read and write Wiki Pages and transform them into HTML for display in a browser.
The functions are written in the Elm programming language.
Side-by-Side Comparison
In the figure above, we see the same page displayed on one side (left) by the fedwiki reference implementation and on the other side (right) by the elm-pages prototype. The prototype uses the Wiki module.
We define a module named `Wiki` that exposes various types and functions related to Wiki Page JSON.
Let's break down the code step by step:
1. `module Wiki exposing (Event(..), Page, Story(..), pageDecoder, pageEncoder, renderStory)`: This line declares a module named `Wiki` and specifies which values (types, functions) are accessible from outside the module. 1. `import Html exposing (Html)`: This line imports the `Html` module from the Elm standard library, making the `Html` type and related functions available for use. 1. `import Json.Decode as Decode` and `import Json.Encode as Encode`: These lines import the `Json.Decode` and `Json.Encode` modules, which provide functions for decoding and encoding JSON data, respectively. They are used later in the module. 1. `type alias Page = ...`: This defines a custom type alias named `Page`. A `Page` has three fields: `title` (a string), `story` (a list of `Story` items), and `journal` (a list of `Event` items, called Actions). 1. `pageDecoder : Decode.Decoder Page`: This defines a JSON decoder for the `Page` type. It maps over three fields ("title", "story", "journal") to construct a `Page`. 1. `pageEncoder : Page -> Encode.Value`: This defines a function that encodes a `Page` into a JSON value. 1. `type Story = ...`: This defines a custom type called `Story`. It can initially be one of four variants: `Future`, `Factory`, `Paragraph` or `EmptyStory`. Other variants will be added later (see Plugins – the story item type identifies the plugin that can render the item). 1. `renderStory : Story -> Html msg`: This defines a function `renderStory` that takes a `Story` and returns HTML based on the story item type. 1. `storyDecoder : Decode.Decoder Story`: This defines a JSON decoder for the `Story` type. It uses `Decode.oneOf` to choose among the possible variants (`Future`, `Paragraph`, `Factory`, `EmptyStory`) based on the data. 1. `storyEncoder : Story -> Encode.Value`: This defines a function that encodes a `Story` into a JSON value. 1. `type Event = ...`: This defines a custom type named `Event`. It can initially be one of three variants: `Create`, `AddFactory`, or `Edit`. 1. `eventDecoder : Decode.Decoder Event`: This defines a JSON decoder for the `Event` type. It uses `Decode.oneOf` to choose among the possible Actions (`Create`, `AddFactory`, `Edit`) based on the data. Note: Add other types as needed (remove, move, fork). 1. We define JSON decoders for specific event types (`CreateEvent`, `AddFactoryEvent`, `EditEvent`, …). 1. `journalEncoder : Event -> Encode.Value`: This defines a function that encodes an `Event` into a JSON value. 1. Comments in the code provide additional information and explanations for some of the functions and types.
Overall, this Elm module provides a framework for working with Wiki Page JSON, including types for pages, stories, and events, along with functions for encoding and decoding these types to and from JSON. The `renderStory` function generates HTML based on the type of story items provided.
refactor(renderStory): Move function to Wiki module. commit
~
An item, often but not always a paragraph, makes up one self-contained element of a wiki page's Story.
We define the schema for federated wiki pages to the depth that we know it. We use a BNF-like notation to suggest JSON elements. Any ambiguity will be resolved by examining the example. We close with a brief reflection on the successes of the format.
> A story is an array of paragraph-like items. The type identifies the plugin that can render the item.
> The journal contains a Sequence of actions that creates the story. Actions are of a small number of types relating to editing actions.
To track successes and failures when using Decode.oneOf, you can use Result type to capture the outcome of each decoding attempt. Instead of directly applying Decode.oneOf to a list of decoders, you can map each decoder with Decode.attempt to wrap it in a Result type. This way, you can keep track of the success or failure of each decoding attempt.