[
  {
    "path": ".gitignore",
    "content": "node_modules\ndist\n\nyarn.lock\nyarn-error.lock\nyarn-error.log\n \n.DS_Store\n"
  },
  {
    "path": ".mocharc.json",
    "content": "{\n  \"diff\": true,\n  \"extension\": [\"ts\"],\n  \"package\": \"./package.json\",\n  \"reporter\": \"spec\",\n  \"slow\": 75,\n  \"timeout\": 2000,\n  \"ui\": \"bdd\",\n  \"watch-files\": [\"test/**/*.ts\"]\n}\n"
  },
  {
    "path": ".npmignore",
    "content": "elm-app/\nnode_modules/\nsrc/\ntest/\nimg/\n\nwebpack.config.js\n.babelrc\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 4,\n  \"semi\": true,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": ".tool-versions",
    "content": "nodejs 20.5.0\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n- switch to vitest\n\n## [1.2.1] - 2023-08-05\n\n### Removed\n\n- Wrongly placed `prettier` that was set as dependency instead of dev-dependency has been Removed\n\n## [1.2.0] - 2023-08-04\n\n### Added\n\n- add support for Custom formatters in Firefox\n\n### Changed\n\n- drop building with webpack in favour of vite\n- clean out the code to get pass the checks from new version of TS\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Tomáš Látal\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n    <h1>Elm Debug Transformer</h1>\n    <a href=\"https://badge.fury.io/js/elm-debug-transformer\">\n      <img src=\"https://badge.fury.io/js/elm-debug-transformer.svg\" alt=\"version\">\n    </a>\n    <p>Transform Elm Debug.log output into nice log object with custom formatters</p>\n</div>\n\nThe standard Elm `Debug.log` console output:\n\n![Elm Debug.log in console without formatter](img/ugly_output.png)\n\nand the same output with this package \n\n![Elm Debug.log with this package and custom formatter enabled in Chrome](img/nice_output.png)\n\nThe main module exposes `register()` function that replaces your `console.log()` and try to parse each incoming message with Elm parser. If it fails, it would pass the original message.\n\n\n## Installation\n\nJust install this module with Yarn:\n\n```\nyarn add -D elm-debug-transformer\n```\n\nor NPM:\n\n```\nnpm install elm-debug-transformer\n```\n\n### Get it directly from CDN\n\n[Roman Potashow](https://github.com/justgook) pointed out on Elm Slack that you can use the NPM package directly without the need of installing it.\n\n```\n<script src=\"https://unpkg.com/elm-debug-transformer@<VERSION>/dist/elm-console-debug.js\"></script>\n\n<script>ElmConsoleDebug.register()</script>\n```\n\n#### Bookmarklet\n[Ale Grilli](https://github.com/agj) created a bookmarklet for enabling transformer on any page. Just add this to your bookmark\nURL and run it on the pages you want the transformer to work on.\n\n\nBookmarklet below is for version 1.2.1\n\n```\njavascript:(function()%7Bconsole.info(%22Loading%20Elm%20Debug%20Transformer%E2%80%A6%22)%3Bimport(%22%2F%2Funpkg.com%2Felm-debug-transformer%401.2.1%2Fdist%2Findex.mjs%22).then((ElmDebugger)%20%3D%3E%20%7BElmDebugger.register()%3Bconsole.info(%22Elm%20Debug%20Transformer%20loaded!%22)%3B%7D)%7D)()\n```\n\n## Usage\n\nThere is a nice summary of the usage in Alex Korban's article [Get improved Debug.log output in the browser console](https://korban.net/posts/elm/2019-07-02-improved-debug-log-output-browser-console/)\n\n### `register()`\nRegister the console debugger in your main JS file before you initialize Elm application:\n\n```\nimport * as ElmDebugger from 'elm-debug-transformer';\n\nElmDebugger.register();\n\n// rest of application\n```\n\nHere's a sample HTML for your reference:\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>My Elm App</title>\n</head>\n<body>\n  <main></main>\n  <script src=\"https://unpkg.com/elm-debug-transformer@latest/dist/elm-console-debug.js\"></script>\n  <script>ElmConsoleDebug.register({simple_mode: false, debug: false, limit: 10000});</script>\n  <script src=\"elm.js\"></script>\n  <script>\n    var app = Elm.Main.init({ node: document.querySelector('main') });\n  </script>\n</body>\n</html>\n```\n\n### `parse()`\nSince version 1.1.0 the parser function is exposed as well, so you can use it to parse Debug.log output into JSON structure and work with it later as you wish.\n\n```\nimport {parse} ElmDebugger from 'elm-debug-transformer';\n\nconst parsedValue = parse(\"debug tag: [1,2,3]\");\n```\n\n\n### Enable custom formatters in Chrome and Firefox dev tools\nAvailable in Chrome 47 and higher and in Firefox 116 and higher.\n\nThe output object is kind of chatty right now (it carries information about parsed type etc. - less verbose version is worked on right now). \n\nIf your browser is Firefox 116 and above or if it have have Chrome dev tools, you can enable custom formatters so you get less noise and more nice output.\n\n#### How to enable custom formatters in Chrome:\n  - Open DevTools\n  - Go to Preferences (\"cog wheel\" icon in the upper right corner of DevTools > Preferences > Console)\n  - Check-in \"Enable custom formatters\"\n  - Close DevTools\n  - Open DevTools\n\n#### How to enable custom formatters in Firefox:\n  - Open DevTools\n  - Go to Settings (\"three dots\" icon in the upper right corner of DevTools > Settings F1 > Advanced settings)\n  - Check-in \"Enable custom formatters\"\n  - Close DevTools\n  - Open DevTools\n\nNote: You might need to refresh the page first time you open Console panel with existing logs - custom formatters are applied only to newly printed console messages.\n\nThat way the `Debug.log` would output simpler JS object without `type` information. `Tuple`, `Set`, `Array` and `List` would become arrays and `Dict` would become JS object with keys and values.\n\n### Options\nOptions object can be provided to `register` function:\n\n```\nimport * as ElmDebugger from 'elm-debug-transformer';\n\nElmDebugger.register({simple_mode: true, debug: false, limit: 10000});\n```\n\n| parameter     | type    | description                                                                                                                               | default value   |\n|---------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------|----------------:|\n| `limit`       | number  | number of message characters after which the parser won't parse the message. (Helpful for bypass the parsing of large datastructures)     | `1 000 000`     |\n| `debug`       | boolean | include original message and parser error with the message                                                                                | `false`         |\n| `simple_mode` | boolean | force output to be in simple object format                                                                                                | `false`         |\n| `theme` | `light`|`dark` | sets theme colour of debug output. It is useful for switching on the dark mode of devtools.                                                                                                | `light`         |\n\n\n\n## Credits\n\nThis would probably not see the light of the day without [Matt Zeunert](https://github.com/mattzeunert) and his [blogpost](https://www.mattzeunert.com/2016/02/19/custom-chrome-devtools-object-formatters.html) about writing custom formatters. Thank you!\n\n"
  },
  {
    "path": "example/.gitignore",
    "content": "# Distribution\nbuild/\n\n# elm-package generated files\nelm-stuff\n\n# elm-repl generated files\nrepl-temp-*\n\n# Dependency directories\nnode_modules\n\n# Desktop Services Store on macOS\n.DS_Store\n"
  },
  {
    "path": "example/.tool-versions",
    "content": "nodejs 20.5.0\n"
  },
  {
    "path": "example/README.md",
    "content": "# Tesing Elm App\n\nFirst build the elm-debug-parser from root with\n\n```\nyarn start\n```\n"
  },
  {
    "path": "example/elm-tooling.json",
    "content": "{\n    \"tools\": {\n        \"elm\": \"0.19.1\",\n        \"elm-format\": \"0.8.7\",\n        \"elm-json\": \"0.2.13\"\n    }\n}\n"
  },
  {
    "path": "example/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.0\",\n            \"elm/core\": \"1.0.0\",\n            \"elm/html\": \"1.0.0\",\n            \"turboMaCk/any-dict\": \"1.1.0\"\n        },\n        \"indirect\": {\n            \"elm/json\": \"1.0.0\",\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.0\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {\n            \"elm-explorations/test\": \"1.0.0\"\n        },\n        \"indirect\": {\n            \"elm/random\": \"1.0.0\"\n        }\n    }\n}\n"
  },
  {
    "path": "example/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <meta name=\"theme-color\" content=\"#000000\">\n    <title>Elm Debugger testing app</title>\n</head>\n<body>\n    <noscript>\n        You need to enable JavaScript to run this app.\n    </noscript>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"./src/index.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "example/package.json",
    "content": "{\n  \"name\": \"elm-app\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"vite\"\n  },\n  \"devDependencies\": {\n    \"elm-debug-transformer\": \"^1.2.1\",\n    \"elm-tooling\": \"^1.14.0\",\n    \"vite\": \"^4.4.8\",\n    \"vite-plugin-elm\": \"^2.8.0\",\n    \"vite-plugin-elm-debug-transformer\": \"^0.0.1\"\n  }\n}\n"
  },
  {
    "path": "example/src/Main.elm",
    "content": "module Main exposing (Model, Msg(..), init, main, update, view)\n\nimport Array exposing (Array)\nimport Browser\nimport Dict exposing (Dict)\nimport Html exposing (Html, div, h1, img, text)\nimport Html.Attributes exposing (src, style)\nimport Html.Events exposing (onClick)\nimport Set exposing (Set)\n\n\n\n---- MODEL ----\n\n\ntype CustomType\n    = None\n    | Some String Int\n    | Recursive CustomType\n    | Complex (List ( Int, CustomType ))\n    | With_Underscore1\n\n\ntype alias User =\n    { name : String, age : Int }\n\n\ntype CustomRecord\n    = WithRecord (List User)\n\n\ntype Tree a\n    = Leaf a\n    | Node (Tree a) (Tree a)\n\n\ntype alias Model =\n    { array : Array Int\n    , set : Set String\n    , dict : Dict Int String\n    , dictWithTuples : Dict ( Int, String, Int ) String\n    , bools : ( Bool, Bool )\n    , binaryTree : Tree CustomType\n    , custom : CustomType\n    , customRecord : CustomRecord\n    , tuple : ( Int, Int )\n    , triplet : ( Int, String, Int )\n    , nonEmptyList : ( Int, List Int )\n    , complexTuple : ( Int, ( String, ( String, Int ) ) )\n    , int : Int\n    , unit : ()\n    , string : String\n    , list : List (Maybe (List String))\n    , listSingleton : List String\n    , listOfLists : List (List (List String))\n    , function : Int -> String\n    }\n\n\ninit : ( Model, Cmd Msg )\ninit =\n    ( { array = Array.fromList [ 1, 2, 3, 4, 5678, 3464637, 893145, -29 ]\n      , set = Set.fromList [ \"a\", \"b\", \"Some really long string with some nonsense\" ]\n      , bools = ( True, False )\n      , dict = Dict.fromList [ ( 1, \"a\" ), ( 2, \"b\" ), ( 234, \"String longer than one char\" ) ]\n      , dictWithTuples = Dict.fromList [ ( ( 0, \"b\", 1 ), \"a\" ), ( ( 0, \"c\", 1 ), \"b\" ), ( ( 4, \"d\", 1 ), \"String longer than one char\" ) ]\n      , custom = Complex [ ( 1, Some \"text\" 1 ), ( 2, Recursive (Complex []) ), ( 3, None ), ( 4, With_Underscore1 ) ]\n      , tuple = ( 1, 2 )\n      , triplet = ( 1, \"b\", 1 )\n      , complexTuple = ( 1, ( \"longer string\", ( \"much longer string\", 1 ) ) )\n      , int = 123\n      , string = \"Some string\"\n      , list = [ Nothing, Just [ \"String\" ], Nothing, Nothing ]\n      , listSingleton = [ \"Singleton\" ]\n      , listOfLists = [ [ [ \"a\", \"b\" ], [ \"c\", \"d\" ] ], [ [ \"e\", \"f\" ], [ \"g\", \"h\" ] ] ]\n      , nonEmptyList = ( 1, [] )\n      , function = String.fromInt\n      , binaryTree = Node (Node (Leaf None) (Leaf None)) (Node (Leaf None) (Leaf None))\n      , unit = ()\n      , customRecord = WithRecord [ { name = \"Joe\", age = 21 } ]\n      }\n    , Cmd.none\n    )\n\n\n\n---- UPDATE ----\n\n\ntype Msg\n    = DebugOutputClicked\n\n\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n    let\n        _ =\n            Debug.log \"Debug with 2 numbers 7 chars like !_+))($ and emojis 💪 : \" model\n    in\n    ( model, Cmd.none )\n\n\n\n---- VIEW ----\n\n\nview : Model -> Html Msg\nview model =\n    div [ style \"text-align\" \"center\" ]\n        [ img [ src \"/logo.svg\", style \"max-width\" \"200px\" ] []\n        , h1 [] [ text \"Your Elm App is working!\" ]\n        , Html.button [ onClick DebugOutputClicked ] [ Html.text \"Debug Model to console\" ]\n        ]\n\n\n\n---- PROGRAM ----\n\n\nmain : Program () Model Msg\nmain =\n    Browser.element\n        { view = view\n        , init = \\_ -> init\n        , update = update\n        , subscriptions = always Sub.none\n        }\n"
  },
  {
    "path": "example/src/index.js",
    "content": "import { Elm } from './Main.elm';\n//import * as ElmDebugger from 'elm-debug-transformer';\n\n//ElmDebugger.register({simple_mode: false, debug: true, limit: 10000});\n\nElm.Main.init({\n    node: document.getElementById('root'),\n});\n"
  },
  {
    "path": "example/vite.config.js",
    "content": "import { defineConfig } from 'vite'\nimport plugin from 'vite-plugin-elm'\nimport transformer from 'vite-plugin-elm-debug-transformer'\n\nexport default defineConfig({\n  plugins: [plugin(), transformer({theme: 'dark'}) ]\n})\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"elm-debug-transformer\",\n  \"version\": \"1.2.1\",\n  \"description\": \"Transform Elm Debug.log output into nice log object with custom formatter\",\n  \"author\": \"Tomas Latal <tom@tomaslatal.cz>\",\n  \"repository\": \"https://github.com/kraklin/elm-debug-transformer\",\n  \"keywords\": [\n    \"elm\",\n    \"debug\",\n    \"console\",\n    \"parser\",\n    \"formatter\"\n  ],\n  \"main\": \"./dist/index.js\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.js\"\n    }\n  },\n  \"module\": \"./dist/index.mjs\",\n  \"typings\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\",\n  \"private\": false,\n  \"scripts\": {\n    \"pegjs\": \"pegjs --plugin ./node_modules/ts-pegjs/src/tspegjs -o src/elm-debug-parser.ts src/elm-debug.pegjs\",\n    \"test\": \"vitest run\",\n    \"build\": \"npm run pegjs && tsc && vite build\",\n    \"build:watch\": \"npm run pegjs && tsc && vite build --watch\",\n    \"prepublishOnly\": \"npm run test && npm run build\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-typescript\": \"^11.1.2\",\n    \"@types/lodash\": \"^4.14.134\",\n    \"@types/node\": \"^20.4.7\",\n    \"jsdom\": \"^22.1.0\",\n    \"lodash\": \"^4.17.15\",\n    \"pegjs\": \"^0.10.0\",\n    \"prettier\": \"^3.0.1\",\n    \"rollup-plugin-typescript-paths\": \"^1.4.0\",\n    \"ts-pegjs\": \"^0.2.5\",\n    \"tslib\": \"^2.6.1\",\n    \"typescript\": \"^5.1.6\",\n    \"vite\": \"^4.4.8\",\n    \"vite-plugin-peggy-loader\": \"^1.0.1\",\n    \"vitest\": \"^0.34.1\"\n  },\n  \"prettier\": {\n    \"trailingComma\": \"es5\",\n    \"tabWidth\": 4,\n    \"semi\": true,\n    \"singleQuote\": true\n  }\n}\n"
  },
  {
    "path": "src/CommonTypes.ts",
    "content": "import JsonML from './JsonML';\n\nexport interface IFormatter {\n    format(obj: IElmDebugValue): any;\n}\n\nexport interface IJsonMLFormatter {\n    theme: ITheme;\n    handleHeader(obj: ElmDebugValueType, config?: IConfig): JsonML;\n    handleBody(obj: ElmDebugValueType, config?: IConfig): JsonML | null;\n}\n\nexport interface IDevToolsFormatter {\n    header(obj: ElmDebugValueType, config?: IConfig): any[] | null;\n    hasBody(obj: ElmDebugValueType, config?: IConfig): boolean;\n    body(obj: ElmDebugValueType, config?: IConfig): any[] | null;\n}\n\nexport interface IFormatterElement {\n    header(config?: IConfig): JsonML;\n    body?(config?: IConfig): JsonML | null;\n}\n\nexport type IThemeOption = \"dark\" | \"light\"\n\nexport interface ITheme {\n  booleanStyle: string;\n  stringStyle: string;\n  numberStyle: string;\n  debugTagStyle: string;\n  greyedStyle: string;\n  greyedItalicsStyle: string;\n  customTypeNameStyle: string;\n  typeNameStyle: string;\n  dataStructureNameStyle: string;\n  keyElementStyle: string;\n  bytesStyle: string;\n  expandableBorderStyle: string;\n  elmLogoElementStyle: string;\n}\n\nexport interface IConfig {\n    elmFormat: boolean;\n    level: number;\n    misc?: any;\n    key?: JsonML;\n}\n\nexport type ElmDebugValueType =\n    | IElmDebugValue\n    | IElmDebugCustomValue\n    | IElmDebugRecordValue\n    | IElmDebugListValue\n    | IElmDebugDictValue\n    | IElmDebugTypeValueType\n    | IElmDebugNumberValue\n    | IElmDebugStringValue\n    | IElmDebugBoolValue;\n\nexport interface IElmDebugValue {\n    type: string;\n    name?: string;\n    value?: ElmDebugValueType;\n}\n\nexport interface IElmDebugCustomValue {\n    type: string;\n    name: string;\n    value: ElmDebugValueType[];\n}\n\nexport interface IElmDebugTypeValueType {\n    type: string;\n    name: string;\n}\n\nexport interface IElmDebugListValue {\n    type: string;\n    value: ElmDebugValueType[];\n}\n\nexport interface IElmDebugRecordValue {\n    type: string;\n    value: { [key: string]: ElmDebugValueType };\n}\n\nexport interface IElmDebugDictValue {\n    type: string;\n    value: Array<{ key: ElmDebugValueType; value: ElmDebugValueType }>;\n}\n\nexport interface IElmDebugNumberValue {\n    type: string;\n    value: number | string;\n}\n\nexport interface IElmDebugStringValue {\n    type: string;\n    value: string;\n}\n\nexport interface IElmDebugBoolValue {\n    type: string;\n    value: boolean;\n}\n\nexport function isElmValue(value: any): value is IElmDebugValue {\n    return (value as IElmDebugValue).type !== undefined;\n}\n\nexport function isElmCustomValue(value: any): value is IElmDebugCustomValue {\n    return value.type === 'Custom';\n}\n\nexport function isElmRecordValue(value: any): value is IElmDebugRecordValue {\n    return value.type === 'Record';\n}\n\nexport function isElmListValue(value: any): value is IElmDebugListValue {\n    return (\n        value.type === 'List' ||\n        value.type === 'Array' ||\n        value.type === 'Set' ||\n        value.type === 'Tuple'\n    );\n}\n\nexport function isElmNumberType(value: any): value is IElmDebugNumberValue {\n    return value.type === 'Number';\n}\n\nexport function isElmTypeValue(value: any): value is IElmDebugTypeValueType {\n    return value.type === 'Type';\n}\n\nexport function isElmDictValue(value: any): value is IElmDebugDictValue {\n    return value.type === 'Dict';\n}\n"
  },
  {
    "path": "src/JsonML.ts",
    "content": "import { IConfig } from './CommonTypes';\nexport type TagName = 'div' | 'span';\n\nexport default class JSONMLElement {\n    private attributes: { [key: string]: any };\n    private jsonML: any[];\n\n    constructor(tagName: TagName) {\n        this.attributes = {};\n        this.jsonML = [tagName, this.attributes];\n    }\n\n    public toJSONML(): any {\n        return this.jsonML;\n    }\n\n    public withChild(element: JSONMLElement) {\n        this.jsonML.push(element.toJSONML());\n        return this;\n    }\n\n    public withChildren(elements: JSONMLElement[]) {\n        const children = elements.map(child => child.toJSONML());\n        this.jsonML = this.jsonML.concat(children);\n        return this;\n    }\n\n    public withObject(\n        key: JSONMLElement,\n        object: any,\n        config: IConfig = { elmFormat: true, level: 0 }\n    ) {\n        config.key = key;\n        this.jsonML.push(['object', { object, config }]);\n        return this;\n    }\n\n    public withStyle(style: string) {\n        this.attributes.style =\n            this.attributes.style === undefined\n                ? style\n                : this.attributes.style + style;\n        return this;\n    }\n\n    public withAttribute(key: string, value: any) {\n        this.attributes[key] = value;\n        return this;\n    }\n\n    public withText(value: any) {\n        this.jsonML.push(value + '');\n        return this;\n    }\n\n    public toStr(): string {\n        return this.toStrInner(this.jsonML);\n    }\n\n    private toStrInner(jsonML: any[]): string {\n        return jsonML\n            .map((item, index) => {\n                if (index < 2) {\n                    return '';\n                } else if (typeof item === 'string') {\n                    return item;\n                } else if (item instanceof Array) {\n                    return this.toStrInner(item);\n                } else {\n                    return '';\n                }\n            })\n            .join('');\n    }\n}\n"
  },
  {
    "path": "src/elm-debug-parser.ts",
    "content": "// tslint:disable:only-arrow-functions\n// tslint:disable:object-literal-shorthand\n// tslint:disable:trailing-comma\n// tslint:disable:object-literal-sort-keys\n// tslint:disable:one-variable-per-declaration\n// tslint:disable:max-line-length\n// tslint:disable:no-consecutive-blank-lines\n// tslint:disable:align\n\n\n// Generated by PEG.js v. 0.10.0 (ts-pegjs plugin v. 0.2.7 )\n//\n// https://pegjs.org/   https://github.com/metadevpro/ts-pegjs\n\n\"use strict\";\n\nexport interface IFilePosition {\n  offset: number;\n  line: number;\n  column: number;\n}\n\nexport interface IFileRange {\n  start: IFilePosition;\n  end: IFilePosition;\n}\n\nexport interface ILiteralExpectation {\n  type: \"literal\";\n  text: string;\n  ignoreCase: boolean;\n}\n\nexport interface IClassParts extends Array<string | IClassParts> {}\n\nexport interface IClassExpectation {\n  type: \"class\";\n  parts: IClassParts;\n  inverted: boolean;\n  ignoreCase: boolean;\n}\n\nexport interface IAnyExpectation {\n  type: \"any\";\n}\n\nexport interface IEndExpectation {\n  type: \"end\";\n}\n\nexport interface IOtherExpectation {\n  type: \"other\";\n  description: string;\n}\n\nexport type Expectation = ILiteralExpectation | IClassExpectation | IAnyExpectation | IEndExpectation | IOtherExpectation;\n\nexport class SyntaxError extends Error {\n  public static buildMessage(expected: Expectation[], found: string | null) {\n    function hex(ch: string): string {\n      return ch.charCodeAt(0).toString(16).toUpperCase();\n    }\n\n    function literalEscape(s: string): string {\n      return s\n        .replace(/\\\\/g, \"\\\\\\\\\")\n        .replace(/\"/g,  \"\\\\\\\"\")\n        .replace(/\\0/g, \"\\\\0\")\n        .replace(/\\t/g, \"\\\\t\")\n        .replace(/\\n/g, \"\\\\n\")\n        .replace(/\\r/g, \"\\\\r\")\n        .replace(/[\\x00-\\x0F]/g,            (ch) => \"\\\\x0\" + hex(ch) )\n        .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, (ch) => \"\\\\x\"  + hex(ch) );\n    }\n\n    function classEscape(s: string): string {\n      return s\n        .replace(/\\\\/g, \"\\\\\\\\\")\n        .replace(/\\]/g, \"\\\\]\")\n        .replace(/\\^/g, \"\\\\^\")\n        .replace(/-/g,  \"\\\\-\")\n        .replace(/\\0/g, \"\\\\0\")\n        .replace(/\\t/g, \"\\\\t\")\n        .replace(/\\n/g, \"\\\\n\")\n        .replace(/\\r/g, \"\\\\r\")\n        .replace(/[\\x00-\\x0F]/g,            (ch) => \"\\\\x0\" + hex(ch) )\n        .replace(/[\\x10-\\x1F\\x7F-\\x9F]/g, (ch) => \"\\\\x\"  + hex(ch) );\n    }\n\n    function describeExpectation(expectation: Expectation) {\n      switch (expectation.type) {\n        case \"literal\":\n          return \"\\\"\" + literalEscape(expectation.text) + \"\\\"\";\n        case \"class\":\n          const escapedParts = expectation.parts.map((part) => {\n            return Array.isArray(part)\n              ? classEscape(part[0] as string) + \"-\" + classEscape(part[1] as string)\n              : classEscape(part);\n          });\n\n          return \"[\" + (expectation.inverted ? \"^\" : \"\") + escapedParts + \"]\";\n        case \"any\":\n          return \"any character\";\n        case \"end\":\n          return \"end of input\";\n        case \"other\":\n          return expectation.description;\n      }\n    }\n\n    function describeExpected(expected1: Expectation[]) {\n      const descriptions = expected1.map(describeExpectation);\n      let i: number;\n      let j: number;\n\n      descriptions.sort();\n\n      if (descriptions.length > 0) {\n        for (i = 1, j = 1; i < descriptions.length; i++) {\n          if (descriptions[i - 1] !== descriptions[i]) {\n            descriptions[j] = descriptions[i];\n            j++;\n          }\n        }\n        descriptions.length = j;\n      }\n\n      switch (descriptions.length) {\n        case 1:\n          return descriptions[0];\n\n        case 2:\n          return descriptions[0] + \" or \" + descriptions[1];\n\n        default:\n          return descriptions.slice(0, -1).join(\", \")\n            + \", or \"\n            + descriptions[descriptions.length - 1];\n      }\n    }\n\n    function describeFound(found1: string | null) {\n      return found1 ? \"\\\"\" + literalEscape(found1) + \"\\\"\" : \"end of input\";\n    }\n\n    return \"Expected \" + describeExpected(expected) + \" but \" + describeFound(found) + \" found.\";\n  }\n\n  public message: string;\n  public expected: Expectation[];\n  public found: string | null;\n  public location: IFileRange;\n  public name: string;\n\n  constructor(message: string, expected: Expectation[], found: string | null, location: IFileRange) {\n    super();\n    this.message = message;\n    this.expected = expected;\n    this.found = found;\n    this.location = location;\n    this.name = \"SyntaxError\";\n\n    if (typeof (Error as any).captureStackTrace === \"function\") {\n      (Error as any).captureStackTrace(this, SyntaxError);\n    }\n  }\n}\n\nfunction peg$parse(input: string, options?: IParseOptions) {\n  options = options !== undefined ? options : {};\n\n  const peg$FAILED: Readonly<{}> = {};\n\n  const peg$startRuleFunctions: {[id: string]: any} = { DebugString: peg$parseDebugString };\n  let peg$startRuleFunction: () => any = peg$parseDebugString;\n\n  const peg$c0 = \":\";\n  const peg$c1 = peg$literalExpectation(\":\", false);\n  const peg$c2 = function(tag: any, value: any): any {return {type: \"ElmDebug\", name: tag, value: value};};\n  const peg$c3 = function(value: any): any {return {type: \"ElmDebug\", name: \"\", value: value};};\n  const peg$c4 = \"{}\";\n  const peg$c5 = peg$literalExpectation(\"{}\", false);\n  const peg$c6 = function(): any {return {type: \"Record\", value: {}};};\n  const peg$c7 = \"{ \";\n  const peg$c8 = peg$literalExpectation(\"{ \", false);\n  const peg$c9 = \" = \";\n  const peg$c10 = peg$literalExpectation(\" = \", false);\n  const peg$c11 = \" }\";\n  const peg$c12 = peg$literalExpectation(\" }\", false);\n  const peg$c13 = function(key: any, value: any): any {return {type: \"Record\", value: {[key]: value}}};\n  const peg$c14 = \", \";\n  const peg$c15 = peg$literalExpectation(\", \", false);\n  const peg$c16 = function(key: any, value: any, tag: any, otherVal: any): any {return {[tag]: otherVal};};\n  const peg$c17 = function(key: any, value: any, values: any): any { var composed = [{[key]: value},...values].reduce((item, obj) => {return {...item,...obj} },{}); return {type: \"Record\", value: composed}};\n  const peg$c18 = \"Dict.fromList \";\n  const peg$c19 = peg$literalExpectation(\"Dict.fromList \", false);\n  const peg$c20 = function(values: any): any {return {type: \"Dict\", value: values.map((tuple) => { return {key: tuple.value[0], value: tuple.value[1]};})}};\n  const peg$c21 = \"Set.fromList \";\n  const peg$c22 = peg$literalExpectation(\"Set.fromList \", false);\n  const peg$c23 = function(values: any): any {return {type: \"Set\", value: values};};\n  const peg$c24 = \"Array.fromList \";\n  const peg$c25 = peg$literalExpectation(\"Array.fromList \", false);\n  const peg$c26 = function(values: any): any {return {type: \"Array\", value: values};};\n  const peg$c27 = \"()\";\n  const peg$c28 = peg$literalExpectation(\"()\", false);\n  const peg$c29 = function(): any {return {type:\"Unit\"}};\n  const peg$c30 = \"(\";\n  const peg$c31 = peg$literalExpectation(\"(\", false);\n  const peg$c32 = \",\";\n  const peg$c33 = peg$literalExpectation(\",\", false);\n  const peg$c34 = function(head: any, item: any): any {return item;};\n  const peg$c35 = \")\";\n  const peg$c36 = peg$literalExpectation(\")\", false);\n  const peg$c37 = function(head: any, others: any): any {return {type: \"Tuple\", value: [head,...others]};};\n  const peg$c38 = function(customType: any): any {return customType;};\n  const peg$c39 = function(mainType: any, value: any): any {return value;};\n  const peg$c40 = function(mainType: any, values: any): any {return {type: \"Custom\", name: mainType.name, value: values};};\n  const peg$c41 = function(mainType: any, customType: any): any {return {type: \"Custom\", name: mainType.name, value: customType};};\n  const peg$c42 = function(list: any): any {return {type: \"List\", value: list};};\n  const peg$c43 = /^[0-9.]/;\n  const peg$c44 = peg$classExpectation([[\"0\", \"9\"], \".\"], false, false);\n  const peg$c45 = function(digits: any): any {return {type: \"Number\", value: parseFloat(toStr(digits))};};\n  const peg$c46 = \"-\";\n  const peg$c47 = peg$literalExpectation(\"-\", false);\n  const peg$c48 = function(digits: any): any {return {type: \"Number\", value: parseFloat(\"-\"+toStr(digits))};};\n  const peg$c49 = \"NaN\";\n  const peg$c50 = peg$literalExpectation(\"NaN\", false);\n  const peg$c51 = function(): any {return {type: \"Number\", value: \"NaN\"};};\n  const peg$c52 = \"Infinity\";\n  const peg$c53 = peg$literalExpectation(\"Infinity\", false);\n  const peg$c54 = function(): any {return {type: \"Number\", value: \"Infinity\"};};\n  const peg$c55 = \"-Infinity\";\n  const peg$c56 = peg$literalExpectation(\"-Infinity\", false);\n  const peg$c57 = function(): any {return {type: \"Number\", value: \"-Infinity\"};};\n  const peg$c58 = \"True\";\n  const peg$c59 = peg$literalExpectation(\"True\", false);\n  const peg$c60 = function(): any {return {type: \"Boolean\", value: true};};\n  const peg$c61 = \"False\";\n  const peg$c62 = peg$literalExpectation(\"False\", false);\n  const peg$c63 = function(): any {return {type: \"Boolean\", value: false};};\n  const peg$c64 = \"<function>\";\n  const peg$c65 = peg$literalExpectation(\"<function>\", false);\n  const peg$c66 = function(): any {return {type: \"Function\"};};\n  const peg$c67 = \"<internals>\";\n  const peg$c68 = peg$literalExpectation(\"<internals>\", false);\n  const peg$c69 = function(): any {return {type: \"Internals\"};};\n  const peg$c70 = \"<\";\n  const peg$c71 = peg$literalExpectation(\"<\", false);\n  const peg$c72 = /^[0-9]/;\n  const peg$c73 = peg$classExpectation([[\"0\", \"9\"]], false, false);\n  const peg$c74 = \" bytes>\";\n  const peg$c75 = peg$literalExpectation(\" bytes>\", false);\n  const peg$c76 = function(digits: any): any {return {type: \"Bytes\", value: parseInt(toStr(digits), 10)};};\n  const peg$c77 = \"\\\"\";\n  const peg$c78 = peg$literalExpectation(\"\\\"\", false);\n  const peg$c79 = \"\\\\\";\n  const peg$c80 = peg$literalExpectation(\"\\\\\", false);\n  const peg$c81 = \">\";\n  const peg$c82 = peg$literalExpectation(\">\", false);\n  const peg$c83 = peg$anyExpectation();\n  const peg$c84 = function(char: any): any { return char; };\n  const peg$c85 = function(chars: any): any {return { type: \"File\", value: chars.join('') };};\n  const peg$c86 = /^[a-zA-Z0-9_]/;\n  const peg$c87 = peg$classExpectation([[\"a\", \"z\"], [\"A\", \"Z\"], [\"0\", \"9\"], \"_\"], false, false);\n  const peg$c88 = function(chars: any): any {return toStr(chars);};\n  const peg$c89 = /^[A-Z]/;\n  const peg$c90 = peg$classExpectation([[\"A\", \"Z\"]], false, false);\n  const peg$c91 = function(type: any): any {return {type: \"Type\", name: toStr(flat(type))};};\n  const peg$c92 = function(tag: any): any { return toStr(tag); };\n  const peg$c93 = function(chars: any): any { return {type: \"String\", value: chars.join('')}; };\n  const peg$c94 = \"'\";\n  const peg$c95 = peg$literalExpectation(\"'\", false);\n  const peg$c96 = function(chars: any): any { return { type: \"String\", value: chars.join('')}; };\n  const peg$c97 = \"[]\";\n  const peg$c98 = peg$literalExpectation(\"[]\", false);\n  const peg$c99 = function(): any {return [];};\n  const peg$c100 = \"[\";\n  const peg$c101 = peg$literalExpectation(\"[\", false);\n  const peg$c102 = \"]\";\n  const peg$c103 = peg$literalExpectation(\"]\", false);\n  const peg$c104 = function(singleton: any): any {return singleton;};\n  const peg$c105 = function(list: any): any {return [list];};\n  const peg$c106 = function(head: any, value: any): any {return value;};\n  const peg$c107 = function(head: any, tail: any): any {return [head, ...tail]};\n  const peg$c108 = function(sequence: any): any { return sequence; };\n  const peg$c109 = \"b\";\n  const peg$c110 = peg$literalExpectation(\"b\", false);\n  const peg$c111 = function(): any { return \"\\b\";   };\n  const peg$c112 = \"f\";\n  const peg$c113 = peg$literalExpectation(\"f\", false);\n  const peg$c114 = function(): any { return \"\\f\";   };\n  const peg$c115 = \"n\";\n  const peg$c116 = peg$literalExpectation(\"n\", false);\n  const peg$c117 = function(): any { return \"\\n\";   };\n  const peg$c118 = \"r\";\n  const peg$c119 = peg$literalExpectation(\"r\", false);\n  const peg$c120 = function(): any { return \"\\r\";   };\n  const peg$c121 = \"t\";\n  const peg$c122 = peg$literalExpectation(\"t\", false);\n  const peg$c123 = function(): any { return \"\\t\";   };\n  const peg$c124 = \"v\";\n  const peg$c125 = peg$literalExpectation(\"v\", false);\n  const peg$c126 = function(): any { return \"\\x0B\"; };\n  const peg$c127 = peg$otherExpectation(\"whitespace\");\n  const peg$c128 = /^[ \\t\\n\\r]/;\n  const peg$c129 = peg$classExpectation([\" \", \"\\t\", \"\\n\", \"\\r\"], false, false);\n\n  let peg$currPos = 0;\n  let peg$savedPos = 0;\n  const peg$posDetailsCache = [{ line: 1, column: 1 }];\n  let peg$maxFailPos = 0;\n  let peg$maxFailExpected: Expectation[] = [];\n  let peg$silentFails = 0;\n\n  let peg$result;\n\n  if (options.startRule !== undefined) {\n    if (!(options.startRule in peg$startRuleFunctions)) {\n      throw new Error(\"Can't start parsing from rule \\\"\" + options.startRule + \"\\\".\");\n    }\n\n    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];\n  }\n\n  function text(): string {\n    return input.substring(peg$savedPos, peg$currPos);\n  }\n\n  function location(): IFileRange {\n    return peg$computeLocation(peg$savedPos, peg$currPos);\n  }\n\n  function expected(description: string, location1?: IFileRange) {\n    location1 = location1 !== undefined\n      ? location1\n      : peg$computeLocation(peg$savedPos, peg$currPos);\n\n    throw peg$buildStructuredError(\n      [peg$otherExpectation(description)],\n      input.substring(peg$savedPos, peg$currPos),\n      location1\n    );\n  }\n\n  function error(message: string, location1?: IFileRange) {\n    location1 = location1 !== undefined\n      ? location1\n      : peg$computeLocation(peg$savedPos, peg$currPos);\n\n    throw peg$buildSimpleError(message, location1);\n  }\n\n  function peg$literalExpectation(text1: string, ignoreCase: boolean): ILiteralExpectation {\n    return { type: \"literal\", text: text1, ignoreCase: ignoreCase };\n  }\n\n  function peg$classExpectation(parts: IClassParts, inverted: boolean, ignoreCase: boolean): IClassExpectation {\n    return { type: \"class\", parts: parts, inverted: inverted, ignoreCase: ignoreCase };\n  }\n\n  function peg$anyExpectation(): IAnyExpectation {\n    return { type: \"any\" };\n  }\n\n  function peg$endExpectation(): IEndExpectation {\n    return { type: \"end\" };\n  }\n\n  function peg$otherExpectation(description: string): IOtherExpectation {\n    return { type: \"other\", description: description };\n  }\n\n  function peg$computePosDetails(pos: number) {\n    let details = peg$posDetailsCache[pos];\n    let p;\n\n    if (details) {\n      return details;\n    } else {\n      p = pos - 1;\n      while (!peg$posDetailsCache[p]) {\n        p--;\n      }\n\n      details = peg$posDetailsCache[p];\n      details = {\n        line: details.line,\n        column: details.column\n      };\n\n      while (p < pos) {\n        if (input.charCodeAt(p) === 10) {\n          details.line++;\n          details.column = 1;\n        } else {\n          details.column++;\n        }\n\n        p++;\n      }\n\n      peg$posDetailsCache[pos] = details;\n\n      return details;\n    }\n  }\n\n  function peg$computeLocation(startPos: number, endPos: number): IFileRange {\n    const startPosDetails = peg$computePosDetails(startPos);\n    const endPosDetails = peg$computePosDetails(endPos);\n\n    return {\n      start: {\n        offset: startPos,\n        line: startPosDetails.line,\n        column: startPosDetails.column\n      },\n      end: {\n        offset: endPos,\n        line: endPosDetails.line,\n        column: endPosDetails.column\n      }\n    };\n  }\n\n  function peg$fail(expected1: Expectation) {\n    if (peg$currPos < peg$maxFailPos) { return; }\n\n    if (peg$currPos > peg$maxFailPos) {\n      peg$maxFailPos = peg$currPos;\n      peg$maxFailExpected = [];\n    }\n\n    peg$maxFailExpected.push(expected1);\n  }\n\n  function peg$buildSimpleError(message: string, location1: IFileRange) {\n    return new SyntaxError(message, [], \"\", location1);\n  }\n\n  function peg$buildStructuredError(expected1: Expectation[], found: string | null, location1: IFileRange) {\n    return new SyntaxError(\n      SyntaxError.buildMessage(expected1, found),\n      expected1,\n      found,\n      location1\n    );\n  }\n\n  function peg$parseDebugString(): any {\n    let s0, s1, s2, s3, s4, s5;\n\n    s0 = peg$currPos;\n    s1 = peg$parseTag();\n    if (s1 !== peg$FAILED) {\n      s2 = [];\n      s3 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 58) {\n        s4 = peg$c0;\n        peg$currPos++;\n      } else {\n        s4 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c1); }\n      }\n      if (s4 !== peg$FAILED) {\n        s5 = peg$parse_();\n        if (s5 !== peg$FAILED) {\n          s4 = [s4, s5];\n          s3 = s4;\n        } else {\n          peg$currPos = s3;\n          s3 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s3;\n        s3 = peg$FAILED;\n      }\n      if (s3 !== peg$FAILED) {\n        while (s3 !== peg$FAILED) {\n          s2.push(s3);\n          s3 = peg$currPos;\n          if (input.charCodeAt(peg$currPos) === 58) {\n            s4 = peg$c0;\n            peg$currPos++;\n          } else {\n            s4 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c1); }\n          }\n          if (s4 !== peg$FAILED) {\n            s5 = peg$parse_();\n            if (s5 !== peg$FAILED) {\n              s4 = [s4, s5];\n              s3 = s4;\n            } else {\n              peg$currPos = s3;\n              s3 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s3;\n            s3 = peg$FAILED;\n          }\n        }\n      } else {\n        s2 = peg$FAILED;\n      }\n      if (s2 !== peg$FAILED) {\n        s3 = peg$parseValue();\n        if (s3 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c2(s1, s3);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 58) {\n        s1 = peg$c0;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c1); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parse_();\n        if (s2 !== peg$FAILED) {\n          s3 = peg$parseValue();\n          if (s3 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c3(s3);\n            s0 = s1;\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseValue(): any {\n    let s0;\n\n    s0 = peg$parseRecord();\n    if (s0 === peg$FAILED) {\n      s0 = peg$parseArray();\n      if (s0 === peg$FAILED) {\n        s0 = peg$parseSet();\n        if (s0 === peg$FAILED) {\n          s0 = peg$parseDict();\n          if (s0 === peg$FAILED) {\n            s0 = peg$parseList();\n            if (s0 === peg$FAILED) {\n              s0 = peg$parseCustomTypeWithParens();\n              if (s0 === peg$FAILED) {\n                s0 = peg$parseCustomType();\n                if (s0 === peg$FAILED) {\n                  s0 = peg$parseTuple();\n                  if (s0 === peg$FAILED) {\n                    s0 = peg$parseNumber();\n                    if (s0 === peg$FAILED) {\n                      s0 = peg$parseBoolean();\n                      if (s0 === peg$FAILED) {\n                        s0 = peg$parseType();\n                        if (s0 === peg$FAILED) {\n                          s0 = peg$parseInternals();\n                          if (s0 === peg$FAILED) {\n                            s0 = peg$parseBytes();\n                            if (s0 === peg$FAILED) {\n                              s0 = peg$parseFile();\n                              if (s0 === peg$FAILED) {\n                                s0 = peg$parseString();\n                              }\n                            }\n                          }\n                        }\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseCustomTypeValue(): any {\n    let s0;\n\n    s0 = peg$parseRecord();\n    if (s0 === peg$FAILED) {\n      s0 = peg$parseArray();\n      if (s0 === peg$FAILED) {\n        s0 = peg$parseSet();\n        if (s0 === peg$FAILED) {\n          s0 = peg$parseDict();\n          if (s0 === peg$FAILED) {\n            s0 = peg$parseList();\n            if (s0 === peg$FAILED) {\n              s0 = peg$parseCustomTypeWithParens();\n              if (s0 === peg$FAILED) {\n                s0 = peg$parseTuple();\n                if (s0 === peg$FAILED) {\n                  s0 = peg$parseNumber();\n                  if (s0 === peg$FAILED) {\n                    s0 = peg$parseBoolean();\n                    if (s0 === peg$FAILED) {\n                      s0 = peg$parseType();\n                      if (s0 === peg$FAILED) {\n                        s0 = peg$parseInternals();\n                        if (s0 === peg$FAILED) {\n                          s0 = peg$parseBytes();\n                          if (s0 === peg$FAILED) {\n                            s0 = peg$parseFile();\n                            if (s0 === peg$FAILED) {\n                              s0 = peg$parseString();\n                            }\n                          }\n                        }\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseRecord(): any {\n    let s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 2) === peg$c4) {\n      s1 = peg$c4;\n      peg$currPos += 2;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c5); }\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c6();\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.substr(peg$currPos, 2) === peg$c7) {\n        s1 = peg$c7;\n        peg$currPos += 2;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c8); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parseVariableName();\n        if (s2 !== peg$FAILED) {\n          if (input.substr(peg$currPos, 3) === peg$c9) {\n            s3 = peg$c9;\n            peg$currPos += 3;\n          } else {\n            s3 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c10); }\n          }\n          if (s3 !== peg$FAILED) {\n            s4 = peg$parseValue();\n            if (s4 !== peg$FAILED) {\n              if (input.substr(peg$currPos, 2) === peg$c11) {\n                s5 = peg$c11;\n                peg$currPos += 2;\n              } else {\n                s5 = peg$FAILED;\n                if (peg$silentFails === 0) { peg$fail(peg$c12); }\n              }\n              if (s5 !== peg$FAILED) {\n                peg$savedPos = s0;\n                s1 = peg$c13(s2, s4);\n                s0 = s1;\n              } else {\n                peg$currPos = s0;\n                s0 = peg$FAILED;\n              }\n            } else {\n              peg$currPos = s0;\n              s0 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n      if (s0 === peg$FAILED) {\n        s0 = peg$currPos;\n        if (input.substr(peg$currPos, 2) === peg$c7) {\n          s1 = peg$c7;\n          peg$currPos += 2;\n        } else {\n          s1 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c8); }\n        }\n        if (s1 !== peg$FAILED) {\n          s2 = peg$parseVariableName();\n          if (s2 !== peg$FAILED) {\n            if (input.substr(peg$currPos, 3) === peg$c9) {\n              s3 = peg$c9;\n              peg$currPos += 3;\n            } else {\n              s3 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c10); }\n            }\n            if (s3 !== peg$FAILED) {\n              s4 = peg$parseValue();\n              if (s4 !== peg$FAILED) {\n                s5 = [];\n                s6 = peg$currPos;\n                if (input.substr(peg$currPos, 2) === peg$c14) {\n                  s7 = peg$c14;\n                  peg$currPos += 2;\n                } else {\n                  s7 = peg$FAILED;\n                  if (peg$silentFails === 0) { peg$fail(peg$c15); }\n                }\n                if (s7 !== peg$FAILED) {\n                  s8 = peg$parseVariableName();\n                  if (s8 !== peg$FAILED) {\n                    if (input.substr(peg$currPos, 3) === peg$c9) {\n                      s9 = peg$c9;\n                      peg$currPos += 3;\n                    } else {\n                      s9 = peg$FAILED;\n                      if (peg$silentFails === 0) { peg$fail(peg$c10); }\n                    }\n                    if (s9 !== peg$FAILED) {\n                      s10 = peg$parseValue();\n                      if (s10 !== peg$FAILED) {\n                        peg$savedPos = s6;\n                        s7 = peg$c16(s2, s4, s8, s10);\n                        s6 = s7;\n                      } else {\n                        peg$currPos = s6;\n                        s6 = peg$FAILED;\n                      }\n                    } else {\n                      peg$currPos = s6;\n                      s6 = peg$FAILED;\n                    }\n                  } else {\n                    peg$currPos = s6;\n                    s6 = peg$FAILED;\n                  }\n                } else {\n                  peg$currPos = s6;\n                  s6 = peg$FAILED;\n                }\n                while (s6 !== peg$FAILED) {\n                  s5.push(s6);\n                  s6 = peg$currPos;\n                  if (input.substr(peg$currPos, 2) === peg$c14) {\n                    s7 = peg$c14;\n                    peg$currPos += 2;\n                  } else {\n                    s7 = peg$FAILED;\n                    if (peg$silentFails === 0) { peg$fail(peg$c15); }\n                  }\n                  if (s7 !== peg$FAILED) {\n                    s8 = peg$parseVariableName();\n                    if (s8 !== peg$FAILED) {\n                      if (input.substr(peg$currPos, 3) === peg$c9) {\n                        s9 = peg$c9;\n                        peg$currPos += 3;\n                      } else {\n                        s9 = peg$FAILED;\n                        if (peg$silentFails === 0) { peg$fail(peg$c10); }\n                      }\n                      if (s9 !== peg$FAILED) {\n                        s10 = peg$parseValue();\n                        if (s10 !== peg$FAILED) {\n                          peg$savedPos = s6;\n                          s7 = peg$c16(s2, s4, s8, s10);\n                          s6 = s7;\n                        } else {\n                          peg$currPos = s6;\n                          s6 = peg$FAILED;\n                        }\n                      } else {\n                        peg$currPos = s6;\n                        s6 = peg$FAILED;\n                      }\n                    } else {\n                      peg$currPos = s6;\n                      s6 = peg$FAILED;\n                    }\n                  } else {\n                    peg$currPos = s6;\n                    s6 = peg$FAILED;\n                  }\n                }\n                if (s5 !== peg$FAILED) {\n                  if (input.substr(peg$currPos, 2) === peg$c11) {\n                    s6 = peg$c11;\n                    peg$currPos += 2;\n                  } else {\n                    s6 = peg$FAILED;\n                    if (peg$silentFails === 0) { peg$fail(peg$c12); }\n                  }\n                  if (s6 !== peg$FAILED) {\n                    peg$savedPos = s0;\n                    s1 = peg$c17(s2, s4, s5);\n                    s0 = s1;\n                  } else {\n                    peg$currPos = s0;\n                    s0 = peg$FAILED;\n                  }\n                } else {\n                  peg$currPos = s0;\n                  s0 = peg$FAILED;\n                }\n              } else {\n                peg$currPos = s0;\n                s0 = peg$FAILED;\n              }\n            } else {\n              peg$currPos = s0;\n              s0 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseDict(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 14) === peg$c18) {\n      s1 = peg$c18;\n      peg$currPos += 14;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c19); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = peg$parseListValue();\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c20(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseSet(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 13) === peg$c21) {\n      s1 = peg$c21;\n      peg$currPos += 13;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c22); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = peg$parseListValue();\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c23(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseArray(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 15) === peg$c24) {\n      s1 = peg$c24;\n      peg$currPos += 15;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c25); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = peg$parseListValue();\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c26(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseTuple(): any {\n    let s0, s1, s2, s3, s4, s5, s6, s7, s8;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 2) === peg$c27) {\n      s1 = peg$c27;\n      peg$currPos += 2;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c28); }\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c29();\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 40) {\n        s1 = peg$c30;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c31); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parseValue();\n        if (s2 !== peg$FAILED) {\n          s3 = [];\n          s4 = peg$currPos;\n          s5 = peg$parse_();\n          if (s5 !== peg$FAILED) {\n            if (input.charCodeAt(peg$currPos) === 44) {\n              s6 = peg$c32;\n              peg$currPos++;\n            } else {\n              s6 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c33); }\n            }\n            if (s6 !== peg$FAILED) {\n              s7 = peg$parse_();\n              if (s7 !== peg$FAILED) {\n                s8 = peg$parseValue();\n                if (s8 !== peg$FAILED) {\n                  peg$savedPos = s4;\n                  s5 = peg$c34(s2, s8);\n                  s4 = s5;\n                } else {\n                  peg$currPos = s4;\n                  s4 = peg$FAILED;\n                }\n              } else {\n                peg$currPos = s4;\n                s4 = peg$FAILED;\n              }\n            } else {\n              peg$currPos = s4;\n              s4 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s4;\n            s4 = peg$FAILED;\n          }\n          if (s4 !== peg$FAILED) {\n            while (s4 !== peg$FAILED) {\n              s3.push(s4);\n              s4 = peg$currPos;\n              s5 = peg$parse_();\n              if (s5 !== peg$FAILED) {\n                if (input.charCodeAt(peg$currPos) === 44) {\n                  s6 = peg$c32;\n                  peg$currPos++;\n                } else {\n                  s6 = peg$FAILED;\n                  if (peg$silentFails === 0) { peg$fail(peg$c33); }\n                }\n                if (s6 !== peg$FAILED) {\n                  s7 = peg$parse_();\n                  if (s7 !== peg$FAILED) {\n                    s8 = peg$parseValue();\n                    if (s8 !== peg$FAILED) {\n                      peg$savedPos = s4;\n                      s5 = peg$c34(s2, s8);\n                      s4 = s5;\n                    } else {\n                      peg$currPos = s4;\n                      s4 = peg$FAILED;\n                    }\n                  } else {\n                    peg$currPos = s4;\n                    s4 = peg$FAILED;\n                  }\n                } else {\n                  peg$currPos = s4;\n                  s4 = peg$FAILED;\n                }\n              } else {\n                peg$currPos = s4;\n                s4 = peg$FAILED;\n              }\n            }\n          } else {\n            s3 = peg$FAILED;\n          }\n          if (s3 !== peg$FAILED) {\n            if (input.charCodeAt(peg$currPos) === 41) {\n              s4 = peg$c35;\n              peg$currPos++;\n            } else {\n              s4 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c36); }\n            }\n            if (s4 !== peg$FAILED) {\n              peg$savedPos = s0;\n              s1 = peg$c37(s2, s3);\n              s0 = s1;\n            } else {\n              peg$currPos = s0;\n              s0 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseCustomTypeWithParens(): any {\n    let s0, s1, s2, s3, s4, s5;\n\n    s0 = peg$currPos;\n    if (input.charCodeAt(peg$currPos) === 40) {\n      s1 = peg$c30;\n      peg$currPos++;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c31); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = peg$parse_();\n      if (s2 !== peg$FAILED) {\n        s3 = peg$parseCustomType();\n        if (s3 !== peg$FAILED) {\n          s4 = peg$parse_();\n          if (s4 !== peg$FAILED) {\n            if (input.charCodeAt(peg$currPos) === 41) {\n              s5 = peg$c35;\n              peg$currPos++;\n            } else {\n              s5 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c36); }\n            }\n            if (s5 !== peg$FAILED) {\n              peg$savedPos = s0;\n              s1 = peg$c38(s3);\n              s0 = s1;\n            } else {\n              peg$currPos = s0;\n              s0 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseCustomType(): any {\n    let s0, s1, s2, s3, s4, s5;\n\n    s0 = peg$currPos;\n    s1 = peg$parseType();\n    if (s1 !== peg$FAILED) {\n      s2 = [];\n      s3 = peg$currPos;\n      s4 = peg$parse_();\n      if (s4 !== peg$FAILED) {\n        s5 = peg$parseCustomTypeValue();\n        if (s5 !== peg$FAILED) {\n          peg$savedPos = s3;\n          s4 = peg$c39(s1, s5);\n          s3 = s4;\n        } else {\n          peg$currPos = s3;\n          s3 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s3;\n        s3 = peg$FAILED;\n      }\n      if (s3 !== peg$FAILED) {\n        while (s3 !== peg$FAILED) {\n          s2.push(s3);\n          s3 = peg$currPos;\n          s4 = peg$parse_();\n          if (s4 !== peg$FAILED) {\n            s5 = peg$parseCustomTypeValue();\n            if (s5 !== peg$FAILED) {\n              peg$savedPos = s3;\n              s4 = peg$c39(s1, s5);\n              s3 = s4;\n            } else {\n              peg$currPos = s3;\n              s3 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s3;\n            s3 = peg$FAILED;\n          }\n        }\n      } else {\n        s2 = peg$FAILED;\n      }\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c40(s1, s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      s1 = peg$parseType();\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parse_();\n        if (s2 !== peg$FAILED) {\n          s3 = peg$parseCustomTypeWithParens();\n          if (s3 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c41(s1, s3);\n            s0 = s1;\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseList(): any {\n    let s0, s1;\n\n    s0 = peg$currPos;\n    s1 = peg$parseListValue();\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c42(s1);\n    }\n    s0 = s1;\n\n    return s0;\n  }\n\n  function peg$parseNumber(): any {\n    let s0, s1, s2, s3, s4;\n\n    s0 = peg$currPos;\n    s1 = [];\n    if (peg$c43.test(input.charAt(peg$currPos))) {\n      s2 = input.charAt(peg$currPos);\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c44); }\n    }\n    if (s2 !== peg$FAILED) {\n      while (s2 !== peg$FAILED) {\n        s1.push(s2);\n        if (peg$c43.test(input.charAt(peg$currPos))) {\n          s2 = input.charAt(peg$currPos);\n          peg$currPos++;\n        } else {\n          s2 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c44); }\n        }\n      }\n    } else {\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c45(s1);\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 45) {\n        s1 = peg$c46;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c47); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parse_();\n        if (s2 !== peg$FAILED) {\n          s3 = [];\n          if (peg$c43.test(input.charAt(peg$currPos))) {\n            s4 = input.charAt(peg$currPos);\n            peg$currPos++;\n          } else {\n            s4 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c44); }\n          }\n          if (s4 !== peg$FAILED) {\n            while (s4 !== peg$FAILED) {\n              s3.push(s4);\n              if (peg$c43.test(input.charAt(peg$currPos))) {\n                s4 = input.charAt(peg$currPos);\n                peg$currPos++;\n              } else {\n                s4 = peg$FAILED;\n                if (peg$silentFails === 0) { peg$fail(peg$c44); }\n              }\n            }\n          } else {\n            s3 = peg$FAILED;\n          }\n          if (s3 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c48(s3);\n            s0 = s1;\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n      if (s0 === peg$FAILED) {\n        s0 = peg$currPos;\n        if (input.substr(peg$currPos, 3) === peg$c49) {\n          s1 = peg$c49;\n          peg$currPos += 3;\n        } else {\n          s1 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c50); }\n        }\n        if (s1 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c51();\n        }\n        s0 = s1;\n        if (s0 === peg$FAILED) {\n          s0 = peg$currPos;\n          if (input.substr(peg$currPos, 8) === peg$c52) {\n            s1 = peg$c52;\n            peg$currPos += 8;\n          } else {\n            s1 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c53); }\n          }\n          if (s1 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c54();\n          }\n          s0 = s1;\n          if (s0 === peg$FAILED) {\n            s0 = peg$currPos;\n            if (input.substr(peg$currPos, 9) === peg$c55) {\n              s1 = peg$c55;\n              peg$currPos += 9;\n            } else {\n              s1 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c56); }\n            }\n            if (s1 !== peg$FAILED) {\n              peg$savedPos = s0;\n              s1 = peg$c57();\n            }\n            s0 = s1;\n          }\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseBoolean(): any {\n    let s0, s1;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 4) === peg$c58) {\n      s1 = peg$c58;\n      peg$currPos += 4;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c59); }\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c60();\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.substr(peg$currPos, 5) === peg$c61) {\n        s1 = peg$c61;\n        peg$currPos += 5;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c62); }\n      }\n      if (s1 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c63();\n      }\n      s0 = s1;\n    }\n\n    return s0;\n  }\n\n  function peg$parseInternals(): any {\n    let s0, s1;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 10) === peg$c64) {\n      s1 = peg$c64;\n      peg$currPos += 10;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c65); }\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c66();\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.substr(peg$currPos, 11) === peg$c67) {\n        s1 = peg$c67;\n        peg$currPos += 11;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c68); }\n      }\n      if (s1 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c69();\n      }\n      s0 = s1;\n    }\n\n    return s0;\n  }\n\n  function peg$parseBytes(): any {\n    let s0, s1, s2, s3;\n\n    s0 = peg$currPos;\n    if (input.charCodeAt(peg$currPos) === 60) {\n      s1 = peg$c70;\n      peg$currPos++;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c71); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = [];\n      if (peg$c72.test(input.charAt(peg$currPos))) {\n        s3 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s3 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c73); }\n      }\n      if (s3 !== peg$FAILED) {\n        while (s3 !== peg$FAILED) {\n          s2.push(s3);\n          if (peg$c72.test(input.charAt(peg$currPos))) {\n            s3 = input.charAt(peg$currPos);\n            peg$currPos++;\n          } else {\n            s3 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c73); }\n          }\n        }\n      } else {\n        s2 = peg$FAILED;\n      }\n      if (s2 !== peg$FAILED) {\n        if (input.substr(peg$currPos, 7) === peg$c74) {\n          s3 = peg$c74;\n          peg$currPos += 7;\n        } else {\n          s3 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c75); }\n        }\n        if (s3 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c76(s2);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseFile(): any {\n    let s0, s1, s2, s3, s4, s5;\n\n    s0 = peg$currPos;\n    if (input.charCodeAt(peg$currPos) === 60) {\n      s1 = peg$c70;\n      peg$currPos++;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c71); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = [];\n      s3 = peg$currPos;\n      s4 = peg$currPos;\n      peg$silentFails++;\n      if (input.charCodeAt(peg$currPos) === 34) {\n        s5 = peg$c77;\n        peg$currPos++;\n      } else {\n        s5 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c78); }\n      }\n      if (s5 === peg$FAILED) {\n        if (input.charCodeAt(peg$currPos) === 92) {\n          s5 = peg$c79;\n          peg$currPos++;\n        } else {\n          s5 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c80); }\n        }\n        if (s5 === peg$FAILED) {\n          if (input.charCodeAt(peg$currPos) === 60) {\n            s5 = peg$c70;\n            peg$currPos++;\n          } else {\n            s5 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c71); }\n          }\n          if (s5 === peg$FAILED) {\n            if (input.charCodeAt(peg$currPos) === 62) {\n              s5 = peg$c81;\n              peg$currPos++;\n            } else {\n              s5 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c82); }\n            }\n          }\n        }\n      }\n      peg$silentFails--;\n      if (s5 === peg$FAILED) {\n        s4 = undefined;\n      } else {\n        peg$currPos = s4;\n        s4 = peg$FAILED;\n      }\n      if (s4 !== peg$FAILED) {\n        if (input.length > peg$currPos) {\n          s5 = input.charAt(peg$currPos);\n          peg$currPos++;\n        } else {\n          s5 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c83); }\n        }\n        if (s5 !== peg$FAILED) {\n          peg$savedPos = s3;\n          s4 = peg$c84(s5);\n          s3 = s4;\n        } else {\n          peg$currPos = s3;\n          s3 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s3;\n        s3 = peg$FAILED;\n      }\n      if (s3 !== peg$FAILED) {\n        while (s3 !== peg$FAILED) {\n          s2.push(s3);\n          s3 = peg$currPos;\n          s4 = peg$currPos;\n          peg$silentFails++;\n          if (input.charCodeAt(peg$currPos) === 34) {\n            s5 = peg$c77;\n            peg$currPos++;\n          } else {\n            s5 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c78); }\n          }\n          if (s5 === peg$FAILED) {\n            if (input.charCodeAt(peg$currPos) === 92) {\n              s5 = peg$c79;\n              peg$currPos++;\n            } else {\n              s5 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c80); }\n            }\n            if (s5 === peg$FAILED) {\n              if (input.charCodeAt(peg$currPos) === 60) {\n                s5 = peg$c70;\n                peg$currPos++;\n              } else {\n                s5 = peg$FAILED;\n                if (peg$silentFails === 0) { peg$fail(peg$c71); }\n              }\n              if (s5 === peg$FAILED) {\n                if (input.charCodeAt(peg$currPos) === 62) {\n                  s5 = peg$c81;\n                  peg$currPos++;\n                } else {\n                  s5 = peg$FAILED;\n                  if (peg$silentFails === 0) { peg$fail(peg$c82); }\n                }\n              }\n            }\n          }\n          peg$silentFails--;\n          if (s5 === peg$FAILED) {\n            s4 = undefined;\n          } else {\n            peg$currPos = s4;\n            s4 = peg$FAILED;\n          }\n          if (s4 !== peg$FAILED) {\n            if (input.length > peg$currPos) {\n              s5 = input.charAt(peg$currPos);\n              peg$currPos++;\n            } else {\n              s5 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c83); }\n            }\n            if (s5 !== peg$FAILED) {\n              peg$savedPos = s3;\n              s4 = peg$c84(s5);\n              s3 = s4;\n            } else {\n              peg$currPos = s3;\n              s3 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s3;\n            s3 = peg$FAILED;\n          }\n        }\n      } else {\n        s2 = peg$FAILED;\n      }\n      if (s2 !== peg$FAILED) {\n        if (input.charCodeAt(peg$currPos) === 62) {\n          s3 = peg$c81;\n          peg$currPos++;\n        } else {\n          s3 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c82); }\n        }\n        if (s3 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c85(s2);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseVariableName(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    s1 = [];\n    if (peg$c86.test(input.charAt(peg$currPos))) {\n      s2 = input.charAt(peg$currPos);\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c87); }\n    }\n    if (s2 !== peg$FAILED) {\n      while (s2 !== peg$FAILED) {\n        s1.push(s2);\n        if (peg$c86.test(input.charAt(peg$currPos))) {\n          s2 = input.charAt(peg$currPos);\n          peg$currPos++;\n        } else {\n          s2 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c87); }\n        }\n      }\n    } else {\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c88(s1);\n    }\n    s0 = s1;\n\n    return s0;\n  }\n\n  function peg$parseType(): any {\n    let s0, s1, s2, s3, s4;\n\n    s0 = peg$currPos;\n    s1 = peg$currPos;\n    if (peg$c89.test(input.charAt(peg$currPos))) {\n      s2 = input.charAt(peg$currPos);\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c90); }\n    }\n    if (s2 !== peg$FAILED) {\n      s3 = [];\n      if (peg$c86.test(input.charAt(peg$currPos))) {\n        s4 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s4 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c87); }\n      }\n      if (s4 !== peg$FAILED) {\n        while (s4 !== peg$FAILED) {\n          s3.push(s4);\n          if (peg$c86.test(input.charAt(peg$currPos))) {\n            s4 = input.charAt(peg$currPos);\n            peg$currPos++;\n          } else {\n            s4 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c87); }\n          }\n        }\n      } else {\n        s3 = peg$FAILED;\n      }\n      if (s3 !== peg$FAILED) {\n        s2 = [s2, s3];\n        s1 = s2;\n      } else {\n        peg$currPos = s1;\n        s1 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s1;\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c91(s1);\n    }\n    s0 = s1;\n\n    return s0;\n  }\n\n  function peg$parseTag(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    s1 = [];\n    s2 = peg$parseTagChar();\n    if (s2 !== peg$FAILED) {\n      while (s2 !== peg$FAILED) {\n        s1.push(s2);\n        s2 = peg$parseTagChar();\n      }\n    } else {\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c92(s1);\n    }\n    s0 = s1;\n\n    return s0;\n  }\n\n  function peg$parseString(): any {\n    let s0, s1, s2, s3;\n\n    s0 = peg$currPos;\n    if (input.charCodeAt(peg$currPos) === 34) {\n      s1 = peg$c77;\n      peg$currPos++;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c78); }\n    }\n    if (s1 !== peg$FAILED) {\n      s2 = [];\n      s3 = peg$parseDoubleStringCharacter();\n      while (s3 !== peg$FAILED) {\n        s2.push(s3);\n        s3 = peg$parseDoubleStringCharacter();\n      }\n      if (s2 !== peg$FAILED) {\n        if (input.charCodeAt(peg$currPos) === 34) {\n          s3 = peg$c77;\n          peg$currPos++;\n        } else {\n          s3 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c78); }\n        }\n        if (s3 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c93(s2);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 39) {\n        s1 = peg$c94;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c95); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = [];\n        s3 = peg$parseSingleStringCharacter();\n        while (s3 !== peg$FAILED) {\n          s2.push(s3);\n          s3 = peg$parseSingleStringCharacter();\n        }\n        if (s2 !== peg$FAILED) {\n          if (input.charCodeAt(peg$currPos) === 39) {\n            s3 = peg$c94;\n            peg$currPos++;\n          } else {\n            s3 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c95); }\n          }\n          if (s3 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c96(s2);\n            s0 = s1;\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseListValue(): any {\n    let s0, s1, s2, s3, s4, s5, s6, s7;\n\n    s0 = peg$currPos;\n    if (input.substr(peg$currPos, 2) === peg$c97) {\n      s1 = peg$c97;\n      peg$currPos += 2;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c98); }\n    }\n    if (s1 !== peg$FAILED) {\n      peg$savedPos = s0;\n      s1 = peg$c99();\n    }\n    s0 = s1;\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      s1 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 91) {\n        s2 = peg$c100;\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c101); }\n      }\n      if (s2 !== peg$FAILED) {\n        s3 = peg$parseValue();\n        if (s3 !== peg$FAILED) {\n          if (input.charCodeAt(peg$currPos) === 93) {\n            s4 = peg$c102;\n            peg$currPos++;\n          } else {\n            s4 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c103); }\n          }\n          if (s4 !== peg$FAILED) {\n            peg$savedPos = s1;\n            s2 = peg$c104(s3);\n            s1 = s2;\n          } else {\n            peg$currPos = s1;\n            s1 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s1;\n          s1 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s1;\n        s1 = peg$FAILED;\n      }\n      if (s1 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c105(s1);\n      }\n      s0 = s1;\n      if (s0 === peg$FAILED) {\n        s0 = peg$currPos;\n        if (input.charCodeAt(peg$currPos) === 91) {\n          s1 = peg$c100;\n          peg$currPos++;\n        } else {\n          s1 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c101); }\n        }\n        if (s1 !== peg$FAILED) {\n          s2 = peg$parseValue();\n          if (s2 !== peg$FAILED) {\n            s3 = [];\n            s4 = peg$currPos;\n            if (input.charCodeAt(peg$currPos) === 44) {\n              s5 = peg$c32;\n              peg$currPos++;\n            } else {\n              s5 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c33); }\n            }\n            if (s5 !== peg$FAILED) {\n              s6 = peg$parse_();\n              if (s6 !== peg$FAILED) {\n                s7 = peg$parseValue();\n                if (s7 !== peg$FAILED) {\n                  peg$savedPos = s4;\n                  s5 = peg$c106(s2, s7);\n                  s4 = s5;\n                } else {\n                  peg$currPos = s4;\n                  s4 = peg$FAILED;\n                }\n              } else {\n                peg$currPos = s4;\n                s4 = peg$FAILED;\n              }\n            } else {\n              peg$currPos = s4;\n              s4 = peg$FAILED;\n            }\n            if (s4 !== peg$FAILED) {\n              while (s4 !== peg$FAILED) {\n                s3.push(s4);\n                s4 = peg$currPos;\n                if (input.charCodeAt(peg$currPos) === 44) {\n                  s5 = peg$c32;\n                  peg$currPos++;\n                } else {\n                  s5 = peg$FAILED;\n                  if (peg$silentFails === 0) { peg$fail(peg$c33); }\n                }\n                if (s5 !== peg$FAILED) {\n                  s6 = peg$parse_();\n                  if (s6 !== peg$FAILED) {\n                    s7 = peg$parseValue();\n                    if (s7 !== peg$FAILED) {\n                      peg$savedPos = s4;\n                      s5 = peg$c106(s2, s7);\n                      s4 = s5;\n                    } else {\n                      peg$currPos = s4;\n                      s4 = peg$FAILED;\n                    }\n                  } else {\n                    peg$currPos = s4;\n                    s4 = peg$FAILED;\n                  }\n                } else {\n                  peg$currPos = s4;\n                  s4 = peg$FAILED;\n                }\n              }\n            } else {\n              s3 = peg$FAILED;\n            }\n            if (s3 !== peg$FAILED) {\n              if (input.charCodeAt(peg$currPos) === 93) {\n                s4 = peg$c102;\n                peg$currPos++;\n              } else {\n                s4 = peg$FAILED;\n                if (peg$silentFails === 0) { peg$fail(peg$c103); }\n              }\n              if (s4 !== peg$FAILED) {\n                peg$savedPos = s0;\n                s1 = peg$c107(s2, s3);\n                s0 = s1;\n              } else {\n                peg$currPos = s0;\n                s0 = peg$FAILED;\n              }\n            } else {\n              peg$currPos = s0;\n              s0 = peg$FAILED;\n            }\n          } else {\n            peg$currPos = s0;\n            s0 = peg$FAILED;\n          }\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseDoubleStringCharacter(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    s1 = peg$currPos;\n    peg$silentFails++;\n    if (input.charCodeAt(peg$currPos) === 34) {\n      s2 = peg$c77;\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c78); }\n    }\n    if (s2 === peg$FAILED) {\n      if (input.charCodeAt(peg$currPos) === 92) {\n        s2 = peg$c79;\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c80); }\n      }\n    }\n    peg$silentFails--;\n    if (s2 === peg$FAILED) {\n      s1 = undefined;\n    } else {\n      peg$currPos = s1;\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      if (input.length > peg$currPos) {\n        s2 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c83); }\n      }\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c84(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 92) {\n        s1 = peg$c79;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c80); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parseEscapeSequence();\n        if (s2 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c108(s2);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseSingleStringCharacter(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    s1 = peg$currPos;\n    peg$silentFails++;\n    if (input.charCodeAt(peg$currPos) === 39) {\n      s2 = peg$c94;\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c95); }\n    }\n    if (s2 === peg$FAILED) {\n      if (input.charCodeAt(peg$currPos) === 92) {\n        s2 = peg$c79;\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c80); }\n      }\n    }\n    peg$silentFails--;\n    if (s2 === peg$FAILED) {\n      s1 = undefined;\n    } else {\n      peg$currPos = s1;\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      if (input.length > peg$currPos) {\n        s2 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c83); }\n      }\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c84(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n    if (s0 === peg$FAILED) {\n      s0 = peg$currPos;\n      if (input.charCodeAt(peg$currPos) === 92) {\n        s1 = peg$c79;\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c80); }\n      }\n      if (s1 !== peg$FAILED) {\n        s2 = peg$parseEscapeSequence();\n        if (s2 !== peg$FAILED) {\n          peg$savedPos = s0;\n          s1 = peg$c108(s2);\n          s0 = s1;\n        } else {\n          peg$currPos = s0;\n          s0 = peg$FAILED;\n        }\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parseTagChar(): any {\n    let s0, s1, s2;\n\n    s0 = peg$currPos;\n    s1 = peg$currPos;\n    peg$silentFails++;\n    if (input.charCodeAt(peg$currPos) === 58) {\n      s2 = peg$c0;\n      peg$currPos++;\n    } else {\n      s2 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c1); }\n    }\n    peg$silentFails--;\n    if (s2 === peg$FAILED) {\n      s1 = undefined;\n    } else {\n      peg$currPos = s1;\n      s1 = peg$FAILED;\n    }\n    if (s1 !== peg$FAILED) {\n      if (input.length > peg$currPos) {\n        s2 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s2 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c83); }\n      }\n      if (s2 !== peg$FAILED) {\n        peg$savedPos = s0;\n        s1 = peg$c84(s2);\n        s0 = s1;\n      } else {\n        peg$currPos = s0;\n        s0 = peg$FAILED;\n      }\n    } else {\n      peg$currPos = s0;\n      s0 = peg$FAILED;\n    }\n\n    return s0;\n  }\n\n  function peg$parseEscapeSequence(): any {\n    let s0, s1;\n\n    if (input.charCodeAt(peg$currPos) === 39) {\n      s0 = peg$c94;\n      peg$currPos++;\n    } else {\n      s0 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c95); }\n    }\n    if (s0 === peg$FAILED) {\n      if (input.charCodeAt(peg$currPos) === 34) {\n        s0 = peg$c77;\n        peg$currPos++;\n      } else {\n        s0 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c78); }\n      }\n      if (s0 === peg$FAILED) {\n        if (input.charCodeAt(peg$currPos) === 92) {\n          s0 = peg$c79;\n          peg$currPos++;\n        } else {\n          s0 = peg$FAILED;\n          if (peg$silentFails === 0) { peg$fail(peg$c80); }\n        }\n        if (s0 === peg$FAILED) {\n          s0 = peg$currPos;\n          if (input.charCodeAt(peg$currPos) === 98) {\n            s1 = peg$c109;\n            peg$currPos++;\n          } else {\n            s1 = peg$FAILED;\n            if (peg$silentFails === 0) { peg$fail(peg$c110); }\n          }\n          if (s1 !== peg$FAILED) {\n            peg$savedPos = s0;\n            s1 = peg$c111();\n          }\n          s0 = s1;\n          if (s0 === peg$FAILED) {\n            s0 = peg$currPos;\n            if (input.charCodeAt(peg$currPos) === 102) {\n              s1 = peg$c112;\n              peg$currPos++;\n            } else {\n              s1 = peg$FAILED;\n              if (peg$silentFails === 0) { peg$fail(peg$c113); }\n            }\n            if (s1 !== peg$FAILED) {\n              peg$savedPos = s0;\n              s1 = peg$c114();\n            }\n            s0 = s1;\n            if (s0 === peg$FAILED) {\n              s0 = peg$currPos;\n              if (input.charCodeAt(peg$currPos) === 110) {\n                s1 = peg$c115;\n                peg$currPos++;\n              } else {\n                s1 = peg$FAILED;\n                if (peg$silentFails === 0) { peg$fail(peg$c116); }\n              }\n              if (s1 !== peg$FAILED) {\n                peg$savedPos = s0;\n                s1 = peg$c117();\n              }\n              s0 = s1;\n              if (s0 === peg$FAILED) {\n                s0 = peg$currPos;\n                if (input.charCodeAt(peg$currPos) === 114) {\n                  s1 = peg$c118;\n                  peg$currPos++;\n                } else {\n                  s1 = peg$FAILED;\n                  if (peg$silentFails === 0) { peg$fail(peg$c119); }\n                }\n                if (s1 !== peg$FAILED) {\n                  peg$savedPos = s0;\n                  s1 = peg$c120();\n                }\n                s0 = s1;\n                if (s0 === peg$FAILED) {\n                  s0 = peg$currPos;\n                  if (input.charCodeAt(peg$currPos) === 116) {\n                    s1 = peg$c121;\n                    peg$currPos++;\n                  } else {\n                    s1 = peg$FAILED;\n                    if (peg$silentFails === 0) { peg$fail(peg$c122); }\n                  }\n                  if (s1 !== peg$FAILED) {\n                    peg$savedPos = s0;\n                    s1 = peg$c123();\n                  }\n                  s0 = s1;\n                  if (s0 === peg$FAILED) {\n                    s0 = peg$currPos;\n                    if (input.charCodeAt(peg$currPos) === 118) {\n                      s1 = peg$c124;\n                      peg$currPos++;\n                    } else {\n                      s1 = peg$FAILED;\n                      if (peg$silentFails === 0) { peg$fail(peg$c125); }\n                    }\n                    if (s1 !== peg$FAILED) {\n                      peg$savedPos = s0;\n                      s1 = peg$c126();\n                    }\n                    s0 = s1;\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    return s0;\n  }\n\n  function peg$parse_(): any {\n    let s0, s1;\n\n    peg$silentFails++;\n    s0 = [];\n    if (peg$c128.test(input.charAt(peg$currPos))) {\n      s1 = input.charAt(peg$currPos);\n      peg$currPos++;\n    } else {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c129); }\n    }\n    while (s1 !== peg$FAILED) {\n      s0.push(s1);\n      if (peg$c128.test(input.charAt(peg$currPos))) {\n        s1 = input.charAt(peg$currPos);\n        peg$currPos++;\n      } else {\n        s1 = peg$FAILED;\n        if (peg$silentFails === 0) { peg$fail(peg$c129); }\n      }\n    }\n    peg$silentFails--;\n    if (s0 === peg$FAILED) {\n      s1 = peg$FAILED;\n      if (peg$silentFails === 0) { peg$fail(peg$c127); }\n    }\n\n    return s0;\n  }\n\n\n    function flat(arr) { return arr.reduce((acc, val) => acc.concat(val), []);}\n    function toStr(chars) {return chars.join(\"\")};\n\n\n  peg$result = peg$startRuleFunction();\n\n  if (peg$result !== peg$FAILED && peg$currPos === input.length) {\n    return peg$result;\n  } else {\n    if (peg$result !== peg$FAILED && peg$currPos < input.length) {\n      peg$fail(peg$endExpectation());\n    }\n\n    throw peg$buildStructuredError(\n      peg$maxFailExpected,\n      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,\n      peg$maxFailPos < input.length\n        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)\n        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)\n    );\n  }\n}\n\nexport interface IParseOptions {\n  filename?: string;\n  startRule?: string;\n  tracer?: any;\n  [key: string]: any;\n}\nexport type ParseFunction = (input: string, options?: IParseOptions) => any;\nexport const parse: ParseFunction = peg$parse;\n\n"
  },
  {
    "path": "src/elm-debug.pegjs",
    "content": "// Set.toList, Array.toList\n{\n  function flat(arr) { return arr.reduce((acc, val) => acc.concat(val), []);}\n  function toStr(chars) {return chars.join(\"\")};\n}\n\nDebugString \n  = tag:Tag (\":\" _ )+ value:Value {return {type: \"ElmDebug\", name: tag, value: value};}\n  / \":\" _ value:Value {return {type: \"ElmDebug\", name: \"\", value: value};}\n\nValue\n  = Record / Array / Set / Dict / List / CustomTypeWithParens / CustomType / Tuple / Number / Boolean / Type / Internals / Bytes / File / String\n\nCustomTypeValue\n  = Record / Array / Set / Dict / List / CustomTypeWithParens / Tuple / Number / Boolean / Type / Internals / Bytes / File / String\n\nRecord\n  = \"{}\" {return {type: \"Record\", value: {}};}\n  / \"{ \" key:VariableName \" = \" value:Value \" }\" {return {type: \"Record\", value: {[key]: value}}}\n  / \"{ \" key:VariableName \" = \" value:Value values:(\", \" tag:VariableName \" = \" otherVal:Value {return {[tag]: otherVal};})* \" }\" { var composed = [{[key]: value},...values].reduce((item, obj) => {return {...item,...obj} },{}); return {type: \"Record\", value: composed}}\n\nDict\n  = \"Dict.fromList \" values:ListValue {return {type: \"Dict\", value: values.map((tuple) => { return {key: tuple.value[0], value: tuple.value[1]};})}}\n\nSet\n  = \"Set.fromList \" values:ListValue {return {type: \"Set\", value: values};}\n\nArray\n  = \"Array.fromList \" values:ListValue {return {type: \"Array\", value: values};}\n\nTuple\n  = \"()\" {return {type:\"Unit\"}}\n  / \"(\" head:Value others:(_ \",\" _ item:Value {return item;})+ \")\" {return {type: \"Tuple\", value: [head,...others]};}\n\nCustomTypeWithParens\n  = \"(\" _ customType:CustomType _ \")\" {return customType;}\n\nCustomType \n  = mainType:Type values:(_ value:CustomTypeValue {return value;})+ {return {type: \"Custom\", name: mainType.name, value: values};}\n  / mainType:Type _ customType:CustomTypeWithParens {return {type: \"Custom\", name: mainType.name, value: customType};}\n\nList \n  = list:ListValue {return {type: \"List\", value: list};}\n\n\nNumber =\n  digits:[0-9\\.]+ {return {type: \"Number\", value: parseFloat(toStr(digits))};}\n\t/ \"-\" _ digits:[0-9\\.]+ {return {type: \"Number\", value: parseFloat(\"-\"+toStr(digits))};}\n\t/ \"NaN\" {return {type: \"Number\", value: \"NaN\"};}\n\t/ \"Infinity\" {return {type: \"Number\", value: \"Infinity\"};}\n\t/ \"-Infinity\" {return {type: \"Number\", value: \"-Infinity\"};}\n\nBoolean\n  = \"True\" {return {type: \"Boolean\", value: true};}\n  / \"False\" {return {type: \"Boolean\", value: false};}\n\nInternals\n  = \"<function>\" {return {type: \"Function\"};}\n  / \"<internals>\" {return {type: \"Internals\"};}\n\nBytes \n  = \"<\" digits:[0-9]+ \" bytes>\" {return {type: \"Bytes\", value: parseInt(toStr(digits), 10)};}\n\nFile\n  = \"<\" chars:(!('\"' / \"\\\\\" / \"<\" / \">\") char:. { return char; })+ \">\" {return { type: \"File\", value: chars.join('') };}\n\nVariableName =\n\tchars:[a-zA-Z0-9_]+ {return toStr(chars);}\n    \nType = \n  // type returns array in array -> \"Yes\" -> [\"Y\",[\"e\", \"s\"]] -- need to flat that array\n\ttype: ([A-Z][a-zA-Z0-9_]+) {return {type: \"Type\", name: toStr(flat(type))};}\n\nTag =\n  tag:TagChar+ { return toStr(tag); }\n\nString\n  = '\"' chars:DoubleStringCharacter* '\"' { return {type: \"String\", value: chars.join('')}; }\n  / \"'\" chars:SingleStringCharacter* \"'\" { return { type: \"String\", value: chars.join('')}; }\n\n\nListValue\n  = \"[]\" {return [];} \n  / list:(\"[\" singleton:Value \"]\" {return singleton;}) {return [list];}\n  / \"[\" head:Value tail:(\",\" _ value:Value {return value;})+ \"]\" {return [head, ...tail]}\n  \n\nDoubleStringCharacter\n  = !('\"' / \"\\\\\") char:. { return char; }\n  / \"\\\\\" sequence:EscapeSequence { return sequence; }\n\nSingleStringCharacter\n  = !(\"'\" / \"\\\\\") char:. { return char; }\n  / \"\\\\\" sequence:EscapeSequence { return sequence; }\n\nTagChar\n  = !(\":\") char:. { return char; }\n\nEscapeSequence\n  = \"'\"\n  / '\"'\n  / \"\\\\\"\n  / \"b\"  { return \"\\b\";   }\n  / \"f\"  { return \"\\f\";   }\n  / \"n\"  { return \"\\n\";   }\n  / \"r\"  { return \"\\r\";   }\n  / \"t\"  { return \"\\t\";   }\n  / \"v\"  { return \"\\x0B\"; }\n\n_ \"whitespace\"\n  = [ \\t\\n\\r]*\n\n"
  },
  {
    "path": "src/formatters/JsonMLFormatter.ts",
    "content": "import * as _ from 'lodash';\nimport * as T from '../CommonTypes';\nimport JsonML from '../JsonML';\nimport { toElement } from './elements/Elements';\nimport EllipsisElement from './elements/EllipsisElement';\n\n/* tslint:disable */\ndeclare global {\n    interface Window {\n        devtoolsFormatters: any;\n    }\n}\n/* tslint:enable*/\n\nexport default class JsonMLFormatter\n    implements T.IFormatter, T.IJsonMLFormatter, T.IDevToolsFormatter {\n\n    public theme:T.ITheme;\n\n    constructor(theme: T.ITheme) {\n        window.devtoolsFormatters = [this];\n        this.theme = theme;\n    }\n\n    public format = (obj: T.IElmDebugValue): any => {\n        return obj;\n    }\n\n    public header = (obj: T.IElmDebugValue, config: T.IConfig): any[] | null => {\n        if (!!config && !!config.key && config.elmFormat) {\n            return new JsonML('div')\n                .withChild(config.key)\n                .withChild(this.handleHeader(obj, config))\n                .toJSONML();\n        }\n        if (!!obj.type && obj.type === 'ElmDebug') {\n            return new JsonML('div')\n                .withChild(this.handleHeader(obj))\n                .toJSONML();\n        } else {\n            return null;\n        }\n    }\n\n    public hasBody = (obj: T.IElmDebugValue, config: T.IConfig): boolean =>{\n        const element = toElement(obj, this as T.IJsonMLFormatter);\n        return (\n            element !== null &&\n            element.body !== undefined &&\n            element.body() !== null\n        );\n    }\n\n    public body = (obj: T.IElmDebugValue, config: T.IConfig): any[] | null => {\n        if (this.handleBody(obj) === null) {\n            return null;\n        }\n\n        return this.handleBody(obj)?.toJSONML();\n    }\n\n    public handleHeader = (\n        obj: T.ElmDebugValueType | undefined,\n        config: T.IConfig = { elmFormat: true, level: 0 }\n    ): JsonML => {\n        if(obj === undefined) {\n            return new JsonML('span').withText('undefined value');\n        }\n\n        const newConfig = _.clone(config);\n        const element = toElement(obj, this as T.IJsonMLFormatter);\n\n        newConfig.level = config.level + 1;\n\n        if (element) {\n            return element.header(newConfig);\n        } else {\n            return new JsonML('span').withText('UNPARSED: ').withText(obj);\n        }\n    }\n\n    public handleBody = (\n        obj: T.ElmDebugValueType,\n        config?: T.IConfig\n    ): JsonML | null => {\n        const element = toElement(obj, this as T.IJsonMLFormatter);\n        if (element) {\n            return element.body !== undefined ? element.body(config) : null;\n        } else {\n            return new JsonML('div').withText('UNPARSED body: ').withText(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "src/formatters/SimpleFormatter.ts",
    "content": "import { defaults, mapValues } from 'lodash';\nimport * as T from '../CommonTypes';\n\nexport default class SimpleFormatter implements T.IFormatter {\n    public format(obj: T.IElmDebugValue): object {\n      if(obj.name !== undefined && obj.value !== undefined){\n        return { [obj.name]: this.formatValue(obj.value) };\n      }\n      else { \n        return {}\n      }\n    }\n\n    public formatArray(array: T.ElmDebugValueType[]): object[] {\n        return array.map(v => this.formatValue(v));\n    }\n\n    public formatCustom(\n        custom: T.IElmDebugCustomValue\n    ): { [key: string]: any } {\n        return {\n            [custom.name]:\n                custom.value.length === 1\n                    ? this.formatValue(custom.value[0])\n                    : this.formatArray(custom.value),\n        };\n    }\n\n    public formatValue(formatee: T.ElmDebugValueType): any {\n        if (T.isElmCustomValue(formatee)) {\n            return this.formatCustom(formatee);\n        }\n\n        if (T.isElmRecordValue(formatee)) {\n            return mapValues(formatee.value, v => this.formatValue(v));\n        }\n\n        if (T.isElmListValue(formatee)) {\n            return this.formatArray(formatee.value);\n        }\n\n        if (T.isElmDictValue(formatee)) {\n            return formatee.value.reduce(\n                (result, dictItem: { [k: string]: any }) => {\n                    return defaults(\n                        {\n                            [this.formatValue(dictItem.key)]: this.formatValue(\n                                dictItem.value\n                            ),\n                        },\n                        result\n                    );\n                },\n                {}\n            );\n        }\n\n        if (T.isElmTypeValue(formatee)) {\n            return formatee.name;\n        }\n\n        if (T.isElmNumberType(formatee)) {\n            return formatee.value;\n        }\n\n        switch (formatee.type) {\n            case 'Function':\n                return '<function>';\n\n            case 'Internals':\n                return '<internals>';\n\n            case 'Bytes':\n                return formatee.value + ' B';\n\n            case 'File':\n                return formatee.value;\n\n            case 'Unit':\n                return '()';\n\n            case 'String':\n                return formatee.value;\n\n            case 'Boolean':\n                return formatee.value;\n\n            default:\n                return formatee.value !== undefined &&\n                    T.isElmValue(formatee.value)\n                    ? this.formatValue(formatee.value)\n                    : formatee;\n        }\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/BooleanElement.ts",
    "content": "import { \n  IElmDebugBoolValue, \n  IFormatterElement,\n  IJsonMLFormatter\n\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\n\nexport default class BooleanElement implements IFormatterElement {\n    private elmObj: IElmDebugBoolValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugBoolValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.booleanStyle)\n            .withText(this.elmObj.value ? 'True' : 'False');\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/BytesElement.ts",
    "content": "import { \n  IElmDebugValue, \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\n\nexport default class BytesElement implements IFormatterElement {\n    private elmObj: IElmDebugValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.bytesStyle)\n            .withText(this.elmObj.value + ' B');\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/CustomTypeElement.ts",
    "content": "import * as _ from 'lodash';\nimport {\n    IConfig,\n    IElmDebugCustomValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\nimport EllipsisElement from './EllipsisElement';\n\nexport default class CustomTypeElement implements IFormatterElement {\n    private elmObj: IElmDebugCustomValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugCustomValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = (config: IConfig = { elmFormat: true, level: 0 }) => {\n        if (this.elmObj.value.length === 0) {\n            return new JsonML('span')\n                .withStyle(this.formatter.theme.customTypeNameStyle)\n                .withText(this.elmObj.name);\n        }\n        if (this.elmObj.value.length === 1) {\n            return this.wrappedHeader(\n                new JsonML('span')\n                    .withStyle(this.formatter.theme.customTypeNameStyle)\n                    .withText(this.elmObj.name + ' ')\n                    .withChild(\n                        this.formatter.handleHeader(\n                            this.elmObj.value[0],\n                            config\n                        )\n                    ),\n                config\n            );\n        } else {\n            if (config !== null && config.level > 1) {\n                return this.wrappedHeader(\n                    new JsonML('span')\n                        .withText(this.elmObj.name + ' ')\n                        .withStyle(this.formatter.theme.customTypeNameStyle)\n                        .withChild(new EllipsisElement().header()),\n                    config\n                );\n            } else {\n                const children = this.elmObj.value\n                    .map(child => {\n                        return {\n                            child,\n                            jsonml: new JsonML('span').withChild(\n                                this.formatter.handleHeader(child, config)\n                            ),\n                        };\n                    })\n\n                    .reduce((acc, child) => {\n                        acc.push(child.jsonml);\n                        acc.push(new JsonML('span').withText(' '));\n                        return acc;\n                    }, [] as any[]);\n\n                children.splice(-1, 1);\n\n                return this.wrappedHeader(\n                    new JsonML('span')\n                        .withText(this.elmObj.name + ' ')\n                        .withStyle(this.formatter.theme.customTypeNameStyle)\n                        .withChildren(children),\n                    config\n                );\n            }\n        }\n    }\n\n    public body = (): JsonML | null => {\n        if (\n            this.elmObj.value.length === 1 &&\n            this.formatter.handleBody(this.elmObj.value[0]) === null\n        ) {\n            return null;\n        }\n\n        const children = this.elmObj.value.map((child, index) => {\n            const element = new JsonML('span')\n                .withChild(\n                    new JsonML('span')\n                        .withStyle(this.formatter.theme.keyElementStyle)\n                        .withText(`${index}`)\n                )\n                .withText(': ');\n\n            if (this.formatter.handleBody(child) === null) {\n                element.withStyle('margin-left: 13px;');\n            }\n\n            return new JsonML('div').withObject(element, child);\n        });\n\n        return new JsonML('div')\n            .withStyle('margin-left: 15px;')\n            .withStyle(this.formatter.theme.expandableBorderStyle)\n            .withChildren(children);\n    }\n\n    private wrappedHeader = (obj: JsonML, config?: IConfig): JsonML => {\n        if (config && config.level > 1) {\n            return new JsonML('span')\n                .withText('( ')\n                .withChild(obj)\n                .withText(' )');\n        } else {\n            return obj;\n        }\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/DebugElement.ts",
    "content": "import {\n    IElmDebugValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\n\nexport default class DebugElment implements IFormatterElement {\n    private elmObj: IElmDebugValue;\n    private formatter: IJsonMLFormatter;\n    private elmLogoElement: JsonML;\n\n    constructor(obj: IElmDebugValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n        this.elmLogoElement = new JsonML('span').withStyle(this.formatter.theme.elmLogoElementStyle);\n    }\n\n    public header = () => {\n      if (this.elmObj?.value) {\n        return new JsonML('span')\n            .withChild(this.elmLogoElement)\n            .withChild(\n                new JsonML('span')\n                    .withChild(\n                        new JsonML('span')\n                            .withStyle(this.formatter.theme.debugTagStyle)\n                            .withText(this.elmObj.name)\n                    )\n                    .withText(': ')\n            )\n            .withChild(this.formatter.handleHeader(this.elmObj.value));\n      }\n\n      return new JsonML('span').withText(\"WTF\");\n    }\n\n    public body = () => {\n      if (this.elmObj?.value) {\n        return this.formatter.handleBody(this.elmObj.value);\n      }\n\n      return null;\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/DictElement.ts",
    "content": "import {\n    IConfig,\n    IElmDebugDictValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\n\nexport default class DictElement implements IFormatterElement {\n    private elmObj: IElmDebugDictValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugDictValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        if (this.elmObj.value.length === 0) {\n            return new JsonML('span')\n                .withStyle(this.formatter.theme.greyedStyle)\n                .withText('Dict.empty');\n        }\n\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.dataStructureNameStyle)\n            .withText('Dict')\n            .withChild(\n                new JsonML('span').withText(`(${this.elmObj.value.length})`)\n            );\n    }\n\n    public body = (config?: IConfig) => {\n        const children = this.elmObj.value.map(child => {\n            const key = this.formatter.handleHeader(child.key, config);\n            const element = new JsonML('span')\n                .withChild(\n                    new JsonML('span').withStyle(this.formatter.theme.keyElementStyle).withChild(key)\n                )\n                .withText(': ');\n\n            if (this.formatter.handleBody(child.value, config) === null) {\n                element.withStyle('margin-left: 13px;');\n            }\n\n            return new JsonML('div').withObject(element, child.value, config);\n        });\n\n        return new JsonML('div')\n            .withStyle(this.formatter.theme.expandableBorderStyle)\n            .withChildren(children);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/Elements.ts",
    "content": "import * as T from '../../CommonTypes';\n\nimport BooleanElement from './BooleanElement';\nimport BytesElement from './BytesElement';\nimport CustomTypeElement from './CustomTypeElement';\nimport DebugElement from './DebugElement';\nimport DictElement from './DictElement';\nimport FilesElement from './FilesElement';\nimport InternalsElement from './InternalsElement';\nimport ListElement from './ListElement';\nimport NumberElement from './NumberElement';\nimport RecordElement from './RecordElement';\nimport StringElement from './StringElement';\nimport TupleElement from './TupleElement';\nimport TypeElement from './TypeElement';\n\nexport function toElement(\n    obj: T.ElmDebugValueType,\n    formatter: T.IJsonMLFormatter\n): T.IFormatterElement | null {\n    if (obj.type === 'String') {\n        return new StringElement(obj as T.IElmDebugStringValue, formatter);\n    } else if (obj.type === 'Boolean') {\n        return new BooleanElement(obj as T.IElmDebugBoolValue, formatter);\n    } else if (T.isElmValue(obj) && obj.type === 'ElmDebug') {\n        return new DebugElement(obj, formatter);\n    } else if (T.isElmNumberType(obj)) {\n        return new NumberElement(obj, formatter);\n    } else if (T.isElmTypeValue(obj)) {\n        return new TypeElement(obj, formatter);\n    } else if (T.isElmCustomValue(obj)) {\n        return new CustomTypeElement(obj, formatter);\n    } else if (T.isElmDictValue(obj)) {\n        return new DictElement(obj, formatter);\n    } else if (T.isElmListValue(obj)) {\n        return obj.type === 'Tuple'\n            ? new TupleElement(obj, formatter)\n            : new ListElement(obj, formatter);\n    } else if (T.isElmRecordValue(obj)) {\n        return new RecordElement(obj, formatter);\n    } else if (\n        obj.type === 'Function' ||\n        obj.type === 'Internals' ||\n        obj.type === 'Unit'\n    ) {\n        return new InternalsElement(obj.type as string, formatter);\n    } else if (obj.type === 'Bytes') {\n        return new BytesElement(obj as T.IElmDebugValue, formatter);\n    } else if (obj.type === 'File') {\n        return new FilesElement(obj as T.IElmDebugValue, formatter);\n    }\n\n    return null;\n}\n"
  },
  {
    "path": "src/formatters/elements/EllipsisElement.ts",
    "content": "import {\n    IElmDebugRecordValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\nimport { GreyedOutStyle } from './Styles';\n\nexport default class EllipsisElement implements IFormatterElement {\n    public header = () => {\n        return new JsonML('span').withStyle(GreyedOutStyle).withText('…');\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/FilesElement.ts",
    "content": "import { \n  IElmDebugValue, \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\n\nexport default class FilesElement implements IFormatterElement {\n    private elmObj: IElmDebugValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.bytesStyle)\n            .withText(this.elmObj.value);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/InternalsElement.ts",
    "content": "import { \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\n\nexport default class InternalsElement implements IFormatterElement {\n    private elmObj: string;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: string, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        let value = '';\n\n        switch (this.elmObj) {\n            case 'Internals':\n                value = '<internals>';\n                break;\n            case 'Function':\n                value = '<function>';\n                break;\n            case 'Unit':\n                value = '()';\n                break;\n        }\n\n        return new JsonML('span')\n          .withStyle(this.formatter.theme.greyedItalicsStyle)\n          .withText(value);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/ListElement.ts",
    "content": "import {\n    IConfig,\n    IElmDebugListValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\n\nexport default class ListElement implements IFormatterElement {\n    private elmObj: IElmDebugListValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugListValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = (config?: IConfig) => {\n        if (this.elmObj.value.length === 0) {\n            return new JsonML('span').withStyle(this.formatter.theme.greyedStyle).withText('[]');\n        }\n        if (this.elmObj.value.length === 1) {\n            return new JsonML('span')\n                .withStyle(this.formatter.theme.greyedStyle)\n                .withText('[')\n                .withChild(\n                    new JsonML('span').withChild(\n                        this.formatter.handleHeader(\n                            this.elmObj.value[0],\n                            config\n                        )\n                    )\n                )\n                .withText(']');\n        }\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.dataStructureNameStyle)\n            .withText(this.elmObj.type)\n            .withChild(\n                new JsonML('span').withText(`(${this.elmObj.value.length})`)\n            );\n    }\n\n    public body = (config?: IConfig): JsonML | null => {\n        if (this.elmObj.value.length === 0) {\n            return null;\n        }\n\n        const children = this.elmObj.value.map((child, index) => {\n            const element = new JsonML('span')\n                .withChild(\n                    new JsonML('span')\n                        .withStyle(this.formatter.theme.keyElementStyle)\n                        .withText(`${index}`)\n                )\n                .withText(': ');\n\n            if (this.formatter.handleBody(child, config) === null) {\n                element.withStyle('margin-left: 13px');\n            }\n\n            return new JsonML('div').withObject(element, child);\n        });\n\n        return new JsonML('div')\n            .withStyle(this.formatter.theme.expandableBorderStyle)\n            .withChildren(children);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/NumberElement.ts",
    "content": "import { \n  IElmDebugNumberValue, \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\n\nexport default class NumberElement implements IFormatterElement {\n    private elmObj: IElmDebugNumberValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugNumberValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.numberStyle)\n            .withText(this.elmObj.value);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/RecordElement.ts",
    "content": "import {\n    IConfig,\n    IElmDebugRecordValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\nimport EllipsisElement from './EllipsisElement';\n\nexport default class RecordElement implements IFormatterElement {\n    private elmObj: IElmDebugRecordValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugRecordValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = (config: IConfig) => {\n        if (!!config && config.level > 2) {\n            return new JsonML('span')\n                .withText('{ ')\n                .withChild(new EllipsisElement().header())\n                .withText(' }');\n        }\n        const keys = Object.keys(this.elmObj.value);\n        const children = keys\n            .map(k => {\n                return new JsonML('span')\n                    .withStyle(this.formatter.theme.keyElementStyle)\n                    .withText(k +': ')\n                    .withChild(\n                        this.formatter.handleHeader(\n                            this.elmObj.value[k],\n                            config\n                        )\n                    );\n            })\n            .reduce(\n                (accObj, child) => {\n                    const lengthWithChild = accObj.size + child.toStr().length;\n                    if (accObj.hasEllipsis) {\n                        return accObj;\n                    }\n\n                    if (lengthWithChild < 50) {\n                        accObj.acc.push(child);\n                        accObj.size = lengthWithChild;\n                    } else {\n                        accObj.acc.push(new EllipsisElement().header());\n                        accObj.hasEllipsis = true;\n                    }\n\n                    return accObj;\n                },\n                { acc: [] as any[], size: 0, hasEllipsis: false }\n            )\n            .acc.reduce((acc, child) => {\n                acc.push(new JsonML('span').withText(', '));\n                acc.push(child);\n                return acc;\n            }, [] as any[]);\n\n        children.splice(0, 1);\n\n        return new JsonML('span')\n            .withText('{ ')\n            .withChildren(children)\n            .withText(' }');\n    }\n\n    public body = (config: IConfig) => {\n        const keys = Object.keys(this.elmObj.value);\n        const objects = keys.map(k => {\n            const keyElement = new JsonML('span')\n                .withStyle(this.formatter.theme.keyElementStyle)\n                .withText(k)\n                .withText(': ');\n            if (\n                this.formatter.handleBody(this.elmObj.value[k], config) === null\n            ) {\n                keyElement.withStyle('margin-left: 13px;');\n            }\n\n            return new JsonML('div').withObject(\n                keyElement,\n                this.elmObj.value[k]\n            );\n        });\n\n        return new JsonML('div')\n            .withStyle('margin-left: 15px;')\n            .withChildren(objects);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/StringElement.ts",
    "content": "import { \n  IElmDebugStringValue, \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\n\nexport default class StringElement implements IFormatterElement {\n    private elmObj: IElmDebugStringValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugStringValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.stringStyle)\n            .withText(`\"${this.elmObj.value}\"`);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/Styles.ts",
    "content": "import {ITheme} from '../../CommonTypes'\n\n// elm colors\n// ---------------\n// yellow - da9e26\n// green  - 81cf46\n// darkgreen - 70b53c\n// dark   - 34495e\n// blue   - da9e26\n\n\nexport const GreyedOutStyle =  'color: grey; font-weight: normal;';\n\nconst ElmLogoElementStyle =\n    'width: 12px; height: 12px; display: inline-block; position: relative; top: 2px;background-size: contain; background-repeat: no-repeat; margin-right: 0.5em; background-position: center center; background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI1NnB4IiBoZWlnaHQ9IjI1NnB4IiB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+Cgk8Zz4KCQk8cG9seWdvbiBmaWxsPSIjNUZCNENCIiBwb2ludHM9IjEyOCAxMzUuMDIyMDI5IDcuMDIyODIxMDUgMjU2IDI0OC45Nzc5NzEgMjU2Ij48L3BvbHlnb24+CgkJPHBvbHlnb24gZmlsbD0iI0VFQTQwMCIgcG9pbnRzPSIyMDIuMzMyMzEzIDE5NS4zMTEwNzUgMjU2IDI0OC45Nzk1NTQgMjU2IDE0MS42NDMzODgiPjwvcG9seWdvbj4KCQk8cG9seWdvbiBmaWxsPSIjNTk2Mjc3IiBwb2ludHM9IjEyMC45Nzc5NzEgMTI4IDAgNy4wMjIwMjkyMSAwIDI0OC45Nzk1NTQiPjwvcG9seWdvbj4KCQk8cG9seWdvbiBmaWxsPSIjNUZCNENCIiBwb2ludHM9IjI1NiAxMTMuODA2Mjg0IDI1NiAwIDE0Mi4xOTI5MjQgMCI+PC9wb2x5Z29uPgoJCTxwb2x5Z29uIGZpbGw9IiM4Q0Q2MzYiIHBvaW50cz0iMTk1LjU4MzUwNCA2Ny40MzQyMTU5IDI1NS44NzIzMTIgMTI3LjcyMzAyNCAxOTUuMzA4NTg5IDE4OC4yODY3NDggMTM1LjAxOTc4IDEyNy45OTc5NCI+PC9wb2x5Z29uPgoJCTxwb2x5Z29uIGZpbGw9IiM4Q0Q2MzYiIHBvaW50cz0iNy4wMjEyMzczNyAwIDYyLjc0NjEyMjggNTUuNzI1Njc3MiAxODMuODc1MzM1IDU1LjcyNTY3NzIgMTI4LjE0OTY1OCAwIj48L3BvbHlnb24+CgkJPHBvbHlnb24gZmlsbD0iI0VFQTQwMCIgcG9pbnRzPSIxMjggMTIwLjk3ODc2MyAxODMuMzIxODM5IDY1LjY1NjEzMTUgNzIuNjc3MzY4OSA2NS42NTYxMzE1Ij48L3BvbHlnb24+Cgk8L2c+Cjwvc3ZnPgo=);';\n\nexport const lightTheme: ITheme = {\n  booleanStyle: 'color: #65b5ca; font-weight: normal;',\n  bytesStyle: 'color: #34495e; font-weight: normal;',\n  customTypeNameStyle: 'color: #70b53c; font-weight: bold;',\n  dataStructureNameStyle: 'color: #70b53c; font-weight: normal;',\n  debugTagStyle: 'color: grey; font-weight: normal;',\n  elmLogoElementStyle: ElmLogoElementStyle,\n  expandableBorderStyle: 'margin-left: 4px; padding-left: 11px; border-left: 1px solid grey;',\n  greyedItalicsStyle: 'color: grey; font-weight: normal; font-style: italic;',\n  greyedStyle: 'color: grey; font-weight: normal;',\n  keyElementStyle: 'color: #34495e; font-weight: normal; font-style: italic;',\n  numberStyle: 'color: #da9e26; font-weight: normal;',\n  stringStyle: 'color: #65b5ca; font-weight: normal;',\n  typeNameStyle: 'color: #70b53c; font-weight: bold;',\n}\n\nexport const darkTheme: ITheme = {\n  ...lightTheme, \n  debugTagStyle: 'color: white; font-weight: normal;',\n  keyElementStyle: 'color: #ed78e6; font-weight: normal; font-style: italic;'\n}\n\n\n"
  },
  {
    "path": "src/formatters/elements/TupleElement.ts",
    "content": "import {\n    IConfig,\n    IElmDebugListValue,\n    IFormatterElement,\n    IJsonMLFormatter,\n} from '../../CommonTypes';\nimport JsonML from '../../JsonML';\nimport EllipsisElement from './EllipsisElement';\n\nexport default class TupleElement implements IFormatterElement {\n    private elmObj: IElmDebugListValue;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugListValue, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = (config?: IConfig) => {\n        if (!!config && config.level > 1) {\n            return new JsonML('span')\n                .withText('( ')\n                .withChild(\n                    this.formatter.handleHeader(this.elmObj.value[0], config)\n                )\n                .withChild(new JsonML('span').withText(', '))\n                .withChild(new EllipsisElement().header())\n                .withText(' )');\n        }\n        const children = this.elmObj.value\n            .map(child => this.formatter.handleHeader(child, config))\n            .reduce((acc, child) => {\n                acc.push(new JsonML('span').withText(', '));\n                acc.push(child);\n                return acc;\n            }, [] as any[]);\n\n        children.splice(0, 1);\n\n        return new JsonML('span')\n            .withText('( ')\n            .withChildren(children)\n            .withText(' )');\n    }\n\n    public body = (config?: IConfig): JsonML | null => {\n        if (this.elmObj.value.length <= 1) {\n            return null;\n        }\n\n        const children = this.elmObj.value.map((child, index) => {\n            const element = new JsonML('span')\n                .withChild(\n                    new JsonML('span')\n                        .withStyle(this.formatter.theme.keyElementStyle)\n                        .withText(`${index}`)\n                )\n                .withText(': ');\n\n            if (this.formatter.handleBody(child, config) === null) {\n                element.withStyle('margin-left: 13px;');\n            }\n\n            return new JsonML('div').withObject(element, child);\n        });\n\n        return new JsonML('div')\n            .withStyle(this.formatter.theme.expandableBorderStyle)\n            .withChildren(children);\n    }\n}\n"
  },
  {
    "path": "src/formatters/elements/TypeElement.ts",
    "content": "import { \n  IElmDebugTypeValueType, \n  IFormatterElement,\n  IJsonMLFormatter\n} from '../../CommonTypes';\n\nimport JsonML from '../../JsonML';\n\nexport default class TypeElement implements IFormatterElement {\n    private elmObj: IElmDebugTypeValueType;\n    private formatter: IJsonMLFormatter;\n\n    constructor(obj: IElmDebugTypeValueType, formatter: IJsonMLFormatter) {\n        this.elmObj = obj;\n        this.formatter = formatter;\n    }\n\n    public header = () => {\n        return new JsonML('span')\n            .withStyle(this.formatter.theme.typeNameStyle)\n            .withText(this.elmObj.name);\n    }\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import * as _ from 'lodash';\nimport { IElmDebugValue, IThemeOption } from './CommonTypes';\nimport { parse as elmDebugParse } from './elm-debug-parser';\nimport { darkTheme, lightTheme  } from './formatters/elements/Styles';\nimport JsonMLFormatter from './formatters/JsonMLFormatter';\nimport SimpleFormatter from './formatters/SimpleFormatter';\n\n/* tslint:disable */\ndeclare global {\n    interface Window {\n        chrome: any;\n        __ELM_DEBUG_TRANSFORM_OPTIONS__?: IOptions;\n    }\n}\n/* tslint:enable*/\n\ninterface IOptions {\n    active?: boolean;\n    debug?: boolean;\n    simple_mode?: boolean;\n    limit?: number;\n    theme?: IThemeOption;\n}\n\nconst defaultOptions: IOptions = {\n    active: true,\n    debug: false,\n    limit: 1000000,\n    simple_mode: false,\n    theme: \"light\"\n}\n\nexport function parse(message: string) : IElmDebugValue {\n  return elmDebugParse(message) as IElmDebugValue;\n}\n\nexport function register(opts: IOptions | undefined): IOptions {\n\n    if(window.__ELM_DEBUG_TRANSFORM_OPTIONS__){\n      return window.__ELM_DEBUG_TRANSFORM_OPTIONS__;\n    }\n    \n    const log = console.log;\n\n    if (opts && opts.theme === undefined) {\n      opts.theme = window.matchMedia(\"(prefers-color-scheme: dark)\").matches \n        ? \"dark\" \n        : \"light\";\n    }\n\n    let currentOpts = _.merge(defaultOptions, opts);\n\n    console.log = function() {\n        if (!arguments || arguments.length > 1) {\n            log.apply(console, arguments as any);\n            return;\n        }\n        const msg = arguments[0];\n\n        if (!msg || !currentOpts.limit || msg.length > currentOpts.limit) {\n            log.call(console, msg);\n            return;\n        }\n\n        if (!currentOpts.limit || msg.length > currentOpts.limit) {\n            log.call(console, msg);\n            return;\n        }\n        \n        const themeStyle = (currentOpts.theme === \"dark\") \n          ? darkTheme \n          : lightTheme;\n\n        const formatter =\n            !!currentOpts.simple_mode \n                ? new SimpleFormatter()\n                : new JsonMLFormatter(themeStyle);\n        try {\n            if (!!currentOpts.debug) {\n                log.call(console, 'Original message:', msg);\n            }\n\n            const parsed = parse(msg);\n\n            log.call(\n                console,\n                JSON.parse(JSON.stringify(formatter.format(parsed)))\n            );\n        } catch (err) {\n            if (!!currentOpts.debug) {\n                console.error(`Parsing error: ${err}`);\n            }\n            log.call(console, msg);\n        }\n    };\n\n    window.__ELM_DEBUG_TRANSFORM_OPTIONS__ = currentOpts;\n    return currentOpts;\n}\n"
  },
  {
    "path": "src/peg-file.d.ts",
    "content": "declare module '*.pegjs' {\n    const content: {\n        default: string;\n    };\n    export = content;\n}\n"
  },
  {
    "path": "test/builders.ts",
    "content": "import * as _ from 'lodash';\nimport {\n    IElmDebugListValue,\n    IElmDebugRecordValue,\n    IElmDebugValue,\n    IFormatter,\n} from '../src/CommonTypes';\nimport * as Styles from '../src/formatters/elements/Styles';\n\nexport function elmDebug(values: any): IElmDebugValue {\n    return { type: 'ElmDebug', name: 'Debug', value: values };\n}\n\nexport function list(\n    values: any[],\n    typeName: string = 'List'\n): IElmDebugListValue {\n    return { type: typeName, value: values };\n}\n\nexport function record(values: { [key: string]: any }): IElmDebugRecordValue {\n    return { type: 'Record', value: values };\n}\n\nexport function n(val: number) {\n    return { type: 'Number', value: val };\n}\n\nexport function customType(name: string, values: any[]) {\n    return { type: 'Custom', name, value: values };\n}\n\nexport function type(name: string) {\n    return { type: 'Type', name };\n}\n\nexport function dict(dictionary: object) {\n    return {\n        type: 'Dict',\n        value: _.toPairs(dictionary).map(item => {\n            return { key: item[0], value: item[1] };\n        }),\n    };\n}\nexport function tuple(values: any[]): IElmDebugListValue {\n    return { type: 'Tuple', value: values };\n}\n\nexport function bool(value: boolean) {\n    return { type: 'Boolean', value };\n}\n\nexport function str(value: string) {\n    return { type: 'String', value };\n}\n\nexport function MLDebug(values: any[]): any[] {\n    return [\n        'span',\n        {},\n        ['span', { style: Styles.lightTheme.elmLogoElementStyle }],\n        ['span', {}, ['span', { style: Styles.lightTheme.debugTagStyle }, 'Debug'], ': '],\n        ...values,\n    ];\n}\nexport function MLString(value: string): any[] {\n    return ['span', { style: Styles.lightTheme.stringStyle }, `\"${value}\"`];\n}\n\nexport function MLNumber(num: number): any[] {\n    return ['span', { style: Styles.lightTheme.numberStyle }, num.toString()];\n}\n\nexport function MLBool(value: boolean): any[] {\n    return ['span', { style: Styles.lightTheme.booleanStyle }, value ? 'True' : 'False'];\n}\n\nexport function MLList(typeName: string, length: number): any[] {\n    if (length === 0) {\n        return ['span', { style: 'color: grey; font-weight: normal;' }, '[]'];\n    } else {\n        return [\n            'span',\n            { style: Styles.lightTheme.dataStructureNameStyle },\n            typeName,\n            ['span', {}, `(${length})`],\n        ];\n    }\n}\n\nexport function MLCustomType(name: string, value?: any[]): any[] {\n    if (value === undefined) {\n        return ['span', { style: Styles.lightTheme.customTypeNameStyle }, name];\n    }\n\n    return [\n        'span',\n        { style: Styles.lightTheme.customTypeNameStyle },\n        name + ' ',\n        ...value,\n    ];\n}\n\nexport function MLTuple(values: any[]): any[] {\n    const valuesWithCommas = values.reduce((acc: any[], v) => {\n        acc.push(['span', {}, ', ']);\n        acc.push(v);\n        return acc;\n    }, []);\n    valuesWithCommas.splice(0, 1);\n    valuesWithCommas.push(' )');\n\n    return ['span', {}, '( ', ...valuesWithCommas];\n}\n\nexport function MLEllipsis(): any[] {\n    return ['span', { style: Styles.lightTheme.greyedStyle }, '…'];\n}\n\nexport function MLRecord(values: any[]) {\n    const valuesWithCommas = values.reduce((acc, item) => {\n        acc.push(['span', {}, ', ']);\n        acc.push(item);\n        return acc;\n    }, []);\n\n    valuesWithCommas.splice(0, 1);\n\n    return ['span', {}, '{ '].concat(valuesWithCommas).concat([' }']);\n}\n\nexport function MLRecordValue(name: string, value: any): any[] {\n    return ['span', { style: Styles.lightTheme.keyElementStyle }, name + ': ', value];\n}\nexport function MLKeyValueBody(keyName: string, object: any): any[] {\n    const jsonML = [\n        'span',\n        { style: Styles.lightTheme.keyElementStyle + 'margin-left: 13px;' },\n        keyName,\n        ': ',\n    ];\n\n    const key = {\n        attributes: {\n            style: Styles.lightTheme.keyElementStyle + 'margin-left: 13px;',\n        },\n        jsonML,\n    };\n\n    return [\n        'div',\n        {},\n        ['object', { config: { elmFormat: true, key }, object }],\n    ];\n}\n\nexport function MLBody(children: any[]) {\n    return ['div', { style: 'margin-left: 15px;' }, ...children];\n}\n\nexport function MLObject(child: any, key: any) {\n    return ['object', { object: child, config: { elmFormat: true, key } }];\n}\n"
  },
  {
    "path": "test/jsonml-formatter.spec.ts",
    "content": "import { describe, expect, it, assert, beforeEach } from 'vitest';\nimport { IJsonMLFormatter } from '../src/CommonTypes';\nimport * as Styles from '../src/formatters/elements/Styles';\nimport JsonMLFormatter from '../src/formatters/JsonMLFormatter';\nimport * as B from './builders';\n\nlet formatter: IJsonMLFormatter;\n\nbeforeEach(() => {\n    formatter = new JsonMLFormatter(Styles.lightTheme);\n});\n\ndescribe('JSONML formatting', () => {\n    describe('Header values', () => {\n        describe('should return values for simple values', () => {\n            it('string', () => {\n                const value = B.str('string');\n                const expected = [B.MLString('string')];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('number', () => {\n                const value = B.n(1);\n                const expected = [B.MLNumber(1)];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('boolean True', () => {\n                const value = B.bool(true);\n                const expected = [B.MLBool(true)];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('boolean False', () => {\n                const value = B.bool(false);\n                const expected = [B.MLBool(false)];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n        describe('should return values for array like structures', () => {\n            it('Empty list', () => {\n                const value = B.list([], 'List');\n                const expected = [B.MLList('List', 0)];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('Array with one value', () => {\n                const value = B.list([B.n(1)], 'Array');\n                const expected = [\n                    [\n                        'span',\n                        { style: Styles.lightTheme.greyedStyle },\n                        '[',\n                        ['span', {}, B.MLNumber(1)],\n                        ']',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('Set with more values', () => {\n                const value = B.list(['a', 'b', 'c'], 'Set');\n                const expected = [B.MLList('Set', 3)];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('Tuple with three values', () => {\n                const value = B.tuple([B.str('a'), B.str('b'), B.str('c')]);\n                const expected = [\n                    B.MLTuple([\n                        B.MLString('a'),\n                        B.MLString('b'),\n                        B.MLString('c'),\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('Nested tuple should be truncated', () => {\n                const value = B.tuple([\n                    B.tuple([B.tuple([B.str('a'), B.str('b')]), B.str('c')]),\n                    B.str('d'),\n                ]);\n                const expected = [\n                    B.MLTuple([\n                        B.MLTuple([\n                            B.MLTuple([B.MLString('a'), B.MLEllipsis()]),\n                            B.MLEllipsis(),\n                        ]),\n                        B.MLString('d'),\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n        describe('should handle Types and Custom types', () => {\n            it('Type', () => {\n                const value = B.type('Nothing');\n                const expected = [B.MLCustomType('Nothing')];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('CustomType without values', () => {\n                const value = B.customType('CustomType', []);\n                const expected = [B.MLCustomType('CustomType')];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('CustomType with one value', () => {\n                const value = B.customType('CustomType', [B.n(1)]);\n                const expected = [\n                    B.MLCustomType('CustomType', [B.MLNumber(1)]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('CustomType with two terminal values', () => {\n                const value = B.customType('CustomType', [B.n(1), B.n(1)]);\n                const expected = [\n                    B.MLCustomType('CustomType', [\n                        ['span', {}, B.MLNumber(1)],\n                        ['span', {}, ' '],\n                        ['span', {}, B.MLNumber(1)],\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('CustomType with variants as custom types with values', () => {\n                const value = B.customType('Tree', [\n                    B.customType('Left', [B.n(1), B.n(2)]),\n                    B.customType('Right', [B.n(3), B.n(4)]),\n                ]);\n                const expected = [\n                    B.MLCustomType('Tree', [\n                        [\n                            'span',\n                            {},\n                            [\n                                'span',\n                                {},\n                                '( ',\n                                B.MLCustomType('Left', [B.MLEllipsis()]),\n                                ' )',\n                            ],\n                        ],\n                        ['span', {}, ' '],\n                        [\n                            'span',\n                            {},\n                            [\n                                'span',\n                                {},\n                                '( ',\n                                B.MLCustomType('Right', [B.MLEllipsis()]),\n                                ' )',\n                            ],\n                        ],\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n        describe('should handle Records', () => {\n            it('simple record', () => {\n                const value = B.record({ name: B.str('Name') });\n                const expected = [\n                    B.MLRecord([B.MLRecordValue('name', B.MLString('Name'))]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('record with two values', () => {\n                const value = B.record({ name: B.str('Name'), age: B.n(12) });\n                const expected = [\n                    B.MLRecord([\n                        B.MLRecordValue('name', B.MLString('Name')),\n                        B.MLRecordValue('age', B.MLNumber(12)),\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('record with long child content should be truncated to 50 chars', () => {\n                const value = B.record({\n                    name: B.str('Name'),\n                    string: B.str(\n                        'Some really long string to simulate long content for the record'\n                    ),\n                });\n                const expected = [\n                    B.MLRecord([\n                        B.MLRecordValue('name', B.MLString('Name')),\n                        B.MLEllipsis(),\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('record with long child content continued with short child content shoul not show the short one', () => {\n                const value = B.record({\n                    a: B.str('a'),\n                    b: B.str(\n                        'Some really long string to simulate long content for the record'\n                    ),\n                    c: B.str('c'),\n                });\n                const expected = [\n                    B.MLRecord([\n                        B.MLRecordValue('a', B.MLString('a')),\n                        B.MLEllipsis(),\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('record nested in the custom value should be shown with ellipsis', () => {\n                const value = B.customType('Tree', [\n                    B.list([B.record({ name: B.str('Name'), age: B.n(12) })]),\n                ]);\n\n                const expected = [\n                    B.MLCustomType('Tree', [\n                        [\n                            'span',\n                            { style: Styles.lightTheme.greyedStyle },\n                            '[',\n                            [\n                                'span',\n                                {},\n                                ['span', {}, '{ ', B.MLEllipsis(), ' }'],\n                            ],\n                            ']',\n                        ],\n                    ]),\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n\n        describe('should return values for Dict', () => {\n            it('Empty dict', () => {\n                const value = B.dict({});\n                const expected = [\n                    [\n                        'span',\n                        { style: 'color: grey; font-weight: normal;' },\n                        'Dict.empty',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('Nonempty dict should show Dict(#count)', () => {\n                const value = B.dict({ a: 'b', b: 'a' });\n\n                const expected = [\n                    [\n                        'span',\n                        { style: Styles.lightTheme.dataStructureNameStyle },\n                        'Dict',\n                        ['span', {}, '(2)'],\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n        describe('should return values for internals', () => {\n            it('Function', () => {\n                const value = { type: 'Function' };\n                const expected = [\n                    [\n                        'span',\n                        {\n                            style:\n                                'color: grey; font-weight: normal; font-style: italic;',\n                        },\n                        '<function>',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('Internals', () => {\n                const value = { type: 'Internals' };\n                const expected = [\n                    [\n                        'span',\n                        {\n                            style:\n                                'color: grey; font-weight: normal; font-style: italic;',\n                        },\n                        '<internals>',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n            it('Unit', () => {\n                const value = { type: 'Unit' };\n                const expected = [\n                    [\n                        'span',\n                        {\n                            style:\n                                'color: grey; font-weight: normal; font-style: italic;',\n                        },\n                        '()',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n        describe('should handle values for bytes and files', () => {\n            it('Bytes', () => {\n                const value = { type: 'Bytes', value: 1234 };\n                const expected = [\n                    [\n                        'span',\n                        {\n                            style: Styles.lightTheme.bytesStyle,\n                        },\n                        '1234 B',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n\n            it('Files', () => {\n                const value = { type: 'File', value: 'Name-of_the.file' };\n                const expected = [\n                    [\n                        'span',\n                        {\n                            style: Styles.lightTheme.bytesStyle,\n                        },\n                        'Name-of_the.file',\n                    ],\n                ];\n\n                expect(\n                    formatter.handleHeader(B.elmDebug(value)).toJSONML()\n                ).to.deep.equal(B.MLDebug(expected));\n            });\n        });\n    });\n    describe('Body values', () => {\n        describe('Values without body should return null', () => {\n            it('String', () => {\n                const value = B.str('String');\n\n                assert.isNull(formatter.handleBody(value));\n            });\n\n            it('Number', () => {\n                const value = B.n(12);\n\n                assert.isNull(formatter.handleBody(value));\n            });\n\n            it('Boolean', () => {\n                const value = B.bool(true);\n\n                assert.isNull(formatter.handleBody(value));\n            });\n\n            it('Unit', () => {\n                const value = { type: 'Unit' };\n\n                assert.isNull(formatter.handleBody(value));\n            });\n            it('Function', () => {\n                const value = { type: 'Function' };\n\n                assert.isNull(formatter.handleBody(value));\n            });\n            it('Internals', () => {\n                const value = { type: 'Internals' };\n\n                assert.isNull(formatter.handleBody(value));\n            });\n            it('Bytes', () => {\n                const value = { type: 'Bytes', value: 1234 };\n\n                assert.isNull(formatter.handleBody(value));\n            });\n            it('Files', () => {\n                const value = { type: 'File', value: 'Some_file.name' };\n\n                assert.isNull(formatter.handleBody(value));\n            });\n        });\n\n        describe('List values', () => {\n            it('Empty list should not be expandable', () => {\n                const value = B.list([]);\n\n                assert.isNull(formatter.handleBody(value));\n            });\n\n            it('List with value should be expandable', () => {\n                const value = B.list([B.n(1)]);\n\n                assert.isNotNull(formatter.handleBody(value));\n            });\n        });\n\n        describe.skip('should handle body of the record values', () => {\n            it('Record with one value', () => {\n                const value = B.record({ age: B.n(12) });\n                const expected = [B.MLKeyValueBody('age', B.n(12))];\n\n                expect(formatter.handleBody(value)?.toJSONML()).to.deep.equal(\n                    B.MLBody(expected)\n                );\n            });\n        });\n        describe.skip('should return values for array like structures', () => {\n            it('Empty list', () => {\n                const value = B.list([], 'List');\n                const expected: any = null;\n\n                expect(formatter.handleBody(value)).to.deep.equal(expected);\n            });\n            it('Array with 2 values', () => {\n                const value = B.list([B.n(2), B.n(3)], 'Array');\n                const expected: any = [\n                    B.MLKeyValueBody('[0]', B.MLNumber(2)),\n                    B.MLKeyValueBody('[1]', B.MLNumber(3)),\n                ];\n\n                expect(formatter.handleBody(value)?.toJSONML()).to.deep.equal(\n                    B.MLBody(expected)\n                );\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "test/jsonml.spec.ts",
    "content": "import { describe, expect, it} from 'vitest';\nimport JsonML from '../src/JsonML';\n\ndescribe('JsonML', () => {\n    it('should return span with empty values after construction', () => {\n        expect(new JsonML('span').toJSONML()).to.deep.equal(['span', {}]);\n    });\n\n    it('should return span with style attributes', () => {\n        expect(\n            new JsonML('span').withStyle('color: red;').toJSONML()\n        ).to.deep.equal(['span', { style: 'color: red;' }]);\n    });\n    it('should return div with text child node', () => {\n        expect(new JsonML('div').withText('child').toJSONML()).to.deep.equal([\n            'div',\n            {},\n            'child',\n        ]);\n    });\n    it('should return div with two child nodes', () => {\n        const child = new JsonML('span');\n        const parent = new JsonML('div').withChild(child);\n        expect(parent.toJSONML()).to.deep.equal(['div', {}, ['span', {}]]);\n    });\n});\n"
  },
  {
    "path": "test/parser.spec.ts",
    "content": "import { describe, expect, should, it} from 'vitest';\nimport { readFileSync } from 'fs';\nimport { generate } from 'pegjs';\nimport * as B from './builders';\n\nconst parser = generate(readFileSync('src/elm-debug.pegjs', 'utf8'));\n\ndescribe('Parsing', () => {\n    describe('Basic type parsing', () => {\n        it('without tag tag', () => {\n            expect(parser.parse(': True').value).to.deep.equal(B.bool(true));\n        });\n\n        it('with multiple `:` in the tag', () => {\n            expect(parser.parse('tag string :: : True').value).to.deep.equal(\n                B.bool(true)\n            );\n        });\n\n        it('with numbers in the tag', () => {\n          expect(parser.parse('1234567890: True').value).to.deep.equal(\n                B.bool(true)\n            );\n        });\n\n        it('with non alphabetic characters', () => {\n          expect(parser.parse('!@#$%^&*()_+-=[]{}|\\\\,./<>?~`: True').value).to.deep.equal(\n                B.bool(true)\n            );\n        });\n\n        it('with emojis in tag', () => {\n          expect(parser.parse('with 1 Emoji 👍 : False').value).to.deep.equal(\n                B.bool(false)\n            );\n        });\n\n\n        it('Boolean', () => {\n            expect(parser.parse('tag string: True').value).to.deep.equal(\n                B.bool(true)\n            );\n        });\n\n        it('Integer', () => {\n            expect(parser.parse('integer: 123').value).to.deep.equal({\n                type: 'Number',\n                value: 123,\n            });\n        });\n\n        it('Negative Integer', () => {\n            expect(parser.parse('integer: - 123').value).to.deep.equal({\n                type: 'Number',\n                value: -123,\n            });\n        });\n\n        describe('Non number values', () => {\n            it('Infinity', () => {\n                expect(parser.parse('integer: Infinity').value).to.deep.equal({\n                    type: 'Number',\n                    value: 'Infinity',\n                });\n            });\n            it('-Infinity', () => {\n                expect(parser.parse('integer: -Infinity').value).to.deep.equal({\n                    type: 'Number',\n                    value: '-Infinity',\n                });\n            });\n            it('NaN', () => {\n                expect(parser.parse('integer: NaN').value).to.deep.equal({\n                    type: 'Number',\n                    value: 'NaN',\n                });\n            });\n        });\n\n        it('Float', () => {\n            expect(parser.parse('float: 123.45').value).to.deep.equal({\n                type: 'Number',\n                value: 123.45,\n            });\n        });\n\n        it('Negative Float', () => {\n            expect(parser.parse('float: - 123.45').value).to.deep.equal({\n                type: 'Number',\n                value: -123.45,\n            });\n        });\n\n        it('String', () => {\n            expect(parser.parse('string: \"Lorem Ipsum.\"').value).to.deep.equal(\n                B.str('Lorem Ipsum.')\n            );\n        });\n\n        it('String with escaped quotes', () => {\n            expect(\n                parser.parse('string: \"Lorem Ipsum. \\\\\"with some quotes\\\\\"\"')\n                    .value\n            ).to.deep.equal(B.str('Lorem Ipsum. \"with some quotes\"'));\n        });\n    });\n\n    describe('Tuples', () => {\n        it('Empty tuple', () => {\n            expect(parser.parse('tuple: ()').value).to.deep.equal({\n                type: 'Unit',\n            });\n        });\n\n        it('Basic tuple', () => {\n            expect(parser.parse('tuple: (123, False)').value).to.deep.equal({\n                type: 'Tuple',\n                value: [{ type: 'Number', value: 123 }, B.bool(false)],\n            });\n        });\n\n        it('Arbitrary long tuple', () => {\n            expect(\n                parser.parse('tuple: (123, \"Some string.\", True, 12.34)').value\n            ).to.deep.equal({\n                type: 'Tuple',\n                value: [\n                    { type: 'Number', value: 123 },\n                    B.str('Some string.'),\n                    B.bool(true),\n                    { type: 'Number', value: 12.34 },\n                ],\n            });\n        });\n\n        it('Tuple in tuple', () => {\n            expect(\n                parser.parse('tuple in tuple: (123, (True, 12.34))').value\n            ).to.deep.equal({\n                type: 'Tuple',\n                value: [\n                    { type: 'Number', value: 123 },\n                    {\n                        type: 'Tuple',\n                        value: [B.bool(true), { type: 'Number', value: 12.34 }],\n                    },\n                ],\n            });\n        });\n        it('Tuple with one item is not a tuple', () => new Promise(done => { \n          try {\n                parser.parse('not tuple: (123)');\n          }\n          catch (err: any){\n            expect(err.name).to.eql('SyntaxError')\n          }\n          done();\n        }));\n    });\n\n    describe('List', () => {\n        it('Empty list', () => {\n            expect(parser.parse('list: []').value).to.deep.equal({\n                type: 'List',\n                value: [],\n            });\n        });\n\n        it('Singleton', () => {\n            expect(parser.parse('singleton: [1]').value).to.deep.equal({\n                type: 'List',\n                value: [{ type: 'Number', value: 1 }],\n            });\n        });\n        it('List', () => {\n            expect(\n                parser.parse('list: [\"s1\",\"s2\",\"s3\",\"s4\"]').value\n            ).to.deep.equal({\n                type: 'List',\n                value: [B.str('s1'), B.str('s2'), B.str('s3'), B.str('s4')],\n            });\n        });\n        it('List of tuples', () => {\n            expect(\n                parser.parse('list: [(\"s1\",\"s2\"),(\"s3\",\"s4\")]').value\n            ).to.deep.equal({\n                type: 'List',\n                value: [\n                    { type: 'Tuple', value: [B.str('s1'), B.str('s2')] },\n                    { type: 'Tuple', value: [B.str('s3'), B.str('s4')] },\n                ],\n            });\n        });\n    });\n\n    describe('Dict', () => {\n        it('Empty dict', () => {\n            expect(parser.parse('dict: Dict.fromList []').value).to.deep.equal({\n                type: 'Dict',\n                value: [],\n            });\n        });\n        it('Filled dict', () => {\n            expect(\n                parser.parse('dict: Dict.fromList [(1,\"a\"),(2,\"b\")]').value\n            ).to.deep.equal({\n                type: 'Dict',\n                value: [\n                    { key: { type: 'Number', value: 1 }, value: B.str('a') },\n                    { key: { type: 'Number', value: 2 }, value: B.str('b') },\n                ],\n            });\n        });\n    });\n\n    describe('Set', () => {\n        it('Empty Set', () => {\n            expect(parser.parse('Set: Set.fromList []').value).to.deep.equal({\n                type: 'Set',\n                value: [],\n            });\n        });\n        it('Filled set', () => {\n            expect(\n                parser.parse('Set: Set.fromList [\"1\",\"2\",\"3\"]').value\n            ).to.deep.equal({\n                type: 'Set',\n                value: [B.str('1'), B.str('2'), B.str('3')],\n            });\n        });\n    });\n\n    describe('Array', () => {\n        it('Empty Array', () => {\n            expect(\n                parser.parse('Array: Array.fromList []').value\n            ).to.deep.equal({ type: 'Array', value: [] });\n        });\n        it('Filled Array', () => {\n            expect(\n                parser.parse('Array: Array.fromList [\"1\",\"2\",\"3\"]').value\n            ).to.deep.equal({\n                type: 'Array',\n                value: [B.str('1'), B.str('2'), B.str('3')],\n            });\n        });\n    });\n\n    describe('Record', () => {\n        it('Empty record', () => {\n            expect(parser.parse('record: {}').value).to.deep.equal({\n                type: 'Record',\n                value: {},\n            });\n        });\n        it('Record', () => {\n            expect(\n                parser.parse('record: { name = \"Name\" }').value\n            ).to.deep.equal({\n                type: 'Record',\n                value: { name: B.str('Name') },\n            });\n        });\n        it('Record with more values', () => {\n            expect(\n                parser.parse(\n                    'record: { name = \"Name\", warning = Nothing, waves = [] }'\n                ).value\n            ).to.deep.equal({\n                type: 'Record',\n                value: {\n                    name: B.str('Name'),\n                    warning: { type: 'Type', name: 'Nothing' },\n                    waves: { type: 'List', value: [] },\n                },\n            });\n        });\n        it('Nested records', () => {\n            expect(\n                parser.parse(\n                    'record: { name = \"Name\", warning = { name = Nothing, waves = [] } }'\n                ).value\n            ).to.deep.equal({\n                type: 'Record',\n                value: {\n                    name: B.str('Name'),\n                    warning: {\n                        type: 'Record',\n                        value: {\n                            name: { type: 'Type', name: 'Nothing' },\n                            waves: { type: 'List', value: [] },\n                        },\n                    },\n                },\n            });\n        });\n        it('Vector', () => {\n            expect(\n                parser.parse('vec: { 0 = 0, 1 = 0, 2 = 0 }').value\n            ).to.deep.equal({\n                type: 'Record',\n                value: {\n                    '0': { type: 'Number', value: 0 },\n                    '1': { type: 'Number', value: 0 },\n                    '2': { type: 'Number', value: 0 },\n                },\n            });\n        });\n    });\n\n    describe('Custom types', () => {\n        it('Custom type name with number', () => {\n            expect(\n                parser.parse('custom type: User1 \"Adam\"').value\n            ).to.deep.equal({\n                name: 'User1',\n                type: 'Custom',\n                value: [B.str('Adam')],\n            });\n        });\n        it('Custom type name with underscore', () => {\n            expect(\n                parser.parse('custom type: User_name \"Adam\"').value\n            ).to.deep.equal({\n                name: 'User_name',\n                type: 'Custom',\n                value: [B.str('Adam')],\n            });\n        });\n        it('Custom type with one value', () => {\n            expect(\n                parser.parse('custom type: User \"Adam\"').value\n            ).to.deep.equal({\n                name: 'User',\n                type: 'Custom',\n                value: [B.str('Adam')],\n            });\n        });\n        it('Custom type with more values', () => {\n            expect(\n                parser.parse('custom type: User \"Adam\" 123 (1,False)').value\n            ).to.deep.equal({\n                name: 'User',\n                type: 'Custom',\n                value: [\n                    B.str('Adam'),\n                    { type: 'Number', value: 123 },\n                    {\n                        type: 'Tuple',\n                        value: [{ type: 'Number', value: 1 }, B.bool(false)],\n                    },\n                ],\n            });\n        });\n        it('Custom type in parenthesis', () => {\n            expect(\n                parser.parse('custom type: (User (Data \"Adam\" 123 (1,False)))')\n                    .value\n            ).to.deep.equal({\n                name: 'User',\n                type: 'Custom',\n                value: [\n                    {\n                        name: 'Data',\n                        type: 'Custom',\n                        value: [\n                            B.str('Adam'),\n                            { type: 'Number', value: 123 },\n                            {\n                                type: 'Tuple',\n                                value: [\n                                    { type: 'Number', value: 1 },\n                                    B.bool(false),\n                                ],\n                            },\n                        ],\n                    },\n                ],\n            });\n        });\n        it('Custom type in parenthesis with record', () => {\n            expect(\n                parser.parse('custom type: (User { age = 23 })').value\n            ).to.deep.equal({\n                name: 'User',\n                type: 'Custom',\n                value: [\n                    {\n                        type: 'Record',\n                        value: { age: { type: 'Number', value: 23 } },\n                    },\n                ],\n            });\n        });\n        it('Custom type with two Nothings next to each other', () => {\n            expect(\n                parser.parse(\n                    'custom type: CacheKey (Id \"cache_id\") Nothing Nothing'\n                ).value\n            ).to.deep.equal({\n                name: 'CacheKey',\n                type: 'Custom',\n                value: [\n                    {\n                      name: 'Id',\n                      type: 'Custom',\n                      value: [\n                        {type: 'String',\n                        value: \"cache_id\"\n                        }\n                      ]\n                    }\n                    ,{\n                      name: 'Nothing',\n                      type: 'Type',\n                    }\n                    ,{\n                      name: 'Nothing',\n                      type: 'Type',\n                    }\n                ],\n\n            });\n        });\n        it('Custom type with more values in parenthesis', () => {\n            expect(\n                parser.parse(\n                    'custom type: User (Data \"(tuple, in, string)\" 123 (1,False))'\n                ).value\n            ).to.deep.equal({\n                name: 'User',\n                type: 'Custom',\n                value: [\n                    {\n                        name: 'Data',\n                        type: 'Custom',\n                        value: [\n                            B.str('(tuple, in, string)'),\n                            { type: 'Number', value: 123 },\n                            {\n                                type: 'Tuple',\n                                value: [\n                                    { type: 'Number', value: 1 },\n                                    B.bool(false),\n                                ],\n                            },\n                        ],\n                    },\n                ],\n            });\n        });\n    });\n\n    describe('Internals', () => {\n        it('Function value', () => {\n            expect(parser.parse('custom type: <function>').value).to.deep.equal(\n                { type: 'Function' }\n            );\n        });\n        it('Internals value', () => {\n            expect(\n                parser.parse('custom type: <internals>').value\n            ).to.deep.equal({ type: 'Internals' });\n        });\n    });\n\n    describe('Bytes', () => {\n        it('Bytes', () => {\n            expect(parser.parse('bytes: <24294 bytes>').value).to.deep.equal({\n                type: 'Bytes',\n                value: 24294,\n            });\n        });\n    });\n\n    describe('File', () => {\n        it('File', () => {\n            expect(\n                parser.parse(\n                    'file: <Some-name-[and]_extrachars(0000239649).extension>'\n                ).value\n            ).to.deep.equal({\n                type: 'File',\n                value: 'Some-name-[and]_extrachars(0000239649).extension',\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "test/simple-formatter.spec.ts",
    "content": "import { beforeEach, describe, expect, should, it} from 'vitest';\nimport { IFormatter } from '../src/CommonTypes';\nimport SimpleFormatter from '../src/formatters/SimpleFormatter';\nimport * as B from './builders';\n\nlet formatter: IFormatter;\n\nbeforeEach(() => {\n    formatter = new SimpleFormatter();\n});\n\ndescribe('Simple formatting', () => {\n    describe('should return values for simple values', () => {\n        it('string', () => {\n            expect(formatter.format(B.elmDebug(B.str('string')))).to.deep.equal(\n                {\n                    Debug: 'string',\n                }\n            );\n        });\n\n        it('int', () => {\n            expect(formatter.format(B.elmDebug(B.n(123)))).to.deep.equal({\n                Debug: 123,\n            });\n        });\n\n        it('bool', () => {\n            expect(formatter.format(B.elmDebug(B.bool(false)))).to.deep.equal({\n                Debug: false,\n            });\n        });\n        it('unit', () => {\n            expect(\n                formatter.format(B.elmDebug({ type: 'Unit' }))\n            ).to.deep.equal({\n                Debug: '()',\n            });\n        });\n    });\n\n    describe('should return values for lists', () => {\n        it('empty list', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(\n                        B.record({\n                            list: B.list([]),\n                        })\n                    )\n                )\n            ).to.deep.equal({ Debug: { list: [] } });\n        });\n\n        it('numbers list', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(\n                        B.record({\n                            list: B.list([B.n(1), B.n(2), B.n(3)]),\n                        })\n                    )\n                )\n            ).to.deep.equal({ Debug: { list: [1, 2, 3] } });\n        });\n    });\n\n    describe('should return values for custom types', () => {\n        it('Simple type', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(\n                        B.record({\n                            list: B.list([]),\n                        })\n                    )\n                )\n            ).to.deep.equal({ Debug: { list: [] } });\n        });\n\n        it('list of Maybe types', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(\n                        B.record({\n                            list: B.list([\n                                B.type('Nothing'),\n                                B.customType('Just', [\n                                    B.list([B.str('String')]),\n                                ]),\n                                B.type('Nothing'),\n                                B.type('Nothing'),\n                            ]),\n                        })\n                    )\n                )\n            ).to.deep.equal({\n                Debug: {\n                    list: [\n                        'Nothing',\n                        { Just: ['String'] },\n                        'Nothing',\n                        'Nothing',\n                    ],\n                },\n            });\n        });\n\n        it('Custom with just one value', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(B.customType('Just', [B.str('String')]))\n                )\n            ).to.deep.equal({ Debug: { Just: 'String' } });\n        });\n\n        it('Nested custom', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(\n                        B.customType('Just', [\n                            B.customType('Node', [\n                                B.customType('Leaf', [B.n(1)]),\n                                B.customType('Leaf', [B.n(2)]),\n                            ]),\n                        ])\n                    )\n                )\n            ).to.deep.equal({\n                Debug: { Just: { Node: [{ Leaf: 1 }, { Leaf: 2 }] } },\n            });\n        });\n    });\n\n    describe('should return values for records', () => {\n        it('simple record', () => {\n            expect(\n                formatter.format(\n                    B.elmDebug(B.record({ name: B.str('Name'), age: B.n(12) }))\n                )\n            ).to.deep.equal({ Debug: { name: 'Name', age: 12 } });\n        });\n    });\n\n    describe('should return values for dictionaries', () => {\n        it('handles simple record', () => {\n            const value = B.elmDebug(\n                B.dict({ name: B.str('Name'), age: B.str('12') })\n            );\n\n            expect(formatter.format(value)).to.deep.equal({\n                Debug: {\n                    age: '12',\n                    name: 'Name',\n                },\n            });\n        });\n    });\n\n    describe('should return values for internals', () => {\n        it('Function', () => {\n            const value = B.elmDebug({ type: 'Function' });\n\n            expect(formatter.format(value)).to.deep.equal({\n                Debug: '<function>',\n            });\n        });\n\n        it('Internals', () => {\n            const value = B.elmDebug({ type: 'Internals' });\n\n            expect(formatter.format(value)).to.deep.equal({\n                Debug: '<internals>',\n            });\n        });\n    });\n\n    describe('should return values for bytes and files', () => {\n        it('Bytes', () => {\n            const value = B.elmDebug({ type: 'Bytes', value: 1234 });\n\n            expect(formatter.format(value)).to.deep.equal({ Debug: '1234 B' });\n        });\n\n        it('Files', () => {\n            const value = B.elmDebug({\n                type: 'File',\n                value: 'Name-of_the.file',\n            });\n\n            expect(formatter.format(value)).to.deep.equal({\n                Debug: 'Name-of_the.file',\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"lib\": [\n      \"DOM\",\n      \"DOM.Iterable\",\n      \"ESNext\"\n    ],\n    \"types\": [\n      \"vite/client\",\n      \"node\",\n    ],\n    \"allowJs\": false,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noImplicitAny\": false,\n    \"noEmit\": true,\n    \"jsx\": \"preserve\",\n    \"baseUrl\": \"./\",\n    \"paths\": {\n      \"~/*\": [\n        \"src/*\"\n      ]\n    }\n  },\n  \"include\": [\n    \"./src\"\n  ],\n  \"exclude\": [\n    \"src/elm-debug-parser.ts\",\n    \"node_modules\",\n    \"elm-app\"\n  ]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"extends\": [\n    \"tslint:latest\",\n    \"tslint-config-prettier\"\n  ],\n  \"linterOptions\": {\n    \"exclude\": [\n      \"src/**/elm-debug-parser.ts\",\n      \"elm-app\"\n    ]\n  },\n  \"jsRules\": {},\n  \"rules\": {\n    \"no-console\": [\n      false\n    ],\n    \"max-classes-per-file\": [\n      false\n    ]\n  },\n  \"rulesDirectory\": []\n}\n"
  },
  {
    "path": "vite.config.js",
    "content": "// vite.config.ts\nimport { defineConfig } from \"vite\";\n\nimport typescript from \"@rollup/plugin-typescript\";\nimport path from \"path\";\nimport { typescriptPaths } from \"rollup-plugin-typescript-paths\";\n\nexport default defineConfig({\n  plugins: [],\n  resolve: {\n    alias: [\n      {\n        find: \"~\",\n        replacement: path.resolve(__dirname, \"./src\"),\n      },\n    ],\n  },\n  server: {\n    port: 3000,\n  },\n  build: {\n    manifest: true,\n    minify: true,\n    reportCompressedSize: true,\n    lib: {\n      entry: path.resolve(__dirname, \"src/index.ts\"),\n      fileName: \"index\",\n      formats: [\"es\", \"cjs\"],\n    },\n    rollupOptions: {\n      external: [],\n      plugins: [\n        typescriptPaths({\n          preserveExtensions: true,\n        }),\n        typescript({\n          sourceMap: false,\n          declaration: true,\n          outDir: \"dist\",\n        }),\n      ],\n    },\n  },\n});\n"
  },
  {
    "path": "vitest.config.js",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  define: { global: \"window\", \"process.env\": process.env },\n  test: {\n    environment: \"jsdom\"\n  }\n});\n"
  }
]